Includes: - docs/: architecture, block-schema, migration-plan, product-specification - scripts/: bidi_table, decompose-decisions, extract-claims, seed-knowledge, etc. - skill-legal-decision/: SKILL.md + references + block-schema - skill-legal-assistant/: SKILL.md - skill-legal-docx/: SKILL.md + references - .claude/commands/: bidi-table skill - .taskmaster/: task config + PRDs - .gitignore: exclude legacy/, kiryat-yearim/, node_modules/, memory/ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
140 lines
4.6 KiB
Python
140 lines
4.6 KiB
Python
#!/usr/bin/env python3
|
||
"""Export a decision from DB to DOCX using the CJS template generator.
|
||
|
||
Usage: python export-decision-docx.py <case_number> [output.docx]
|
||
|
||
Pulls decision blocks from DB, generates structure JSON,
|
||
invokes create-decision-structure.cjs to produce DOCX.
|
||
"""
|
||
|
||
import asyncio
|
||
import json
|
||
import subprocess
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src"))
|
||
|
||
from legal_mcp.services.db import get_pool, init_schema, close_pool
|
||
|
||
CJS_SCRIPT = Path(__file__).parent.parent / "skill-legal-decision" / "scripts" / "create-decision-structure.cjs"
|
||
|
||
|
||
def block_id_to_hebrew(block_id: str) -> str:
|
||
"""Map block_id to Hebrew letter label."""
|
||
mapping = {
|
||
"block-alef": "א", "block-bet": "ב", "block-gimel": "ג",
|
||
"block-dalet": "ד", "block-he": "ה", "block-vav": "ו",
|
||
"block-zayin": "ז", "block-chet": "ח", "block-tet": "ט",
|
||
"block-yod": "י", "block-yod-alef": "יא", "block-yod-bet": "יב",
|
||
}
|
||
return mapping.get(block_id, "")
|
||
|
||
|
||
async def main():
|
||
if len(sys.argv) < 2:
|
||
print("שימוש: python export-decision-docx.py <מספר_תיק> [output.docx]")
|
||
sys.exit(1)
|
||
|
||
case_number = sys.argv[1]
|
||
output_path = sys.argv[2] if len(sys.argv) > 2 else f"החלטה-{case_number}.docx"
|
||
|
||
await init_schema()
|
||
pool = await get_pool()
|
||
|
||
async with pool.acquire() as conn:
|
||
# Get case info
|
||
case = await conn.fetchrow(
|
||
"SELECT * FROM cases WHERE case_number = $1", case_number
|
||
)
|
||
if not case:
|
||
print(f"תיק {case_number} לא נמצא")
|
||
sys.exit(1)
|
||
|
||
# Get decision
|
||
decision = await conn.fetchrow(
|
||
"SELECT * FROM decisions WHERE case_id = $1 AND status = 'final'",
|
||
case["id"],
|
||
)
|
||
if not decision:
|
||
print(f"אין החלטה סופית לתיק {case_number}")
|
||
sys.exit(1)
|
||
|
||
# Get blocks
|
||
blocks = await conn.fetch(
|
||
"""SELECT block_id, block_index, title, content, word_count
|
||
FROM decision_blocks
|
||
WHERE decision_id = $1
|
||
ORDER BY block_index""",
|
||
decision["id"],
|
||
)
|
||
|
||
await close_pool()
|
||
|
||
# Build structure JSON for CJS script
|
||
appellants = json.loads(case["appellants"]) if isinstance(case["appellants"], str) else case["appellants"]
|
||
respondents = json.loads(case["respondents"]) if isinstance(case["respondents"], str) else case["respondents"]
|
||
|
||
structure = {
|
||
"metadata": {
|
||
"case_number": case["case_number"],
|
||
"title": case["title"],
|
||
"subject": case["subject"],
|
||
"property_address": case["property_address"],
|
||
"committee": case["committee_type"],
|
||
"outcome": decision["outcome"] or "",
|
||
"decision_date": str(decision["decision_date"]) if decision["decision_date"] else "",
|
||
"author": decision["author"],
|
||
},
|
||
"parties": {
|
||
"appellants": [{"name": a} for a in appellants],
|
||
"respondents": [{"name": r} for r in respondents],
|
||
},
|
||
"blocks": [],
|
||
}
|
||
|
||
for block in blocks:
|
||
content = block["content"] or ""
|
||
# Skip empty header blocks
|
||
if block["block_id"] in ("block-alef", "block-bet", "block-gimel", "block-dalet") and not content:
|
||
continue
|
||
|
||
paragraphs = [p.strip() for p in content.split("\n") if p.strip()]
|
||
|
||
structure["blocks"].append({
|
||
"id": block["block_id"],
|
||
"index": block["block_index"],
|
||
"title": block["title"],
|
||
"hebrew_letter": block_id_to_hebrew(block["block_id"]),
|
||
"word_count": block["word_count"],
|
||
"paragraphs": paragraphs,
|
||
})
|
||
|
||
# Write JSON (absolute paths)
|
||
output_abs = Path(output_path).resolve()
|
||
json_path = output_abs.with_suffix(".json")
|
||
json_path.parent.mkdir(parents=True, exist_ok=True)
|
||
|
||
with open(json_path, "w", encoding="utf-8") as f:
|
||
json.dump(structure, f, ensure_ascii=False, indent=2)
|
||
print(f"JSON נוצר: {json_path}")
|
||
|
||
# Run CJS script with absolute paths
|
||
result = subprocess.run(
|
||
["node", str(CJS_SCRIPT), str(json_path), str(output_abs)],
|
||
capture_output=True, text=True,
|
||
cwd=str(CJS_SCRIPT.parent),
|
||
)
|
||
|
||
if result.returncode == 0:
|
||
print(f"✅ DOCX נוצר: {output_path}")
|
||
else:
|
||
print(f"❌ שגיאה ביצירת DOCX:")
|
||
print(result.stderr)
|
||
# JSON is still available for manual processing
|
||
print(f"ה-JSON זמין: {json_path}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
asyncio.run(main())
|