Ali2206 commited on
Commit
c452c78
·
1 Parent(s): 5a50355

device token

Browse files
Files changed (1) hide show
  1. api/routes/pdf.py +179 -38
api/routes/pdf.py CHANGED
@@ -2,6 +2,12 @@ from fastapi import APIRouter, HTTPException, Depends, Response
2
  from db.mongo import patients_collection
3
  from core.security import get_current_user
4
  from utils.helpers import calculate_age, format_timestamp
 
 
 
 
 
 
5
  from datetime import datetime
6
  from bson import ObjectId
7
  from bson.errors import InvalidId
@@ -46,47 +52,182 @@ async def generate_patient_pdf(patient_id: str, current_user: dict = Depends(get
46
  # Set the generated_on date
47
  generated_on = datetime.now().strftime("%A, %B %d, %Y at %I:%M %p %Z")
48
 
49
- # For now, always generate a text report to avoid LaTeX dependencies
50
- print("📄 Generating text report (LaTeX not available)")
51
 
52
- # Create a simple text report
53
- text_report = f"""
54
- PATIENT MEDICAL REPORT
55
- Generated on {generated_on}
56
-
57
- DEMOGRAPHICS:
58
- - FHIR ID: {patient.get('fhir_id', 'N/A')}
59
- - Full Name: {patient.get('full_name', 'N/A')}
60
- - Gender: {patient.get('gender', 'N/A')}
61
- - Date of Birth: {patient.get('date_of_birth', 'N/A')}
62
- - Age: {calculate_age(patient.get('date_of_birth', '')) or 'N/A'}
63
- - Address: {', '.join(filter(None, [
64
- patient.get('address', ''),
65
- patient.get('city', ''),
66
- patient.get('state', ''),
67
- patient.get('postal_code', ''),
68
- patient.get('country', '')
69
- ]))}
70
- - Marital Status: {patient.get('marital_status', 'N/A')}
71
- - Language: {patient.get('language', 'N/A')}
72
-
73
- CLINICAL NOTES:
74
- {chr(10).join([f"- {n.get('date', 'N/A')} | {n.get('type', 'N/A')}: {n.get('text', 'N/A')}" for n in notes]) if notes else "No notes available"}
75
-
76
- CONDITIONS:
77
- {chr(10).join([f"- {c.get('code', 'N/A')} | Status: {c.get('status', 'N/A')} | Onset: {c.get('onset_date', 'N/A')}" for c in conditions]) if conditions else "No conditions available"}
78
-
79
- MEDICATIONS:
80
- {chr(10).join([f"- {m.get('name', 'N/A')} | Status: {m.get('status', 'N/A')} | Dosage: {m.get('dosage', 'N/A')}" for m in medications]) if medications else "No medications available"}
81
-
82
- ENCOUNTERS:
83
- {chr(10).join([f"- {e.get('type', 'N/A')} | Status: {e.get('status', 'N/A')} | Provider: {e.get('service_provider', 'N/A')}" for e in encounters]) if encounters else "No encounters available"}
84
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
  response = Response(
87
- content=text_report,
88
- media_type="text/plain",
89
- headers={"Content-Disposition": f"attachment; filename=patient_{patient.get('fhir_id', 'unknown')}_report.txt"}
90
  )
91
  return response
92
 
 
2
  from db.mongo import patients_collection
3
  from core.security import get_current_user
4
  from utils.helpers import calculate_age, format_timestamp
5
+ from reportlab.lib.pagesizes import letter, A4
6
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
7
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
8
+ from reportlab.lib.units import inch
9
+ from reportlab.lib import colors
10
+ from io import BytesIO
11
  from datetime import datetime
12
  from bson import ObjectId
13
  from bson.errors import InvalidId
 
52
  # Set the generated_on date
53
  generated_on = datetime.now().strftime("%A, %B %d, %Y at %I:%M %p %Z")
54
 
55
+ # Generate PDF using ReportLab
56
+ print("📄 Generating PDF report using ReportLab")
57
 
58
+ # Create a buffer to store the PDF
59
+ buffer = BytesIO()
60
+
61
+ # Create the PDF document
62
+ doc = SimpleDocTemplate(buffer, pagesize=A4)
63
+ story = []
64
+
65
+ # Get styles
66
+ styles = getSampleStyleSheet()
67
+ title_style = ParagraphStyle(
68
+ 'CustomTitle',
69
+ parent=styles['Heading1'],
70
+ fontSize=16,
71
+ spaceAfter=30,
72
+ alignment=1 # Center alignment
73
+ )
74
+ heading_style = ParagraphStyle(
75
+ 'CustomHeading',
76
+ parent=styles['Heading2'],
77
+ fontSize=14,
78
+ spaceAfter=12,
79
+ spaceBefore=20
80
+ )
81
+ normal_style = styles['Normal']
82
+
83
+ # Title
84
+ story.append(Paragraph("PATIENT MEDICAL REPORT", title_style))
85
+ story.append(Paragraph(f"Generated on {generated_on}", normal_style))
86
+ story.append(Spacer(1, 20))
87
+
88
+ # Demographics section
89
+ story.append(Paragraph("DEMOGRAPHICS", heading_style))
90
+
91
+ demographics_data = [
92
+ ["FHIR ID", patient.get('fhir_id', 'N/A')],
93
+ ["Full Name", patient.get('full_name', 'N/A')],
94
+ ["Gender", patient.get('gender', 'N/A')],
95
+ ["Date of Birth", patient.get('date_of_birth', 'N/A')],
96
+ ["Age", str(calculate_age(patient.get('date_of_birth', '')) or 'N/A')],
97
+ ["Address", ', '.join(filter(None, [
98
+ patient.get('address', ''),
99
+ patient.get('city', ''),
100
+ patient.get('state', ''),
101
+ patient.get('postal_code', ''),
102
+ patient.get('country', '')
103
+ ]))],
104
+ ["Marital Status", patient.get('marital_status', 'N/A')],
105
+ ["Language", patient.get('language', 'N/A')]
106
+ ]
107
+
108
+ demographics_table = Table(demographics_data, colWidths=[2*inch, 4*inch])
109
+ demographics_table.setStyle(TableStyle([
110
+ ('BACKGROUND', (0, 0), (0, -1), colors.grey),
111
+ ('TEXTCOLOR', (0, 0), (0, -1), colors.whitesmoke),
112
+ ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
113
+ ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
114
+ ('FONTSIZE', (0, 0), (-1, -1), 10),
115
+ ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
116
+ ('GRID', (0, 0), (-1, -1), 1, colors.black)
117
+ ]))
118
+ story.append(demographics_table)
119
+ story.append(Spacer(1, 20))
120
+
121
+ # Clinical Notes section
122
+ story.append(Paragraph("CLINICAL NOTES", heading_style))
123
+ if notes:
124
+ notes_data = [["Date", "Type", "Text"]]
125
+ for note in notes:
126
+ notes_data.append([
127
+ note.get('date', 'N/A'),
128
+ note.get('type', 'N/A'),
129
+ note.get('text', 'N/A')[:100] + "..." if len(note.get('text', '')) > 100 else note.get('text', 'N/A')
130
+ ])
131
+ notes_table = Table(notes_data, colWidths=[1.5*inch, 1.5*inch, 3*inch])
132
+ notes_table.setStyle(TableStyle([
133
+ ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
134
+ ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
135
+ ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
136
+ ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
137
+ ('FONTSIZE', (0, 0), (-1, -1), 9),
138
+ ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
139
+ ('GRID', (0, 0), (-1, -1), 1, colors.black)
140
+ ]))
141
+ story.append(notes_table)
142
+ else:
143
+ story.append(Paragraph("No notes available", normal_style))
144
+ story.append(Spacer(1, 20))
145
+
146
+ # Conditions section
147
+ story.append(Paragraph("MEDICAL CONDITIONS", heading_style))
148
+ if conditions:
149
+ conditions_data = [["Code", "Status", "Onset Date"]]
150
+ for condition in conditions:
151
+ conditions_data.append([
152
+ condition.get('code', 'N/A'),
153
+ condition.get('status', 'N/A'),
154
+ condition.get('onset_date', 'N/A')
155
+ ])
156
+ conditions_table = Table(conditions_data, colWidths=[2*inch, 2*inch, 2*inch])
157
+ conditions_table.setStyle(TableStyle([
158
+ ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
159
+ ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
160
+ ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
161
+ ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
162
+ ('FONTSIZE', (0, 0), (-1, -1), 9),
163
+ ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
164
+ ('GRID', (0, 0), (-1, -1), 1, colors.black)
165
+ ]))
166
+ story.append(conditions_table)
167
+ else:
168
+ story.append(Paragraph("No conditions available", normal_style))
169
+ story.append(Spacer(1, 20))
170
+
171
+ # Medications section
172
+ story.append(Paragraph("MEDICATIONS", heading_style))
173
+ if medications:
174
+ medications_data = [["Name", "Status", "Dosage"]]
175
+ for medication in medications:
176
+ medications_data.append([
177
+ medication.get('name', 'N/A'),
178
+ medication.get('status', 'N/A'),
179
+ medication.get('dosage', 'N/A')
180
+ ])
181
+ medications_table = Table(medications_data, colWidths=[2.5*inch, 1.5*inch, 2*inch])
182
+ medications_table.setStyle(TableStyle([
183
+ ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
184
+ ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
185
+ ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
186
+ ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
187
+ ('FONTSIZE', (0, 0), (-1, -1), 9),
188
+ ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
189
+ ('GRID', (0, 0), (-1, -1), 1, colors.black)
190
+ ]))
191
+ story.append(medications_table)
192
+ else:
193
+ story.append(Paragraph("No medications available", normal_style))
194
+ story.append(Spacer(1, 20))
195
+
196
+ # Encounters section
197
+ story.append(Paragraph("ENCOUNTERS", heading_style))
198
+ if encounters:
199
+ encounters_data = [["Type", "Status", "Provider"]]
200
+ for encounter in encounters:
201
+ encounters_data.append([
202
+ encounter.get('type', 'N/A'),
203
+ encounter.get('status', 'N/A'),
204
+ encounter.get('service_provider', 'N/A')
205
+ ])
206
+ encounters_table = Table(encounters_data, colWidths=[2*inch, 1.5*inch, 2.5*inch])
207
+ encounters_table.setStyle(TableStyle([
208
+ ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
209
+ ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
210
+ ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
211
+ ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
212
+ ('FONTSIZE', (0, 0), (-1, -1), 9),
213
+ ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
214
+ ('GRID', (0, 0), (-1, -1), 1, colors.black)
215
+ ]))
216
+ story.append(encounters_table)
217
+ else:
218
+ story.append(Paragraph("No encounters available", normal_style))
219
+
220
+ # Build the PDF
221
+ doc.build(story)
222
+
223
+ # Get the PDF content
224
+ pdf_content = buffer.getvalue()
225
+ buffer.close()
226
 
227
  response = Response(
228
+ content=pdf_content,
229
+ media_type="application/pdf",
230
+ headers={"Content-Disposition": f"attachment; filename=patient_{patient.get('fhir_id', 'unknown')}_report.pdf"}
231
  )
232
  return response
233