Spaces:
Sleeping
Sleeping
File size: 6,445 Bytes
061a93c f547301 061a93c 295d256 061a93c 295d256 061a93c 295d256 f547301 295d256 f547301 295d256 f547301 295d256 f547301 fde5743 f547301 fde5743 f547301 fde5743 061a93c f547301 061a93c 295d256 fde5743 295d256 061a93c 295d256 061a93c |
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 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
import csv
from fpdf import FPDF
import tempfile
import os
def _safe_text_for_pdf(s: object) -> str:
"""
Ensure text passed to FPDF only contains characters encodable in latin-1.
FPDF (classic) writes using latin-1 encoding by default and will raise
an error when encountering characters outside that range (e.g. •).
This helper replaces unsupported characters with a best-effort replacement
so PDF generation doesn't fail.
"""
if s is None:
return ""
try:
text = str(s)
except Exception:
text = ""
# encode -> decode using latin-1 with replacement to avoid exceptions
return text.encode('latin-1', 'replace').decode('latin-1')
def export_evidence_pack_pdf(data, filename=None):
"""
Export evidence pack as PDF. Data should include clause, summary, checklist, scenario, metadata.
Returns path to PDF file.
"""
pdf = FPDF()
pdf.add_page()
pdf.set_font("Arial", "B", size=16)
pdf.cell(200, 10, txt="Evidence Pack", ln=True, align='C')
pdf.ln(10)
# Clause section
pdf.set_font("Arial", "B", size=12)
pdf.cell(0, 8, txt="Clause:", ln=True)
pdf.set_font("Arial", size=10)
clause_text = data.get('clause_text', 'No clause information available')
pdf.multi_cell(0, 6, _safe_text_for_pdf(clause_text))
pdf.ln(3)
# Summary section
pdf.set_font("Arial", "B", size=12)
pdf.cell(0, 8, txt="Summary:", ln=True)
pdf.set_font("Arial", size=10)
summary_text = data.get('summary', 'No summary available')
pdf.multi_cell(0, 6, _safe_text_for_pdf(summary_text))
pdf.ln(3)
# Checklist section
pdf.set_font("Arial", "B", size=12)
pdf.cell(0, 8, txt="Checklist:", ln=True)
pdf.set_font("Arial", size=10)
checklist = data.get('role_checklist', [])
if checklist:
for item in checklist:
# use a simple hyphen bullet and sanitize text
pdf.multi_cell(0, 6, _safe_text_for_pdf(f"- {item}"))
else:
pdf.multi_cell(0, 6, "No checklist items available")
pdf.ln(3)
# Source information section
pdf.set_font("Arial", "B", size=12)
pdf.cell(0, 8, txt="Source Information:", ln=True)
pdf.set_font("Arial", size=10)
pdf.multi_cell(0, 6, _safe_text_for_pdf(f"Source: {data.get('source_title', 'Not specified')}"))
pdf.multi_cell(0, 6, _safe_text_for_pdf(f"Clause ID: {data.get('clause_id', 'Not assigned')}"))
pdf.multi_cell(0, 6, _safe_text_for_pdf(f"Date: {data.get('date', 'Not specified')}"))
pdf.multi_cell(0, 6, _safe_text_for_pdf(f"URL: {data.get('url', 'Not available')}"))
# User role and context information
if data.get('user_role'):
pdf.multi_cell(0, 6, _safe_text_for_pdf(f"User Role: {data.get('user_role', '').title()}"))
if data.get('language_preference'):
pdf.multi_cell(0, 6, _safe_text_for_pdf(f"Language: {data.get('language_preference', '').title()}"))
pdf.ln(5)
scenario = data.get('scenario_analysis',{})
if scenario:
pdf.multi_cell(0, 8, _safe_text_for_pdf(f"Scenario Analysis:"))
pdf.multi_cell(0, 8, _safe_text_for_pdf(f"Yearly Results: {scenario.get('yearly_results','')}"))
pdf.multi_cell(0, 8, _safe_text_for_pdf(f"Cumulative Base: {scenario.get('cumulative_base','')}"))
pdf.multi_cell(0, 8, _safe_text_for_pdf(f"Cumulative Scenario: {scenario.get('cumulative_scenario','')}"))
pdf.multi_cell(0, 8, _safe_text_for_pdf(f"Optimistic: {scenario.get('optimistic','')}"))
pdf.multi_cell(0, 8, _safe_text_for_pdf(f"Pessimistic: {scenario.get('pessimistic','')}"))
pdf.multi_cell(0, 8, _safe_text_for_pdf(f"Driver Breakdown: {scenario.get('driver_breakdown','')}"))
if not filename:
filename = os.path.join(tempfile.gettempdir(), f"evidence_pack_{os.getpid()}.pdf")
pdf.output(filename)
return filename
def export_evidence_pack_csv(data, filename=None):
"""
Export evidence pack as CSV. Data should include clause, summary, checklist, scenario, metadata.
Returns path to CSV file.
"""
if not filename:
filename = os.path.join(tempfile.gettempdir(), f"evidence_pack_{os.getpid()}.csv")
with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(["Field", "Value"])
writer.writerow(["Clause", data.get('clause_text', 'No clause information available')])
writer.writerow(["Summary", data.get('summary', 'No summary available')])
# Handle checklist properly
checklist = data.get('role_checklist', [])
if checklist:
checklist_text = '; '.join(checklist)
else:
checklist_text = "No checklist items available"
writer.writerow(["Checklist", checklist_text])
writer.writerow(["Source", data.get('source_title', 'Not specified')])
writer.writerow(["Clause ID", data.get('clause_id', 'Not assigned')])
writer.writerow(["Date", data.get('date', 'Not specified')])
writer.writerow(["URL", data.get('url', 'Not available')])
# Add timestamp if available
if 'timestamp' in data:
writer.writerow(["Generated At", data.get('timestamp', '')])
# Add original query if available
if 'original_query' in data:
writer.writerow(["Original Query", data.get('original_query', '')])
# Add user context information
if 'user_role' in data:
writer.writerow(["User Role", data.get('user_role', '').title()])
if 'language_preference' in data:
writer.writerow(["Language Preference", data.get('language_preference', '').title()])
scenario = data.get('scenario_analysis', {})
if scenario:
writer.writerow(["=== SCENARIO ANALYSIS ===", ""])
writer.writerow(["Yearly Results", scenario.get('yearly_results', '')])
writer.writerow(["Cumulative Base", scenario.get('cumulative_base', '')])
writer.writerow(["Cumulative Scenario", scenario.get('cumulative_scenario', '')])
writer.writerow(["Optimistic", scenario.get('optimistic', '')])
writer.writerow(["Pessimistic", scenario.get('pessimistic', '')])
writer.writerow(["Driver Breakdown", scenario.get('driver_breakdown', '')])
return filename
|