function export_to_pdf_v1
Flask route handler that exports a chat conversation to a PDF file with formatted messages, roles, and references using the reportlab library.
/tf/active/vicechatdev/docchat/app.py
1839 - 1962
moderate
Purpose
This function provides a PDF export feature for chat conversations in a DocChat application. It receives a conversation history via POST request, formats it with custom styles (different colors for user/assistant messages), includes references when present, and returns a downloadable PDF file. The function is protected by login_required decorator and handles errors gracefully, including missing reportlab dependency.
Source Code
def export_to_pdf():
"""Export chat conversation to PDF"""
try:
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
from reportlab.lib.colors import HexColor
from io import BytesIO
data = request.get_json()
conversation = data.get('conversation', [])
if not conversation:
return jsonify({'error': 'No conversation to export'}), 400
# Create PDF
file_stream = BytesIO()
doc = SimpleDocTemplate(file_stream, pagesize=letter,
topMargin=0.75*inch, bottomMargin=0.75*inch)
# Define styles
styles = getSampleStyleSheet()
title_style = ParagraphStyle(
'CustomTitle',
parent=styles['Heading1'],
fontSize=24,
textColor=HexColor('#2563eb'),
spaceAfter=30,
alignment=1 # Center
)
date_style = ParagraphStyle(
'DateStyle',
parent=styles['Normal'],
fontSize=10,
textColor=HexColor('#808080'),
alignment=1 # Center
)
user_style = ParagraphStyle(
'UserStyle',
parent=styles['Heading2'],
fontSize=14,
textColor=HexColor('#2563eb'),
spaceAfter=6
)
assistant_style = ParagraphStyle(
'AssistantStyle',
parent=styles['Heading2'],
fontSize=14,
textColor=HexColor('#10b981'),
spaceAfter=6
)
content_style = ParagraphStyle(
'ContentStyle',
parent=styles['Normal'],
fontSize=11,
leading=16
)
ref_style = ParagraphStyle(
'RefStyle',
parent=styles['Normal'],
fontSize=9,
leftIndent=20
)
# Build document
story = []
# Add title
story.append(Paragraph('DocChat Conversation History', title_style))
story.append(Paragraph(
f'Exported on {datetime.now().strftime("%B %d, %Y at %H:%M")}',
date_style
))
story.append(Spacer(1, 0.5*inch))
# Add conversation
for msg in conversation:
role = msg.get('role', 'user')
content = msg.get('content', '')
# Add role heading
if role == 'user':
story.append(Paragraph('You', user_style))
else:
story.append(Paragraph('Assistant', assistant_style))
# Add content (escape HTML special chars)
escaped_content = content.replace('&', '&').replace('<', '<').replace('>', '>')
story.append(Paragraph(escaped_content, content_style))
# Add references if present
if role == 'assistant' and 'references' in msg and msg['references']:
story.append(Spacer(1, 0.1*inch))
story.append(Paragraph('<b>References:</b>', ref_style))
for i, ref in enumerate(msg['references'], 1):
ref_text = f"{i}. {ref.get('file_name', 'Unknown document')}"
story.append(Paragraph(ref_text, ref_style))
story.append(Spacer(1, 0.3*inch))
# Build PDF
doc.build(story)
file_stream.seek(0)
return send_file(
file_stream,
mimetype='application/pdf',
as_attachment=True,
download_name=f'chat-export-{datetime.now().strftime("%Y%m%d")}.pdf'
)
except ImportError:
logger.error("reportlab not installed")
return jsonify({'error': 'PDF export requires reportlab library'}), 500
except Exception as e:
logger.error(f"Error exporting to PDF: {e}")
return jsonify({'error': str(e)}), 500
Return Value
Returns a Flask Response object containing either: (1) A PDF file (mimetype='application/pdf') with filename format 'chat-export-YYYYMMDD.pdf' for successful exports, (2) A JSON error response with status 400 if conversation is empty, (3) A JSON error response with status 500 if reportlab is not installed or other exceptions occur. The PDF contains formatted conversation with title, export date, role-based colored headings, message content, and references.
Dependencies
flaskreportlabloggingdatetimeio
Required Imports
from flask import request
from flask import jsonify
from flask import send_file
from datetime import datetime
import logging
Conditional/Optional Imports
These imports are only needed under specific conditions:
from reportlab.lib.pagesizes import letter
Condition: Required for PDF generation, imported lazily inside function to handle missing dependency gracefully
Required (conditional)from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
Condition: Required for PDF styling, imported lazily inside function
Required (conditional)from reportlab.lib.units import inch
Condition: Required for PDF layout measurements, imported lazily inside function
Required (conditional)from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
Condition: Required for PDF document structure, imported lazily inside function
Required (conditional)from reportlab.lib.colors import HexColor
Condition: Required for custom color styling in PDF, imported lazily inside function
Required (conditional)from io import BytesIO
Condition: Required for in-memory file handling, imported lazily inside function
Required (conditional)Usage Example
# Client-side usage (JavaScript fetch example):
const conversation = [
{role: 'user', content: 'What is machine learning?'},
{role: 'assistant', content: 'Machine learning is...', references: [{file_name: 'ml_guide.pdf'}]}
];
fetch('/api/export/pdf', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({conversation: conversation})
})
.then(response => response.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'chat-export.pdf';
a.click();
});
# Server-side testing:
import requests
response = requests.post('http://localhost:5000/api/export/pdf',
json={'conversation': [{'role': 'user', 'content': 'Hello'}]},
cookies={'session': 'valid_session_token'})
with open('export.pdf', 'wb') as f:
f.write(response.content)
Best Practices
- Always ensure reportlab is installed before deploying this feature (pip install reportlab)
- The function escapes HTML special characters (&, <, >) to prevent PDF rendering issues
- Validate conversation data on client-side before sending to reduce 400 errors
- The function uses BytesIO for in-memory file handling to avoid disk I/O
- Error handling includes specific ImportError for missing reportlab dependency
- PDF styling uses HexColor for consistent branding (blue for user, green for assistant)
- The login_required decorator must be properly configured to protect this endpoint
- Consider adding rate limiting to prevent abuse of PDF generation
- Large conversations may cause memory issues; consider pagination or size limits
- The function uses secure filename generation with timestamp to avoid conflicts
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function export_report 73.6% similar
-
function export_to_word 72.6% similar
-
function export_to_pdf 67.4% similar
-
function export_document 66.8% similar
-
function api_export_document 66.2% similar