MiChaelinzo commited on
Commit
f10ca6a
·
verified ·
1 Parent(s): d82d227

Update callbackmanager.py

Browse files

cyberpunk_theme = gr.themes.Monochrome(
primary_hue="cyan",
secondary_hue="pink",
neutral_hue="slate",
font=["Source Code Pro", "monospace"], # Retro monospace font
font_mono=["Source Code Pro", "monospace"]
)

Files changed (1) hide show
  1. callbackmanager.py +416 -228
callbackmanager.py CHANGED
@@ -6,8 +6,8 @@ import tempfile
6
  from datetime import datetime
7
  import traceback
8
  import logging
9
- from huggingface_hub import InferenceClient # Import InferenceClient
10
- from urllib.parse import urlparse, parse_qs # Import URL parsing utilities
11
 
12
  # Set up logging
13
  logging.basicConfig(level=logging.INFO)
@@ -19,11 +19,11 @@ from pdfutils import PDFGenerator, generate_discharge_summary
19
  # Import necessary libraries for new file types and AI analysis functions
20
  import pydicom # For DICOM
21
  import hl7 # For HL7
22
- from xml.etree import ElementTree # For XML and CCDA
23
- from pypdf import PdfReader # For PDF
24
- import csv # For CSV
25
- import io # For IO operations
26
- from PIL import Image # For image handling
27
 
28
  system_instructions = """
29
  **Discharge Guard - Medical Data Analysis Assistant**
@@ -57,18 +57,25 @@ system_instructions = """
57
  """
58
 
59
  # Initialize Inference Client - Ensure YOUR_HF_TOKEN is set in environment variables or replace with your actual token
60
- HF_TOKEN = os.getenv("HF_TOKEN") # Or replace with your actual token string
61
  if not HF_TOKEN:
62
- raise ValueError("HF_TOKEN environment variable not set. Please set your Hugging Face API token.")
 
 
63
  client = InferenceClient(api_key=HF_TOKEN)
64
- model_name = "meta-llama/Llama-3.3-70B-Instruct" # Specify the model to use
 
65
 
66
- def analyze_dicom_file_with_ai(dicom_file_path): # Modified to accept file path
67
  """Analyzes DICOM file metadata using Discharge Guard AI."""
68
  try:
69
- dicom_file = pydicom.dcmread(dicom_file_path.name) # Read dicom using path, access file through .name for Gradio UploadedFile
 
 
70
  dicom_metadata_json = dicom_file.to_json_dict()
71
- prediction_response, trace_data_dicom_ai = analyze_dicom_content_ai(dicom_metadata_json) # Call content analysis
 
 
72
  if prediction_response:
73
  report = f"Discharge Guard AI Analysis of DICOM Metadata:\n\nDICOM Metadata Analysis Report:\n{prediction_response}\n\nDisclaimer: The Discharge Guard -generated analysis is for conceptual informational purposes only and may or **NOT medical advice.** Analysis is based on DICOM *metadata* and not image interpretation."
74
  return report
@@ -81,7 +88,8 @@ def analyze_dicom_file_with_ai(dicom_file_path): # Modified to accept file path
81
  except Exception as e:
82
  return f"Error during DICOM file processing in analyze_dicom_file_with_ai: {e}"
83
 
84
- def analyze_dicom_content_ai(dicom_metadata_json): # Copied from your code
 
85
  """Analyzes DICOM metadata JSON content using Discharge Guard AI."""
86
  prompt_text = f"""{system_instructions} \n\n Perform a **deep and comprehensive analysis** of the following DICOM metadata in JSON format to provide a **structured summary and identify potential clinically relevant information with deep insights**. Focus not just on summarizing fields, but on **interpreting their clinical significance, identifying subtle patterns, and drawing inferences about the study's implications**. Think like an experienced radiologist reviewing this metadata for crucial diagnostic clues. Remember this is metadata, not the image itself, so focus on what can be gleaned from the data itself. Provide a "**Deep DICOM Metadata Analysis Report**". Important: Use the API Directories fhir endpoints FROM THIS LINK: https://app.meldrx.com/api/directories/fhir/endpoints.
87
  **DICOM Metadata (JSON):**
@@ -109,7 +117,7 @@ def analyze_dicom_content_ai(dicom_metadata_json): # Copied from your code
109
  model=model_name,
110
  messages=[{"role": "user", "content": prompt_text}],
111
  temperature=0.4,
112
- max_tokens=1024, # Adjust as needed
113
  top_p=0.9,
114
  )
115
  the_response = response.choices[0].message.content
@@ -120,13 +128,16 @@ def analyze_dicom_content_ai(dicom_metadata_json): # Copied from your code
120
  trace_data_detail_dicom_analysis["error"] = f"AI Analysis Error: {e}"
121
  return error_message, trace_data_detail_dicom_analysis
122
 
 
123
  # ... (Paste other AI analysis functions: analyze_hl7_file_with_ai, analyze_cda_xml_file_with_ai, analyze_pdf_file_with_ai, analyze_csv_file_with_ai here - ensure to adapt file reading for Gradio file paths if necessary) ...
124
  def analyze_hl7_file_with_ai(hl7_file_path):
125
  """Analyzes HL7 file content using Discharge Guard AI."""
126
  try:
127
- with open(hl7_file_path.name, 'r') as f: # Open file using path, access file through .name for Gradio UploadedFile
128
  hl7_message_raw = f.read()
129
- prediction_response, trace_data_hl7_ai = analyze_hl7_content_ai(hl7_message_raw)
 
 
130
 
131
  if prediction_response:
132
  report = f"Discharge Guard AI Analysis of HL7 Message:\n\nHL7 Message Analysis Report:\n{prediction_response}\n\n**Disclaimer:** The Discharge Guard AGI-generated analysis is for conceptual informational purposes only and may or **NOT medical advice.** Analysis is based on HL7 message content."
@@ -140,7 +151,8 @@ def analyze_hl7_file_with_ai(hl7_file_path):
140
  except Exception as e:
141
  return f"Error during HL7 file processing in analyze_hl7_file_with_ai: {e}"
142
 
143
- def analyze_hl7_content_ai(hl7_message_string): # Copied from your code
 
144
  """Analyzes HL7 message content using Discharge Guard AI."""
145
  prompt_text = f"""{system_instructions} \n\n Conduct a **deep and thorough analysis** of the following HL7 message content to provide a **structured summary and identify key clinical information with deep understanding**. Go beyond basic parsing; aim to **interpret the clinical narrative** embedded within the HL7 message. **Engage in deep search to contextualize medical codes and terminology**. Provide a "**Comprehensive HL7 Message Analysis Report**".
146
  **HL7 Message Content:**
@@ -168,7 +180,7 @@ def analyze_hl7_content_ai(hl7_message_string): # Copied from your code
168
  model=model_name,
169
  messages=[{"role": "user", "content": prompt_text}],
170
  temperature=0.4,
171
- max_tokens=1024, # Adjust as needed
172
  top_p=0.9,
173
  )
174
  the_response = response.choices[0].message.content
@@ -180,10 +192,12 @@ def analyze_hl7_content_ai(hl7_message_string): # Copied from your code
180
  return error_message, trace_data_detail_hl7_analysis
181
 
182
 
183
- def analyze_cda_xml_file_with_ai(cda_xml_file_path): # Modified to accept file path
184
  """Analyzes generic CDA or XML file content using Discharge Guard AI (more generalized version) Important: Use the API Directories fhir endpoints FROM THIS LINK: https://app.meldrx.com/api/directories/fhir/endpoints."""
185
  try:
186
- with open(cda_xml_file_path.name, 'r') as f: # Open file using path, access file through .name for Gradio UploadedFile
 
 
187
  cda_xml_content = f.read()
188
  prediction_response, trace_data_cda_xml_ai = analyze_cda_xml_content_ai(
189
  cda_xml_content
@@ -200,7 +214,8 @@ def analyze_cda_xml_file_with_ai(cda_xml_file_path): # Modified to accept file p
200
  except Exception as e:
201
  return f"Error during XML/CDA file processing in analyze_cda_xml_file_with_ai: {e}"
202
 
203
- def analyze_cda_xml_content_ai(cda_xml_content): # Copied from your code
 
204
  """Analyzes generic CDA or XML content using Discharge Guard AI (more generalized version)."""
205
 
206
  prompt_text = f"""{system_instructions} \n\n Analyze the following medical XML/CDA content to provide a **structured and comprehensive patient data analysis**, similar to how a medical professional would review a patient's chart or a clinical document. You need to parse the XML structure yourself to extract the relevant information. Use bullet points, tables, or numbered steps for complex tasks. Provide a "Medical Document Analysis" report.
@@ -230,7 +245,7 @@ def analyze_cda_xml_content_ai(cda_xml_content): # Copied from your code
230
  model=model_name,
231
  messages=[{"role": "user", "content": prompt_text}],
232
  temperature=0.4,
233
- max_tokens=1024, # Adjust as needed
234
  top_p=0.9,
235
  )
236
  the_response = response.choices[0].message.content
@@ -242,17 +257,21 @@ def analyze_cda_xml_content_ai(cda_xml_content): # Copied from your code
242
  return error_message, trace_data_detail_cda_xml_analysis
243
 
244
 
245
- def analyze_pdf_file_with_ai(pdf_file_path): # Modified to accept file path
246
  """Analyzes PDF file content using Discharge Guard AI."""
247
  try:
248
- with open(pdf_file_path.name, 'rb') as f: # Open file in binary mode for PdfReader, access file through .name for Gradio UploadedFile
249
- pdf_file = f # Pass file object to PdfReader
 
 
250
  pdf_reader = PdfReader(pdf_file)
251
  text_content = ""
252
  for page in pdf_reader.pages:
253
  text_content += page.extract_text()
254
 
255
- prediction_response, trace_data_pdf_ai = analyze_pdf_content_ai(text_content)
 
 
256
 
257
  if prediction_response:
258
  report = f"Discharge Guard AI Analysis of PDF Content:\n\nMedical Report Analysis Report:\n{prediction_response}\n\n**Disclaimer:** The Discharge Guard AGI-generated analysis is for conceptual informational purposes only and may or **NOT medical advice.** Analysis is based on PDF text content."
@@ -266,7 +285,8 @@ def analyze_pdf_file_with_ai(pdf_file_path): # Modified to accept file path
266
  except Exception as e:
267
  return f"Error during PDF file processing in analyze_pdf_file_with_ai: {e}"
268
 
269
- def analyze_pdf_content_ai(pdf_text_content): # Copied from your code
 
270
  """Analyzes PDF text content using Discharge Guard AI."""
271
  prompt_text = f"""{system_instructions} \n\n Analyze the following medical PDF text content to provide a **structured summary and identify key clinical information**. Focus on patient demographics, medical history, findings, diagnoses, medications, recommendations, and any important clinical details conveyed in the document. Provide a "Medical Report Analysis" report.
272
  **Medical PDF Text Content:**
@@ -294,7 +314,7 @@ def analyze_pdf_content_ai(pdf_text_content): # Copied from your code
294
  model=model_name,
295
  messages=[{"role": "user", "content": prompt_text}],
296
  temperature=0.4,
297
- max_tokens=1024, # Adjust as needed
298
  top_p=0.9,
299
  )
300
  the_response = response.choices[0].message.content
@@ -306,10 +326,12 @@ def analyze_pdf_content_ai(pdf_text_content): # Copied from your code
306
  return error_message, trace_data_detail_pdf_analysis
307
 
308
 
309
- def analyze_csv_file_with_ai(csv_file_path): # Modified to accept file path
310
  """Analyzes CSV file content using Discharge Guard AI."""
311
  try:
312
- csv_content = csv_file_path.read().decode('utf-8') # Read content directly from UploadedFile
 
 
313
  prediction_response, trace_data_csv_ai = analyze_csv_content_ai(csv_content)
314
 
315
  if prediction_response:
@@ -324,7 +346,8 @@ def analyze_csv_file_with_ai(csv_file_path): # Modified to accept file path
324
  except Exception as e:
325
  return f"Error during CSV file processing in analyze_csv_file_with_ai: {e}"
326
 
327
- def analyze_csv_content_ai(csv_content_string): # Copied from your code
 
328
  """Analyzes CSV content (string) using Discharge Guard AI."""
329
  prompt_text = f"""{system_instructions} \n\n Analyze the following medical CSV data to provide a **structured summary and identify potential clinical insights**. Assume the CSV represents patient-related medical data. Focus on understanding the columns, summarizing key data points, identifying trends or patterns, and noting any potential clinical significance of the data. Provide a "Data Analysis" report.
330
  **Medical CSV Data:**
@@ -352,7 +375,7 @@ def analyze_csv_content_ai(csv_content_string): # Copied from your code
352
  model=model_name,
353
  messages=[{"role": "user", "content": prompt_text}],
354
  temperature=0.4,
355
- max_tokens=1024, # Adjust as needed
356
  top_p=0.9,
357
  )
358
  the_response = response.choices[0].message.content
@@ -384,19 +407,21 @@ class CallbackManager:
384
  self.auth_code = code
385
  if self.api.authenticate_with_code(code):
386
  self.access_token = self.api.access_token
387
- return f"Authentication successful! Access Token: {self.access_token[:10]}... (truncated)"
388
- return "Authentication failed. Please check the code."
 
 
389
 
390
  def get_patient_data(self) -> str:
391
  """Fetch patient data from MeldRx"""
392
  try:
393
  if not self.access_token:
394
  logger.warning("Not authenticated when getting patient data")
395
- return "Not authenticated. Please provide a valid authorization code first."
396
 
397
  # For demo purposes, if there's no actual API connected, return mock data
398
  # Remove this in production and use the real API call
399
- if not hasattr(self.api, 'get_patients') or self.api.get_patients is None:
400
  logger.info("Using mock patient data (no API connection)")
401
  # Return mock FHIR bundle with patient data
402
  mock_data = {
@@ -413,18 +438,14 @@ class CallbackManager:
413
  {
414
  "use": "official",
415
  "family": "Smith",
416
- "given": ["John"]
417
  }
418
  ],
419
  "gender": "male",
420
  "birthDate": "1970-01-01",
421
  "address": [
422
- {
423
- "city": "Boston",
424
- "state": "MA",
425
- "postalCode": "02108"
426
- }
427
- ]
428
  }
429
  },
430
  {
@@ -435,7 +456,7 @@ class CallbackManager:
435
  {
436
  "use": "official",
437
  "family": "Johnson",
438
- "given": ["Jane"]
439
  }
440
  ],
441
  "gender": "female",
@@ -444,12 +465,12 @@ class CallbackManager:
444
  {
445
  "city": "Cambridge",
446
  "state": "MA",
447
- "postalCode": "02139"
448
  }
449
- ]
450
  }
451
- }
452
- ]
453
  }
454
  return json.dumps(mock_data, indent=2)
455
 
@@ -457,17 +478,22 @@ class CallbackManager:
457
  logger.info("Calling Meldrx API to get patients")
458
  patients = self.api.get_patients()
459
  if patients is not None:
460
- return json.dumps(patients, indent=2) if patients else "No patient data returned."
461
- return "Failed to retrieve patient data."
 
 
 
 
462
  except Exception as e:
463
  error_msg = f"Error in get_patient_data: {str(e)}"
464
  logger.error(error_msg)
465
- return f"Error retrieving patient data: {str(e)}"
 
466
 
467
  def get_patient_documents(self, patient_id: str = None):
468
  """Fetch patient documents from MeldRx"""
469
  if not self.access_token:
470
- return "Not authenticated. Please provide a valid authorization code first."
471
 
472
  try:
473
  # This would call the actual MeldRx API to get documents for a specific patient
@@ -486,42 +512,94 @@ class CallbackManager:
486
  "date": "2023-01-17",
487
  "author": "Lab System",
488
  "content": "CBC results: WBC 7.5, RBC 4.2, Hgb 14.1...",
489
- }
490
  ]
491
  except Exception as e:
492
- return f"Error retrieving patient documents: {str(e)}"
 
493
 
494
  def display_form(
495
- first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
496
- doctor_first_name, doctor_last_name, doctor_middle_initial, hospital_name, doctor_address,
497
- doctor_city, doctor_state, doctor_zip,
498
- admission_date, referral_source, admission_method, discharge_date, discharge_reason, date_of_death,
499
- diagnosis, procedures, medications, preparer_name, preparer_job_title
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
500
  ):
501
  form = f"""
502
- **Patient Discharge Form**
503
- - Name: {first_name} {middle_initial} {last_name}
504
- - Date of Birth: {dob}, Age: {age}, Sex: {sex}
505
- - Address: {address}, {city}, {state}, {zip_code}
506
- - Doctor: {doctor_first_name} {doctor_middle_initial} {doctor_last_name}
507
- - Hospital/Clinic: {hospital_name}
508
- - Doctor Address: {doctor_address}, {doctor_city}, {doctor_state}, {doctor_zip}
509
- - Admission Date: {admission_date}, Source: {referral_source}, Method: {admission_method}
510
- - Discharge Date: {discharge_date}, Reason: {discharge_reason}
511
- - Date of Death: {date_of_death}
512
- - Diagnosis: {diagnosis}
513
- - Procedures: {procedures}
514
- - Medications: {medications}
 
515
  - Prepared By: {preparer_name}, {preparer_job_title}
 
516
  """
517
  return form
518
 
 
519
  def generate_pdf_from_form(
520
- first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
521
- doctor_first_name, doctor_last_name, doctor_middle_initial, hospital_name, doctor_address,
522
- doctor_city, doctor_state, doctor_zip,
523
- admission_date, referral_source, admission_method, discharge_date, discharge_reason, date_of_death,
524
- diagnosis, procedures, medications, preparer_name, preparer_job_title
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
  ):
526
  """Generate a PDF discharge form using the provided data"""
527
 
@@ -539,7 +617,7 @@ def generate_pdf_from_form(
539
  "address": address,
540
  "city": city,
541
  "state": state,
542
- "zip": zip_code
543
  }
544
 
545
  discharge_info = {
@@ -547,25 +625,27 @@ def generate_pdf_from_form(
547
  "date_of_discharge": discharge_date,
548
  "source_of_admission": referral_source,
549
  "mode_of_admission": admission_method,
550
- "discharge_against_advice": "Yes" if discharge_reason == "Discharge Against Advice" else "No"
 
 
551
  }
552
 
553
  diagnosis_info = {
554
  "diagnosis": diagnosis,
555
  "operation_procedure": procedures,
556
  "treatment": "", # Not collected in the form
557
- "follow_up": "" # Not collected in the form
558
  }
559
 
560
  medication_info = {
561
  "medications": [medications] if medications else [],
562
- "instructions": "" # Not collected in the form
563
  }
564
 
565
  prepared_by = {
566
  "name": preparer_name,
567
  "title": preparer_job_title,
568
- "signature": "" # Not collected in the form
569
  }
570
 
571
  # Generate PDF
@@ -574,17 +654,18 @@ def generate_pdf_from_form(
574
  discharge_info,
575
  diagnosis_info,
576
  medication_info,
577
- prepared_by
578
  )
579
 
580
  # Create temporary file to save the PDF
581
- temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.pdf')
582
  temp_file.write(pdf_buffer.read())
583
  temp_file_path = temp_file.name
584
  temp_file.close()
585
 
586
  return temp_file_path
587
 
 
588
  def generate_pdf_from_meldrx(patient_data):
589
  """Generate a PDF using patient data from MeldRx"""
590
  if isinstance(patient_data, str):
@@ -607,10 +688,10 @@ def generate_pdf_from_meldrx(patient_data):
607
  # Extract patient info
608
  patient_info = {
609
  "name": f"{patient.get('name', {}).get('given', [''])[0]} {patient.get('name', {}).get('family', '')}",
610
- "dob": patient.get('birthDate', 'Unknown'),
611
- "patient_id": patient.get('id', 'Unknown'),
612
  "admission_date": datetime.now().strftime("%Y-%m-%d"), # Mock data
613
- "physician": "Dr. Provider" # Mock data
614
  }
615
 
616
  # Mock LLM-generated content - This part needs to be replaced with actual AI generation if desired for MeldRx PDF
@@ -619,70 +700,91 @@ def generate_pdf_from_meldrx(patient_data):
619
  "treatment": "Treatment summary would be generated by AI based on patient data from MeldRx.",
620
  "medications": "Medication list would be generated by AI based on patient data from MeldRx.",
621
  "follow_up": "Follow-up instructions would be generated by AI based on patient data from MeldRx.",
622
- "special_instructions": "Special instructions would be generated by AI based on patient data from MeldRx."
623
  }
624
 
625
  # Create discharge summary - Using No-AI PDF generation for now, replace with AI-content generation later
626
  output_dir = tempfile.mkdtemp()
627
- pdf_path = generate_discharge_summary(patient_info, llm_content, output_dir) # Still using No-AI template
 
 
628
 
629
- return pdf_path, "PDF generated successfully (No AI Content in PDF yet)" # Indicate No-AI content
630
 
631
  except Exception as e:
632
  return None, f"Error generating PDF: {str(e)}"
633
 
 
634
  def generate_discharge_paper_one_click():
635
  """One-click function to fetch patient data and generate discharge paper with AI Content."""
636
  patient_data_str = CALLBACK_MANAGER.get_patient_data()
637
- if patient_data_str.startswith("Not authenticated") or patient_data_str.startswith("Failed") or patient_data_str.startswith("Error"):
638
- return None, patient_data_str # Return error message if authentication or data fetch fails
 
 
 
 
639
 
640
  try:
641
  patient_data = json.loads(patient_data_str)
642
 
643
  # --- AI Content Generation for Discharge Summary ---
644
  # This is a placeholder - Replace with actual AI call using InferenceClient and patient_data to generate content
645
- ai_generated_content = generate_ai_discharge_content(patient_data) # Placeholder AI function
 
 
646
 
647
  if not ai_generated_content:
648
  return None, "Error: AI content generation failed."
649
 
650
  # --- PDF Generation with AI Content ---
651
- pdf_path, status_message = generate_pdf_from_meldrx_with_ai_content(patient_data, ai_generated_content) # Function to generate PDF with AI content
 
 
652
 
653
  if pdf_path:
654
  return pdf_path, status_message
655
  else:
656
- return None, status_message # Return status message if PDF generation fails
657
 
658
  except json.JSONDecodeError:
659
  return None, "Error: Patient data is not in valid JSON format."
660
  except Exception as e:
661
  return None, f"Error during discharge paper generation: {str(e)}"
662
 
 
663
  def generate_ai_discharge_content(patient_data):
664
  """Placeholder function to generate AI content for discharge summary.
665
- Replace this with actual AI call using InferenceClient and patient_data."""
666
  try:
667
- patient_name = f"{patient_data['entry'][0]['resource']['name'][0]['given'][0]} {patient_data['entry'][0]['resource']['name'][0]['family']}" if patient_data.get('entry') else "Unknown Patient"
 
 
 
 
668
  prompt_text = f"""{system_instructions}\n\nGenerate a discharge summary content (diagnosis, treatment, medications, follow-up instructions, special instructions) for patient: {patient_name}. Base the content on available patient data (if any provided, currently not provided in detail in this mock-up). Focus on creating clinically relevant and informative summary. Remember this is for informational purposes and NOT medical advice."""
669
 
670
  response = client.chat.completions.create(
671
  model=model_name,
672
  messages=[{"role": "user", "content": prompt_text}],
673
- temperature=0.6, # Adjust temperature as needed for content generation
674
- max_tokens=1024, # Adjust max_tokens as needed
675
  top_p=0.9,
676
  )
677
  ai_content = response.choices[0].message.content
678
 
679
  # Basic parsing of AI content - improve this based on desired output structure from LLM
680
  llm_content = {
681
- "diagnosis": "AI Generated Diagnosis (Placeholder):\n" + extract_section(ai_content, "Diagnosis"), # Example extraction - refine based on LLM output
682
- "treatment": "AI Generated Treatment (Placeholder):\n" + extract_section(ai_content, "Treatment"),
683
- "medications": "AI Generated Medications (Placeholder):\n" + extract_section(ai_content, "Medications"),
684
- "follow_up": "AI Generated Follow-up (Placeholder):\n" + extract_section(ai_content, "Follow-up Instructions"),
685
- "special_instructions": "AI Generated Special Instructions (Placeholder):\n" + extract_section(ai_content, "Special Instructions")
 
 
 
 
 
686
  }
687
  return llm_content
688
 
@@ -690,11 +792,12 @@ def generate_ai_discharge_content(patient_data):
690
  logger.error(f"Error generating AI discharge content: {e}")
691
  return None
692
 
 
693
  def extract_section(ai_content, section_title):
694
  """Simple placeholder function to extract section from AI content.
695
- Improve this with more robust parsing based on LLM output format."""
696
  start_marker = f"**{section_title}:**"
697
- end_marker = "\n\n" # Adjust based on typical LLM output structure
698
  start_index = ai_content.find(start_marker)
699
  if start_index != -1:
700
  start_index += len(start_marker)
@@ -723,60 +826,72 @@ def generate_pdf_from_meldrx_with_ai_content(patient_data, llm_content):
723
 
724
  patient_info = {
725
  "name": f"{patient.get('name', {}).get('given', [''])[0]} {patient.get('name', {}).get('family', '')}",
726
- "dob": patient.get('birthDate', 'Unknown'),
727
- "patient_id": patient.get('id', 'Unknown'),
728
  "admission_date": datetime.now().strftime("%Y-%m-%d"), # Mock data
729
- "physician": "Dr. AI Provider" # Mock data - Indicate AI generated
730
  }
731
 
732
-
733
  output_dir = tempfile.mkdtemp()
734
- pdf_path = generate_discharge_summary(patient_info, llm_content, output_dir) # Using AI content now
 
 
735
 
736
- return pdf_path, "PDF generated successfully with AI Content" # Indicate AI content
737
 
738
  except Exception as e:
739
  return None, f"Error generating PDF with AI content: {str(e)}"
740
 
 
741
  def extract_auth_code_from_url(redirected_url):
742
  """Extracts the authorization code from the redirected URL."""
743
  try:
744
  parsed_url = urlparse(redirected_url)
745
  query_params = parse_qs(parsed_url.query)
746
  if "code" in query_params:
747
- return query_params["code"][0], None # Return code and no error
748
  else:
749
- return None, "Authorization code not found in URL." # Return None and error message
750
  except Exception as e:
751
- return None, f"Error parsing URL: {e}" # Return None and error message
 
752
 
753
  # Create a simplified interface to avoid complex component interactions
754
  CALLBACK_MANAGER = CallbackManager(
755
  redirect_uri="https://multitransformer-discharge-guard.hf.space/callback",
756
- client_secret=None
 
 
 
 
 
 
 
 
 
757
  )
758
 
759
- # Create the UI
760
- with gr.Blocks() as demo:
761
- gr.Markdown("# Patient Discharge Form with MeldRx & Medical File Analysis + AI") # Updated title
762
 
763
- with gr.Tab("Authenticate with MeldRx"):
764
- gr.Markdown("## SMART on FHIR Authentication")
765
  auth_url_output = gr.Textbox(label="Authorization URL", value=CALLBACK_MANAGER.get_auth_url(), interactive=False)
766
- gr.Markdown("Copy the URL above, open it in a browser, log in, and paste the **entire redirected URL** from your browser's address bar below.") # Updated instructions
767
  redirected_url_input = gr.Textbox(label="Redirected URL") # New textbox for redirected URL
768
- extract_code_button = gr.Button("Extract Authorization Code") # Button to extract code
769
  extracted_code_output = gr.Textbox(label="Extracted Authorization Code", interactive=False) # Textbox to show extracted code
770
 
771
  auth_code_input = gr.Textbox(label="Authorization Code (from above, or paste manually if extraction fails)", interactive=True) # Updated label to be clearer
772
- auth_submit = gr.Button("Submit Code for Authentication")
773
- auth_result = gr.Textbox(label="Authentication Result")
774
 
775
- patient_data_button = gr.Button("Fetch Patient Data")
776
  patient_data_output = gr.Textbox(label="Patient Data", lines=10)
777
 
778
  # Add button to generate PDF from MeldRx data (No AI)
779
- meldrx_pdf_button = gr.Button("Generate PDF from MeldRx Data (No AI)") # Renamed button
780
  meldrx_pdf_status = gr.Textbox(label="PDF Generation Status (No AI)") # Renamed status
781
  meldrx_pdf_download = gr.File(label="Download Generated PDF (No AI)") # Renamed download
782
 
@@ -784,37 +899,39 @@ with gr.Blocks() as demo:
784
  """Processes the redirected URL to extract and display the authorization code."""
785
  auth_code, error_message = extract_auth_code_from_url(redirected_url)
786
  if auth_code:
787
- return auth_code, "Authorization code extracted!"
788
  else:
789
- return "", error_message or "Could not extract authorization code."
790
 
791
 
792
  extract_code_button.click(
793
  fn=process_redirected_url,
794
  inputs=redirected_url_input,
795
- outputs=[extracted_code_output, auth_result] # Reusing auth_result for extraction status
796
  )
797
 
798
-
799
  auth_submit.click(
800
  fn=CALLBACK_MANAGER.set_auth_code,
801
- inputs=extracted_code_output, # Using extracted code as input for authentication
802
- outputs=auth_result
803
  )
804
 
 
 
 
805
 
806
- with gr.Tab("Patient Dashboard"):
807
- gr.Markdown("## Patient Data")
808
- dashboard_output = gr.HTML("<p>Fetch patient data from the Authentication tab first.</p>")
809
-
810
- refresh_btn = gr.Button("Refresh Data")
811
 
812
  # Simple function to update dashboard based on fetched data
813
  def update_dashboard():
814
  try:
815
  data = CALLBACK_MANAGER.get_patient_data()
816
- if data.startswith("Not authenticated") or data.startswith("Failed") or data.startswith("Error"):
817
- return f"<p>{data}</p>"
 
 
 
 
818
 
819
  try:
820
  # Parse the data
@@ -828,7 +945,7 @@ with gr.Blocks() as demo:
828
  patients.append(resource)
829
 
830
  # Generate HTML card
831
- html = "<h3>Patients</h3>"
832
  for patient in patients:
833
  # Extract name
834
  name = patient.get("name", [{}])[0]
@@ -839,24 +956,25 @@ with gr.Blocks() as demo:
839
  gender = patient.get("gender", "unknown").capitalize()
840
  birth_date = patient.get("birthDate", "Unknown")
841
 
842
- # Generate HTML card
843
  html += f"""
844
- <div style="border: 1px solid #ddd; padding: 10px; margin: 10px 0; border-radius: 5px;">
845
- <h4>{given} {family}</h4>
846
- <p><strong>Gender:</strong> {gender}</p>
847
- <p><strong>Birth Date:</strong> {birth_date}</p>
848
- <p><strong>ID:</strong> {patient.get("id", "Unknown")}</p>
849
  </div>
850
  """
851
 
852
  return html
853
  except Exception as e:
854
- return f"<p>Error parsing patient data: {str(e)}</p>"
855
  except Exception as e:
856
- return f"<p>Error fetching patient data: {str(e)}</p>"
857
 
858
- with gr.Tab("Discharge Form"):
859
- gr.Markdown("## Patient Details")
 
860
  with gr.Row():
861
  first_name = gr.Textbox(label="First Name")
862
  last_name = gr.Textbox(label="Last Name")
@@ -870,174 +988,244 @@ with gr.Blocks() as demo:
870
  city = gr.Textbox(label="City")
871
  state = gr.Textbox(label="State")
872
  zip_code = gr.Textbox(label="Zip Code")
873
- gr.Markdown("## Primary Healthcare Professional Details")
874
  with gr.Row():
875
  doctor_first_name = gr.Textbox(label="Doctor's First Name")
876
  doctor_last_name = gr.Textbox(label="Doctor's Last Name")
877
- doctor_middle_initial = gr.Textbox(label="Middle Initial")
878
  hospital_name = gr.Textbox(label="Hospital/Clinic Name")
879
  doctor_address = gr.Textbox(label="Address")
880
  with gr.Row():
881
  doctor_city = gr.Textbox(label="City")
882
  doctor_state = gr.Textbox(label="State")
883
  doctor_zip = gr.Textbox(label="Zip Code")
884
- gr.Markdown("## Admission and Discharge Details")
885
  with gr.Row():
886
  admission_date = gr.Textbox(label="Date of Admission")
887
  referral_source = gr.Textbox(label="Source of Referral")
888
  admission_method = gr.Textbox(label="Method of Admission")
889
  with gr.Row():
890
  discharge_date = gr.Textbox(label="Date of Discharge")
891
- discharge_reason = gr.Radio(["Treated", "Transferred", "Discharge Against Advice", "Patient Died"], label="Discharge Reason")
 
 
 
892
  date_of_death = gr.Textbox(label="Date of Death (if applicable)")
893
- gr.Markdown("## Diagnosis & Procedures")
894
  diagnosis = gr.Textbox(label="Diagnosis")
895
  procedures = gr.Textbox(label="Operation & Procedures")
896
- gr.Markdown("## Medication Details")
897
  medications = gr.Textbox(label="Medication on Discharge")
898
- gr.Markdown("## Prepared By")
899
  with gr.Row():
900
  preparer_name = gr.Textbox(label="Name")
901
  preparer_job_title = gr.Textbox(label="Job Title")
902
 
903
  # Add buttons for both display form and generate PDF
904
  with gr.Row():
905
- submit_display = gr.Button("Display Form")
906
- submit_pdf = gr.Button("Generate PDF (No AI)") # Renamed button to clarify no AI
907
 
908
  # Output areas
909
- form_output = gr.Markdown()
910
- pdf_output = gr.File(label="Download PDF (No AI)") # Renamed output to clarify no AI
911
 
912
  # Connect the display form button
913
  submit_display.click(
914
  display_form,
915
  inputs=[
916
- first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
917
- doctor_first_name, doctor_last_name, doctor_middle_initial, hospital_name, doctor_address,
918
- doctor_city, doctor_state, doctor_zip,
919
- admission_date, referral_source, admission_method, discharge_date, discharge_reason, date_of_death,
920
- diagnosis, procedures, medications, preparer_name, preparer_job_title
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
921
  ],
922
- outputs=form_output
923
  )
924
 
925
  # Connect the generate PDF button (No AI version)
926
  submit_pdf.click(
927
  generate_pdf_from_form,
928
  inputs=[
929
- first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
930
- doctor_first_name, doctor_last_name, doctor_middle_initial, hospital_name, doctor_address,
931
- doctor_city, doctor_state, doctor_zip,
932
- admission_date, referral_source, admission_method, discharge_date, discharge_reason, date_of_death,
933
- diagnosis, procedures, medications, preparer_name, preparer_job_title
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
934
  ],
935
- outputs=pdf_output
936
  )
937
 
938
- with gr.Tab("Medical File Analysis"):
939
- gr.Markdown("## Analyze Medical Files with Discharge Guard AI")
940
  with gr.Column():
941
- dicom_file = gr.File(file_types=['.dcm'], label="Upload DICOM File (.dcm)")
 
 
942
  dicom_ai_output = gr.Textbox(label="DICOM Analysis Report", lines=5)
943
- analyze_dicom_button = gr.Button("Analyze DICOM with AI")
944
 
945
- hl7_file = gr.File(file_types=['.hl7'], label="Upload HL7 File (.hl7)")
 
 
946
  hl7_ai_output = gr.Textbox(label="HL7 Analysis Report", lines=5)
947
- analyze_hl7_button = gr.Button("Analyze HL7 with AI")
948
 
949
- xml_file = gr.File(file_types=['.xml'], label="Upload XML File (.xml)")
 
 
950
  xml_ai_output = gr.Textbox(label="XML Analysis Report", lines=5)
951
- analyze_xml_button = gr.Button("Analyze XML with AI")
952
 
953
- ccda_file = gr.File(file_types=['.xml', '.cda', '.ccd'], label="Upload CCDA File (.xml, .cda, .ccd)")
 
 
954
  ccda_ai_output = gr.Textbox(label="CCDA Analysis Report", lines=5)
955
- analyze_ccda_button = gr.Button("Analyze CCDA with AI")
956
-
957
- ccd_file = gr.File(file_types=['.ccd'], label="Upload CCD File (.ccd)") # Redundant, as CCDA also handles .ccd, but kept for clarity
958
- ccd_ai_output = gr.Textbox(label="CCD Analysis Report", lines=5) # Redundant
959
- analyze_ccd_button = gr.Button("Analyze CCD with AI") # Redundant
960
- pdf_file = gr.File(file_types=['.pdf'], label="Upload PDF File (.pdf)")
 
 
 
 
 
 
 
961
  pdf_ai_output = gr.Textbox(label="PDF Analysis Report", lines=5)
962
- analyze_pdf_button = gr.Button("Analyze PDF with AI")
963
 
964
- csv_file = gr.File(file_types=['.csv'], label="Upload CSV File (.csv)")
 
 
965
  csv_ai_output = gr.Textbox(label="CSV Analysis Report", lines=5)
966
- analyze_csv_button = gr.Button("Analyze CSV with AI")
967
-
968
 
969
  # Connect AI Analysis Buttons - using REAL AI functions now
970
  analyze_dicom_button.click(
971
- analyze_dicom_file_with_ai, # Call REAL AI function
972
- inputs=dicom_file, outputs=dicom_ai_output
 
973
  )
974
  analyze_hl7_button.click(
975
- analyze_hl7_file_with_ai, # Call REAL AI function
976
- inputs=hl7_file, outputs=hl7_ai_output
 
977
  )
978
  analyze_xml_button.click(
979
- analyze_cda_xml_file_with_ai, # Call REAL AI function
980
- inputs=xml_file, outputs=xml_ai_output
 
981
  )
982
  analyze_ccda_button.click(
983
- analyze_cda_xml_file_with_ai, # Call REAL AI function
984
- inputs=ccda_file, outputs=ccda_ai_output
 
985
  )
986
- analyze_ccd_button.click( # Redundant button, but kept for UI if needed
987
- analyze_cda_xml_file_with_ai, # Call REAL AI function
988
- inputs=ccd_file, outputs=ccd_ai_output
 
989
  )
990
  analyze_pdf_button.click(
991
- analyze_pdf_file_with_ai,
992
- inputs=pdf_file,
993
- outputs=pdf_ai_output
994
  )
995
  analyze_csv_button.click(
996
- analyze_csv_file_with_ai,
997
- inputs=csv_file,
998
- outputs=csv_ai_output
999
  )
1000
 
1001
-
1002
- with gr.Tab("One-Click Discharge Paper (AI)"): # New Tab for One-Click Discharge Paper with AI
1003
- gr.Markdown("## One-Click Medical Discharge Paper Generation with AI Content") # Updated title
1004
- one_click_ai_pdf_button = gr.Button("Generate Discharge Paper with AI (One-Click)") # Updated button label
1005
- one_click_ai_pdf_status = gr.Textbox(label="Discharge Paper Generation Status (AI)") # Updated status label
1006
- one_click_ai_pdf_download = gr.File(label="Download Discharge Paper (AI)") # Updated download label
 
 
 
 
 
 
 
1007
 
1008
  one_click_ai_pdf_button.click(
1009
- generate_discharge_paper_one_click, # Use the one-click function that now calls AI
1010
  inputs=[],
1011
- outputs=[one_click_ai_pdf_download, one_click_ai_pdf_status]
1012
  )
1013
 
1014
-
1015
  # Connect the patient data buttons
1016
  patient_data_button.click(
1017
  fn=CALLBACK_MANAGER.get_patient_data,
1018
  inputs=None,
1019
- outputs=patient_data_output
1020
  )
1021
 
1022
  # Connect refresh button to update dashboard
1023
  refresh_btn.click(
1024
- fn=update_dashboard,
1025
- inputs=None,
1026
- outputs=dashboard_output
1027
  )
1028
 
1029
  # Corrected the button click function name here to `generate_pdf_from_meldrx` (No AI PDF)
1030
  meldrx_pdf_button.click(
1031
  fn=generate_pdf_from_meldrx,
1032
  inputs=patient_data_output,
1033
- outputs=[meldrx_pdf_download, meldrx_pdf_status]
1034
  )
1035
 
1036
  # Connect patient data updates to dashboard
1037
  patient_data_button.click(
1038
- fn=update_dashboard,
1039
- inputs=None,
1040
- outputs=dashboard_output
1041
  )
1042
 
1043
  # Launch with sharing enabled for public access
 
6
  from datetime import datetime
7
  import traceback
8
  import logging
9
+ from huggingface_hub import InferenceClient # Import InferenceClient
10
+ from urllib.parse import urlparse, parse_qs # Import URL parsing utilities
11
 
12
  # Set up logging
13
  logging.basicConfig(level=logging.INFO)
 
19
  # Import necessary libraries for new file types and AI analysis functions
20
  import pydicom # For DICOM
21
  import hl7 # For HL7
22
+ from xml.etree import ElementTree # For XML and CCDA
23
+ from pypdf import PdfReader # For PDF
24
+ import csv # For CSV
25
+ import io # For IO operations
26
+ from PIL import Image # For image handling
27
 
28
  system_instructions = """
29
  **Discharge Guard - Medical Data Analysis Assistant**
 
57
  """
58
 
59
  # Initialize Inference Client - Ensure YOUR_HF_TOKEN is set in environment variables or replace with your actual token
60
+ HF_TOKEN = os.getenv("HF_TOKEN") # Or replace with your actual token string
61
  if not HF_TOKEN:
62
+ raise ValueError(
63
+ "HF_TOKEN environment variable not set. Please set your Hugging Face API token."
64
+ )
65
  client = InferenceClient(api_key=HF_TOKEN)
66
+ model_name = "meta-llama/Llama-3.3-70B-Instruct" # Specify the model to use
67
+
68
 
69
+ def analyze_dicom_file_with_ai(dicom_file_path): # Modified to accept file path
70
  """Analyzes DICOM file metadata using Discharge Guard AI."""
71
  try:
72
+ dicom_file = pydicom.dcmread(
73
+ dicom_file_path.name
74
+ ) # Read dicom using path, access file through .name for Gradio UploadedFile
75
  dicom_metadata_json = dicom_file.to_json_dict()
76
+ prediction_response, trace_data_dicom_ai = analyze_dicom_content_ai(
77
+ dicom_metadata_json
78
+ ) # Call content analysis
79
  if prediction_response:
80
  report = f"Discharge Guard AI Analysis of DICOM Metadata:\n\nDICOM Metadata Analysis Report:\n{prediction_response}\n\nDisclaimer: The Discharge Guard -generated analysis is for conceptual informational purposes only and may or **NOT medical advice.** Analysis is based on DICOM *metadata* and not image interpretation."
81
  return report
 
88
  except Exception as e:
89
  return f"Error during DICOM file processing in analyze_dicom_file_with_ai: {e}"
90
 
91
+
92
+ def analyze_dicom_content_ai(dicom_metadata_json): # Copied from your code
93
  """Analyzes DICOM metadata JSON content using Discharge Guard AI."""
94
  prompt_text = f"""{system_instructions} \n\n Perform a **deep and comprehensive analysis** of the following DICOM metadata in JSON format to provide a **structured summary and identify potential clinically relevant information with deep insights**. Focus not just on summarizing fields, but on **interpreting their clinical significance, identifying subtle patterns, and drawing inferences about the study's implications**. Think like an experienced radiologist reviewing this metadata for crucial diagnostic clues. Remember this is metadata, not the image itself, so focus on what can be gleaned from the data itself. Provide a "**Deep DICOM Metadata Analysis Report**". Important: Use the API Directories fhir endpoints FROM THIS LINK: https://app.meldrx.com/api/directories/fhir/endpoints.
95
  **DICOM Metadata (JSON):**
 
117
  model=model_name,
118
  messages=[{"role": "user", "content": prompt_text}],
119
  temperature=0.4,
120
+ max_tokens=1024, # Adjust as needed
121
  top_p=0.9,
122
  )
123
  the_response = response.choices[0].message.content
 
128
  trace_data_detail_dicom_analysis["error"] = f"AI Analysis Error: {e}"
129
  return error_message, trace_data_detail_dicom_analysis
130
 
131
+
132
  # ... (Paste other AI analysis functions: analyze_hl7_file_with_ai, analyze_cda_xml_file_with_ai, analyze_pdf_file_with_ai, analyze_csv_file_with_ai here - ensure to adapt file reading for Gradio file paths if necessary) ...
133
  def analyze_hl7_file_with_ai(hl7_file_path):
134
  """Analyzes HL7 file content using Discharge Guard AI."""
135
  try:
136
+ with open(hl7_file_path.name, "r") as f: # Open file using path, access file through .name for Gradio UploadedFile
137
  hl7_message_raw = f.read()
138
+ prediction_response, trace_data_hl7_ai = analyze_hl7_content_ai(
139
+ hl7_message_raw
140
+ )
141
 
142
  if prediction_response:
143
  report = f"Discharge Guard AI Analysis of HL7 Message:\n\nHL7 Message Analysis Report:\n{prediction_response}\n\n**Disclaimer:** The Discharge Guard AGI-generated analysis is for conceptual informational purposes only and may or **NOT medical advice.** Analysis is based on HL7 message content."
 
151
  except Exception as e:
152
  return f"Error during HL7 file processing in analyze_hl7_file_with_ai: {e}"
153
 
154
+
155
+ def analyze_hl7_content_ai(hl7_message_string): # Copied from your code
156
  """Analyzes HL7 message content using Discharge Guard AI."""
157
  prompt_text = f"""{system_instructions} \n\n Conduct a **deep and thorough analysis** of the following HL7 message content to provide a **structured summary and identify key clinical information with deep understanding**. Go beyond basic parsing; aim to **interpret the clinical narrative** embedded within the HL7 message. **Engage in deep search to contextualize medical codes and terminology**. Provide a "**Comprehensive HL7 Message Analysis Report**".
158
  **HL7 Message Content:**
 
180
  model=model_name,
181
  messages=[{"role": "user", "content": prompt_text}],
182
  temperature=0.4,
183
+ max_tokens=1024, # Adjust as needed
184
  top_p=0.9,
185
  )
186
  the_response = response.choices[0].message.content
 
192
  return error_message, trace_data_detail_hl7_analysis
193
 
194
 
195
+ def analyze_cda_xml_file_with_ai(cda_xml_file_path): # Modified to accept file path
196
  """Analyzes generic CDA or XML file content using Discharge Guard AI (more generalized version) Important: Use the API Directories fhir endpoints FROM THIS LINK: https://app.meldrx.com/api/directories/fhir/endpoints."""
197
  try:
198
+ with open(
199
+ cda_xml_file_path.name, "r"
200
+ ) as f: # Open file using path, access file through .name for Gradio UploadedFile
201
  cda_xml_content = f.read()
202
  prediction_response, trace_data_cda_xml_ai = analyze_cda_xml_content_ai(
203
  cda_xml_content
 
214
  except Exception as e:
215
  return f"Error during XML/CDA file processing in analyze_cda_xml_file_with_ai: {e}"
216
 
217
+
218
+ def analyze_cda_xml_content_ai(cda_xml_content): # Copied from your code
219
  """Analyzes generic CDA or XML content using Discharge Guard AI (more generalized version)."""
220
 
221
  prompt_text = f"""{system_instructions} \n\n Analyze the following medical XML/CDA content to provide a **structured and comprehensive patient data analysis**, similar to how a medical professional would review a patient's chart or a clinical document. You need to parse the XML structure yourself to extract the relevant information. Use bullet points, tables, or numbered steps for complex tasks. Provide a "Medical Document Analysis" report.
 
245
  model=model_name,
246
  messages=[{"role": "user", "content": prompt_text}],
247
  temperature=0.4,
248
+ max_tokens=1024, # Adjust as needed
249
  top_p=0.9,
250
  )
251
  the_response = response.choices[0].message.content
 
257
  return error_message, trace_data_detail_cda_xml_analysis
258
 
259
 
260
+ def analyze_pdf_file_with_ai(pdf_file_path): # Modified to accept file path
261
  """Analyzes PDF file content using Discharge Guard AI."""
262
  try:
263
+ with open(
264
+ pdf_file_path.name, "rb"
265
+ ) as f: # Open file in binary mode for PdfReader, access file through .name for Gradio UploadedFile
266
+ pdf_file = f # Pass file object to PdfReader
267
  pdf_reader = PdfReader(pdf_file)
268
  text_content = ""
269
  for page in pdf_reader.pages:
270
  text_content += page.extract_text()
271
 
272
+ prediction_response, trace_data_pdf_ai = analyze_pdf_content_ai(
273
+ text_content
274
+ )
275
 
276
  if prediction_response:
277
  report = f"Discharge Guard AI Analysis of PDF Content:\n\nMedical Report Analysis Report:\n{prediction_response}\n\n**Disclaimer:** The Discharge Guard AGI-generated analysis is for conceptual informational purposes only and may or **NOT medical advice.** Analysis is based on PDF text content."
 
285
  except Exception as e:
286
  return f"Error during PDF file processing in analyze_pdf_file_with_ai: {e}"
287
 
288
+
289
+ def analyze_pdf_content_ai(pdf_text_content): # Copied from your code
290
  """Analyzes PDF text content using Discharge Guard AI."""
291
  prompt_text = f"""{system_instructions} \n\n Analyze the following medical PDF text content to provide a **structured summary and identify key clinical information**. Focus on patient demographics, medical history, findings, diagnoses, medications, recommendations, and any important clinical details conveyed in the document. Provide a "Medical Report Analysis" report.
292
  **Medical PDF Text Content:**
 
314
  model=model_name,
315
  messages=[{"role": "user", "content": prompt_text}],
316
  temperature=0.4,
317
+ max_tokens=1024, # Adjust as needed
318
  top_p=0.9,
319
  )
320
  the_response = response.choices[0].message.content
 
326
  return error_message, trace_data_detail_pdf_analysis
327
 
328
 
329
+ def analyze_csv_file_with_ai(csv_file_path): # Modified to accept file path
330
  """Analyzes CSV file content using Discharge Guard AI."""
331
  try:
332
+ csv_content = csv_file_path.read().decode(
333
+ "utf-8"
334
+ ) # Read content directly from UploadedFile
335
  prediction_response, trace_data_csv_ai = analyze_csv_content_ai(csv_content)
336
 
337
  if prediction_response:
 
346
  except Exception as e:
347
  return f"Error during CSV file processing in analyze_csv_file_with_ai: {e}"
348
 
349
+
350
+ def analyze_csv_content_ai(csv_content_string): # Copied from your code
351
  """Analyzes CSV content (string) using Discharge Guard AI."""
352
  prompt_text = f"""{system_instructions} \n\n Analyze the following medical CSV data to provide a **structured summary and identify potential clinical insights**. Assume the CSV represents patient-related medical data. Focus on understanding the columns, summarizing key data points, identifying trends or patterns, and noting any potential clinical significance of the data. Provide a "Data Analysis" report.
353
  **Medical CSV Data:**
 
375
  model=model_name,
376
  messages=[{"role": "user", "content": prompt_text}],
377
  temperature=0.4,
378
+ max_tokens=1024, # Adjust as needed
379
  top_p=0.9,
380
  )
381
  the_response = response.choices[0].message.content
 
407
  self.auth_code = code
408
  if self.api.authenticate_with_code(code):
409
  self.access_token = self.api.access_token
410
+ return (
411
+ f"<span style='color:#00FF7F;'>Authentication successful!</span> Access Token: {self.access_token[:10]}... (truncated)" # Neon Green Success
412
+ )
413
+ return "<span style='color:#FF4500;'>Authentication failed. Please check the code.</span>" # Neon Orange Error
414
 
415
  def get_patient_data(self) -> str:
416
  """Fetch patient data from MeldRx"""
417
  try:
418
  if not self.access_token:
419
  logger.warning("Not authenticated when getting patient data")
420
+ return "<span style='color:#FF8C00;'>Not authenticated. Please provide a valid authorization code first.</span>" # Neon Dark Orange
421
 
422
  # For demo purposes, if there's no actual API connected, return mock data
423
  # Remove this in production and use the real API call
424
+ if not hasattr(self.api, "get_patients") or self.api.get_patients is None:
425
  logger.info("Using mock patient data (no API connection)")
426
  # Return mock FHIR bundle with patient data
427
  mock_data = {
 
438
  {
439
  "use": "official",
440
  "family": "Smith",
441
+ "given": ["John"],
442
  }
443
  ],
444
  "gender": "male",
445
  "birthDate": "1970-01-01",
446
  "address": [
447
+ {"city": "Boston", "state": "MA", "postalCode": "02108"}
448
+ ],
 
 
 
 
449
  }
450
  },
451
  {
 
456
  {
457
  "use": "official",
458
  "family": "Johnson",
459
+ "given": ["Jane"],
460
  }
461
  ],
462
  "gender": "female",
 
465
  {
466
  "city": "Cambridge",
467
  "state": "MA",
468
+ "postalCode": "02139",
469
  }
470
+ ],
471
  }
472
+ },
473
+ ],
474
  }
475
  return json.dumps(mock_data, indent=2)
476
 
 
478
  logger.info("Calling Meldrx API to get patients")
479
  patients = self.api.get_patients()
480
  if patients is not None:
481
+ return (
482
+ json.dumps(patients, indent=2)
483
+ if patients
484
+ else "<span style='color:#FFFF00;'>No patient data returned.</span>" # Neon Yellow
485
+ )
486
+ return "<span style='color:#DC143C;'>Failed to retrieve patient data.</span>" # Crimson Error
487
  except Exception as e:
488
  error_msg = f"Error in get_patient_data: {str(e)}"
489
  logger.error(error_msg)
490
+ return f"<span style='color:#FF6347;'>Error retrieving patient data: {str(e)}</span> {str(e)}" # Tomato Error
491
+
492
 
493
  def get_patient_documents(self, patient_id: str = None):
494
  """Fetch patient documents from MeldRx"""
495
  if not self.access_token:
496
+ return "<span style='color:#FF8C00;'>Not authenticated. Please provide a valid authorization code first.</span>" # Neon Dark Orange
497
 
498
  try:
499
  # This would call the actual MeldRx API to get documents for a specific patient
 
512
  "date": "2023-01-17",
513
  "author": "Lab System",
514
  "content": "CBC results: WBC 7.5, RBC 4.2, Hgb 14.1...",
515
+ },
516
  ]
517
  except Exception as e:
518
+ return f"<span style='color:#FF6347;'>Error retrieving patient documents: {str(e)}</span>: {str(e)}" # Tomato Error
519
+
520
 
521
  def display_form(
522
+ first_name,
523
+ last_name,
524
+ middle_initial,
525
+ dob,
526
+ age,
527
+ sex,
528
+ address,
529
+ city,
530
+ state,
531
+ zip_code,
532
+ doctor_first_name,
533
+ doctor_last_name,
534
+ doctor_middle_initial,
535
+ hospital_name,
536
+ doctor_address,
537
+ doctor_city,
538
+ doctor_state,
539
+ doctor_zip,
540
+ admission_date,
541
+ referral_source,
542
+ admission_method,
543
+ discharge_date,
544
+ discharge_reason,
545
+ date_of_death,
546
+ diagnosis,
547
+ procedures,
548
+ medications,
549
+ preparer_name,
550
+ preparer_job_title,
551
  ):
552
  form = f"""
553
+ <div style='color:#00FFFF; font-family: monospace;'>
554
+ **Patient Discharge Form** <br>
555
+ - Name: {first_name} {middle_initial} {last_name} <br>
556
+ - Date of Birth: {dob}, Age: {age}, Sex: {sex} <br>
557
+ - Address: {address}, {city}, {state}, {zip_code} <br>
558
+ - Doctor: {doctor_first_name} {doctor_middle_initial} {doctor_last_name} <br>
559
+ - Hospital/Clinic: {hospital_name} <br>
560
+ - Doctor Address: {doctor_address}, {doctor_city}, {doctor_state}, {doctor_zip} <br>
561
+ - Admission Date: {admission_date}, Source: {referral_source}, Method: {admission_method} <br>
562
+ - Discharge Date: {discharge_date}, Reason: {discharge_reason} <br>
563
+ - Date of Death: {date_of_death} <br>
564
+ - Diagnosis: {diagnosis} <br>
565
+ - Procedures: {procedures} <br>
566
+ - Medications: {medications} <br>
567
  - Prepared By: {preparer_name}, {preparer_job_title}
568
+ </div>
569
  """
570
  return form
571
 
572
+
573
  def generate_pdf_from_form(
574
+ first_name,
575
+ last_name,
576
+ middle_initial,
577
+ dob,
578
+ age,
579
+ sex,
580
+ address,
581
+ city,
582
+ state,
583
+ zip_code,
584
+ doctor_first_name,
585
+ doctor_last_name,
586
+ doctor_middle_initial,
587
+ hospital_name,
588
+ doctor_address,
589
+ doctor_city,
590
+ doctor_state,
591
+ doctor_zip,
592
+ admission_date,
593
+ referral_source,
594
+ admission_method,
595
+ discharge_date,
596
+ discharge_reason,
597
+ date_of_death,
598
+ diagnosis,
599
+ procedures,
600
+ medications,
601
+ preparer_name,
602
+ preparer_job_title,
603
  ):
604
  """Generate a PDF discharge form using the provided data"""
605
 
 
617
  "address": address,
618
  "city": city,
619
  "state": state,
620
+ "zip": zip_code,
621
  }
622
 
623
  discharge_info = {
 
625
  "date_of_discharge": discharge_date,
626
  "source_of_admission": referral_source,
627
  "mode_of_admission": admission_method,
628
+ "discharge_against_advice": "Yes"
629
+ if discharge_reason == "Discharge Against Advice"
630
+ else "No",
631
  }
632
 
633
  diagnosis_info = {
634
  "diagnosis": diagnosis,
635
  "operation_procedure": procedures,
636
  "treatment": "", # Not collected in the form
637
+ "follow_up": "", # Not collected in the form
638
  }
639
 
640
  medication_info = {
641
  "medications": [medications] if medications else [],
642
+ "instructions": "", # Not collected in the form
643
  }
644
 
645
  prepared_by = {
646
  "name": preparer_name,
647
  "title": preparer_job_title,
648
+ "signature": "", # Not collected in the form
649
  }
650
 
651
  # Generate PDF
 
654
  discharge_info,
655
  diagnosis_info,
656
  medication_info,
657
+ prepared_by,
658
  )
659
 
660
  # Create temporary file to save the PDF
661
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf")
662
  temp_file.write(pdf_buffer.read())
663
  temp_file_path = temp_file.name
664
  temp_file.close()
665
 
666
  return temp_file_path
667
 
668
+
669
  def generate_pdf_from_meldrx(patient_data):
670
  """Generate a PDF using patient data from MeldRx"""
671
  if isinstance(patient_data, str):
 
688
  # Extract patient info
689
  patient_info = {
690
  "name": f"{patient.get('name', {}).get('given', [''])[0]} {patient.get('name', {}).get('family', '')}",
691
+ "dob": patient.get("birthDate", "Unknown"),
692
+ "patient_id": patient.get("id", "Unknown"),
693
  "admission_date": datetime.now().strftime("%Y-%m-%d"), # Mock data
694
+ "physician": "Dr. Provider", # Mock data
695
  }
696
 
697
  # Mock LLM-generated content - This part needs to be replaced with actual AI generation if desired for MeldRx PDF
 
700
  "treatment": "Treatment summary would be generated by AI based on patient data from MeldRx.",
701
  "medications": "Medication list would be generated by AI based on patient data from MeldRx.",
702
  "follow_up": "Follow-up instructions would be generated by AI based on patient data from MeldRx.",
703
+ "special_instructions": "Special instructions would be generated by AI based on patient data from MeldRx.",
704
  }
705
 
706
  # Create discharge summary - Using No-AI PDF generation for now, replace with AI-content generation later
707
  output_dir = tempfile.mkdtemp()
708
+ pdf_path = generate_discharge_summary(
709
+ patient_info, llm_content, output_dir
710
+ ) # Still using No-AI template
711
 
712
+ return pdf_path, "PDF generated successfully (No AI Content in PDF yet)" # Indicate No-AI content
713
 
714
  except Exception as e:
715
  return None, f"Error generating PDF: {str(e)}"
716
 
717
+
718
  def generate_discharge_paper_one_click():
719
  """One-click function to fetch patient data and generate discharge paper with AI Content."""
720
  patient_data_str = CALLBACK_MANAGER.get_patient_data()
721
+ if (
722
+ patient_data_str.startswith("Not authenticated")
723
+ or patient_data_str.startswith("Failed")
724
+ or patient_data_str.startswith("Error")
725
+ ):
726
+ return None, patient_data_str # Return error message if authentication or data fetch fails
727
 
728
  try:
729
  patient_data = json.loads(patient_data_str)
730
 
731
  # --- AI Content Generation for Discharge Summary ---
732
  # This is a placeholder - Replace with actual AI call using InferenceClient and patient_data to generate content
733
+ ai_generated_content = generate_ai_discharge_content(
734
+ patient_data
735
+ ) # Placeholder AI function
736
 
737
  if not ai_generated_content:
738
  return None, "Error: AI content generation failed."
739
 
740
  # --- PDF Generation with AI Content ---
741
+ pdf_path, status_message = generate_pdf_from_meldrx_with_ai_content(
742
+ patient_data, ai_generated_content
743
+ ) # Function to generate PDF with AI content
744
 
745
  if pdf_path:
746
  return pdf_path, status_message
747
  else:
748
+ return None, status_message # Return status message if PDF generation fails
749
 
750
  except json.JSONDecodeError:
751
  return None, "Error: Patient data is not in valid JSON format."
752
  except Exception as e:
753
  return None, f"Error during discharge paper generation: {str(e)}"
754
 
755
+
756
  def generate_ai_discharge_content(patient_data):
757
  """Placeholder function to generate AI content for discharge summary.
758
+ Replace this with actual AI call using InferenceClient and patient_data."""
759
  try:
760
+ patient_name = (
761
+ f"{patient_data['entry'][0]['resource']['name'][0]['given'][0]} {patient_data['entry'][0]['resource']['name'][0]['family']}"
762
+ if patient_data.get("entry")
763
+ else "Unknown Patient"
764
+ )
765
  prompt_text = f"""{system_instructions}\n\nGenerate a discharge summary content (diagnosis, treatment, medications, follow-up instructions, special instructions) for patient: {patient_name}. Base the content on available patient data (if any provided, currently not provided in detail in this mock-up). Focus on creating clinically relevant and informative summary. Remember this is for informational purposes and NOT medical advice."""
766
 
767
  response = client.chat.completions.create(
768
  model=model_name,
769
  messages=[{"role": "user", "content": prompt_text}],
770
+ temperature=0.6, # Adjust temperature as needed for content generation
771
+ max_tokens=1024, # Adjust max_tokens as needed
772
  top_p=0.9,
773
  )
774
  ai_content = response.choices[0].message.content
775
 
776
  # Basic parsing of AI content - improve this based on desired output structure from LLM
777
  llm_content = {
778
+ "diagnosis": "AI Generated Diagnosis (Placeholder):\n"
779
+ + extract_section(ai_content, "Diagnosis"), # Example extraction - refine based on LLM output
780
+ "treatment": "AI Generated Treatment (Placeholder):\n"
781
+ + extract_section(ai_content, "Treatment"),
782
+ "medications": "AI Generated Medications (Placeholder):\n"
783
+ + extract_section(ai_content, "Medications"),
784
+ "follow_up": "AI Generated Follow-up (Placeholder):\n"
785
+ + extract_section(ai_content, "Follow-up Instructions"),
786
+ "special_instructions": "AI Generated Special Instructions (Placeholder):\n"
787
+ + extract_section(ai_content, "Special Instructions"),
788
  }
789
  return llm_content
790
 
 
792
  logger.error(f"Error generating AI discharge content: {e}")
793
  return None
794
 
795
+
796
  def extract_section(ai_content, section_title):
797
  """Simple placeholder function to extract section from AI content.
798
+ Improve this with more robust parsing based on LLM output format."""
799
  start_marker = f"**{section_title}:**"
800
+ end_marker = "\n\n" # Adjust based on typical LLM output structure
801
  start_index = ai_content.find(start_marker)
802
  if start_index != -1:
803
  start_index += len(start_marker)
 
826
 
827
  patient_info = {
828
  "name": f"{patient.get('name', {}).get('given', [''])[0]} {patient.get('name', {}).get('family', '')}",
829
+ "dob": patient.get("birthDate", "Unknown"),
830
+ "patient_id": patient.get("id", "Unknown"),
831
  "admission_date": datetime.now().strftime("%Y-%m-%d"), # Mock data
832
+ "physician": "Dr. AI Provider", # Mock data - Indicate AI generated
833
  }
834
 
 
835
  output_dir = tempfile.mkdtemp()
836
+ pdf_path = generate_discharge_summary(
837
+ patient_info, llm_content, output_dir
838
+ ) # Using AI content now
839
 
840
+ return pdf_path, "PDF generated successfully with AI Content" # Indicate AI content
841
 
842
  except Exception as e:
843
  return None, f"Error generating PDF with AI content: {str(e)}"
844
 
845
+
846
  def extract_auth_code_from_url(redirected_url):
847
  """Extracts the authorization code from the redirected URL."""
848
  try:
849
  parsed_url = urlparse(redirected_url)
850
  query_params = parse_qs(parsed_url.query)
851
  if "code" in query_params:
852
+ return query_params["code"][0], None # Return code and no error
853
  else:
854
+ return None, "Authorization code not found in URL." # Return None and error message
855
  except Exception as e:
856
+ return None, f"Error parsing URL: {e}" # Return None and error message
857
+
858
 
859
  # Create a simplified interface to avoid complex component interactions
860
  CALLBACK_MANAGER = CallbackManager(
861
  redirect_uri="https://multitransformer-discharge-guard.hf.space/callback",
862
+ client_secret=None,
863
+ )
864
+
865
+ # Define the cyberpunk theme - using a dark base and neon accents
866
+ cyberpunk_theme = gr.themes.Monochrome(
867
+ primary_hue="cyan",
868
+ secondary_hue="pink",
869
+ neutral_hue="slate",
870
+ font=["Source Code Pro", "monospace"], # Retro monospace font
871
+ font_mono=["Source Code Pro", "monospace"]
872
  )
873
 
874
+ # Create the UI with the cyberpunk theme
875
+ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
876
+ gr.Markdown("<h1 style='color:#00FFFF; text-shadow: 0 0 5px #00FFFF;'>Discharge Guard <span style='color:#FF00FF; text-shadow: 0 0 5px #FF00FF;'>Cyber</span></h1>") # Cyberpunk Title
877
 
878
+ with gr.Tab("Authenticate with MeldRx", elem_classes="cyberpunk-tab"): # Optional: Class for tab styling
879
+ gr.Markdown("<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>SMART on FHIR Authentication</h2>") # Neon Tab Header
880
  auth_url_output = gr.Textbox(label="Authorization URL", value=CALLBACK_MANAGER.get_auth_url(), interactive=False)
881
+ gr.Markdown("<p style='color:#A9A9A9;'>Copy the URL above, open it in a browser, log in, and paste the <span style='color:#00FFFF;'>entire redirected URL</span> from your browser's address bar below.</p>") # Subdued instructions with neon highlight
882
  redirected_url_input = gr.Textbox(label="Redirected URL") # New textbox for redirected URL
883
+ extract_code_button = gr.Button("Extract Authorization Code", elem_classes="cyberpunk-button") # Cyberpunk button style
884
  extracted_code_output = gr.Textbox(label="Extracted Authorization Code", interactive=False) # Textbox to show extracted code
885
 
886
  auth_code_input = gr.Textbox(label="Authorization Code (from above, or paste manually if extraction fails)", interactive=True) # Updated label to be clearer
887
+ auth_submit = gr.Button("Submit Code for Authentication", elem_classes="cyberpunk-button") # Cyberpunk button style
888
+ auth_result = gr.HTML(label="Authentication Result") # Use HTML for styled result
889
 
890
+ patient_data_button = gr.Button("Fetch Patient Data", elem_classes="cyberpunk-button") # Cyberpunk button style
891
  patient_data_output = gr.Textbox(label="Patient Data", lines=10)
892
 
893
  # Add button to generate PDF from MeldRx data (No AI)
894
+ meldrx_pdf_button = gr.Button("Generate PDF from MeldRx Data (No AI)", elem_classes="cyberpunk-button") # Renamed button
895
  meldrx_pdf_status = gr.Textbox(label="PDF Generation Status (No AI)") # Renamed status
896
  meldrx_pdf_download = gr.File(label="Download Generated PDF (No AI)") # Renamed download
897
 
 
899
  """Processes the redirected URL to extract and display the authorization code."""
900
  auth_code, error_message = extract_auth_code_from_url(redirected_url)
901
  if auth_code:
902
+ return auth_code, "<span style='color:#00FF7F;'>Authorization code extracted!</span>" # Neon Green Success
903
  else:
904
+ return "", f"<span style='color:#FF4500;'>Could not extract authorization code.</span> {error_message or ''}" # Neon Orange Error
905
 
906
 
907
  extract_code_button.click(
908
  fn=process_redirected_url,
909
  inputs=redirected_url_input,
910
+ outputs=[extracted_code_output, auth_result] # Reusing auth_result for extraction status
911
  )
912
 
 
913
  auth_submit.click(
914
  fn=CALLBACK_MANAGER.set_auth_code,
915
+ inputs=extracted_code_output, # Using extracted code as input for authentication
916
+ outputs=auth_result,
917
  )
918
 
919
+ with gr.Tab("Patient Dashboard", elem_classes="cyberpunk-tab"): # Optional: Class for tab styling
920
+ gr.Markdown("<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Patient Data</h2>") # Neon Tab Header
921
+ dashboard_output = gr.HTML("<p style='color:#A9A9A9;'>Fetch patient data from the Authentication tab first.</p>") # Subdued placeholder text
922
 
923
+ refresh_btn = gr.Button("Refresh Data", elem_classes="cyberpunk-button") # Cyberpunk button style
 
 
 
 
924
 
925
  # Simple function to update dashboard based on fetched data
926
  def update_dashboard():
927
  try:
928
  data = CALLBACK_MANAGER.get_patient_data()
929
+ if (
930
+ data.startswith("<span style='color:#FF8C00;'>Not authenticated")
931
+ or data.startswith("<span style='color:#DC143C;'>Failed")
932
+ or data.startswith("<span style='color:#FF6347;'>Error")
933
+ ):
934
+ return f"<p style='color:#FF8C00;'>{data}</p>" # Show auth errors in orange
935
 
936
  try:
937
  # Parse the data
 
945
  patients.append(resource)
946
 
947
  # Generate HTML card
948
+ html = "<h3 style='color:#00FFFF; text-shadow: 0 0 2px #00FFFF;'>Patients</h3>" # Neon Sub-header
949
  for patient in patients:
950
  # Extract name
951
  name = patient.get("name", [{}])[0]
 
956
  gender = patient.get("gender", "unknown").capitalize()
957
  birth_date = patient.get("birthDate", "Unknown")
958
 
959
+ # Generate HTML card with cyberpunk styling
960
  html += f"""
961
+ <div style="border: 1px solid #00FFFF; padding: 10px; margin: 10px 0; border-radius: 5px; background-color: #222; box-shadow: 0 0 5px #00FFFF;">
962
+ <h4 style='color:#00FFFF;'>{given} {family}</h4>
963
+ <p style='color:#A9A9A9;'><strong>Gender:</strong> <span style='color:#00FFFF;'>{gender}</span></p>
964
+ <p style='color:#A9A9A9;'><strong>Birth Date:</strong> <span style='color:#00FFFF;'>{birth_date}</span></p>
965
+ <p style='color:#A9A9A9;'><strong>ID:</strong> <span style='color:#00FFFF;'>{patient.get("id", "Unknown")}</span></p>
966
  </div>
967
  """
968
 
969
  return html
970
  except Exception as e:
971
+ return f"<p style='color:#FF6347;'>Error parsing patient data: {str(e)}</p>" # Tomato Error
972
  except Exception as e:
973
+ return f"<p style='color:#FF6347;'>Error fetching patient data: {str(e)}</p>" # Tomato Error
974
 
975
+
976
+ with gr.Tab("Discharge Form", elem_classes="cyberpunk-tab"): # Optional: Class for tab styling
977
+ gr.Markdown("<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Patient Details</h2>") # Neon Tab Header
978
  with gr.Row():
979
  first_name = gr.Textbox(label="First Name")
980
  last_name = gr.Textbox(label="Last Name")
 
988
  city = gr.Textbox(label="City")
989
  state = gr.Textbox(label="State")
990
  zip_code = gr.Textbox(label="Zip Code")
991
+ gr.Markdown("<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Primary Healthcare Professional Details</h2>") # Neon Sub-header
992
  with gr.Row():
993
  doctor_first_name = gr.Textbox(label="Doctor's First Name")
994
  doctor_last_name = gr.Textbox(label="Doctor's Last Name")
995
+ doctor_middle_initial = gr.Textbox(label="Doctor's Middle Initial")
996
  hospital_name = gr.Textbox(label="Hospital/Clinic Name")
997
  doctor_address = gr.Textbox(label="Address")
998
  with gr.Row():
999
  doctor_city = gr.Textbox(label="City")
1000
  doctor_state = gr.Textbox(label="State")
1001
  doctor_zip = gr.Textbox(label="Zip Code")
1002
+ gr.Markdown("<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Admission and Discharge Details</h2>") # Neon Sub-header
1003
  with gr.Row():
1004
  admission_date = gr.Textbox(label="Date of Admission")
1005
  referral_source = gr.Textbox(label="Source of Referral")
1006
  admission_method = gr.Textbox(label="Method of Admission")
1007
  with gr.Row():
1008
  discharge_date = gr.Textbox(label="Date of Discharge")
1009
+ discharge_reason = gr.Radio(
1010
+ ["Treated", "Transferred", "Discharge Against Advice", "Patient Died"],
1011
+ label="Discharge Reason",
1012
+ )
1013
  date_of_death = gr.Textbox(label="Date of Death (if applicable)")
1014
+ gr.Markdown("<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Diagnosis & Procedures</h2>") # Neon Sub-header
1015
  diagnosis = gr.Textbox(label="Diagnosis")
1016
  procedures = gr.Textbox(label="Operation & Procedures")
1017
+ gr.Markdown("<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Medication Details</h2>") # Neon Sub-header
1018
  medications = gr.Textbox(label="Medication on Discharge")
1019
+ gr.Markdown("<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Prepared By</h2>") # Neon Sub-header
1020
  with gr.Row():
1021
  preparer_name = gr.Textbox(label="Name")
1022
  preparer_job_title = gr.Textbox(label="Job Title")
1023
 
1024
  # Add buttons for both display form and generate PDF
1025
  with gr.Row():
1026
+ submit_display = gr.Button("Display Form", elem_classes="cyberpunk-button") # Cyberpunk button style
1027
+ submit_pdf = gr.Button("Generate PDF (No AI)", elem_classes="cyberpunk-button") # Renamed button to clarify no AI and styled
1028
 
1029
  # Output areas
1030
+ form_output = gr.HTML() # Use HTML to render styled form
1031
+ pdf_output = gr.File(label="Download PDF (No AI)") # Renamed output to clarify no AI
1032
 
1033
  # Connect the display form button
1034
  submit_display.click(
1035
  display_form,
1036
  inputs=[
1037
+ first_name,
1038
+ last_name,
1039
+ middle_initial,
1040
+ dob,
1041
+ age,
1042
+ sex,
1043
+ address,
1044
+ city,
1045
+ state,
1046
+ zip_code,
1047
+ doctor_first_name,
1048
+ doctor_last_name,
1049
+ doctor_middle_initial,
1050
+ hospital_name,
1051
+ doctor_address,
1052
+ doctor_city,
1053
+ doctor_state,
1054
+ doctor_zip,
1055
+ admission_date,
1056
+ referral_source,
1057
+ admission_method,
1058
+ discharge_date,
1059
+ discharge_reason,
1060
+ date_of_death,
1061
+ diagnosis,
1062
+ procedures,
1063
+ medications,
1064
+ preparer_name,
1065
+ preparer_job_title,
1066
  ],
1067
+ outputs=form_output,
1068
  )
1069
 
1070
  # Connect the generate PDF button (No AI version)
1071
  submit_pdf.click(
1072
  generate_pdf_from_form,
1073
  inputs=[
1074
+ first_name,
1075
+ last_name,
1076
+ middle_initial,
1077
+ dob,
1078
+ age,
1079
+ sex,
1080
+ address,
1081
+ city,
1082
+ state,
1083
+ zip_code,
1084
+ doctor_first_name,
1085
+ doctor_last_name,
1086
+ doctor_middle_initial,
1087
+ hospital_name,
1088
+ doctor_address,
1089
+ doctor_city,
1090
+ doctor_state,
1091
+ doctor_zip,
1092
+ admission_date,
1093
+ referral_source,
1094
+ admission_method,
1095
+ discharge_date,
1096
+ discharge_reason,
1097
+ date_of_death,
1098
+ diagnosis,
1099
+ procedures,
1100
+ medications,
1101
+ preparer_name,
1102
+ preparer_job_title,
1103
  ],
1104
+ outputs=pdf_output,
1105
  )
1106
 
1107
+ with gr.Tab("Medical File Analysis", elem_classes="cyberpunk-tab"): # Optional: Class for tab styling
1108
+ gr.Markdown("<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Analyze Medical Files with Discharge Guard AI</h2>") # Neon Tab Header
1109
  with gr.Column():
1110
+ dicom_file = gr.File(
1111
+ file_types=[".dcm"], label="Upload DICOM File (.dcm)"
1112
+ )
1113
  dicom_ai_output = gr.Textbox(label="DICOM Analysis Report", lines=5)
1114
+ analyze_dicom_button = gr.Button("Analyze DICOM with AI", elem_classes="cyberpunk-button") # Cyberpunk button style
1115
 
1116
+ hl7_file = gr.File(
1117
+ file_types=[".hl7"], label="Upload HL7 File (.hl7)"
1118
+ )
1119
  hl7_ai_output = gr.Textbox(label="HL7 Analysis Report", lines=5)
1120
+ analyze_hl7_button = gr.Button("Analyze HL7 with AI", elem_classes="cyberpunk-button") # Cyberpunk button style
1121
 
1122
+ xml_file = gr.File(
1123
+ file_types=[".xml"], label="Upload XML File (.xml)"
1124
+ )
1125
  xml_ai_output = gr.Textbox(label="XML Analysis Report", lines=5)
1126
+ analyze_xml_button = gr.Button("Analyze XML with AI", elem_classes="cyberpunk-button") # Cyberpunk button style
1127
 
1128
+ ccda_file = gr.File(
1129
+ file_types=[".xml", ".cda", ".ccd"], label="Upload CCDA File (.xml, .cda, .ccd)"
1130
+ )
1131
  ccda_ai_output = gr.Textbox(label="CCDA Analysis Report", lines=5)
1132
+ analyze_ccda_button = gr.Button("Analyze CCDA with AI", elem_classes="cyberpunk-button") # Cyberpunk button style
1133
+
1134
+ ccd_file = gr.File(
1135
+ file_types=[".ccd"],
1136
+ label="Upload CCD File (.ccd)",
1137
+ ) # Redundant, as CCDA also handles .ccd, but kept for clarity
1138
+ ccd_ai_output = gr.Textbox(
1139
+ label="CCD Analysis Report", lines=5
1140
+ ) # Redundant
1141
+ analyze_ccd_button = gr.Button("Analyze CCD with AI", elem_classes="cyberpunk-button") # Cyberpunk button style # Redundant
1142
+ pdf_file = gr.File(
1143
+ file_types=[".pdf"], label="Upload PDF File (.pdf)"
1144
+ )
1145
  pdf_ai_output = gr.Textbox(label="PDF Analysis Report", lines=5)
1146
+ analyze_pdf_button = gr.Button("Analyze PDF with AI", elem_classes="cyberpunk-button") # Cyberpunk button style
1147
 
1148
+ csv_file = gr.File(
1149
+ file_types=[".csv"], label="Upload CSV File (.csv)"
1150
+ )
1151
  csv_ai_output = gr.Textbox(label="CSV Analysis Report", lines=5)
1152
+ analyze_csv_button = gr.Button("Analyze CSV with AI", elem_classes="cyberpunk-button") # Cyberpunk button style
 
1153
 
1154
  # Connect AI Analysis Buttons - using REAL AI functions now
1155
  analyze_dicom_button.click(
1156
+ analyze_dicom_file_with_ai, # Call REAL AI function
1157
+ inputs=dicom_file,
1158
+ outputs=dicom_ai_output,
1159
  )
1160
  analyze_hl7_button.click(
1161
+ analyze_hl7_file_with_ai, # Call REAL AI function
1162
+ inputs=hl7_file,
1163
+ outputs=hl7_ai_output,
1164
  )
1165
  analyze_xml_button.click(
1166
+ analyze_cda_xml_file_with_ai, # Call REAL AI function
1167
+ inputs=xml_file,
1168
+ outputs=xml_ai_output,
1169
  )
1170
  analyze_ccda_button.click(
1171
+ analyze_cda_xml_file_with_ai, # Call REAL AI function
1172
+ inputs=ccda_file,
1173
+ outputs=ccda_ai_output,
1174
  )
1175
+ analyze_ccd_button.click( # Redundant button, but kept for UI if needed
1176
+ analyze_cda_xml_file_with_ai, # Call REAL AI function
1177
+ inputs=ccd_file,
1178
+ outputs=ccd_ai_output,
1179
  )
1180
  analyze_pdf_button.click(
1181
+ analyze_pdf_file_with_ai, inputs=pdf_file, outputs=pdf_ai_output
 
 
1182
  )
1183
  analyze_csv_button.click(
1184
+ analyze_csv_file_with_ai, inputs=csv_file, outputs=csv_ai_output
 
 
1185
  )
1186
 
1187
+ with gr.Tab(
1188
+ "One-Click Discharge Paper (AI)", elem_classes="cyberpunk-tab"
1189
+ ): # New Tab for One-Click Discharge Paper with AI, styled
1190
+ gr.Markdown("<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>One-Click Medical Discharge Paper Generation with AI Content</h2>") # Neon Tab Header
1191
+ one_click_ai_pdf_button = gr.Button(
1192
+ "Generate Discharge Paper with AI (One-Click)", elem_classes="cyberpunk-button"
1193
+ ) # Updated button label and styled
1194
+ one_click_ai_pdf_status = gr.Textbox(
1195
+ label="Discharge Paper Generation Status (AI)"
1196
+ ) # Updated status label
1197
+ one_click_ai_pdf_download = gr.File(
1198
+ label="Download Discharge Paper (AI)"
1199
+ ) # Updated download label
1200
 
1201
  one_click_ai_pdf_button.click(
1202
+ generate_discharge_paper_one_click, # Use the one-click function that now calls AI
1203
  inputs=[],
1204
+ outputs=[one_click_ai_pdf_download, one_click_ai_pdf_status],
1205
  )
1206
 
 
1207
  # Connect the patient data buttons
1208
  patient_data_button.click(
1209
  fn=CALLBACK_MANAGER.get_patient_data,
1210
  inputs=None,
1211
+ outputs=patient_data_output,
1212
  )
1213
 
1214
  # Connect refresh button to update dashboard
1215
  refresh_btn.click(
1216
+ fn=update_dashboard, inputs=None, outputs=dashboard_output
 
 
1217
  )
1218
 
1219
  # Corrected the button click function name here to `generate_pdf_from_meldrx` (No AI PDF)
1220
  meldrx_pdf_button.click(
1221
  fn=generate_pdf_from_meldrx,
1222
  inputs=patient_data_output,
1223
+ outputs=[meldrx_pdf_download, meldrx_pdf_status],
1224
  )
1225
 
1226
  # Connect patient data updates to dashboard
1227
  patient_data_button.click(
1228
+ fn=update_dashboard, inputs=None, outputs=dashboard_output
 
 
1229
  )
1230
 
1231
  # Launch with sharing enabled for public access