from reportlab.lib.pagesizes import letter from reportlab.pdfgen import canvas from reportlab.lib import colors from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer from reportlab.lib.styles import getSampleStyleSheet import io def generate_pdf_report(results): """ Generates a PDF report from analysis results. Args: results: List of dictionaries containing analysis findings. Returns: bytes: PDF file content. """ buffer = io.BytesIO() doc = SimpleDocTemplate(buffer, pagesize=letter) elements = [] styles = getSampleStyleSheet() title_style = styles["Title"] heading_style = styles["Heading2"] normal_style = styles["Normal"] # Title elements.append(Paragraph("Semantic Integrity Analysis Report", title_style)) elements.append(Spacer(1, 12)) if not results: elements.append(Paragraph("No integrity issues detected.", normal_style)) else: # Summary elements.append( Paragraph(f"Total Potential Issues Found: {len(results)}", normal_style) ) elements.append(Spacer(1, 12)) # Table Header data = [["S.No", "Label", "Loc", "Reason"]] # Table Data for idx, r in enumerate(results): # Text wrapping for table cells needs explicit Paragraph usage usually, # but for simplicity we truncate or just list them. # To make it robust, we'll list details below the table or keep table simple. row = [ str(idx + 1), r.get("Label", "N/A"), r.get("Location 1", "").replace("Pg ", "P").replace("Ln ", "L"), r.get("Reason", "N/A"), ] data.append(row) # Create Table t = Table(data, colWidths=[30, 90, 60, 320]) t.setStyle( TableStyle( [ ("BACKGROUND", (0, 0), (-1, 0), colors.grey), ("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke), ("ALIGN", (0, 0), (-1, -1), "LEFT"), ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"), ("BOTTOMPADDING", (0, 0), (-1, 0), 12), ("BACKGROUND", (0, 1), (-1, -1), colors.beige), ("GRID", (0, 0), (-1, -1), 1, colors.black), ] ) ) elements.append(t) elements.append(Spacer(1, 24)) # Detailed Findings elements.append(Paragraph("Detailed Findings", heading_style)) for idx, r in enumerate(results): elements.append( Paragraph(f"Issue #{idx + 1}: {r.get('Label')}", normal_style) ) elements.append( Paragraph(f"Reason: {r.get('Reason')}", normal_style) ) elements.append( Paragraph(f"Clause 1: {r.get('Clause 1')}", normal_style) ) elements.append( Paragraph(f"Clause 2: {r.get('Clause 2')}", normal_style) ) elements.append(Spacer(1, 12)) elements.append(Paragraph("-" * 60, normal_style)) elements.append(Spacer(1, 12)) doc.build(elements) buffer.seek(0) return buffer.getvalue()