|
|
|
from reportlab.lib.pagesizes import letter |
|
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image |
|
from reportlab.lib.styles import getSampleStyleSheet |
|
from reportlab.lib.units import inch |
|
from io import BytesIO |
|
from typing import List, Optional |
|
from pathlib import Path |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from models import ChatMessage |
|
from config.settings import settings |
|
from assets.logo import get_logo_path |
|
from services.logger import app_logger |
|
|
|
def generate_pdf_report(chat_messages: List[ChatMessage], patient_name: str = "Patient") -> BytesIO: |
|
buffer = BytesIO() |
|
|
|
doc = SimpleDocTemplate(buffer, pagesize=letter, |
|
leftMargin=0.75*inch, rightMargin=0.75*inch, |
|
topMargin=0.75*inch, bottomMargin=0.75*inch) |
|
styles = getSampleStyleSheet() |
|
story = [] |
|
|
|
|
|
styles['h1'].alignment = 1 |
|
styles['Normal'].spaceBefore = 6 |
|
styles['Normal'].spaceAfter = 6 |
|
code_style = styles['Code'] |
|
code_style.spaceBefore = 6 |
|
code_style.spaceAfter = 6 |
|
code_style.leftIndent = 10 |
|
|
|
|
|
logo_path_str = get_logo_path() |
|
if logo_path_str: |
|
logo_file = Path(logo_path_str) |
|
if logo_file.exists(): |
|
try: |
|
|
|
img = Image(logo_file, width=1.0*inch, height=1.0*inch, preserveAspectRatio=True) |
|
img.hAlign = 'LEFT' |
|
story.append(img) |
|
story.append(Spacer(1, 0.2*inch)) |
|
except Exception as e: |
|
app_logger.warning(f"Could not add logo to PDF from path '{logo_path_str}': {e}") |
|
else: |
|
app_logger.warning(f"Logo path '{logo_path_str}' from get_logo_path() does not exist.") |
|
|
|
|
|
title_text = f"{settings.APP_TITLE} - Consultation Report" |
|
title = Paragraph(title_text, styles['h1']) |
|
story.append(title) |
|
story.append(Spacer(1, 0.2*inch)) |
|
|
|
|
|
patient_info_text = f"<b>Patient:</b> {patient_name}" |
|
patient_info = Paragraph(patient_info_text, styles['h2']) |
|
story.append(patient_info) |
|
story.append(Spacer(1, 0.3*inch)) |
|
|
|
|
|
story.append(Paragraph("<u>Consultation Transcript:</u>", styles['h3'])) |
|
story.append(Spacer(1, 0.1*inch)) |
|
|
|
for msg in chat_messages: |
|
prefix = "" |
|
current_style = styles['Normal'] |
|
|
|
if msg.role == 'assistant': |
|
prefix = "<b>AI Assistant:</b> " |
|
current_style = code_style |
|
elif msg.role == 'user': |
|
prefix = "<b>You:</b> " |
|
current_style = styles['Normal'] |
|
elif msg.role == 'tool': |
|
tool_name = getattr(msg, 'tool_name', 'UnknownTool') |
|
prefix = f"<b>Tool ({tool_name}):</b> " |
|
current_style = code_style |
|
else: |
|
prefix = f"<b>{msg.role.capitalize()}:</b> " |
|
|
|
|
|
|
|
content = msg.content.replace('\n', '<br/>\n') |
|
|
|
content = content.replace("<", "<").replace(">", ">").replace("<br/>", "<br/>") |
|
|
|
try: |
|
story.append(Paragraph(prefix + content, current_style)) |
|
story.append(Spacer(1, 0.05*inch)) |
|
except Exception as e: |
|
app_logger.error(f"Error adding message to PDF: {prefix}{content}. Error: {e}") |
|
story.append(Paragraph(f"<i>Error rendering message: {e}</i>", styles['Italic'])) |
|
|
|
|
|
try: |
|
doc.build(story) |
|
buffer.seek(0) |
|
app_logger.info(f"PDF report generated successfully for patient: {patient_name}") |
|
except Exception as e: |
|
app_logger.error(f"Failed to build PDF document: {e}", exc_info=True) |
|
|
|
buffer = BytesIO() |
|
error_doc = SimpleDocTemplate(buffer, pagesize=letter) |
|
error_story = [Paragraph("Error generating PDF report. Please check logs.", styles['h1'])] |
|
try: |
|
error_doc.build(error_story) |
|
except: pass |
|
buffer.seek(0) |
|
|
|
return buffer |