Dhruv-Ty commited on
Commit
fa383c9
·
verified ·
1 Parent(s): 1015356

Update src/report_generator.py

Browse files
Files changed (1) hide show
  1. src/report_generator.py +189 -61
src/report_generator.py CHANGED
@@ -2,6 +2,7 @@ import json
2
  import os
3
  import re
4
  import tempfile
 
5
  from datetime import datetime
6
  import streamlit as st
7
  from reportlab.lib.pagesizes import A4
@@ -16,6 +17,44 @@ from text_processors import format_conversation_history
16
  from model import orchestrator_chat
17
 
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  def extract_medical_json(conversation_text: str) -> dict:
20
  """
21
  Extract medical report data from conversation text into structured JSON.
@@ -138,12 +177,13 @@ def build_medical_report(data: dict) -> bytes:
138
  # Initialize elements list
139
  elems = []
140
 
141
- # Add logo and company header
142
- logo_path = "src/assets/logo.png" # Adjust path as needed
143
 
144
- # Create a table for the header (logo on left, company info on right)
145
- logo_img = Image(logo_path, width=1.5*inch, height=1.0*inch)
146
 
 
147
  company_info = Paragraph(
148
  """
149
  <b>Daease</b><br/>
@@ -153,19 +193,42 @@ def build_medical_report(data: dict) -> bytes:
153
  styles['CompanyInfo']
154
  )
155
 
156
- header_table = Table([[logo_img, company_info]], colWidths=[doc.width/2.0]*2)
157
- header_table.setStyle(TableStyle([
158
- ('VALIGN', (0, 0), (-1, -1), 'TOP'),
159
- ('ALIGN', (0, 0), (0, 0), 'LEFT'),
160
- ('ALIGN', (1, 0), (1, 0), 'RIGHT'),
161
- ('BOTTOMPADDING', (0, 0), (-1, -1), 10),
162
- ]))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
 
164
  elems.append(header_table)
165
  elems.append(Spacer(1, 0.3*inch))
166
 
167
- # Add title
168
- elems.append(Paragraph("Daease Medical Consultation Report", styles['ReportTitle']))
 
 
 
 
 
 
 
 
 
169
  elems.append(Spacer(1, 0.2*inch))
170
 
171
  # Add a horizontal line
@@ -179,31 +242,51 @@ def build_medical_report(data: dict) -> bytes:
179
  # Patient info in a clean table
180
  patient = data.get('patient', {})
181
 
182
- # Format the patient table data
183
  patient_data = [
184
- ['Patient Information', ''],
185
- ['Name:', patient.get('name', '–')],
186
- ['Age:', patient.get('age', '–')],
187
- ['Gender:', patient.get('gender', '–')],
188
- ['Visit Date:', data.get('visit_date', datetime.now().strftime("%Y-%m-%d"))]
189
  ]
190
 
191
- patient_table = Table(patient_data, colWidths=[doc.width * 0.3, doc.width * 0.7])
 
 
 
 
 
192
  patient_table.setStyle(TableStyle([
193
- ('BACKGROUND', (0, 0), (1, 0), colors.navy),
194
- ('TEXTCOLOR', (0, 0), (1, 0), colors.white),
195
- ('FONTNAME', (0, 0), (1, 0), 'Helvetica-Bold'),
196
- ('SPAN', (0, 0), (1, 0)),
197
- ('ALIGN', (0, 0), (1, 0), 'CENTER'),
 
 
 
 
 
 
 
 
 
 
 
198
  ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
199
- ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
200
- ('BOX', (0, 0), (-1, -1), 1, colors.darkblue),
 
 
 
 
201
  ]))
202
 
203
  elems.append(patient_table)
204
  elems.append(Spacer(1, 0.3*inch))
205
 
206
- # Helper to add sections as tables
207
  def add_section_table(title, content):
208
  if isinstance(content, list):
209
  content = '\n'.join(map(str, content))
@@ -213,26 +296,43 @@ def build_medical_report(data: dict) -> bytes:
213
  if not content or content.strip() == '':
214
  content = '–'
215
 
 
216
  section_data = [
217
- [title, ''],
218
- [Paragraph(content, styles['NormalText']), '']
 
 
 
 
 
 
 
 
 
219
  ]
220
 
221
- # Create table and span the content cell
222
- table = Table(section_data, colWidths=[doc.width * 0.97, doc.width * 0.03])
223
  table.setStyle(TableStyle([
224
- ('BACKGROUND', (0, 0), (1, 0), colors.lightblue),
225
- ('TEXTCOLOR', (0, 0), (1, 0), colors.navy),
226
- ('FONTNAME', (0, 0), (1, 0), 'Helvetica-Bold'),
227
- ('SPAN', (0, 0), (1, 0)), # Span the header row
228
- ('SPAN', (0, 1), (1, 1)), # Span the content row
229
- ('ALIGN', (0, 0), (0, 0), 'LEFT'),
230
- ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
 
 
 
 
 
 
 
 
231
  ('BOX', (0, 0), (-1, -1), 1, colors.lightgrey),
232
- ('LINEBELOW', (0, 0), (1, 0), 1, colors.navy),
233
  ]))
234
 
235
- elems.append(KeepTogether([table, Spacer(1, 0.1*inch)]))
236
 
237
  # Add all medical information sections as tables
238
  add_section_table("Chief Complaint", data.get('chief_complaint'))
@@ -249,27 +349,51 @@ def build_medical_report(data: dict) -> bytes:
249
  # Add AI signature section
250
  elems.append(Spacer(1, 0.4*inch))
251
 
252
- # Try to add AI signature image if available
253
- signature_path = "assets/Logo/LOGO.png" # Fallback to logo if no signature available
254
- try:
255
- signature_img = Image(signature_path, width=1.2*inch, height=0.8*inch)
256
- signature_table = Table([
257
- [Paragraph("<i>Generated by</i>", styles['NormalText'])],
258
- [signature_img],
259
- [Paragraph("<b>Daease AI Medical Assistant</b>", styles['NormalText'])]
260
- ], colWidths=[doc.width * 0.3])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
 
262
- signature_table.setStyle(TableStyle([
263
  ('ALIGN', (0, 0), (0, -1), 'CENTER'),
264
  ('VALIGN', (0, 0), (0, -1), 'MIDDLE'),
265
  ]))
266
- elems.append(signature_table)
267
- except:
268
- # Fallback if image can't be loaded
269
- elems.append(Paragraph("<i>Generated by Daease AI Medical Assistant</i>", styles['NormalText']))
 
 
 
 
 
 
 
 
 
 
270
 
271
- # Add disclaimer
272
- elems.append(Spacer(1, 0.2*inch))
273
  disclaimer = Paragraph(
274
  "<i>Disclaimer: This report is generated by AI for informational purposes only. "
275
  "It should not replace professional medical advice, diagnosis, or treatment. "
@@ -278,7 +402,11 @@ def build_medical_report(data: dict) -> bytes:
278
  name='Disclaimer',
279
  fontName='Helvetica-Oblique',
280
  fontSize=8,
281
- textColor=colors.grey
 
 
 
 
282
  )
283
  )
284
  elems.append(disclaimer)
@@ -349,7 +477,7 @@ def generate_and_download_report():
349
  st.session_state.pdf_data = pdf_bytes # Store PDF data for email
350
 
351
  # Display success message
352
- st.success("Report is ready!")
353
 
354
  # Create two columns for the download and email buttons
355
  col1, col2 = st.columns(2)
@@ -357,7 +485,7 @@ def generate_and_download_report():
357
  with col1:
358
  # Offer download
359
  st.download_button(
360
- label="Download Report",
361
  data=pdf_bytes,
362
  file_name=f"medical_report_{datetime.now().strftime('%Y%m%d')}.pdf",
363
  mime="application/pdf",
@@ -366,7 +494,7 @@ def generate_and_download_report():
366
 
367
  with col2:
368
  # Email button that shows email form when clicked
369
- if st.button("Email Report"):
370
  st.session_state.show_email_form = True
371
  st.rerun()
372
 
 
2
  import os
3
  import re
4
  import tempfile
5
+ import base64
6
  from datetime import datetime
7
  import streamlit as st
8
  from reportlab.lib.pagesizes import A4
 
17
  from model import orchestrator_chat
18
 
19
 
20
+ # Function to encode images to base64 (similar to app.py)
21
+ def get_image_base64(image_path):
22
+ try:
23
+ if os.path.exists(image_path):
24
+ with open(image_path, "rb") as img_file:
25
+ return base64.b64encode(img_file.read()).decode()
26
+ else:
27
+ print(f"Image not found: {image_path}")
28
+ return None
29
+ except Exception as e:
30
+ print(f"Error loading image: {e}")
31
+ return None
32
+
33
+
34
+ # Function to get reportlab Image object or None
35
+ def get_reportlab_image(image_path, width=1.5*inch, height=1.0*inch):
36
+ try:
37
+ if os.path.exists(image_path):
38
+ return Image(image_path, width=width, height=height)
39
+ else:
40
+ # Try to find it in alternate locations
41
+ alt_paths = [
42
+ f"assets/{os.path.basename(image_path)}",
43
+ f"assets/Logo/{os.path.basename(image_path)}",
44
+ image_path.replace("src/assets", "assets")
45
+ ]
46
+
47
+ for path in alt_paths:
48
+ if os.path.exists(path):
49
+ return Image(path, width=width, height=height)
50
+
51
+ print(f"Image not found: {image_path}")
52
+ return None
53
+ except Exception as e:
54
+ print(f"Error creating image: {str(e)}")
55
+ return None
56
+
57
+
58
  def extract_medical_json(conversation_text: str) -> dict:
59
  """
60
  Extract medical report data from conversation text into structured JSON.
 
177
  # Initialize elements list
178
  elems = []
179
 
180
+ # Add logo and company header - use path from app.py
181
+ logo_path = "src/assets/Logo_no_background.png"
182
 
183
+ # Get logo image using our helper
184
+ logo_img = get_reportlab_image(logo_path)
185
 
186
+ # Create a table for the header (logo on left, company info on right)
187
  company_info = Paragraph(
188
  """
189
  <b>Daease</b><br/>
 
193
  styles['CompanyInfo']
194
  )
195
 
196
+ if logo_img:
197
+ # Use the logo in the header table
198
+ header_table = Table([[logo_img, company_info]], colWidths=[doc.width/2.0]*2)
199
+ header_table.setStyle(TableStyle([
200
+ ('VALIGN', (0, 0), (-1, -1), 'TOP'),
201
+ ('ALIGN', (0, 0), (0, 0), 'LEFT'),
202
+ ('ALIGN', (1, 0), (1, 0), 'RIGHT'),
203
+ ('BOTTOMPADDING', (0, 0), (-1, -1), 10),
204
+ ]))
205
+ else:
206
+ # Fallback to text-only header if logo can't be loaded
207
+ header_table = Table([['Daease', company_info]], colWidths=[doc.width/2.0]*2)
208
+ header_table.setStyle(TableStyle([
209
+ ('VALIGN', (0, 0), (-1, -1), 'TOP'),
210
+ ('ALIGN', (0, 0), (0, 0), 'LEFT'),
211
+ ('ALIGN', (1, 0), (1, 0), 'RIGHT'),
212
+ ('BOTTOMPADDING', (0, 0), (-1, -1), 10),
213
+ ('FONTNAME', (0, 0), (0, 0), 'Helvetica-Bold'),
214
+ ('FONTSIZE', (0, 0), (0, 0), 14),
215
+ ('TEXTCOLOR', (0, 0), (0, 0), colors.navy),
216
+ ]))
217
 
218
  elems.append(header_table)
219
  elems.append(Spacer(1, 0.3*inch))
220
 
221
+ # Add title - with more prominent styling
222
+ title_style = ParagraphStyle(
223
+ name='ReportTitleEnhanced',
224
+ fontName='Helvetica-Bold',
225
+ fontSize=18,
226
+ leading=22,
227
+ alignment=TA_CENTER,
228
+ spaceAfter=0.3*inch,
229
+ textColor=colors.navy
230
+ )
231
+ elems.append(Paragraph("Daease Medical Consultation Report", title_style))
232
  elems.append(Spacer(1, 0.2*inch))
233
 
234
  # Add a horizontal line
 
242
  # Patient info in a clean table
243
  patient = data.get('patient', {})
244
 
245
+ # Format the patient table data with improved styling
246
  patient_data = [
247
+ ['Patient Information', '', ''],
248
+ ['Name:', patient.get('name', '–'), ''],
249
+ ['Age:', patient.get('age', '–'), ''],
250
+ ['Gender:', patient.get('gender', '–'), ''],
251
+ ['Visit Date:', data.get('visit_date', datetime.now().strftime("%Y-%m-%d")), '']
252
  ]
253
 
254
+ # Create a more structured patient table with better column distribution
255
+ patient_table = Table(
256
+ patient_data,
257
+ colWidths=[doc.width * 0.2, doc.width * 0.5, doc.width * 0.3],
258
+ rowHeights=[0.4*inch, 0.3*inch, 0.3*inch, 0.3*inch, 0.3*inch]
259
+ )
260
  patient_table.setStyle(TableStyle([
261
+ # Header row styling
262
+ ('BACKGROUND', (0, 0), (2, 0), colors.navy),
263
+ ('TEXTCOLOR', (0, 0), (2, 0), colors.white),
264
+ ('FONTNAME', (0, 0), (2, 0), 'Helvetica-Bold'),
265
+ ('SPAN', (0, 0), (2, 0)), # Span all columns in header
266
+ ('ALIGN', (0, 0), (2, 0), 'CENTER'),
267
+
268
+ # Label column styling (first column)
269
+ ('FONTNAME', (0, 1), (0, -1), 'Helvetica-Bold'),
270
+ ('ALIGN', (0, 1), (0, -1), 'RIGHT'),
271
+ ('RIGHTPADDING', (0, 1), (0, -1), 10),
272
+
273
+ # Value column styling (second column)
274
+ ('ALIGN', (1, 1), (1, -1), 'LEFT'),
275
+
276
+ # Table borders and grid
277
  ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
278
+ ('GRID', (0, 0), (1, -1), 0.5, colors.lightgrey),
279
+ ('BOX', (0, 0), (1, -1), 1, colors.darkblue),
280
+
281
+ # Alternating row colors for better readability
282
+ ('BACKGROUND', (0, 1), (1, 1), colors.whitesmoke),
283
+ ('BACKGROUND', (0, 3), (1, 3), colors.whitesmoke),
284
  ]))
285
 
286
  elems.append(patient_table)
287
  elems.append(Spacer(1, 0.3*inch))
288
 
289
+ # Helper to add sections as tables with improved styling
290
  def add_section_table(title, content):
291
  if isinstance(content, list):
292
  content = '\n'.join(map(str, content))
 
296
  if not content or content.strip() == '':
297
  content = '–'
298
 
299
+ # Create a gradient-like effect with nested tables
300
  section_data = [
301
+ # Header row with gradient-like styling
302
+ [Paragraph(f"<b>{title}</b>",
303
+ ParagraphStyle(
304
+ name='TableHeader',
305
+ fontName='Helvetica-Bold',
306
+ fontSize=11,
307
+ textColor=colors.white,
308
+ alignment=TA_LEFT
309
+ ))],
310
+ # Content row
311
+ [Paragraph(content, styles['NormalText'])]
312
  ]
313
 
314
+ # Create the main table
315
+ table = Table(section_data, colWidths=[doc.width * 0.97], rowHeights=[0.35*inch, None])
316
  table.setStyle(TableStyle([
317
+ # Header styling with gradient-like effect
318
+ ('BACKGROUND', (0, 0), (0, 0), colors.navy),
319
+ ('LINEBELOW', (0, 0), (0, 0), 1, colors.darkblue),
320
+ ('LEFTPADDING', (0, 0), (0, 0), 10),
321
+ ('TOPPADDING', (0, 0), (0, 0), 6),
322
+ ('BOTTOMPADDING', (0, 0), (0, 0), 6),
323
+
324
+ # Content styling
325
+ ('LEFTPADDING', (0, 1), (0, 1), 10),
326
+ ('RIGHTPADDING', (0, 1), (0, 1), 10),
327
+ ('TOPPADDING', (0, 1), (0, 1), 8),
328
+ ('BOTTOMPADDING', (0, 1), (0, 1), 8),
329
+ ('BACKGROUND', (0, 1), (0, 1), colors.white),
330
+
331
+ # Border styling
332
  ('BOX', (0, 0), (-1, -1), 1, colors.lightgrey),
 
333
  ]))
334
 
335
+ elems.append(KeepTogether([table, Spacer(1, 0.15*inch)]))
336
 
337
  # Add all medical information sections as tables
338
  add_section_table("Chief Complaint", data.get('chief_complaint'))
 
349
  # Add AI signature section
350
  elems.append(Spacer(1, 0.4*inch))
351
 
352
+ # Add a horizontal line before signature
353
+ sig_line = Table([['']], colWidths=[doc.width], rowHeights=[1])
354
+ sig_line.setStyle(TableStyle([
355
+ ('LINEABOVE', (0, 0), (-1, -1), 0.5, colors.grey),
356
+ ]))
357
+ elems.append(sig_line)
358
+ elems.append(Spacer(1, 0.2*inch))
359
+
360
+ # Create a robust signature section
361
+ signature_text = Paragraph("<i>Generated by</i>", styles['NormalText'])
362
+ ai_name = Paragraph("<b>Daease AI Medical Assistant</b>", styles['NormalText'])
363
+
364
+ # Use the same logo path for signature
365
+ signature_img = get_reportlab_image("src/assets/logo.png", width=1.2*inch, height=0.8*inch)
366
+
367
+ if signature_img:
368
+ # Create a 3-column table for better alignment
369
+ sig_table = Table(
370
+ [[signature_text, '', ''],
371
+ [signature_img, '', ''],
372
+ [ai_name, '', '']],
373
+ colWidths=[doc.width * 0.3, doc.width * 0.35, doc.width * 0.35]
374
+ )
375
 
376
+ sig_table.setStyle(TableStyle([
377
  ('ALIGN', (0, 0), (0, -1), 'CENTER'),
378
  ('VALIGN', (0, 0), (0, -1), 'MIDDLE'),
379
  ]))
380
+ elems.append(sig_table)
381
+ else:
382
+ # Text-only fallback for signature
383
+ sig_text = Paragraph(
384
+ "<i>Generated by</i><br/><b>Daease AI Medical Assistant</b>",
385
+ ParagraphStyle(
386
+ name='SignatureText',
387
+ fontName='Helvetica-Bold',
388
+ fontSize=10,
389
+ alignment=TA_LEFT,
390
+ spaceAfter=0.1*inch
391
+ )
392
+ )
393
+ elems.append(sig_text)
394
 
395
+ # Add disclaimer with more distinctive styling
396
+ elems.append(Spacer(1, 0.3*inch))
397
  disclaimer = Paragraph(
398
  "<i>Disclaimer: This report is generated by AI for informational purposes only. "
399
  "It should not replace professional medical advice, diagnosis, or treatment. "
 
402
  name='Disclaimer',
403
  fontName='Helvetica-Oblique',
404
  fontSize=8,
405
+ textColor=colors.grey,
406
+ borderWidth=1,
407
+ borderColor=colors.lightgrey,
408
+ borderPadding=5,
409
+ borderRadius=2
410
  )
411
  )
412
  elems.append(disclaimer)
 
477
  st.session_state.pdf_data = pdf_bytes # Store PDF data for email
478
 
479
  # Display success message
480
+ st.success("Your medical report is ready!")
481
 
482
  # Create two columns for the download and email buttons
483
  col1, col2 = st.columns(2)
 
485
  with col1:
486
  # Offer download
487
  st.download_button(
488
+ label="📥 Download Report",
489
  data=pdf_bytes,
490
  file_name=f"medical_report_{datetime.now().strftime('%Y%m%d')}.pdf",
491
  mime="application/pdf",
 
494
 
495
  with col2:
496
  # Email button that shows email form when clicked
497
+ if st.button("📧 Email Report"):
498
  st.session_state.show_email_form = True
499
  st.rerun()
500