import os from reportlab.lib.pagesizes import A4 from reportlab.pdfgen import canvas from reportlab.lib.units import inch from reportlab.lib import colors from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle import markdown2 from datetime import datetime class PDFReportGenerator: def __init__(self, output_dir="data/reports"): self.output_dir = output_dir os.makedirs(output_dir, exist_ok=True) self.styles = getSampleStyleSheet() self._setup_custom_styles() def _setup_custom_styles(self): self.styles.add(ParagraphStyle( name='LegalHeading', parent=self.styles['Heading1'], fontSize=16, textColor=colors.darkblue, spaceAfter=12 )) self.styles.add(ParagraphStyle( name='LegalBody', parent=self.styles['BodyText'], fontSize=11, leading=14, spaceAfter=8 )) def _draw_watermark(self, canvas, doc): """Draws a diagonal watermark on every page.""" canvas.saveState() canvas.setFont("Helvetica-Bold", 60) canvas.setFillColor(colors.lightgrey, alpha=0.2) canvas.translate(A4[0]/2, A4[1]/2) canvas.rotate(45) canvas.drawCentredString(0, 0, "CONFIDENTIAL - AI ADVISORY") canvas.restoreState() # Add Footer canvas.saveState() canvas.setFont("Helvetica", 9) canvas.setFillColor(colors.grey) canvas.drawString(inch, 0.75 * inch, f"Generated by LETA AI - {datetime.now().strftime('%Y-%m-%d %H:%M')}") canvas.drawRightString(A4[0] - inch, 0.75 * inch, f"Page {doc.page}") canvas.restoreState() def generate_report(self, markdown_content: str, filename: str = "advisory.pdf") -> str: """ Converts Markdown to a professional PDF with watermark. """ filepath = os.path.join(self.output_dir, filename) doc = SimpleDocTemplate(filepath, pagesize=A4) # Convert Markdown to HTML (ReportLab handles basic HTML-like tags) # We use a simple parser or just treat paragraphs. # For robustness, we will split by newlines and style accordingly. story = [] # Logo (if exists) # logo_path = "assets/logo.png" # if os.path.exists(logo_path): # story.append(Image(logo_path, width=2*inch, height=1*inch)) # Title story.append(Paragraph("LEGAL ADVISORY OPINION", self.styles['Title'])) story.append(Spacer(1, 24)) # Process Content # Cleaning markdown for ReportLab Paragraphs (basic bold/italic support) lines = markdown_content.split('\n') for line in lines: line = line.strip() if not line: story.append(Spacer(1, 6)) continue if line.startswith('# '): story.append(Paragraph(line[2:], self.styles['LegalHeading'])) elif line.startswith('### ') or line.startswith('**'): # Subheading or bold line clean_line = line.replace('### ', '').replace('**', '') story.append(Paragraph(f"{clean_line}", self.styles['Heading3'])) elif line.startswith('* ') or line.startswith('- '): # Bullet story.append(Paragraph(f"• {line[2:]}", self.styles['LegalBody'])) else: story.append(Paragraph(line, self.styles['LegalBody'])) # Build PDF with Watermark doc.build(story, onFirstPage=self._draw_watermark, onLaterPages=self._draw_watermark) return filepath