Files
Chaim bfec8bdaa3
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 6s
Add dafna-decision-template skill — knowledge for template-based DOCX export
Documents the rules and decisions behind building DOCX files from דפנה's
decision template (טיוטת החלטה.dotx). The implementation lives in
mcp-server/src/legal_mcp/services/analysis_docx_exporter.py; this skill
captures the "why" so future improvements don't need to rediscover it.

Contents:
  SKILL.md                       5 critical rules, style mapping table,
                                 export flow, line classification,
                                 dash policy, placeholder handling,
                                 troubleshooting, future TODOs
  references/dotx-to-docx.md     why python-docx can't open .dotx +
                                 the conversion recipe
  references/rtl-runs.md         why <w:rtl/> is required on every run
                                 (otherwise Hebrew falls back to
                                 Times New Roman)
  references/style-mapping.md    XML dump of every template style,
                                 with the Title-via-theme gotcha
  references/line-classification.md  the 7 regex categories in
                                 _classify_line() with real examples

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 18:57:57 +00:00

12 KiB
Raw Permalink Blame History

name, description
name description
dafna-decision-template ייצוא מסמכי DOCX עבור ועדת ערר לתכנון ובניה מחוז ירושלים (יו"ר עו"ד דפנה תמיר), באמצעות שימוש בסגנונות המוגדרים בטמפלט Word של דפנה (`טיוטת החלטה.dotx`). הסקיל מחיל את סגנונות הטמפלט (Normal/Heading 1/Heading 2/Quote/List Paragraph) על תוכן שנכתב מתוכנתית — בלי להגדיר פונט/גודל/RTL/שוליים ידנית. טריגרים: "ייצוא החלטה", "ייצוא ניתוח משפטי", "DOCX של דפנה", "טמפלט החלטה", "סגנונות החלטה", "Word עם David", "מסמך ועדת ערר", "הורדת החלטה", "פסקה ממוספרת בעברית", "(א) (ב) (ג)", כל בקשה להוציא מסמך Word המבוסס על טמפלט דפנה.

Dafna Decision Template — ייצוא DOCX מסגנונות טמפלט

מה זה עושה

סקיל זה הוא layer דק מעל python-docx שמטעין את הטמפלט של דפנה (skills/docx/decision_template.docx — מומר מ-data/training/טיוטת החלטה.dotx) וכותב תוכן חדש על בסיסו, על ידי שיוך שמות סגנונות בלבד (paragraph.style = "Heading 2"). העיצוב — פונט David, RTL, גדלים, הזחות, מספור אוטומטי — מגיע מה-styles.xml של הטמפלט.

השירות המעשי נמצא ב- mcp-server/src/legal_mcp/services/analysis_docx_exporter.py. הסקיל מתעד את הכללים שה-service מיישם, כך שניתן לשחזר/להרחיב אותם בסקריפטים אחרים ללא צורך לגלות הכל מחדש.


🔴 קריטי — 5 עקרונות שחייבים לזכור

1. לא להגדיר font/size/indent ידנית — תמיד style

# ❌ אל
run.font.name = "David"; run.font.size = Pt(13)
paragraph.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.RIGHT

# ✅ כן
paragraph = doc.add_paragraph(style="Normal")   # כל השאר מגיע מהטמפלט

2. RTL חייב דגלים ב-paragraph וב-run — גם אם הסגנון כולל bidi

# ❌ אל — עברית תצא ב-Times New Roman כי Word לא יודע שזה complex-script
p = doc.add_paragraph(style="Normal")
p.add_run("טקסט בעברית")

# ✅ כן — מסמנים את ה-run כ-RTL
p = doc.add_paragraph(style="Normal")
_mark_paragraph_rtl(p)
run = p.add_run("טקסט בעברית")
_mark_run_rtl(run)    # ← מוסיף <w:rtl/> ל-rPr

בלי הדגל הזה, Word נופל בחזרה ל-ascii font (Times New Roman) במקום ל-cs font (David). זו הסיבה הנפוצה ביותר לתוצאה "עברית ב-Times New Roman".

ראה references/rtl-runs.md לפרטים מלאים.

3. .dotx לא נטען ישירות — יש להמיר ל-.docx פעם אחת

python-docx פותח רק .docx. להמרה: scripts/convert_decision_template.py (בשורש הפרויקט). יש להסיר:

  • word/glossary/* parts
  • Override entries שמצביעים אליהם ב-[Content_Types].xml
  • Relationship glossaryDocument ב-word/_rels/document.xml.rels
  • להחליף content-type מ-...template.main+xml ל-...document.main+xml

ראה references/dotx-to-docx.md.

4. Title לא טוב ככותרת עברית — השתמש ב-Heading 1

הסגנון Title בטמפלט מפנה ל-theme fonts (majorFont). ב-theme1.xml: majorFont.latin = "Aptos Display", majorFont.cs = "" (ריק). לכן עברית תרונדר ב-Latin fallback.

Heading 1 יורש cs="David" מ-Normal — השתמש בו לכותרת ראשית.

5. מספור אוטומטי רק ב-List Paragraph — decimal בלבד

List Paragraph (styleId a0) מקושר ל-numId=1 → numFmt=decimal. כלומר Word יוסיף אוטומטית "1.", "2.", "3." לכל פסקה עם הסגנון הזה.

  • שורות שמתחילות ב-N. → הסר את המספר מהטקסט, החל List Paragraph.
  • שורות שמתחילות ב-(א) (ב) → השתמש ב-List Paragraph עם הסרת <w:numPr>, כי המספור בעברית נכתב בעצמו על ידי המחבר.
  • Bullets (- , ) → הסר את הסימן, השאר Normal.

ראה references/style-mapping.md.


הטמפלט — מיפוי סגנונות

מיפוי מלא של הסגנונות בטמפלט ל-content type. זה ה"חוזה" של הסקיל — כל שינוי דרך השירות צריך להיצמד אליו.

תוכן style name הערה
כותרת מסמך ("ניתוח משפטי וכתיבת עמדה בערר X") Heading 1 יורש cs="David"
כותרת מקטע ראשי (רקע דיוני, פסיקה כללית, סוגיות להכרעה, מסקנות) Heading 2 bold + underline
כותרת משנה בתוך סוגיה (טענה (claim), תשובה, ניתוח, נקודות פתוחות, …) Heading 2
שם subsection (טענת סף 1, סוגיה 2) Normal + bold run
פסקת רקע רגילה Normal David 13pt, justify, RTL
פסקת רשימה ממוספרת (1., 2., 3.) List Paragraph Word ימספר
פסקת רשימה בעברית ((א), (ב)) List Paragraph + _strip_numpr() המספור נשאר בטקסט
ציטוט פסיקה Quote bold + הזחה
citation / מקור Normal + italic

ראה references/style-mapping.md לטבלה מורחבת עם ה-XML של כל סגנון.


תוכן המקור — analysis-and-research.md

הקובץ נכתב על ידי legal-analyst agent. מבנה מצופה:

# ניתוח משפטי וכתיבת עמדה — ערר {case_number}
תאריך: DD.MM.YYYY

## רקע דיוני
{prose content}

## עובדות מוסכמות
1. ...

## עובדות שנויות במחלוקת
1. ...

## טענות סף
### טענה {n}: {title}
**עמדת המבקשת:** ...
**עמדת ועדת הערר:** [ימולא ע"י יו"ר הוועדה]

## סוגיות להכרעה
### סוגיה {n}: {title}
**ממצאים עובדתיים:**
...
**טענה (claim):**
העורר טוען כי:
(א) ...
(ב) ...
**ניתוח:**
...
- **נקודות פתוחות:**
  1. ...
- **הערכה ראשונית:** {prose}
**עמדת ועדת הערר:** [ימולא ע"י יו"ר הוועדה]

## מסקנות
...

ה-parser (research_md.py) חולק את זה ל-threshold_claims[], issues[], prose sections, ו-conclusions. חשוב: שמות sections חייבים להכיל את המילים המופתח (רקע דיוני, טענות סף, …) — ה-parser עובד לפי matching של keywords, לא לפי מספר ה-H2.


זרימת הייצוא

סדר המקטעים ב-DOCX (גם אם סדר ה-H2 ב-MD שונה):

  1. כותרת (Heading 1) + שורת תאריך
  2. רקע (Heading 2) — represented_party, procedural_background, agreed_facts, disputed_facts (אם קיימים)
  3. פסיקה כללית (Heading 2) — case_precedents עם section_id=NULL
  4. טענות סף (Heading 2) — לכל subsection: title, fields, chair_position, precedents
  5. סוגיות להכרעה (Heading 2) — אותה חלוקה
  6. מסקנות (Heading 2) — בסוף

הסיבה: בקריאה משפטית נכון להציג תחילה רקע ועובדות, ואז את הדיון. פסיקה כללית מופיעה לפני הסוגיות כי היא רוחבית.


עיבוד שורות — _classify_line()

ה-service מפרש כל שורה של content לאחת מ-6 קטגוריות:

kind דוגמה מה קורה
label_heading **נקודות פתוחות:** (שורה שלמה, כולל - **X:**) Heading 2
label_heading (plain) העורר טוען כי: (שורה קצרה שמסתיימת ב-:) Heading 2
inline_label **שאלה עקרונית:** מה... Normal עם label bold inline
numbered 1. הנספח אינו מחייב List Paragraph, המספר מוסר
bullet - nevo (קלאסי)... Normal, הסימן מוסר
heb_letter (א) הנספח אינו... List Paragraph + strip numPr
plain רגיל Normal

בנוסף, inline **...** מעובד בכל ריצה דרך _add_runs_with_inline_bold — כל **word** הופך ל-run נפרד עם bold=True.

ראה references/line-classification.md.


מקפים — מדיניות

המשתמש (דפנה) ביקשה: "לא רוצה מקפים בכלל". הסקיל מסיר:

  • (em-dash, U+2014)
  • (en-dash, U+2013)

מכל טקסט שהקוד כותב למסמך (גם תוכן מהמקור). מקפים רגילים (-) נשמרים. הפונקציה: _no_dash().


שדות ריקים — placeholder

שדה chair_position (עמדת ועדת הערר) שמכיל אחד מהסימנים הריקים ([ימולא ע"י יו"ר הוועדה], [טרם מולא], וכד') → מוחלף ב- [טרם מולאה עמדת ועדת הערר] בסגנון italic. זה סימן ויזואלי ברור שנשאר עדיין להשלים.


שימוש — API

from legal_mcp.services.analysis_docx_exporter import build_analysis_docx

path = await build_analysis_docx("8070-25")
# → data/cases/8070-25/exports/ניתוח-משפטי-v{N}.docx

Endpoint ציבורי: GET /api/cases/{case_number}/research/analysis/export-docx


התמודדות עם בעיות נפוצות

"עברית יוצאת ב-Times New Roman"

  • חסר <w:rtl/> ב-run. הוסף _mark_run_rtl(run) אחרי כל add_run.
  • בדוק: הסגנון שאתה משתמש בו יש בו cs="David" (או יורש מ-Normal שיש לו)?

"המספור כפול: '1. (א) ...'"

  • אתה משתמש ב-List Paragraph על שורה עם (א). צריך _strip_numpr(para).

"כוכביות **...** מופיעות במסמך"

  • הקפד להעביר תוכן דרך _add_runs_with_inline_bold(), לא paragraph.add_run().

"התבנית לא נטענת"

  • הרץ מחדש python scripts/convert_decision_template.py. בדוק שה-docx שנוצר פותחיb ב-Word ללא שגיאות.

"המספור ברשימה השנייה ממשיך מהראשונה (4,5,6 במקום 1,2,3)"

  • ידוע. הפתרון: להוסיף override של numId ברמת ה-paragraph הראשון של הרשימה החדשה. עדיין לא מיושם — ראה "שיפורים עתידיים".

שיפורים עתידיים (TODO)

  • Reset של מספור List Paragraph בין רשימות נפרדות (לא רציף).
  • תמיכה ב-פיסקת רשימה - ללא מספור (styleId -) לbullets.
  • עיצוב מותאם לסוג הערר (1xxx/8xxx/9xxx) — כרגע אחיד.
  • אפשרות להוריד רק מקטעים נבחרים (רק טענות סף, רק מסקנות, וכו').

מבנה קבצים

skills/dafna-decision-template/
├── SKILL.md                              ← הקובץ הזה
└── references/
    ├── dotx-to-docx.md                  ← איך ממירים .dotx ל-.docx
    ├── rtl-runs.md                       ← למה `<w:rtl/>` חשוב בכל run
    ├── style-mapping.md                  ← מיפוי מלא של סגנונות הטמפלט
    └── line-classification.md            ← לוגיקת _classify_line()

mcp-server/src/legal_mcp/services/
└── analysis_docx_exporter.py             ← המימוש המעשי

scripts/
└── convert_decision_template.py          ← המרת dotx → docx (חד-פעמי)

skills/docx/
└── decision_template.docx                ← הטמפלט המומר (artifact)

היסטוריה

גרסה תאריך שינוי
v1.0 2026-04-16 יצירת הסקיל. מיפוי ראשוני של סגנונות, תמיכה ב-RTL runs, inline bold, (א)(ב), Heading 1/2, מקטעי רקע.