LiamKhoaLe commited on
Commit
2364a33
·
1 Parent(s): 41d7482

Add references in PDF report with IEEE formatter

Browse files
Files changed (3) hide show
  1. routes/reports.py +12 -2
  2. static/script.js +4 -0
  3. utils/service/pdf.py +77 -1
routes/reports.py CHANGED
@@ -152,12 +152,22 @@ async def generate_report(
152
  async def generate_report_pdf(
153
  user_id: str = Form(...),
154
  project_id: str = Form(...),
155
- report_content: str = Form(...)
 
156
  ):
157
  from utils.service.pdf import generate_report_pdf as generate_pdf
158
  from fastapi.responses import Response
 
159
  try:
160
- pdf_content = await generate_pdf(report_content, user_id, project_id)
 
 
 
 
 
 
 
 
161
  return Response(
162
  content=pdf_content,
163
  media_type="application/pdf",
 
152
  async def generate_report_pdf(
153
  user_id: str = Form(...),
154
  project_id: str = Form(...),
155
+ report_content: str = Form(...),
156
+ sources: str = Form("[]")
157
  ):
158
  from utils.service.pdf import generate_report_pdf as generate_pdf
159
  from fastapi.responses import Response
160
+ import json
161
  try:
162
+ # Parse sources JSON
163
+ sources_list = []
164
+ if sources and sources != "[]":
165
+ try:
166
+ sources_list = json.loads(sources)
167
+ except json.JSONDecodeError:
168
+ logger.warning(f"[REPORT] Failed to parse sources JSON: {sources}")
169
+
170
+ pdf_content = await generate_pdf(report_content, user_id, project_id, sources_list)
171
  return Response(
172
  content=pdf_content,
173
  media_type="application/pdf",
static/script.js CHANGED
@@ -859,10 +859,14 @@
859
  `;
860
 
861
  try {
 
 
 
862
  const formData = new FormData();
863
  formData.append('user_id', user.user_id);
864
  formData.append('project_id', currentProject.project_id);
865
  formData.append('report_content', reportContent);
 
866
 
867
  const response = await fetch('/report/pdf', {
868
  method: 'POST',
 
859
  `;
860
 
861
  try {
862
+ // Find sources from the current message or recent sources
863
+ const sources = findCurrentSources();
864
+
865
  const formData = new FormData();
866
  formData.append('user_id', user.user_id);
867
  formData.append('project_id', currentProject.project_id);
868
  formData.append('report_content', reportContent);
869
+ formData.append('sources', JSON.stringify(sources));
870
 
871
  const response = await fetch('/report/pdf', {
872
  method: 'POST',
utils/service/pdf.py CHANGED
@@ -6,6 +6,7 @@ import tempfile
6
  import markdown
7
  import re
8
  from datetime import datetime
 
9
  from fastapi import HTTPException
10
  from utils.logger import get_logger
11
 
@@ -507,7 +508,70 @@ def _apply_syntax_highlight(escaped_code: str, language: str) -> str:
507
 
508
  return out
509
 
510
- async def generate_report_pdf(report_content: str, user_id: str, project_id: str) -> bytes:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
511
  """
512
  Generate a PDF from report content using reportlab
513
 
@@ -623,6 +687,18 @@ async def generate_report_pdf(report_content: str, user_id: str, project_id: str
623
  # Enhanced markdown parser with proper formatting
624
  story.extend(_parse_markdown_content(report_content, heading1_style, heading2_style, heading3_style, normal_style, code_style))
625
 
 
 
 
 
 
 
 
 
 
 
 
 
626
  # Build PDF
627
  doc.build(story)
628
 
 
6
  import markdown
7
  import re
8
  from datetime import datetime
9
+ from typing import List, Dict
10
  from fastapi import HTTPException
11
  from utils.logger import get_logger
12
 
 
508
 
509
  return out
510
 
511
+
512
+ async def _format_references_ieee(sources: List[Dict]) -> List[str]:
513
+ """Format sources in IEEE citation style using NVIDIA API."""
514
+ try:
515
+ from utils.api.router import generate_answer_with_model
516
+ from helpers.setup import nvidia_rotator
517
+
518
+ if not sources or not nvidia_rotator:
519
+ return []
520
+
521
+ # Prepare source data for formatting
522
+ source_data = []
523
+ for i, source in enumerate(sources, 1):
524
+ source_info = {
525
+ "number": i,
526
+ "filename": source.get("filename", "Unknown"),
527
+ "url": source.get("url", ""),
528
+ "topic_name": source.get("topic_name", ""),
529
+ "kind": source.get("kind", "document")
530
+ }
531
+ source_data.append(source_info)
532
+
533
+ sys_prompt = """You are an expert at formatting academic references in IEEE style.
534
+ Format the provided sources as IEEE-style references. Each reference should be numbered and formatted according to IEEE standards.
535
+
536
+ For web sources: [1] Author/Organization, "Title," Website Name, URL, accessed: Date.
537
+ For documents: [1] Author, "Title," Document Type, Filename, Year.
538
+
539
+ Return only the formatted references, one per line, numbered sequentially."""
540
+
541
+ user_prompt = f"Format these sources in IEEE style:\n\n{source_data}"
542
+
543
+ selection = {"provider": "nvidia", "model": "meta/llama-3.1-8b-instruct"}
544
+ response = await generate_answer_with_model(selection, sys_prompt, user_prompt, None, nvidia_rotator)
545
+
546
+ # Parse the response into individual references
547
+ references = [line.strip() for line in response.split('\n') if line.strip() and line.strip().startswith('[')]
548
+
549
+ # If NVIDIA formatting fails, create basic IEEE format
550
+ if not references:
551
+ references = []
552
+ for i, source in enumerate(sources, 1):
553
+ if source.get("kind") == "web":
554
+ ref = f"[{i}] {source.get('topic_name', 'Unknown')}, \"{source.get('filename', 'Web Source')}\", {source.get('url', '')}, accessed: {datetime.now().strftime('%B %d, %Y')}."
555
+ else:
556
+ ref = f"[{i}] {source.get('topic_name', 'Unknown')}, \"{source.get('filename', 'Document')}\", Document, {datetime.now().year}."
557
+ references.append(ref)
558
+
559
+ return references
560
+
561
+ except Exception as e:
562
+ logger.warning(f"[PDF] IEEE reference formatting failed: {e}")
563
+ # Fallback to basic formatting
564
+ references = []
565
+ for i, source in enumerate(sources, 1):
566
+ if source.get("kind") == "web":
567
+ ref = f"[{i}] {source.get('topic_name', 'Unknown')}, \"{source.get('filename', 'Web Source')}\", {source.get('url', '')}, accessed: {datetime.now().strftime('%B %d, %Y')}."
568
+ else:
569
+ ref = f"[{i}] {source.get('topic_name', 'Unknown')}, \"{source.get('filename', 'Document')}\", Document, {datetime.now().year}."
570
+ references.append(ref)
571
+ return references
572
+
573
+
574
+ async def generate_report_pdf(report_content: str, user_id: str, project_id: str, sources: List[Dict] = None) -> bytes:
575
  """
576
  Generate a PDF from report content using reportlab
577
 
 
687
  # Enhanced markdown parser with proper formatting
688
  story.extend(_parse_markdown_content(report_content, heading1_style, heading2_style, heading3_style, normal_style, code_style))
689
 
690
+ # Add references section if sources provided
691
+ if sources:
692
+ story.append(PageBreak())
693
+ story.append(Paragraph("References", heading1_style))
694
+ story.append(Spacer(1, 12))
695
+
696
+ # Format references in IEEE style using NVIDIA API
697
+ ieee_references = await _format_references_ieee(sources)
698
+ for ref in ieee_references:
699
+ story.append(Paragraph(ref, normal_style))
700
+ story.append(Spacer(1, 6))
701
+
702
  # Build PDF
703
  doc.build(story)
704