| """ |
| 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 = ParagraphStyle( |
| 'CustomTitle', |
| parent=styles['Title'], |
| fontSize=18, |
| spaceAfter=30, |
| alignment=1, |
| textColor=colors.darkblue |
| ) |
| |
| |
| heading_style = ParagraphStyle( |
| 'CustomHeading', |
| parent=styles['Heading1'], |
| fontSize=14, |
| spaceAfter=12, |
| spaceBefore=20, |
| textColor=colors.darkblue |
| ) |
| |
| |
| 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: |
| |
| 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)) |
| |
| |
| doc = SimpleDocTemplate(filename, pagesize=A4) |
| story = [] |
| |
| |
| title_style, heading_style, body_style = create_custom_styles() |
| |
| |
| title = Paragraph(topic, title_style) |
| story.append(title) |
| story.append(Spacer(1, 20)) |
| |
| |
| if draft_text and draft_text.strip(): |
| |
| paragraphs = draft_text.split('\n\n') |
| |
| for paragraph in paragraphs: |
| paragraph = paragraph.strip() |
| if paragraph: |
| |
| if paragraph.startswith('#') or re.match(r'^\d+\.', paragraph): |
| |
| heading_text = re.sub(r'^#+\s*', '', paragraph) |
| heading_text = re.sub(r'^\d+\.\s*', '', heading_text) |
| heading = Paragraph(heading_text, heading_style) |
| story.append(heading) |
| else: |
| |
| body = Paragraph(paragraph, body_style) |
| story.append(body) |
| |
| story.append(Spacer(1, 6)) |
| |
| |
| if bibliography and bibliography.strip(): |
| story.append(PageBreak()) |
| story.append(Paragraph("Bibliography", heading_style)) |
| story.append(Spacer(1, 12)) |
| |
| |
| 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)) |
| |
| |
| doc.build(story) |
| |
| print("✅ PDF saved successfully!") |
| |
| except Exception as e: |
| print(f"❌ Error saving PDF: {e}") |
| raise |
|
|
|
|
|
|
| |