Files
openclaw/skills/contract-audit/scripts/fill_contract_template.py
2026-03-01 17:44:19 +03:00

63 lines
1.9 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
import json
import re
from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED
def fill_docx_template(template_path: str, output_path: str, data: dict) -> int:
with ZipFile(template_path, 'r') as zin:
xml = zin.read('word/document.xml').decode('utf-8', 'ignore')
replaced = 0
for key, value in data.items():
ph = '{{' + str(key) + '}}'
val = str(value)
count = xml.count(ph)
if count:
replaced += count
xml = xml.replace(ph, val)
# warn on unresolved placeholders
unresolved = sorted(set(re.findall(r'\{\{[^{}]+\}\}', xml)))
with ZipFile(template_path, 'r') as zin, ZipFile(output_path, 'w', ZIP_DEFLATED) as zout:
for item in zin.infolist():
content = zin.read(item.filename)
if item.filename == 'word/document.xml':
content = xml.encode('utf-8')
zout.writestr(item, content)
print(f'written: {output_path}')
print(f'replaced: {replaced}')
if unresolved:
print('unresolved_placeholders:')
for u in unresolved:
print(f' - {u}')
else:
print('unresolved_placeholders: none')
return 0
def main():
ap = argparse.ArgumentParser()
ap.add_argument('--template', required=True, help='Path to .docx template with {{PLACEHOLDER}}')
ap.add_argument('--data', required=True, help='Path to JSON map: {"PLACEHOLDER":"value"}')
ap.add_argument('--out', required=True, help='Output .docx path')
args = ap.parse_args()
template = Path(args.template)
data_path = Path(args.data)
out = Path(args.out)
with open(data_path, 'r', encoding='utf-8') as f:
data = json.load(f)
out.parent.mkdir(parents=True, exist_ok=True)
raise SystemExit(fill_docx_template(str(template), str(out), data))
if __name__ == '__main__':
main()