Update callbackmanager.py
Browse files- callbackmanager.py +161 -152
callbackmanager.py
CHANGED
@@ -121,15 +121,14 @@ def analyze_dicom_content_ai(dicom_metadata_json): # Copied from your code
|
|
121 |
top_p=0.9,
|
122 |
)
|
123 |
the_response = response.choices[0].message.content
|
124 |
-
return the_response,
|
125 |
|
126 |
except Exception as e:
|
127 |
error_message = f"AI Analysis Error in analyze_dicom_content_ai (DICOM Metadata): {e}"
|
128 |
trace_data_detail_dicom_analysis["error"] = f"AI Analysis Error: {e}"
|
129 |
-
return error_message,
|
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:
|
@@ -293,7 +292,7 @@ def analyze_pdf_content_ai(pdf_text_content): # Copied from your code
|
|
293 |
```text
|
294 |
{pdf_text_content}
|
295 |
```
|
296 |
-
* Remember, this analysis is for conceptual informational purposes only and **NOT medical advice.** Focus on
|
297 |
"""
|
298 |
|
299 |
trace_data_detail_pdf_analysis = {
|
@@ -387,7 +386,6 @@ def analyze_csv_content_ai(csv_content_string): # Copied from your code
|
|
387 |
return error_message, trace_data_detail_csv_analysis
|
388 |
|
389 |
|
390 |
-
# ... (CallbackManager, display_form, generate_pdf_from_form, generate_pdf_from_meldrx, generate_discharge_paper_one_click, client initialization remain the same) ...
|
391 |
class CallbackManager:
|
392 |
def __init__(self, redirect_uri: str, client_secret: str = None):
|
393 |
client_id = os.getenv("APPID")
|
@@ -408,71 +406,16 @@ class CallbackManager:
|
|
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)"
|
412 |
)
|
413 |
-
return "<span style='color:#FF4500;'>Authentication failed. Please check the code.</span>"
|
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>"
|
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 = {
|
428 |
-
"resourceType": "Bundle",
|
429 |
-
"type": "searchset",
|
430 |
-
"total": 2,
|
431 |
-
"link": [],
|
432 |
-
"entry": [
|
433 |
-
{
|
434 |
-
"resource": {
|
435 |
-
"resourceType": "Patient",
|
436 |
-
"id": "patient1",
|
437 |
-
"name": [
|
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 |
-
{
|
452 |
-
"resource": {
|
453 |
-
"resourceType": "Patient",
|
454 |
-
"id": "patient2",
|
455 |
-
"name": [
|
456 |
-
{
|
457 |
-
"use": "official",
|
458 |
-
"family": "Johnson",
|
459 |
-
"given": ["Jane"],
|
460 |
-
}
|
461 |
-
],
|
462 |
-
"gender": "female",
|
463 |
-
"birthDate": "1985-05-15",
|
464 |
-
"address": [
|
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 |
|
477 |
# Real implementation with API call
|
478 |
logger.info("Calling Meldrx API to get patients")
|
@@ -481,19 +424,18 @@ class CallbackManager:
|
|
481 |
return (
|
482 |
json.dumps(patients, indent=2)
|
483 |
if patients
|
484 |
-
else "<span style='color:#FFFF00;'>No patient data returned.</span>"
|
485 |
)
|
486 |
-
return "<span style='color:#DC143C;'>Failed to retrieve patient data.</span>"
|
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)}"
|
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>"
|
497 |
|
498 |
try:
|
499 |
# This would call the actual MeldRx API to get documents for a specific patient
|
@@ -515,7 +457,7 @@ class CallbackManager:
|
|
515 |
},
|
516 |
]
|
517 |
except Exception as e:
|
518 |
-
return f"<span style='color:#FF6347;'>Error retrieving patient documents: {str(e)}</span>: {str(e)}"
|
519 |
|
520 |
|
521 |
def display_form(
|
@@ -867,47 +809,76 @@ cyberpunk_theme = gr.themes.Monochrome(
|
|
867 |
primary_hue="cyan",
|
868 |
secondary_hue="pink",
|
869 |
neutral_hue="slate",
|
870 |
-
font=["Source Code Pro", "monospace"],
|
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:
|
876 |
-
gr.Markdown(
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
|
881 |
-
gr.Markdown(
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
|
886 |
-
|
887 |
-
|
888 |
-
|
889 |
-
|
890 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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(
|
895 |
-
|
896 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
897 |
|
898 |
def process_redirected_url(redirected_url):
|
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>"
|
903 |
else:
|
904 |
-
return "", f"<span style='color:#FF4500;'>Could not extract authorization code.</span> {error_message or ''}"
|
905 |
-
|
906 |
|
907 |
extract_code_button.click(
|
908 |
fn=process_redirected_url,
|
909 |
inputs=redirected_url_input,
|
910 |
-
outputs=[
|
|
|
|
|
|
|
911 |
)
|
912 |
|
913 |
auth_submit.click(
|
@@ -916,11 +887,19 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
916 |
outputs=auth_result,
|
917 |
)
|
918 |
|
919 |
-
with gr.Tab(
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
924 |
|
925 |
# Simple function to update dashboard based on fetched data
|
926 |
def update_dashboard():
|
@@ -931,7 +910,7 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
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>"
|
935 |
|
936 |
try:
|
937 |
# Parse the data
|
@@ -945,7 +924,7 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
945 |
patients.append(resource)
|
946 |
|
947 |
# Generate HTML card
|
948 |
-
html = "<h3 style='color:#00FFFF; text-shadow: 0 0 2px #00FFFF;'>Patients</h3>"
|
949 |
for patient in patients:
|
950 |
# Extract name
|
951 |
name = patient.get("name", [{}])[0]
|
@@ -968,13 +947,16 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
968 |
|
969 |
return html
|
970 |
except Exception as e:
|
971 |
-
return f"<p style='color:#FF6347;'>Error parsing patient data: {str(e)}</p>"
|
972 |
except Exception as e:
|
973 |
-
return f"<p style='color:#FF6347;'>Error fetching patient data: {str(e)}</p>"
|
974 |
|
|
|
975 |
|
976 |
-
with gr.Tab("Discharge Form", elem_classes="cyberpunk-tab"):
|
977 |
-
gr.Markdown(
|
|
|
|
|
978 |
with gr.Row():
|
979 |
first_name = gr.Textbox(label="First Name")
|
980 |
last_name = gr.Textbox(label="Last Name")
|
@@ -988,7 +970,9 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
988 |
city = gr.Textbox(label="City")
|
989 |
state = gr.Textbox(label="State")
|
990 |
zip_code = gr.Textbox(label="Zip Code")
|
991 |
-
gr.Markdown(
|
|
|
|
|
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")
|
@@ -999,7 +983,9 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
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(
|
|
|
|
|
1003 |
with gr.Row():
|
1004 |
admission_date = gr.Textbox(label="Date of Admission")
|
1005 |
referral_source = gr.Textbox(label="Source of Referral")
|
@@ -1011,24 +997,36 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
1011 |
label="Discharge Reason",
|
1012 |
)
|
1013 |
date_of_death = gr.Textbox(label="Date of Death (if applicable)")
|
1014 |
-
gr.Markdown(
|
|
|
|
|
1015 |
diagnosis = gr.Textbox(label="Diagnosis")
|
1016 |
procedures = gr.Textbox(label="Operation & Procedures")
|
1017 |
-
gr.Markdown(
|
|
|
|
|
1018 |
medications = gr.Textbox(label="Medication on Discharge")
|
1019 |
-
gr.Markdown(
|
|
|
|
|
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(
|
1027 |
-
|
|
|
|
|
|
|
|
|
1028 |
|
1029 |
# Output areas
|
1030 |
-
form_output = gr.HTML()
|
1031 |
-
pdf_output = gr.File(
|
|
|
|
|
1032 |
|
1033 |
# Connect the display form button
|
1034 |
submit_display.click(
|
@@ -1064,7 +1062,7 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
1064 |
preparer_name,
|
1065 |
preparer_job_title,
|
1066 |
],
|
1067 |
-
outputs=form_output
|
1068 |
)
|
1069 |
|
1070 |
# Connect the generate PDF button (No AI version)
|
@@ -1101,35 +1099,44 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
1101 |
preparer_name,
|
1102 |
preparer_job_title,
|
1103 |
],
|
1104 |
-
outputs=pdf_output
|
1105 |
)
|
1106 |
|
1107 |
-
with gr.Tab(
|
1108 |
-
|
|
|
|
|
|
|
|
|
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(
|
|
|
|
|
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(
|
|
|
|
|
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(
|
|
|
|
|
1127 |
|
1128 |
ccda_file = gr.File(
|
1129 |
-
file_types=[".xml", ".cda", ".ccd"],
|
|
|
1130 |
)
|
1131 |
ccda_ai_output = gr.Textbox(label="CCDA Analysis Report", lines=5)
|
1132 |
-
analyze_ccda_button = gr.Button(
|
|
|
|
|
1133 |
|
1134 |
ccd_file = gr.File(
|
1135 |
file_types=[".ccd"],
|
@@ -1138,44 +1145,46 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
1138 |
ccd_ai_output = gr.Textbox(
|
1139 |
label="CCD Analysis Report", lines=5
|
1140 |
) # Redundant
|
1141 |
-
analyze_ccd_button = gr.Button(
|
1142 |
-
|
1143 |
-
|
1144 |
-
)
|
1145 |
pdf_ai_output = gr.Textbox(label="PDF Analysis Report", lines=5)
|
1146 |
-
analyze_pdf_button = gr.Button(
|
|
|
|
|
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(
|
|
|
|
|
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
|
@@ -1187,9 +1196,12 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
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(
|
|
|
|
|
1191 |
one_click_ai_pdf_button = gr.Button(
|
1192 |
-
"Generate Discharge Paper with AI (One-Click)",
|
|
|
1193 |
) # Updated button label and styled
|
1194 |
one_click_ai_pdf_status = gr.Textbox(
|
1195 |
label="Discharge Paper Generation Status (AI)"
|
@@ -1206,21 +1218,17 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
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
|
@@ -1228,5 +1236,6 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
|
1228 |
fn=update_dashboard, inputs=None, outputs=dashboard_output
|
1229 |
)
|
1230 |
|
|
|
1231 |
# Launch with sharing enabled for public access
|
1232 |
demo.launch(ssr_mode=False)
|
|
|
121 |
top_p=0.9,
|
122 |
)
|
123 |
the_response = response.choices[0].message.content
|
124 |
+
return the_response, trace_data_detail_dicom_ai
|
125 |
|
126 |
except Exception as e:
|
127 |
error_message = f"AI Analysis Error in analyze_dicom_content_ai (DICOM Metadata): {e}"
|
128 |
trace_data_detail_dicom_analysis["error"] = f"AI Analysis Error: {e}"
|
129 |
+
return error_message, trace_data_detail_dicom_image_analysis
|
130 |
|
131 |
|
|
|
132 |
def analyze_hl7_file_with_ai(hl7_file_path):
|
133 |
"""Analyzes HL7 file content using Discharge Guard AI."""
|
134 |
try:
|
|
|
292 |
```text
|
293 |
{pdf_text_content}
|
294 |
```
|
295 |
+
* Remember, this analysis is for conceptual informational purposes only and **NOT medical advice.** Focus on deep summarization and structuring the extracted data in a clinically relevant way based on the PDF content.
|
296 |
"""
|
297 |
|
298 |
trace_data_detail_pdf_analysis = {
|
|
|
386 |
return error_message, trace_data_detail_csv_analysis
|
387 |
|
388 |
|
|
|
389 |
class CallbackManager:
|
390 |
def __init__(self, redirect_uri: str, client_secret: str = None):
|
391 |
client_id = os.getenv("APPID")
|
|
|
406 |
if self.api.authenticate_with_code(code):
|
407 |
self.access_token = self.api.access_token
|
408 |
return (
|
409 |
+
f"<span style='color:#00FF7F;'>Authentication successful!</span> Access Token: {self.access_token[:10]}... (truncated)" # Neon Green Success
|
410 |
)
|
411 |
+
return "<span style='color:#FF4500;'>Authentication failed. Please check the code.</span>" # Neon Orange Error
|
412 |
|
413 |
def get_patient_data(self) -> str:
|
414 |
"""Fetch patient data from MeldRx"""
|
415 |
try:
|
416 |
if not self.access_token:
|
417 |
logger.warning("Not authenticated when getting patient data")
|
418 |
+
return "<span style='color:#FF8C00;'>Not authenticated. Please provide a valid authorization code first.</span>" # Neon Dark Orange
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
419 |
|
420 |
# Real implementation with API call
|
421 |
logger.info("Calling Meldrx API to get patients")
|
|
|
424 |
return (
|
425 |
json.dumps(patients, indent=2)
|
426 |
if patients
|
427 |
+
else "<span style='color:#FFFF00;'>No patient data returned.</span>" # Neon Yellow
|
428 |
)
|
429 |
+
return "<span style='color:#DC143C;'>Failed to retrieve patient data.</span>" # Crimson Error
|
430 |
except Exception as e:
|
431 |
error_msg = f"Error in get_patient_data: {str(e)}"
|
432 |
logger.error(error_msg)
|
433 |
+
return f"<span style='color:#FF6347;'>Error retrieving patient data: {str(e)}</span> {str(e)}" # Tomato Error
|
|
|
434 |
|
435 |
def get_patient_documents(self, patient_id: str = None):
|
436 |
"""Fetch patient documents from MeldRx"""
|
437 |
if not self.access_token:
|
438 |
+
return "<span style='color:#FF8C00;'>Not authenticated. Please provide a valid authorization code first.</span>" # Neon Dark Orange
|
439 |
|
440 |
try:
|
441 |
# This would call the actual MeldRx API to get documents for a specific patient
|
|
|
457 |
},
|
458 |
]
|
459 |
except Exception as e:
|
460 |
+
return f"<span style='color:#FF6347;'>Error retrieving patient documents: {str(e)}</span>: {str(e)}" # Tomato Error
|
461 |
|
462 |
|
463 |
def display_form(
|
|
|
809 |
primary_hue="cyan",
|
810 |
secondary_hue="pink",
|
811 |
neutral_hue="slate",
|
812 |
+
font=["Source Code Pro", "monospace"], # Retro monospace font
|
813 |
+
font_mono=["Source Code Pro", "monospace"],
|
814 |
)
|
815 |
|
816 |
# Create the UI with the cyberpunk theme
|
817 |
+
with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
|
818 |
+
gr.Markdown(
|
819 |
+
"<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>"
|
820 |
+
) # Cyberpunk Title
|
821 |
+
|
822 |
+
with gr.Tab("Authenticate with MeldRx", elem_classes="cyberpunk-tab"): # Optional: Class for tab styling
|
823 |
+
gr.Markdown(
|
824 |
+
"<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>SMART on FHIR Authentication</h2>"
|
825 |
+
) # Neon Tab Header
|
826 |
+
auth_url_output = gr.Textbox(
|
827 |
+
label="Authorization URL",
|
828 |
+
value=CALLBACK_MANAGER.get_auth_url(),
|
829 |
+
interactive=False,
|
830 |
+
)
|
831 |
+
gr.Markdown(
|
832 |
+
"<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>"
|
833 |
+
) # Subdued instructions with neon highlight
|
834 |
+
redirected_url_input = gr.Textbox(label="Redirected URL") # New textbox for redirected URL
|
835 |
+
extract_code_button = gr.Button(
|
836 |
+
"Extract Authorization Code", elem_classes="cyberpunk-button"
|
837 |
+
) # Cyberpunk button style
|
838 |
+
extracted_code_output = gr.Textbox(
|
839 |
+
label="Extracted Authorization Code", interactive=False
|
840 |
+
) # Textbox to show extracted code
|
841 |
+
|
842 |
+
auth_code_input = gr.Textbox(
|
843 |
+
label="Authorization Code (from above, or paste manually if extraction fails)",
|
844 |
+
interactive=True,
|
845 |
+
) # Updated label to be clearer
|
846 |
+
auth_submit = gr.Button(
|
847 |
+
"Submit Code for Authentication", elem_classes="cyberpunk-button"
|
848 |
+
) # Cyberpunk button style
|
849 |
+
auth_result = gr.HTML(label="Authentication Result") # Use HTML for styled result
|
850 |
+
|
851 |
+
patient_data_button = gr.Button(
|
852 |
+
"Fetch Patient Data", elem_classes="cyberpunk-button"
|
853 |
+
) # Cyberpunk button style
|
854 |
patient_data_output = gr.Textbox(label="Patient Data", lines=10)
|
855 |
|
856 |
# Add button to generate PDF from MeldRx data (No AI)
|
857 |
+
meldrx_pdf_button = gr.Button(
|
858 |
+
"Generate PDF from MeldRx Data (No AI)", elem_classes="cyberpunk-button"
|
859 |
+
) # Renamed button
|
860 |
+
meldrx_pdf_status = gr.Textbox(
|
861 |
+
label="PDF Generation Status (No AI)"
|
862 |
+
) # Renamed status
|
863 |
+
meldrx_pdf_download = gr.File(
|
864 |
+
label="Download Generated PDF (No AI)"
|
865 |
+
) # Renamed download
|
866 |
|
867 |
def process_redirected_url(redirected_url):
|
868 |
"""Processes the redirected URL to extract and display the authorization code."""
|
869 |
auth_code, error_message = extract_auth_code_from_url(redirected_url)
|
870 |
if auth_code:
|
871 |
+
return auth_code, "<span style='color:#00FF7F;'>Authorization code extracted!</span>" # Neon Green Success
|
872 |
else:
|
873 |
+
return "", f"<span style='color:#FF4500;'>Could not extract authorization code.</span> {error_message or ''}" # Neon Orange Error
|
|
|
874 |
|
875 |
extract_code_button.click(
|
876 |
fn=process_redirected_url,
|
877 |
inputs=redirected_url_input,
|
878 |
+
outputs=[
|
879 |
+
extracted_code_output,
|
880 |
+
auth_result,
|
881 |
+
], # Reusing auth_result for extraction status
|
882 |
)
|
883 |
|
884 |
auth_submit.click(
|
|
|
887 |
outputs=auth_result,
|
888 |
)
|
889 |
|
890 |
+
with gr.Tab(
|
891 |
+
"Patient Dashboard", elem_classes="cyberpunk-tab"
|
892 |
+
): # Optional: Class for tab styling
|
893 |
+
gr.Markdown(
|
894 |
+
"<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Patient Data</h2>"
|
895 |
+
) # Neon Tab Header
|
896 |
+
dashboard_output = gr.HTML(
|
897 |
+
"<p style='color:#A9A9A9;'>Fetch patient data from the Authentication tab first.</p>"
|
898 |
+
) # Subdued placeholder text
|
899 |
+
|
900 |
+
refresh_btn = gr.Button(
|
901 |
+
"Refresh Data", elem_classes="cyberpunk-button"
|
902 |
+
) # Cyberpunk button style
|
903 |
|
904 |
# Simple function to update dashboard based on fetched data
|
905 |
def update_dashboard():
|
|
|
910 |
or data.startswith("<span style='color:#DC143C;'>Failed")
|
911 |
or data.startswith("<span style='color:#FF6347;'>Error")
|
912 |
):
|
913 |
+
return f"<p style='color:#FF8C00;'>{data}</p>" # Show auth errors in orange
|
914 |
|
915 |
try:
|
916 |
# Parse the data
|
|
|
924 |
patients.append(resource)
|
925 |
|
926 |
# Generate HTML card
|
927 |
+
html = "<h3 style='color:#00FFFF; text-shadow: 0 0 2px #00FFFF;'>Patients</h3>" # Neon Sub-header
|
928 |
for patient in patients:
|
929 |
# Extract name
|
930 |
name = patient.get("name", [{}])[0]
|
|
|
947 |
|
948 |
return html
|
949 |
except Exception as e:
|
950 |
+
return f"<p style='color:#FF6347;'>Error parsing patient data: {str(e)}</p>" # Tomato Error
|
951 |
except Exception as e:
|
952 |
+
return f"<p style='color:#FF6347;'>Error fetching patient data: {str(e)}</p>" # Tomato Error
|
953 |
|
954 |
+
refresh_btn.click(fn=update_dashboard, inputs=None, outputs=dashboard_output)
|
955 |
|
956 |
+
with gr.Tab("Discharge Form", elem_classes="cyberpunk-tab"): # Optional: Class for tab styling
|
957 |
+
gr.Markdown(
|
958 |
+
"<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Patient Details</h2>"
|
959 |
+
) # Neon Tab Header
|
960 |
with gr.Row():
|
961 |
first_name = gr.Textbox(label="First Name")
|
962 |
last_name = gr.Textbox(label="Last Name")
|
|
|
970 |
city = gr.Textbox(label="City")
|
971 |
state = gr.Textbox(label="State")
|
972 |
zip_code = gr.Textbox(label="Zip Code")
|
973 |
+
gr.Markdown(
|
974 |
+
"<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Primary Healthcare Professional Details</h2>"
|
975 |
+
) # Neon Sub-header
|
976 |
with gr.Row():
|
977 |
doctor_first_name = gr.Textbox(label="Doctor's First Name")
|
978 |
doctor_last_name = gr.Textbox(label="Doctor's Last Name")
|
|
|
983 |
doctor_city = gr.Textbox(label="City")
|
984 |
doctor_state = gr.Textbox(label="State")
|
985 |
doctor_zip = gr.Textbox(label="Zip Code")
|
986 |
+
gr.Markdown(
|
987 |
+
"<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Admission and Discharge Details</h2>"
|
988 |
+
) # Neon Sub-header
|
989 |
with gr.Row():
|
990 |
admission_date = gr.Textbox(label="Date of Admission")
|
991 |
referral_source = gr.Textbox(label="Source of Referral")
|
|
|
997 |
label="Discharge Reason",
|
998 |
)
|
999 |
date_of_death = gr.Textbox(label="Date of Death (if applicable)")
|
1000 |
+
gr.Markdown(
|
1001 |
+
"<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Diagnosis & Procedures</h2>"
|
1002 |
+
) # Neon Sub-header
|
1003 |
diagnosis = gr.Textbox(label="Diagnosis")
|
1004 |
procedures = gr.Textbox(label="Operation & Procedures")
|
1005 |
+
gr.Markdown(
|
1006 |
+
"<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Medication Details</h2>"
|
1007 |
+
) # Neon Sub-header
|
1008 |
medications = gr.Textbox(label="Medication on Discharge")
|
1009 |
+
gr.Markdown(
|
1010 |
+
"<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Prepared By</h2>"
|
1011 |
+
) # Neon Sub-header
|
1012 |
with gr.Row():
|
1013 |
preparer_name = gr.Textbox(label="Name")
|
1014 |
preparer_job_title = gr.Textbox(label="Job Title")
|
1015 |
|
1016 |
# Add buttons for both display form and generate PDF
|
1017 |
with gr.Row():
|
1018 |
+
submit_display = gr.Button(
|
1019 |
+
"Display Form", elem_classes="cyberpunk-button"
|
1020 |
+
) # Cyberpunk button style
|
1021 |
+
submit_pdf = gr.Button(
|
1022 |
+
"Generate PDF (No AI)", elem_classes="cyberpunk-button"
|
1023 |
+
) # Renamed button to clarify no AI and styled
|
1024 |
|
1025 |
# Output areas
|
1026 |
+
form_output = gr.HTML() # Use HTML to render styled form
|
1027 |
+
pdf_output = gr.File(
|
1028 |
+
label="Download PDF (No AI)"
|
1029 |
+
) # Renamed output to clarify no AI
|
1030 |
|
1031 |
# Connect the display form button
|
1032 |
submit_display.click(
|
|
|
1062 |
preparer_name,
|
1063 |
preparer_job_title,
|
1064 |
],
|
1065 |
+
outputs=form_output,
|
1066 |
)
|
1067 |
|
1068 |
# Connect the generate PDF button (No AI version)
|
|
|
1099 |
preparer_name,
|
1100 |
preparer_job_title,
|
1101 |
],
|
1102 |
+
outputs=pdf_output,
|
1103 |
)
|
1104 |
|
1105 |
+
with gr.Tab(
|
1106 |
+
"Medical File Analysis", elem_classes="cyberpunk-tab"
|
1107 |
+
): # Optional: Class for tab styling
|
1108 |
+
gr.Markdown(
|
1109 |
+
"<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>Analyze Medical Files with Discharge Guard AI</h2>"
|
1110 |
+
) # Neon Tab Header
|
1111 |
with gr.Column():
|
1112 |
dicom_file = gr.File(
|
1113 |
file_types=[".dcm"], label="Upload DICOM File (.dcm)"
|
1114 |
)
|
1115 |
dicom_ai_output = gr.Textbox(label="DICOM Analysis Report", lines=5)
|
1116 |
+
analyze_dicom_button = gr.Button(
|
1117 |
+
"Analyze DICOM with AI", elem_classes="cyberpunk-button"
|
1118 |
+
) # Cyberpunk button style
|
1119 |
|
1120 |
+
hl7_file = gr.File(file_types=[".hl7"], label="Upload HL7 File (.hl7)")
|
|
|
|
|
1121 |
hl7_ai_output = gr.Textbox(label="HL7 Analysis Report", lines=5)
|
1122 |
+
analyze_hl7_button = gr.Button(
|
1123 |
+
"Analyze HL7 with AI", elem_classes="cyberpunk-button"
|
1124 |
+
) # Cyberpunk button style
|
1125 |
|
1126 |
+
xml_file = gr.File(file_types=[".xml"], label="Upload XML File (.xml)")
|
|
|
|
|
1127 |
xml_ai_output = gr.Textbox(label="XML Analysis Report", lines=5)
|
1128 |
+
analyze_xml_button = gr.Button(
|
1129 |
+
"Analyze XML with AI", elem_classes="cyberpunk-button"
|
1130 |
+
) # Cyberpunk button style
|
1131 |
|
1132 |
ccda_file = gr.File(
|
1133 |
+
file_types=[".xml", ".cda", ".ccd"],
|
1134 |
+
label="Upload CCDA File (.xml, .cda, .ccd)",
|
1135 |
)
|
1136 |
ccda_ai_output = gr.Textbox(label="CCDA Analysis Report", lines=5)
|
1137 |
+
analyze_ccda_button = gr.Button(
|
1138 |
+
"Analyze CCDA with AI", elem_classes="cyberpunk-button"
|
1139 |
+
) # Cyberpunk button style
|
1140 |
|
1141 |
ccd_file = gr.File(
|
1142 |
file_types=[".ccd"],
|
|
|
1145 |
ccd_ai_output = gr.Textbox(
|
1146 |
label="CCD Analysis Report", lines=5
|
1147 |
) # Redundant
|
1148 |
+
analyze_ccd_button = gr.Button(
|
1149 |
+
"Analyze CCD with AI", elem_classes="cyberpunk-button"
|
1150 |
+
) # Cyberpunk button style # Redundant
|
1151 |
+
pdf_file = gr.File(file_types=[".pdf"], label="Upload PDF File (.pdf)")
|
1152 |
pdf_ai_output = gr.Textbox(label="PDF Analysis Report", lines=5)
|
1153 |
+
analyze_pdf_button = gr.Button(
|
1154 |
+
"Analyze PDF with AI", elem_classes="cyberpunk-button"
|
1155 |
+
) # Cyberpunk button style
|
1156 |
|
1157 |
+
csv_file = gr.File(file_types=[".csv"], label="Upload CSV File (.csv)")
|
|
|
|
|
1158 |
csv_ai_output = gr.Textbox(label="CSV Analysis Report", lines=5)
|
1159 |
+
analyze_csv_button = gr.Button(
|
1160 |
+
"Analyze CSV with AI", elem_classes="cyberpunk-button"
|
1161 |
+
) # Cyberpunk button style
|
1162 |
|
1163 |
# Connect AI Analysis Buttons - using REAL AI functions now
|
1164 |
analyze_dicom_button.click(
|
1165 |
analyze_dicom_file_with_ai, # Call REAL AI function
|
1166 |
inputs=dicom_file,
|
1167 |
+
outputs=dicom_ai_output,
|
1168 |
)
|
1169 |
analyze_hl7_button.click(
|
1170 |
analyze_hl7_file_with_ai, # Call REAL AI function
|
1171 |
inputs=hl7_file,
|
1172 |
+
outputs=hl7_ai_output,
|
1173 |
)
|
1174 |
analyze_xml_button.click(
|
1175 |
analyze_cda_xml_file_with_ai, # Call REAL AI function
|
1176 |
inputs=xml_file,
|
1177 |
+
outputs=xml_ai_output,
|
1178 |
)
|
1179 |
analyze_ccda_button.click(
|
1180 |
analyze_cda_xml_file_with_ai, # Call REAL AI function
|
1181 |
inputs=ccda_file,
|
1182 |
+
outputs=ccda_ai_output,
|
1183 |
)
|
1184 |
analyze_ccd_button.click( # Redundant button, but kept for UI if needed
|
1185 |
analyze_cda_xml_file_with_ai, # Call REAL AI function
|
1186 |
inputs=ccd_file,
|
1187 |
+
outputs=ccd_ai_output,
|
1188 |
)
|
1189 |
analyze_pdf_button.click(
|
1190 |
analyze_pdf_file_with_ai, inputs=pdf_file, outputs=pdf_ai_output
|
|
|
1196 |
with gr.Tab(
|
1197 |
"One-Click Discharge Paper (AI)", elem_classes="cyberpunk-tab"
|
1198 |
): # New Tab for One-Click Discharge Paper with AI, styled
|
1199 |
+
gr.Markdown(
|
1200 |
+
"<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>One-Click Medical Discharge Paper Generation with AI Content</h2>"
|
1201 |
+
) # Neon Tab Header
|
1202 |
one_click_ai_pdf_button = gr.Button(
|
1203 |
+
"Generate Discharge Paper with AI (One-Click)",
|
1204 |
+
elem_classes="cyberpunk-button",
|
1205 |
) # Updated button label and styled
|
1206 |
one_click_ai_pdf_status = gr.Textbox(
|
1207 |
label="Discharge Paper Generation Status (AI)"
|
|
|
1218 |
|
1219 |
# Connect the patient data buttons
|
1220 |
patient_data_button.click(
|
1221 |
+
fn=CALLBACK_MANAGER.get_patient_data, inputs=None, outputs=patient_data_output
|
|
|
|
|
1222 |
)
|
1223 |
|
1224 |
# Connect refresh button to update dashboard
|
1225 |
+
refresh_btn.click(fn=update_dashboard, inputs=None, outputs=dashboard_output)
|
|
|
|
|
1226 |
|
1227 |
# Corrected the button click function name here to `generate_pdf_from_meldrx` (No AI PDF)
|
1228 |
meldrx_pdf_button.click(
|
1229 |
fn=generate_pdf_from_meldrx,
|
1230 |
inputs=patient_data_output,
|
1231 |
+
outputs=[meldrx_pdf_download, meldrx_pdf_status],
|
1232 |
)
|
1233 |
|
1234 |
# Connect patient data updates to dashboard
|
|
|
1236 |
fn=update_dashboard, inputs=None, outputs=dashboard_output
|
1237 |
)
|
1238 |
|
1239 |
+
|
1240 |
# Launch with sharing enabled for public access
|
1241 |
demo.launch(ssr_mode=False)
|