Spaces:
Running
Running
| from reportlab.lib import colors | |
| from reportlab.lib.pagesizes import A4 | |
| from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle | |
| from reportlab.lib.units import inch, cm | |
| from reportlab.platypus import ( | |
| SimpleDocTemplate, | |
| Paragraph, | |
| Spacer, | |
| Table, | |
| TableStyle, | |
| PageBreak, | |
| HRFlowable, | |
| ) | |
| from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY | |
| from reportlab.pdfgen import canvas | |
| from datetime import datetime | |
| import os | |
| class AnalysisReport: | |
| def __init__(self, output_path): | |
| self.output_path = output_path | |
| self.doc = SimpleDocTemplate( | |
| output_path, | |
| pagesize=A4, | |
| rightMargin=2 * cm, | |
| leftMargin=2 * cm, | |
| topMargin=2 * cm, | |
| bottomMargin=2 * cm, | |
| ) | |
| self.styles = getSampleStyleSheet() | |
| self.story = [] | |
| self._setup_styles() | |
| def _setup_styles(self): | |
| self.title_style = ParagraphStyle( | |
| "CustomTitle", | |
| parent=self.styles["Title"], | |
| fontSize=24, | |
| textColor=colors.HexColor("#0B0F1A"), | |
| spaceAfter=30, | |
| alignment=TA_CENTER, | |
| ) | |
| self.heading1_style = ParagraphStyle( | |
| "CustomHeading1", | |
| parent=self.styles["Heading1"], | |
| fontSize=16, | |
| textColor=colors.HexColor("#1E3A5F"), | |
| spaceBefore=20, | |
| spaceAfter=12, | |
| borderPadding=5, | |
| ) | |
| self.heading2_style = ParagraphStyle( | |
| "CustomHeading2", | |
| parent=self.styles["Heading2"], | |
| fontSize=13, | |
| textColor=colors.HexColor("#2563EB"), | |
| spaceBefore=15, | |
| spaceAfter=8, | |
| ) | |
| self.body_style = ParagraphStyle( | |
| "CustomBody", | |
| parent=self.styles["Normal"], | |
| fontSize=10, | |
| leading=14, | |
| alignment=TA_JUSTIFY, | |
| spaceAfter=8, | |
| ) | |
| self.bullet_style = ParagraphStyle( | |
| "BulletStyle", | |
| parent=self.styles["Normal"], | |
| fontSize=10, | |
| leading=14, | |
| leftIndent=20, | |
| spaceAfter=4, | |
| ) | |
| def add_header(self): | |
| self.story.append(Paragraph("CitationEdge", self.title_style)) | |
| self.story.append( | |
| Paragraph( | |
| "Agentic Architecture Analysis Report", | |
| ParagraphStyle( | |
| "Subtitle", | |
| parent=self.styles["Normal"], | |
| fontSize=14, | |
| textColor=colors.HexColor("#64748B"), | |
| alignment=TA_CENTER, | |
| spaceAfter=5, | |
| ), | |
| ) | |
| ) | |
| self.story.append( | |
| Paragraph( | |
| f"Generated: {datetime.now().strftime('%B %d, %Y')}", | |
| ParagraphStyle( | |
| "Date", | |
| parent=self.styles["Normal"], | |
| fontSize=10, | |
| textColor=colors.HexColor("#94A3B8"), | |
| alignment=TA_CENTER, | |
| spaceAfter=30, | |
| ), | |
| ) | |
| ) | |
| self.story.append( | |
| HRFlowable( | |
| width="100%", | |
| thickness=2, | |
| color=colors.HexColor("#2563EB"), | |
| spaceAfter=30, | |
| ) | |
| ) | |
| def add_summary_table(self): | |
| self.story.append(Paragraph("1. Executive Summary", self.heading1_style)) | |
| data = [ | |
| ["Metric", "Value"], | |
| ["Total Papers Analyzed", "13"], | |
| ["Success Rate", "100% (all completed)"], | |
| ["Avg Processing Time", "~40 seconds"], | |
| ["Papers with Complete Data", "10/13 (77%)"], | |
| ["Papers with Partial Data", "3/13 (23%)"], | |
| ] | |
| table = Table(data, colWidths=[5 * cm, 10 * cm]) | |
| table.setStyle( | |
| TableStyle( | |
| [ | |
| ("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#1E3A5F")), | |
| ("TEXTCOLOR", (0, 0), (-1, 0), colors.white), | |
| ("ALIGN", (0, 0), (-1, -1), "CENTER"), | |
| ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"), | |
| ("FONTSIZE", (0, 0), (-1, 0), 11), | |
| ("BOTTOMPADDING", (0, 0), (-1, 0), 12), | |
| ("TOPPADDING", (0, 0), (-1, 0), 12), | |
| ("BACKGROUND", (0, 1), (-1, -1), colors.HexColor("#F8FAFC")), | |
| ("GRID", (0, 0), (-1, -1), 1, colors.HexColor("#E2E8F0")), | |
| ("FONTNAME", (0, 1), (-1, -1), "Helvetica"), | |
| ("FONTSIZE", (0, 1), (-1, -1), 10), | |
| ("BOTTOMPADDING", (0, 1), (-1, -1), 8), | |
| ("TOPPADDING", (0, 1), (-1, -1), 8), | |
| ] | |
| ) | |
| ) | |
| self.story.append(table) | |
| self.story.append(Spacer(1, 20)) | |
| def add_strengths(self): | |
| self.story.append(Paragraph("2. Strengths", self.heading1_style)) | |
| strengths = [ | |
| "<b>Fast Processing:</b> 30-140s per paper is excellent for multi-agent analysis", | |
| "<b>Keyword Extraction:</b> Captures domain-specific terms accurately (LSTM, Self-Attention, reinforcement learning)", | |
| "<b>Citation Detection:</b> Identifies real citations and cross-references well", | |
| "<b>Claim Classification:</b> Distinguishes between method/result/finding claims effectively", | |
| "<b>Multi-Agent Pipeline:</b> Good separation of concerns between agents (parser, keyword, claim, citation, evidence, argumentation, scoring)", | |
| ] | |
| for s in strengths: | |
| self.story.append(Paragraph(f"• {s}", self.bullet_style)) | |
| self.story.append(Spacer(1, 15)) | |
| def add_weaknesses(self): | |
| self.story.append(Paragraph("3. Weaknesses & Gaps", self.heading1_style)) | |
| self.story.append( | |
| Paragraph("3.1 Low Citation Gap Detection", self.heading2_style) | |
| ) | |
| self.story.append( | |
| Paragraph( | |
| "Most reports show only 0-2 citation gaps, which appears significantly under-detected. " | |
| "Academic papers typically cite 15-40+ references. For a thorough analysis, expected citation " | |
| "gaps should be in the range of 5-15 per paper, depending on the paper length and field.", | |
| self.body_style, | |
| ) | |
| ) | |
| self.story.append(Paragraph("3.2 Weak Evidence Grounding", self.heading2_style)) | |
| self.story.append( | |
| Paragraph( | |
| "Only 1-5% of claims are grounded with citations. For example, Paper 4 with 50 claims " | |
| "shows only 3 grounded claims (0.06%). A well-structured research paper should have 30-50% " | |
| "of claims properly grounded with citations to source materials.", | |
| self.body_style, | |
| ) | |
| ) | |
| self.story.append( | |
| Paragraph("3.3 Incomplete Claim Detection", self.heading2_style) | |
| ) | |
| self.story.append( | |
| Paragraph( | |
| "Average 20-50 claims per paper seems low for dense ML papers. Papers 1, 6, and 9 show " | |
| "only 15-18 claims, which likely indicates under-detection. High-impact ML papers often " | |
| "contain 80-150+ distinct claims that should be identified.", | |
| self.body_style, | |
| ) | |
| ) | |
| self.story.append(Paragraph("3.4 Citation Format Issues", self.heading2_style)) | |
| self.story.append( | |
| Paragraph( | |
| "Some citations show 'Unknown Title' or missing metadata. Author names are occasionally " | |
| "wrong or truncated. The citation extraction should leverage reference section parsing " | |
| "more aggressively.", | |
| self.body_style, | |
| ) | |
| ) | |
| self.story.append(Paragraph("3.5 No Limitation Analysis", self.heading2_style)) | |
| self.story.append( | |
| Paragraph( | |
| "Papers mention 'Limitations' in text but no agent captures this systematically. " | |
| "A dedicated Limitations agent should identify: (a) scope constraints, (b) generalizability " | |
| "issues, (c) comparison baselines, (d) reproducibility concerns.", | |
| self.body_style, | |
| ) | |
| ) | |
| self.story.append( | |
| Paragraph("3.6 Inconsistent Argumentation Mapping", self.heading2_style) | |
| ) | |
| self.story.append( | |
| Paragraph( | |
| "While 'Related To' chains exist in reports, they are sparse. Papers with 50+ claims " | |
| "show minimal argument mapping. The argumentation agent may be failing silently or not " | |
| "finding sufficient claim relationships to map.", | |
| self.body_style, | |
| ) | |
| ) | |
| def add_improvements(self): | |
| self.story.append(PageBreak()) | |
| self.story.append(Paragraph("4. Priority Improvements", self.heading1_style)) | |
| improvements = [ | |
| ( | |
| "HIGH", | |
| "Evidence Grounding Agent", | |
| "Increase grounding from 1-5% to 30-50%. Add sentence-level citation matching. " | |
| "Use coreference resolution to link pronouns to entities.", | |
| ), | |
| ( | |
| "HIGH", | |
| "Citation Gap Detection", | |
| "Improve to 5-15 gaps per paper. Implement cross-reference analysis (when A cites B, " | |
| "but B's claims aren't addressed). Add methodology comparison gaps.", | |
| ), | |
| ( | |
| "HIGH", | |
| "Claim Detection", | |
| "Target 80-150 claims per high-impact paper. Add hedging language detection " | |
| "(may, might, suggests). Separate major from minor claims.", | |
| ), | |
| ( | |
| "MEDIUM", | |
| "Citation Extraction", | |
| "Parse reference section more aggressively. Extract full author lists, venue, year. " | |
| "Handle multiple citation formats (APA, MLA, IEEE, Nature).", | |
| ), | |
| ( | |
| "MEDIUM", | |
| "Limitation Analysis Agent", | |
| "Add new agent or extend claim agent to identify limitations. Classify: scope, " | |
| "generalizability, baseline, reproducibility. Rate severity.", | |
| ), | |
| ( | |
| "MEDIUM", | |
| "Argumentation Mapping", | |
| "Ensure all claims with relationships are mapped. Connect claims across sections " | |
| "(introduction → method → result → conclusion).", | |
| ), | |
| ( | |
| "LOW", | |
| "Multi-modal Support", | |
| "Add support for tables, figures, equations. Extract claims from figure captions. " | |
| "Link table data to supporting claims.", | |
| ), | |
| ( | |
| "LOW", | |
| "Real-time Streaming", | |
| "Provide incremental agent results as jobs run. Better UX for long papers.", | |
| ), | |
| ] | |
| for priority, title, desc in improvements: | |
| color = ( | |
| colors.HexColor("#DC2626") | |
| if priority == "HIGH" | |
| else ( | |
| colors.HexColor("#CA8A04") | |
| if priority == "MEDIUM" | |
| else colors.HexColor("#64748B") | |
| ) | |
| ) | |
| data = [ | |
| [ | |
| Paragraph( | |
| f"<b>[{priority}]</b>", | |
| ParagraphStyle("P", textColor=color, fontSize=9), | |
| ), | |
| Paragraph(f"<b>{title}</b><br/>{desc}", self.body_style), | |
| ] | |
| ] | |
| table = Table(data, colWidths=[2 * cm, 13 * cm]) | |
| table.setStyle( | |
| TableStyle( | |
| [ | |
| ("VALIGN", (0, 0), (-1, -1), "TOP"), | |
| ("BACKGROUND", (0, 0), (-1, -1), colors.HexColor("#F8FAFC")), | |
| ("BOX", (0, 0), (-1, -1), 1, colors.HexColor("#E2E8F0")), | |
| ("LEFTPADDING", (0, 0), (-1, -1), 8), | |
| ("RIGHTPADDING", (0, 0), (-1, -1), 8), | |
| ("TOPPADDING", (0, 0), (-1, -1), 8), | |
| ("BOTTOMPADDING", (0, 0), (-1, -1), 8), | |
| ] | |
| ) | |
| ) | |
| self.story.append(table) | |
| self.story.append(Spacer(1, 8)) | |
| def add_agent_breakdown(self): | |
| self.story.append(Spacer(1, 20)) | |
| self.story.append(Paragraph("5. Agent Pipeline Analysis", self.heading1_style)) | |
| agents = [ | |
| ["Agent", "Purpose", "Current Status", "Rating"], | |
| ["Parser Agent", "Extract text & metadata", "Working well", "Good"], | |
| ["Keyword Agent", "Key concept extraction", "Working well", "Good"], | |
| ["Claim Agent", "Research claim detection", "Under-detecting", "Fair"], | |
| ["Citation Gap Agent", "Gap identification", "Too few gaps", "Poor"], | |
| [ | |
| "Evidence Grounding Agent", | |
| "Grounding in source", | |
| "Very low grounding", | |
| "Poor", | |
| ], | |
| ["Argumentation Agent", "Structure mapping", "Sparse mapping", "Fair"], | |
| ["Scoring Agent", "Quality assessment", "Working", "Good"], | |
| ] | |
| table = Table(agents, colWidths=[4 * cm, 4 * cm, 4 * cm, 2 * cm]) | |
| table.setStyle( | |
| TableStyle( | |
| [ | |
| ("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#1E3A5F")), | |
| ("TEXTCOLOR", (0, 0), (-1, 0), colors.white), | |
| ("ALIGN", (0, 0), (-1, -1), "CENTER"), | |
| ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"), | |
| ("FONTSIZE", (0, 0), (-1, -1), 9), | |
| ("BOTTOMPADDING", (0, 0), (-1, -1), 8), | |
| ("TOPPADDING", (0, 0), (-1, -1), 8), | |
| ("BACKGROUND", (0, 1), (-1, 1), colors.HexColor("#DCFCE7")), | |
| ("BACKGROUND", (0, 2), (-1, 2), colors.HexColor("#DCFCE7")), | |
| ("BACKGROUND", (0, 3), (-1, 3), colors.HexColor("#FEF3C7")), | |
| ("BACKGROUND", (0, 4), (-1, 4), colors.HexColor("#FEE2E2")), | |
| ("BACKGROUND", (0, 5), (-1, 5), colors.HexColor("#FEE2E2")), | |
| ("BACKGROUND", (0, 6), (-1, 6), colors.HexColor("#FEF3C7")), | |
| ("BACKGROUND", (0, 7), (-1, 7), colors.HexColor("#DCFCE7")), | |
| ("GRID", (0, 0), (-1, -1), 1, colors.HexColor("#E2E8F0")), | |
| ] | |
| ) | |
| ) | |
| self.story.append(table) | |
| def add_recommendations(self): | |
| self.story.append(PageBreak()) | |
| self.story.append(Paragraph("6. Recommendations", self.heading1_style)) | |
| short_term = [ | |
| "Improve evidence grounding to target 30%+ coverage", | |
| "Enhance citation gap detection with cross-reference analysis", | |
| "Add hedging language detection for claim classification", | |
| "Parse reference sections more aggressively", | |
| ] | |
| medium_term = [ | |
| "Add dedicated Limitations analysis agent", | |
| "Implement full argumentation chain mapping", | |
| "Add multi-modal support for tables and figures", | |
| "Improve real-time progress streaming", | |
| ] | |
| long_term = [ | |
| "Fine-tune models on research paper corpus", | |
| "Add comparison with arXiv/PubMed knowledge base", | |
| "Implement claim verification against source claims", | |
| "Add novelty/innovation scoring", | |
| ] | |
| self.story.append(Paragraph("Short-term (1-2 weeks)", self.heading2_style)) | |
| for item in short_term: | |
| self.story.append(Paragraph(f"• {item}", self.bullet_style)) | |
| self.story.append(Paragraph("Medium-term (1-2 months)", self.heading2_style)) | |
| for item in medium_term: | |
| self.story.append(Paragraph(f"• {item}", self.bullet_style)) | |
| self.story.append(Paragraph("Long-term (3-6 months)", self.heading2_style)) | |
| for item in long_term: | |
| self.story.append(Paragraph(f"• {item}", self.bullet_style)) | |
| def add_footer(self): | |
| self.story.append(Spacer(1, 40)) | |
| self.story.append( | |
| HRFlowable( | |
| width="100%", | |
| thickness=1, | |
| color=colors.HexColor("#E2E8F0"), | |
| spaceAfter=20, | |
| ) | |
| ) | |
| self.story.append( | |
| Paragraph( | |
| "Report generated by CitationEdge Analysis Platform | IIT Patna Research Project", | |
| ParagraphStyle( | |
| "Footer", | |
| fontSize=8, | |
| textColor=colors.HexColor("#94A3B8"), | |
| alignment=TA_CENTER, | |
| ), | |
| ) | |
| ) | |
| def build(self): | |
| self.add_header() | |
| self.add_summary_table() | |
| self.add_strengths() | |
| self.add_weaknesses() | |
| self.add_improvements() | |
| self.add_agent_breakdown() | |
| self.add_recommendations() | |
| self.add_footer() | |
| self.doc.build(self.story) | |
| return self.output_path | |
| if __name__ == "__main__": | |
| output_path = os.path.join( | |
| os.path.dirname(__file__), "..", "reports", "architecture_analysis_report.pdf" | |
| ) | |
| report = AnalysisReport(output_path) | |
| report.build() | |
| print(f"Report saved: {output_path}") | |