-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathdocx_exporter.py
More file actions
124 lines (105 loc) · 4.23 KB
/
Copy pathdocx_exporter.py
File metadata and controls
124 lines (105 loc) · 4.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
"""
DOCX export for LegalAssist AI.
Generates standards-compliant Office Open XML documents.
"""
import logging
from io import BytesIO
from datetime import datetime
from typing import Optional
from docx import Document
from docx.shared import Inches, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.style import WD_STYLE_TYPE
from database import SessionLocal, Case, CaseDocument, CaseDeadline, CaseTimeline
logger = logging.getLogger(__name__)
ACCENT_COLOR = RGBColor(231, 76, 60)
DARK_BLUE = RGBColor(44, 62, 80)
TEXT_COLOR = RGBColor(40, 40, 40)
def generate_case_docx(case_id: int, user_id: int) -> Optional[bytes]:
"""Generate a standards-compliant DOCX case summary."""
db = SessionLocal()
try:
case = db.query(Case).filter(Case.id == case_id).first()
if not case:
return None
if case.user_id != user_id:
logger.warning("Unauthorized DOCX export attempt", case_id=case_id, user_id=user_id)
return None
documents = db.query(CaseDocument).filter(CaseDocument.case_id == case_id).all()
deadlines = db.query(CaseDeadline).filter(CaseDeadline.case_id == case_id).all()
timeline = db.query(CaseTimeline).filter(CaseTimeline.case_id == case_id).all()
doc = Document()
style = doc.styles["Normal"]
style.font.name = "Calibri"
style.font.size = Pt(11)
style.font.color.rgb = TEXT_COLOR
# Title
title = doc.add_heading("Case Summary", level=0)
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
# Classification
doc.add_heading("Case Classification", level=1)
_label_value(doc, "Case Type", case.case_type.title() if case.case_type else "N/A")
_label_value(doc, "Jurisdiction", case.jurisdiction)
_label_value(doc, "Status", case.status.value.title() if case.status else "N/A")
_label_value(doc, "Filed", case.created_at.strftime("%d %B %Y") if case.created_at else "N/A")
# Documents
doc.add_heading("Evidence Summary", level=1)
if documents:
for d in documents:
p = doc.add_paragraph()
run = p.add_run(f"Type: {d.document_type.value} ")
run.bold = True
run.font.size = Pt(10)
if d.summary:
doc.add_paragraph(d.summary)
else:
doc.add_paragraph("No associated documents.")
# Deadlines
doc.add_heading("Deadlines", level=1)
if deadlines:
table = doc.add_table(rows=1, cols=3)
table.style = "Light Shading Accent 1"
hdr = table.rows[0].cells
hdr[0].text = "Type"
hdr[1].text = "Date"
hdr[2].text = "Status"
for dl in deadlines:
row = table.add_row().cells
row[0].text = dl.deadline_type
row[1].text = dl.deadline_date.strftime("%d %b %Y") if dl.deadline_date else ""
row[2].text = "Completed" if dl.is_completed else "Pending"
else:
doc.add_paragraph("No deadlines recorded.")
# Timeline
doc.add_heading("Procedural Timeline", level=1)
if timeline:
for event in timeline[:20]:
p = doc.add_paragraph()
run = p.add_run(event.event_date.strftime("%d %b %Y") + " ")
run.bold = True
run.font.size = Pt(9)
p.add_run(event.event_type.replace("_", " ").title())
else:
doc.add_paragraph("No timeline events.")
# Footer
doc.add_paragraph()
footer = doc.add_paragraph()
footer.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = footer.add_run("Generated by LegalAssist AI")
run.font.size = Pt(8)
run.font.color.rgb = RGBColor(160, 160, 160)
buffer = BytesIO()
doc.save(buffer)
buffer.seek(0)
return buffer.read()
except Exception as e:
logger.error("DOCX generation failed", exc_info=e)
return None
finally:
db.close()
def _label_value(doc, label: str, value: str):
p = doc.add_paragraph()
run = p.add_run(f"{label}: ")
run.bold = True
run.font.size = Pt(10)
p.add_run(str(value))