from reportlab.platypus import Frame, NextPageTemplate, PageTemplate, BaseDocTemplate, Paragraph, Image, Spacer,Paragraph
from reportlab.lib.units import cm
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
from reportlab.lib.enums import TA_JUSTIFY
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from datetime import datetime
def generate_pdf_report(disease_info, filename="report.pdf")->None:
"""Generates a scientific article-style PDF report with two-column layout and a logo."""
# Custom styles
styles = getSampleStyleSheet()
# Add custom styles
styles.add(ParagraphStyle(
name='TitleStyle',
parent=styles['Heading1'],
fontSize=16,
leading=20,
alignment=1, # Center
spaceAfter=20,
textColor=colors.darkblue
))
styles.add(ParagraphStyle(
name='AuthorStyle',
parent=styles['Heading3'],
fontSize=10,
leading=12,
alignment=1,
spaceAfter=20,
textColor=colors.darkgrey
))
styles.add(ParagraphStyle(
name='AbstractStyle',
parent=styles['BodyText'],
fontSize=10,
leading=12,
alignment=TA_JUSTIFY,
backColor=colors.lightgrey,
borderPadding=5,
spaceAfter=20
))
styles.add(ParagraphStyle(
name='SectionHeader',
parent=styles['Heading2'],
fontSize=12,
leading=14,
spaceBefore=15,
spaceAfter=10,
textColor=colors.darkblue,
underlineWidth=1,
underlineColor=colors.darkblue,
underlineOffset=-5
))
styles.add(ParagraphStyle(
name='LeftColumn',
parent=styles['BodyText'],
fontSize=10,
leading=12,
alignment=TA_JUSTIFY,
leftIndent=0,
rightIndent=5,
spaceAfter=7
))
styles.add(ParagraphStyle(
name='RightColumn',
parent=styles['BodyText'],
fontSize=10,
leading=12,
alignment=TA_JUSTIFY,
leftIndent=5,
rightIndent=0,
spaceAfter=7
))
styles.add(ParagraphStyle(
name='BulletPoint',
parent=styles['BodyText'],
fontSize=10,
leading=12,
leftIndent=15,
bulletIndent=0,
spaceAfter=3,
bulletFontName='Symbol',
bulletFontSize=8
))
styles.add(ParagraphStyle(
name='Reference',
parent=styles['Italic'],
fontSize=8,
leading=10,
textColor=colors.darkgrey,
spaceBefore=15
))
# Create document with two columns
class TwoColumnDocTemplate(BaseDocTemplate):
def __init__(self, filename, **kw):
BaseDocTemplate.__init__(self, filename, **kw)
# Calculate column widths
page_width = self.pagesize[0] - 2*self.leftMargin
col_width = (page_width - 1*cm) / 2 # 1cm gutter
# First page template with title
first_page = PageTemplate(id='FirstPage',
frames=[
Frame(self.leftMargin, self.bottomMargin,
col_width, self.height,
id='leftCol'),
Frame(self.leftMargin + col_width + 1*cm,
self.bottomMargin,
col_width, self.height,
id='rightCol')
])
self.addPageTemplates(first_page)
# Other pages template
other_pages = PageTemplate(id='OtherPages',
frames=[
Frame(self.leftMargin, self.bottomMargin,
col_width, self.height,
id='leftCol2'),
Frame(self.leftMargin + col_width + 1*cm,
self.bottomMargin,
col_width, self.height,
id='rightCol2')
])
self.addPageTemplates(other_pages)
doc = TwoColumnDocTemplate(filename,
pagesize=letter,
leftMargin=2*cm,
rightMargin=2*cm,
topMargin=2*cm,
bottomMargin=2*cm)
story = []
# Add logo at the top (centered)
try:
logo = Image('app/data/logo_platform.jpg', width=6*cm, height=2*cm)
logo.hAlign = 'CENTER'
story.append(logo)
story.append(Spacer(1, 0.3*cm))
except Exception as e:
pass # If logo not found, skip
# Title and authors
title = Paragraph(disease_info.get('Title', 'Medical Condition Report'), styles['TitleStyle'])
authors = Paragraph("Generated by AIHealthCheck AI Assistant", styles['AuthorStyle'])
date = Paragraph(datetime.now().strftime("%B %d, %Y"), styles['AuthorStyle'])
story.append(title)
story.append(authors)
story.append(date)
story.append(NextPageTemplate('OtherPages')) # Switch to two-column layout
# Abstract
abstract_text = f"Abstract
{disease_info.get('Overview', 'No overview available.')}"
abstract = Paragraph(abstract_text, styles['AbstractStyle'])
story.append(abstract)
# Function to format content
def format_content(text, styles):
if not text:
return []
# If it's a list, return each item as a bullet paragraph
if isinstance(text, list):
return [Paragraph(f"• {item}", styles) for item in text]
# If it's a dict, render each key-value pair
if isinstance(text, dict):
items = []
for key, value in text.items():
if isinstance(value, list):
items.append(Paragraph(f"{key}:", styles))
items.extend([Paragraph(f"• {v}", styles) for v in value])
else:
items.append(Paragraph(f"• {key}: {value}", styles))
return items
# Otherwise, treat it as a simple paragraph
return [Paragraph(text, styles)]
# Organize content into left and right columns
left_column_content = [
('Symptoms', disease_info.get('Symptoms')),
('Causes', disease_info.get('Causes')),
('Risk Factors', disease_info.get('Risk factors')),
('Complications', disease_info.get('Complications'))
]
right_column_content = [
('Diagnosis', disease_info.get('Diagnosis')),
('Treatment', disease_info.get('Treatment')),
('Prevention', disease_info.get('Prevention')),
('When to See a Doctor', disease_info.get('When to see a doctor')),
('Lifestyle and Home Remedies', disease_info.get('Lifestyle and home remedies'))
]
# Add left column content
for section, content in left_column_content:
if content:
story.append(Paragraph(section, styles['SectionHeader']))
formatted = format_content(content, styles['LeftColumn'])
if isinstance(formatted, list):
story.extend(formatted)
else:
story.append(formatted)
# Switch to right column
story.append(NextPageTemplate('OtherPages'))
# Add right column content
for section, content in right_column_content:
if content:
story.append(Paragraph(section, styles['SectionHeader']))
formatted = format_content(content, styles['RightColumn'])
if isinstance(formatted, list):
story.extend(formatted)
else:
story.append(formatted)
# Add references
story.append(Paragraph("Medical Recommendations", styles['SectionHeader']))
story.append(Paragraph(disease_info.get('Medical Recommendation', 'No medical recommendations available.'), styles['LeftColumn']))
story.append(Paragraph("References", styles['SectionHeader']))
story.append(Paragraph("1. Mayo Clinic Medical References", styles['Reference']))
# Build the PDF
doc.build(story)