import os import tempfile from jinja2 import Template from loguru import logger HTML = None try: from weasyprint import HTML except (ImportError, OSError) as e: logger.warning(f"WeasyPrint failed to load (missing system GTK libraries): {e}. Fallback to HTML-as-PDF simulation is active.") # A premium, dark-themed HTML template for SRE / Readiness Audit PDF reports AUDIT_PDF_TEMPLATE = """ Archvise Production Readiness Report
Production Readiness Audit Panel

{{ project_name }}

Generated on {{ date_str }}
{{ report.overall_score }}
Production Readiness Score
Files Analyzed
{{ report.files_analyzed }}
Confidence Level
{{ report.confidence.level }} ({{ report.confidence.score }}%)
Safe Load Limit
{{ report.capacity_estimate.safe_range }}
Peak Load Limit
{{ report.capacity_estimate.peak_range }}
Critical Panel Findings
{% for agent_id, agent in report.agents.items() %} {% if agent.findings %}
{{ agent.agent_name }} · {{ agent.agent_role }}
Score: {{ agent.score }}/100
{% for finding in agent.findings %}
{{ finding.severity }} {{ finding.issue }}
Location: {{ finding.location }}
Details: {{ finding.engineer_text }}
{% endfor %}
{% endif %} {% endfor %}
Disclaimer: {{ report.score_disclaimer }}
""" # A premium, dark-themed HTML template for System Design PDF reports DESIGN_PDF_TEMPLATE = """ Archvise System Design Blueprint
System Design Blueprint

{{ design.title }}

Generated on {{ date_str }}
Architecture Type
{{ design.architecture_type }}
Uptime Target
{{ design.reliability.uptime_target }}
Executive Summary (Founder Mode)
{{ design.founder_summary }}
Technical Overview (Engineer Mode)
{{ design.engineer_summary }}
Technology Stack Design
{% for layer, items in design.stack.items() %}
{{ layer }}
{% for item in items %}
{{ item.chip }}
{{ item.reason }}
{% endfor %}
{% endfor %}
Monthly Cost Estimates
Scale / Tier Estimated Cost Main Cost Drivers
1,000 active users {{ design.cost_estimates['1k_users'].monthly_cost }} {{ design.cost_estimates['1k_users'].drivers }}
100,000 active users {{ design.cost_estimates['100k_users'].monthly_cost }} {{ design.cost_estimates['100k_users'].drivers }}
1,000,000 active users {{ design.cost_estimates['1m_users'].monthly_cost }} {{ design.cost_estimates['1m_users'].drivers }}
""" def generate_audit_pdf(report: dict, project_name: str) -> bytes: from datetime import datetime date_str = datetime.utcnow().strftime("%B %d, %Y") # Render Jinja HTML template = Template(AUDIT_PDF_TEMPLATE) html_content = template.render(report=report, project_name=project_name, date_str=date_str) try: if HTML is None: raise RuntimeError("WeasyPrint is not loaded due to missing GTK libraries.") # Create temp file with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp: HTML(string=html_content).write_pdf(tmp.name) tmp.seek(0) pdf_bytes = tmp.read() os.unlink(tmp.name) return pdf_bytes except Exception as e: logger.error(f"WeasyPrint PDF generation failed: {e}. Falling back to standard HTML-as-PDF simulation.") # If WeasyPrint dependencies fail, return simple HTML content in bytes to avoid crashing return html_content.encode("utf-8") def generate_design_pdf(design: dict) -> bytes: from datetime import datetime date_str = datetime.utcnow().strftime("%B %d, %Y") # Render Jinja HTML template = Template(DESIGN_PDF_TEMPLATE) html_content = template.render(design=design, date_str=date_str) try: if HTML is None: raise RuntimeError("WeasyPrint is not loaded due to missing GTK libraries.") # Create temp file with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp: HTML(string=html_content).write_pdf(tmp.name) tmp.seek(0) pdf_bytes = tmp.read() os.unlink(tmp.name) return pdf_bytes except Exception as e: logger.error(f"WeasyPrint PDF generation failed: {e}. Falling back to standard HTML-as-PDF simulation.") # Return fallback HTML return html_content.encode("utf-8")