File size: 2,817 Bytes
690bcb6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import io
from typing import List, Dict

import streamlit as st


def _import_reportlab():
    try:
        from reportlab.lib.pagesizes import A4
        from reportlab.lib.styles import getSampleStyleSheet
        from reportlab.lib.units import mm
        from reportlab.pdfgen import canvas
        from reportlab.platypus import Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle
        from reportlab.lib import colors
        return {
            "A4": A4,
            "getSampleStyleSheet": getSampleStyleSheet,
            "mm": mm,
            "canvas": canvas,
            "Paragraph": Paragraph,
            "SimpleDocTemplate": SimpleDocTemplate,
            "Spacer": Spacer,
            "Table": Table,
            "TableStyle": TableStyle,
            "colors": colors,
        }
    except Exception:
        return None


def build_chat_pdf(messages: List[Dict[str, str]], title: str = "MediLingua Chat Transcript") -> io.BytesIO:
    """
    Create a PDF from chat messages and return as an in-memory BytesIO buffer.
    Each message is a dict with keys: role ('user'|'assistant'), content (str).
    """
    libs = _import_reportlab()
    if libs is None:
        st.error(
            "PDF generation library not found. Install with: `pip install reportlab` and rerun."
        )
        return None

    buffer = io.BytesIO()

    doc = libs["SimpleDocTemplate"](buffer, pagesize=libs["A4"], rightMargin=28, leftMargin=28, topMargin=36, bottomMargin=28)
    styles = libs["getSampleStyleSheet"]()

    elements = []

    # Title
    title_style = styles["Title"]
    elements.append(libs["Paragraph"](title, title_style))
    elements.append(libs["Spacer"](1, 12))

    # Build a table-like layout for messages
    data = []
    table_style_cmds = [
        ("VALIGN", (0, 0), (-1, -1), "TOP"),
        ("INNERGRID", (0, 0), (-1, -1), 0.25, libs["colors"].lightgrey),
        ("BOX", (0, 0), (-1, -1), 0.25, libs["colors"].lightgrey),
        ("LEFTPADDING", (0, 0), (-1, -1), 6),
        ("RIGHTPADDING", (0, 0), (-1, -1), 6),
        ("TOPPADDING", (0, 0), (-1, -1), 6),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 6),
    ]

    role_style = styles["Heading5"]
    body_style = styles["BodyText"]

    for msg in messages:
        role = msg.get("role", "").capitalize()
        content = msg.get("content", "")

        # Left column: role, Right column: content paragraph
        role_par = libs["Paragraph"](f"<b>{role}</b>", role_style)
        content_par = libs["Paragraph"](content.replace("\n", "<br/>"), body_style)
        data.append([role_par, content_par])

    table = libs["Table"](data, colWidths=[30 * libs["mm"], None])
    table.setStyle(libs["TableStyle"](table_style_cmds))
    elements.append(table)

    doc.build(elements)
    buffer.seek(0)
    return buffer