sanggusti commited on
Commit
85e2206
·
1 Parent(s): 28928ac

Had to debug this on the prod, sigh

Browse files
Files changed (2) hide show
  1. callbackmanager.py +332 -9
  2. pdfutils.py +4 -2
callbackmanager.py CHANGED
@@ -1,13 +1,12 @@
1
-
2
  import gradio as gr
3
  from meldrx import MeldRxAPI
4
  import json
5
  import os
 
 
6
 
7
- import gradio as gr
8
- from meldrx import MeldRxAPI
9
- import json
10
- import os
11
 
12
  class CallbackManager:
13
  def __init__(self, redirect_uri: str, client_secret: str = None):
@@ -39,6 +38,33 @@ class CallbackManager:
39
  return json.dumps(patients, indent=2) if patients else "No patient data returned."
40
  return "Failed to retrieve patient data."
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  def display_form(
43
  first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
44
  doctor_first_name, doctor_last_name, doctor_middle_initial, hospital_name, doctor_address,
@@ -62,8 +88,202 @@ def display_form(
62
  - Medications: {medications}
63
  - Prepared By: {preparer_name}, {preparer_job_title}
64
  """
 
 
65
  return form
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  CALLBACK_MANAGER = CallbackManager(
68
  redirect_uri="https://multitransformer-discharge-guard.hf.space/callback",
69
  client_secret=None
@@ -71,6 +291,7 @@ CALLBACK_MANAGER = CallbackManager(
71
 
72
  with gr.Blocks() as demo:
73
  gr.Markdown("# Patient Discharge Form with MeldRx Integration")
 
74
  with gr.Tab("Authenticate with MeldRx"):
75
  gr.Markdown("## SMART on FHIR Authentication")
76
  auth_url_output = gr.Textbox(label="Authorization URL", value=CALLBACK_MANAGER.get_auth_url(), interactive=False)
@@ -78,10 +299,90 @@ with gr.Blocks() as demo:
78
  auth_code_input = gr.Textbox(label="Authorization Code")
79
  auth_submit = gr.Button("Submit Code")
80
  auth_result = gr.Textbox(label="Authentication Result")
 
81
  patient_data_button = gr.Button("Fetch Patient Data")
82
  patient_data_output = gr.Textbox(label="Patient Data")
 
 
 
 
 
 
83
  auth_submit.click(fn=CALLBACK_MANAGER.set_auth_code, inputs=auth_code_input, outputs=auth_result)
84
  patient_data_button.click(fn=CALLBACK_MANAGER.get_patient_data, inputs=None, outputs=patient_data_output)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  with gr.Tab("Discharge Form"):
86
  gr.Markdown("## Patient Details")
87
  with gr.Row():
@@ -126,9 +427,18 @@ with gr.Blocks() as demo:
126
  with gr.Row():
127
  preparer_name = gr.Textbox(label="Name")
128
  preparer_job_title = gr.Textbox(label="Job Title")
129
- submit = gr.Button("Generate Form")
130
- output = gr.Markdown()
131
- submit.click(
 
 
 
 
 
 
 
 
 
132
  display_form,
133
  inputs=[
134
  first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
@@ -137,7 +447,20 @@ with gr.Blocks() as demo:
137
  admission_date, referral_source, admission_method, discharge_date, discharge_reason, date_of_death,
138
  diagnosis, procedures, medications, preparer_name, preparer_job_title
139
  ],
140
- outputs=output
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  )
142
 
143
  demo.launch()
 
 
1
  import gradio as gr
2
  from meldrx import MeldRxAPI
3
  import json
4
  import os
5
+ import tempfile
6
+ from datetime import datetime
7
 
8
+ # Import PDF utilities
9
+ from pdfutils import PDFGenerator, generate_discharge_summary
 
 
10
 
11
  class CallbackManager:
12
  def __init__(self, redirect_uri: str, client_secret: str = None):
 
38
  return json.dumps(patients, indent=2) if patients else "No patient data returned."
39
  return "Failed to retrieve patient data."
40
 
41
+ def get_patient_documents(self, patient_id: str = None):
42
+ """Fetch patient documents from MeldRx"""
43
+ if not self.access_token:
44
+ return "Not authenticated. Please provide a valid authorization code first."
45
+
46
+ try:
47
+ # This would call the actual MeldRx API to get documents for a specific patient
48
+ # For demonstration, we'll return mock document data
49
+ return [
50
+ {
51
+ "doc_id": "doc123",
52
+ "type": "clinical_note",
53
+ "date": "2023-01-16",
54
+ "author": "Dr. Sample Doctor",
55
+ "content": "Patient presented with symptoms of respiratory distress...",
56
+ },
57
+ {
58
+ "doc_id": "doc124",
59
+ "type": "lab_result",
60
+ "date": "2023-01-17",
61
+ "author": "Lab System",
62
+ "content": "CBC results: WBC 7.5, RBC 4.2, Hgb 14.1...",
63
+ }
64
+ ]
65
+ except Exception as e:
66
+ return f"Error retrieving patient documents: {str(e)}"
67
+
68
  def display_form(
69
  first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
70
  doctor_first_name, doctor_last_name, doctor_middle_initial, hospital_name, doctor_address,
 
88
  - Medications: {medications}
89
  - Prepared By: {preparer_name}, {preparer_job_title}
90
  """
91
+
92
+
93
  return form
94
 
95
+ def process_fhir_bundle(fhir_bundle):
96
+ """Extract and structure patient data from FHIR bundle"""
97
+ patients = []
98
+ for entry in fhir_bundle.get("entry", []):
99
+ resource = entry.get("resource", {})
100
+ if resource.get("resourceType") == "Patient":
101
+ patients.append(resource)
102
+ return patients
103
+
104
+ def create_patient_stripe(patient):
105
+ """Create a UI stripe for an individual patient with enhanced functionality"""
106
+ # Safely extract name components
107
+ official_name = next(
108
+ (n for n in patient.get("name", []) if n.get("use") == "official"),
109
+ {}
110
+ )
111
+ given_names = " ".join(official_name.get("given", ["Unknown"]))
112
+ family_name = official_name.get("family", "Unknown")
113
+
114
+ # Extract demographic information
115
+ gender = patient.get("gender", "unknown").capitalize()
116
+ birth_date = patient.get("birthDate", "Unknown")
117
+ patient_id = patient.get("id", "Unknown")
118
+
119
+ # Extract address information
120
+ address = patient.get("address", [{}])[0]
121
+ city = address.get("city", "Unknown")
122
+ state = address.get("state", "")
123
+ postal_code = address.get("postalCode", "")
124
+
125
+ with gr.Row(variant="panel") as stripe:
126
+ with gr.Column(scale=3):
127
+ gr.Markdown(f"""
128
+ **{given_names} {family_name}**
129
+ *{gender} | Born: {birth_date}*
130
+ {city}, {state} {postal_code}
131
+ """)
132
+ gr.Textbox(patient_id, label="Patient ID", visible=False)
133
+
134
+ with gr.Column(scale=1):
135
+ status = gr.Dropdown(
136
+ choices=["Pending", "Reviewed", "Approved", "Rejected"],
137
+ value="Pending",
138
+ label="Review Status"
139
+ )
140
+
141
+ with gr.Column(scale=1):
142
+ generate_btn = gr.Button("Generate Report", visible=False)
143
+ probability = gr.Label("Risk Probability", visible=False)
144
+ documents_btn = gr.Button("View Documents", visible=True)
145
+
146
+ # Dynamic visibility and document handling
147
+ def update_components(selected_status):
148
+ visible = selected_status in ["Reviewed", "Approved"]
149
+ return (
150
+ gr.Button(visible=visible),
151
+ gr.Label(visible=visible, value={"Low": 0.3, "Medium": 0.6, "High": 0.9}.get(selected_status, 0.5))
152
+ )
153
+
154
+ def show_documents(patient_id):
155
+ return CALLBACK_MANAGER.get_patient_documents(patient_id)
156
+
157
+ status.change(
158
+ update_components,
159
+ inputs=status,
160
+ outputs=[generate_btn, probability]
161
+ )
162
+
163
+ documents_btn.click(
164
+ fn=show_documents,
165
+ inputs=patient_id,
166
+ outputs=gr.JSON(label="Patient Documents")
167
+ )
168
+
169
+ return stripe
170
+
171
+
172
+ def generate_pdf_from_form(
173
+ first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
174
+ doctor_first_name, doctor_last_name, doctor_middle_initial, hospital_name, doctor_address,
175
+ doctor_city, doctor_state, doctor_zip,
176
+ admission_date, referral_source, admission_method, discharge_date, discharge_reason, date_of_death,
177
+ diagnosis, procedures, medications, preparer_name, preparer_job_title
178
+ ):
179
+ """Generate a PDF discharge form using the provided data"""
180
+
181
+ # Create PDF generator
182
+ pdf_gen = PDFGenerator()
183
+
184
+ # Format data for PDF generation
185
+ patient_info = {
186
+ "first_name": first_name,
187
+ "last_name": last_name,
188
+ "dob": dob,
189
+ "age": age,
190
+ "sex": sex,
191
+ "mobile": "", # Not collected in the form
192
+ "address": address,
193
+ "city": city,
194
+ "state": state,
195
+ "zip": zip_code
196
+ }
197
+
198
+ discharge_info = {
199
+ "date_of_admission": admission_date,
200
+ "date_of_discharge": discharge_date,
201
+ "source_of_admission": referral_source,
202
+ "mode_of_admission": admission_method,
203
+ "discharge_against_advice": "Yes" if discharge_reason == "Discharge Against Advice" else "No"
204
+ }
205
+
206
+ diagnosis_info = {
207
+ "diagnosis": diagnosis,
208
+ "operation_procedure": procedures,
209
+ "treatment": "", # Not collected in the form
210
+ "follow_up": "" # Not collected in the form
211
+ }
212
+
213
+ medication_info = {
214
+ "medications": [medications] if medications else [],
215
+ "instructions": "" # Not collected in the form
216
+ }
217
+
218
+ prepared_by = {
219
+ "name": preparer_name,
220
+ "title": preparer_job_title,
221
+ "signature": "" # Not collected in the form
222
+ }
223
+
224
+ # Generate PDF
225
+ pdf_buffer = pdf_gen.generate_discharge_form(
226
+ patient_info,
227
+ discharge_info,
228
+ diagnosis_info,
229
+ medication_info,
230
+ prepared_by
231
+ )
232
+
233
+ # Create temporary file to save the PDF
234
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.pdf')
235
+ temp_file.write(pdf_buffer.read())
236
+ temp_file_path = temp_file.name
237
+ temp_file.close()
238
+
239
+ return temp_file_path
240
+
241
+ def generate_pdf_from_meldrx(patient_data):
242
+ """Generate a PDF using patient data from MeldRx"""
243
+ if isinstance(patient_data, str):
244
+ # If it's a string (error message or JSON string), try to parse it
245
+ try:
246
+ patient_data = json.loads(patient_data)
247
+ except:
248
+ return None, "Invalid patient data format"
249
+
250
+ if not patient_data:
251
+ return None, "No patient data available"
252
+
253
+ try:
254
+ # For demonstration, we'll use the first patient in the list if it's a list
255
+ if isinstance(patient_data, list) and len(patient_data):
256
+ patient = patient_data[0]
257
+ else:
258
+ patient = patient_data
259
+
260
+ # Extract patient info
261
+ patient_info = {
262
+ "name": f"{patient.get('name', {}).get('given', [''])[0]} {patient.get('name', {}).get('family', '')}",
263
+ "dob": patient.get('birthDate', 'Unknown'),
264
+ "patient_id": patient.get('id', 'Unknown'),
265
+ "admission_date": datetime.now().strftime("%Y-%m-%d"), # Mock data
266
+ "physician": "Dr. Provider" # Mock data
267
+ }
268
+
269
+ # Mock LLM-generated content
270
+ llm_content = {
271
+ "diagnosis": "Diagnosis information would be generated by LLM",
272
+ "treatment": "Treatment summary would be generated by LLM",
273
+ "medications": "Medication list would be generated by LLM",
274
+ "follow_up": "Follow-up instructions would be generated by LLM",
275
+ "special_instructions": "Special instructions would be generated by LLM"
276
+ }
277
+
278
+ # Create discharge summary
279
+ output_dir = tempfile.mkdtemp()
280
+ pdf_path = generate_discharge_summary(patient_info, llm_content, output_dir)
281
+
282
+ return pdf_path, "PDF generated successfully"
283
+
284
+ except Exception as e:
285
+ return None, f"Error generating PDF: {str(e)}"
286
+
287
  CALLBACK_MANAGER = CallbackManager(
288
  redirect_uri="https://multitransformer-discharge-guard.hf.space/callback",
289
  client_secret=None
 
291
 
292
  with gr.Blocks() as demo:
293
  gr.Markdown("# Patient Discharge Form with MeldRx Integration")
294
+
295
  with gr.Tab("Authenticate with MeldRx"):
296
  gr.Markdown("## SMART on FHIR Authentication")
297
  auth_url_output = gr.Textbox(label="Authorization URL", value=CALLBACK_MANAGER.get_auth_url(), interactive=False)
 
299
  auth_code_input = gr.Textbox(label="Authorization Code")
300
  auth_submit = gr.Button("Submit Code")
301
  auth_result = gr.Textbox(label="Authentication Result")
302
+
303
  patient_data_button = gr.Button("Fetch Patient Data")
304
  patient_data_output = gr.Textbox(label="Patient Data")
305
+
306
+ # Add button to generate PDF from MeldRx data
307
+ meldrx_pdf_button = gr.Button("Generate PDF from MeldRx Data")
308
+ meldrx_pdf_status = gr.Textbox(label="PDF Generation Status")
309
+ meldrx_pdf_download = gr.File(label="Download Generated PDF")
310
+
311
  auth_submit.click(fn=CALLBACK_MANAGER.set_auth_code, inputs=auth_code_input, outputs=auth_result)
312
  patient_data_button.click(fn=CALLBACK_MANAGER.get_patient_data, inputs=None, outputs=patient_data_output)
313
+
314
+ # Add functionality for PDF generation from MeldRx data
315
+ meldrx_pdf_button.click(
316
+ fn=generate_pdf_from_meldrx,
317
+ inputs=patient_data_output,
318
+ outputs=[meldrx_pdf_download, meldrx_pdf_status]
319
+ )
320
+
321
+ with gr.tab("Show Patients Log"):
322
+ gr.Markdown("## Patient Dashboard")
323
+
324
+ # Store patient data in a state variable
325
+ patient_data_state = gr.State()
326
+
327
+ # Pagination controls
328
+ with gr.Row() as pagination_row:
329
+ prev_btn = gr.Button("Previous Page", visible=False)
330
+ next_btn = gr.Button("Next Page", visible=False)
331
+
332
+ # Patient stripes container
333
+ patient_stripes = gr.Column()
334
+
335
+ # Metadata display
336
+ metadata_md = gr.Markdown()
337
+
338
+ # Refresh button
339
+ refresh_btn = gr.Button("Refresh Data")
340
+
341
+ def update_patient_display(patient_data_json):
342
+ try:
343
+ fhir_bundle = json.loads(patient_data_json)
344
+ patients = process_fhir_bundle(fhir_bundle)
345
+
346
+ # Update pagination controls
347
+ has_prev = any(link["relation"] == "previous" for link in fhir_bundle.get("link", []))
348
+ has_next = any(link["relation"] == "next" for link in fhir_bundle.get("link", []))
349
+
350
+ # Create stripes
351
+ stripes = []
352
+ for patient in patients:
353
+ stripes.append(create_patient_stripe(patient))
354
+
355
+ return (
356
+ gr.Row.update(visible=has_prev or has_next),
357
+ gr.Column.update(stripes),
358
+ gr.Markdown.update(value=f"""
359
+ **Bundle Metadata**
360
+ Type: {fhir_bundle.get('type', 'Unknown')}
361
+ Total Patients: {fhir_bundle.get('total', 0)}
362
+ Last Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
363
+ """),
364
+ {"patients": patients, "bundle": fhir_bundle}
365
+ )
366
+ except Exception as e:
367
+ return (
368
+ gr.Row.update(visible=False),
369
+ gr.Column.update([]),
370
+ gr.Markdown.update(value=f"Error loading patient data: {str(e)}"),
371
+ None
372
+ )
373
+
374
+ # Connect data flow
375
+ patient_data_output.change(
376
+ fn=update_patient_display,
377
+ inputs=patient_data_output,
378
+ outputs=[pagination_row, patient_stripes, metadata_md, patient_data_state]
379
+ )
380
+
381
+ refresh_btn.click(
382
+ fn=lambda: CALLBACK_MANAGER.get_patient_data(),
383
+ outputs=patient_data_output
384
+ )
385
+
386
  with gr.Tab("Discharge Form"):
387
  gr.Markdown("## Patient Details")
388
  with gr.Row():
 
427
  with gr.Row():
428
  preparer_name = gr.Textbox(label="Name")
429
  preparer_job_title = gr.Textbox(label="Job Title")
430
+
431
+ # Add buttons for both display form and generate PDF
432
+ with gr.Row():
433
+ submit_display = gr.Button("Display Form")
434
+ submit_pdf = gr.Button("Generate PDF")
435
+
436
+ # Output areas
437
+ form_output = gr.Markdown()
438
+ pdf_output = gr.File(label="Download PDF")
439
+
440
+ # Connect the display form button
441
+ submit_display.click(
442
  display_form,
443
  inputs=[
444
  first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
 
447
  admission_date, referral_source, admission_method, discharge_date, discharge_reason, date_of_death,
448
  diagnosis, procedures, medications, preparer_name, preparer_job_title
449
  ],
450
+ outputs=form_output
451
+ )
452
+
453
+ # Connect the generate PDF button
454
+ submit_pdf.click(
455
+ generate_pdf_from_form,
456
+ inputs=[
457
+ first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
458
+ doctor_first_name, doctor_last_name, doctor_middle_initial, hospital_name, doctor_address,
459
+ doctor_city, doctor_state, doctor_zip,
460
+ admission_date, referral_source, admission_method, discharge_date, discharge_reason, date_of_death,
461
+ diagnosis, procedures, medications, preparer_name, preparer_job_title
462
+ ],
463
+ outputs=pdf_output
464
  )
465
 
466
  demo.launch()
pdfutils.py CHANGED
@@ -8,6 +8,7 @@ from reportlab.lib.enums import TA_JUSTIFY, TA_LEFT, TA_CENTER
8
  from reportlab.platypus import Table, TableStyle
9
  from reportlab.lib import colors
10
  import os
 
11
  from datetime import datetime
12
 
13
  class PDFGenerator:
@@ -348,18 +349,19 @@ class DischargeDocumentCreator:
348
 
349
  return filepath
350
 
351
- def generate_discharge_summary(patient_data, llm_content):
352
  """
353
  Wrapper function to generate a discharge summary document
354
 
355
  Args:
356
  patient_data (dict): Patient information
357
  llm_content (dict): LLM-generated content for discharge summary
 
358
 
359
  Returns:
360
  str: Path to the generated PDF
361
  """
362
- creator = DischargeDocumentCreator()
363
  return creator.generate_discharge_paper(patient_data, llm_content)
364
 
365
  if __name__ == "__main__":
 
8
  from reportlab.platypus import Table, TableStyle
9
  from reportlab.lib import colors
10
  import os
11
+ import json # Add missing import
12
  from datetime import datetime
13
 
14
  class PDFGenerator:
 
349
 
350
  return filepath
351
 
352
+ def generate_discharge_summary(patient_data, llm_content, output_dir='discharge_papers'):
353
  """
354
  Wrapper function to generate a discharge summary document
355
 
356
  Args:
357
  patient_data (dict): Patient information
358
  llm_content (dict): LLM-generated content for discharge summary
359
+ output_dir (str): Directory to save the PDF file
360
 
361
  Returns:
362
  str: Path to the generated PDF
363
  """
364
+ creator = DischargeDocumentCreator(output_dir=output_dir)
365
  return creator.generate_discharge_paper(patient_data, llm_content)
366
 
367
  if __name__ == "__main__":