""" PDF Generation Module This module handles saving research papers to PDF format with enhanced error handling. """ import os import re from typing import Optional, Tuple from reportlab.lib import colors from reportlab.lib.pagesizes import A4, letter from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet from reportlab.lib.units import inch from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont from reportlab.platypus import PageBreak, Paragraph, SimpleDocTemplate, Spacer def create_custom_styles() -> Tuple[ParagraphStyle, ParagraphStyle, ParagraphStyle]: """ Create custom paragraph styles for the PDF Returns: Tuple of (title_style, heading_style, body_style) """ styles = getSampleStyleSheet() # Title style title_style = ParagraphStyle( 'CustomTitle', parent=styles['Title'], fontSize=18, spaceAfter=30, alignment=1, # Center alignment textColor=colors.darkblue ) # Heading style heading_style = ParagraphStyle( 'CustomHeading', parent=styles['Heading1'], fontSize=14, spaceAfter=12, spaceBefore=20, textColor=colors.darkblue ) # Body style body_style = ParagraphStyle( 'CustomBody', parent=styles['Normal'], fontSize=11, spaceAfter=6, leading=14 ) return title_style, heading_style, body_style def save_draft_to_pdf(topic: str, draft_text: str, bibliography: str, filename: str) -> None: """ Save research paper draft and bibliography to PDF Args: topic: The research topic draft_text: The draft text content bibliography: The bibliography content filename: Output PDF filename """ try: # Setup fonts font_dir = "font" if os.path.exists(font_dir): dejavu_bold = os.path.join(font_dir, "dejavu-sans.bold.ttf") dejavu_regular = os.path.join(font_dir, "DejaVuSans.ttf") if os.path.exists(dejavu_bold): pdfmetrics.registerFont(TTFont('DejaVu-Bold', dejavu_bold)) if os.path.exists(dejavu_regular): pdfmetrics.registerFont(TTFont('DejaVu-Regular', dejavu_regular)) # Create PDF document doc = SimpleDocTemplate(filename, pagesize=A4) story = [] # Get custom styles title_style, heading_style, body_style = create_custom_styles() # Add title title = Paragraph(topic, title_style) story.append(title) story.append(Spacer(1, 20)) # Process draft text if draft_text and draft_text.strip(): # Split draft into paragraphs paragraphs = draft_text.split('\n\n') for paragraph in paragraphs: paragraph = paragraph.strip() if paragraph: # Check if it's a heading (starts with # or numbers) if paragraph.startswith('#') or re.match(r'^\d+\.', paragraph): # It's a heading heading_text = re.sub(r'^#+\s*', '', paragraph) # Remove # marks heading_text = re.sub(r'^\d+\.\s*', '', heading_text) # Remove numbers heading = Paragraph(heading_text, heading_style) story.append(heading) else: # It's a body paragraph body = Paragraph(paragraph, body_style) story.append(body) story.append(Spacer(1, 6)) # Add bibliography section if bibliography and bibliography.strip(): story.append(PageBreak()) story.append(Paragraph("Bibliography", heading_style)) story.append(Spacer(1, 12)) # Process bibliography bib_paragraphs = bibliography.split('\n') for bib_para in bib_paragraphs: bib_para = bib_para.strip() if bib_para: bib_body = Paragraph(bib_para, body_style) story.append(bib_body) story.append(Spacer(1, 6)) # Build PDF doc.build(story) print("✅ PDF saved successfully!") except Exception as e: print(f"❌ Error saving PDF: {e}") raise