from fastapi import APIRouter, HTTPException from fastapi.responses import FileResponse from pydantic import BaseModel from fpdf import FPDF import os import tempfile import uuid router = APIRouter() class ExportRequest(BaseModel): title: str content: str citations: list[dict] = [] class PDFGenerator(FPDF): def header(self): self.set_font('helvetica', 'B', 12) self.cell(0, 10, 'InteleX Research Memorandum', 0, 1, 'C') self.ln(5) def footer(self): self.set_y(-15) self.set_font('helvetica', 'I', 8) self.cell(0, 10, f'Page {self.page_no()}', 0, 0, 'C') import re def _clean_text(text: str) -> str: """Strip emojis and non-latin characters that crash FPDF.""" if not text: return " " # Remove markdown headers text = text.replace('#', '').replace('*', '') # Keep only common latin characters and punctuation for standard fonts cleaned = re.sub(r'[^\x00-\x7F]+', '', text) return cleaned if cleaned.strip() else "[Non-supported characters]" @router.post("/pdf") async def export_pdf(req: ExportRequest): try: pdf = PDFGenerator() pdf.add_page() # Ensure we are at the left margin to avoid "horizontal space" errors pdf.set_x(pdf.l_margin) # Title pdf.set_font("helvetica", 'B', 16) title = _clean_text(req.title) pdf.multi_cell(0, 10, title) pdf.ln(10) # Content pdf.set_font("helvetica", '', 11) content = _clean_text(req.content) pdf.set_x(pdf.l_margin) # Reset X before body pdf.multi_cell(0, 7, content) # Citations if req.citations: pdf.ln(10) pdf.set_font("helvetica", 'B', 12) pdf.set_x(pdf.l_margin) pdf.cell(0, 10, 'Sources & Citations', 0, 1) pdf.set_font("helvetica", '', 9) for i, cite in enumerate(req.citations): source_title = cite.get('source_title') or cite.get('sourceTitle') or "Source" ref = cite.get('reference') or "" text = f"[{i+1}] {source_title} - {ref}" pdf.set_x(pdf.l_margin) pdf.multi_cell(0, 5, _clean_text(text)) # Save to temp file tmp_dir = tempfile.gettempdir() filename = f"research_{uuid.uuid4().hex[:8]}.pdf" filepath = os.path.join(tmp_dir, filename) pdf.output(filepath) return FileResponse( path=filepath, filename=filename, media_type='application/pdf' ) except Exception as e: print(f"[Export] PDF Error: {e}") raise HTTPException(status_code=500, detail=str(e))