Tonic commited on
Commit
aaf8cf2
·
unverified ·
1 Parent(s): 0fd27e0

improve one click discharge paper

Browse files
Files changed (2) hide show
  1. app.py +25 -20
  2. utils/oneclick.py +177 -0
app.py CHANGED
@@ -18,7 +18,7 @@ logger = logging.getLogger(__name__)
18
 
19
  # Import PDF utilities
20
  from utils.pdfutils import PDFGenerator, generate_discharge_summary
21
-
22
  # Import necessary libraries for new file types and AI analysis functions
23
  import pydicom # For DICOM
24
  import hl7 # For HL7
@@ -394,25 +394,30 @@ with gr.Blocks(theme=cyberpunk_theme) as demo: # Apply the theme here
394
  analyze_csv_file_with_ai, inputs=csv_file, outputs=csv_ai_output
395
  )
396
 
397
- with gr.Tab(
398
- "One-Click Discharge Paper (AI)", elem_classes="cyberpunk-tab"
399
- ): # New Tab for One-Click Discharge Paper with AI, styled
400
- 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
401
- one_click_ai_pdf_button = gr.Button(
402
- "Generate Discharge Paper with AI (One-Click)", elem_classes="cyberpunk-button"
403
- ) # Updated button label and styled
404
- one_click_ai_pdf_status = gr.Textbox(
405
- label="Discharge Paper Generation Status (AI)"
406
- ) # Updated status label
407
- one_click_ai_pdf_download = gr.File(
408
- label="Download Discharge Paper (AI)"
409
- ) # Updated download label
410
-
411
- one_click_ai_pdf_button.click(
412
- generate_discharge_paper_one_click, # Use the one-click function that now calls AI
413
- inputs=[],
414
- outputs=[one_click_ai_pdf_download, one_click_ai_pdf_status],
415
- )
 
 
 
 
 
416
 
417
  # Connect the patient data buttons
418
  patient_data_button.click(
 
18
 
19
  # Import PDF utilities
20
  from utils.pdfutils import PDFGenerator, generate_discharge_summary
21
+ from utils.oneclick import generate_discharge_paper_one_click
22
  # Import necessary libraries for new file types and AI analysis functions
23
  import pydicom # For DICOM
24
  import hl7 # For HL7
 
394
  analyze_csv_file_with_ai, inputs=csv_file, outputs=csv_ai_output
395
  )
396
 
397
+ with gr.Tab("One-Click Discharge Paper (AI)", elem_classes="cyberpunk-tab"):
398
+ gr.Markdown("<h2 style='color:#00FFFF; text-shadow: 0 0 3px #00FFFF;'>One-Click Medical Discharge Paper Generation with AI Content</h2>")
399
+ with gr.Row():
400
+ patient_id_input = gr.Textbox(label="Patient ID (Optional)", placeholder="Enter Patient ID")
401
+ first_name_input = gr.Textbox(label="First Name (Optional)", placeholder="Enter First Name")
402
+ last_name_input = gr.Textbox(label="Last Name (Optional)", placeholder="Enter Last Name")
403
+ one_click_ai_pdf_button = gr.Button(
404
+ "Generate Discharge Paper with AI (One-Click)", elem_classes="cyberpunk-button"
405
+ )
406
+ one_click_ai_pdf_status = gr.Textbox(label="Discharge Paper Generation Status (AI)")
407
+ one_click_ai_pdf_download = gr.File(label="Download Discharge Paper (AI)")
408
+
409
+ # Initialize MeldRxAPI (ensure client_id, client_secret, workspace_id are set in environment variables)
410
+ client_id = os.getenv("APPID")
411
+ client_secret = os.getenv("CLIENT_SECRET") # Optional, set if required
412
+ workspace_id = os.getenv("WORKSPACE_URL")
413
+ redirect_uri = "https://multitransformer-discharge-guard.hf.space/callback"
414
+ meldrx_api = MeldRxAPI(client_id, client_secret, workspace_id, redirect_uri)
415
+
416
+ one_click_ai_pdf_button.click(
417
+ fn=lambda pid, fname, lname: generate_discharge_paper_one_click(meldrx_api, pid, fname, lname),
418
+ inputs=[patient_id_input, first_name_input, last_name_input],
419
+ outputs=[one_click_ai_pdf_download, one_click_ai_pdf_status],
420
+ )
421
 
422
  # Connect the patient data buttons
423
  patient_data_button.click(
utils/oneclick.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import logging
4
+ from typing import Optional, Dict, Any
5
+ from huggingface_hub import InferenceClient
6
+ from utils.meldrx import MeldRxAPI
7
+ from utils.pdfutils import PDFGenerator
8
+ from datetime import datetime
9
+
10
+ # Set up logging
11
+ logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger(__name__)
13
+
14
+ # Initialize Hugging Face Inference Client
15
+ HF_TOKEN = os.getenv("HF_TOKEN")
16
+ if not HF_TOKEN:
17
+ raise ValueError("HF_TOKEN environment variable not set. Please set your Hugging Face API token.")
18
+ client = InferenceClient(api_key=HF_TOKEN)
19
+ MODEL_NAME = "meta-llama/Llama-3.3-70B-Instruct" # Model to use for discharge summary generation
20
+
21
+ def generate_ai_discharge_summary(patient_data: Dict[str, Any]) -> Optional[str]:
22
+ """
23
+ Generate a discharge summary using the Hugging Face Inference Client based on patient data.
24
+
25
+ Args:
26
+ patient_data (Dict[str, Any]): Patient data in FHIR JSON format.
27
+
28
+ Returns:
29
+ Optional[str]: Generated discharge summary text or None if generation fails.
30
+ """
31
+ try:
32
+ # Extract relevant patient information
33
+ name = patient_data.get("name", [{}])[0]
34
+ full_name = f"{name.get('given', ['Unknown'])[0]} {name.get('family', 'Unknown')}"
35
+ gender = patient_data.get("gender", "Unknown").capitalize()
36
+ birth_date = patient_data.get("birthDate", "Unknown")
37
+ age = calculate_age(birth_date) if birth_date != "Unknown" else "Unknown"
38
+
39
+ # Placeholder for additional clinical data (e.g., diagnosis, treatment)
40
+ # In a real scenario, this would come from related FHIR resources like Encounter, Condition, etc.
41
+ patient_info = (
42
+ f"Patient Name: {full_name}\n"
43
+ f"Gender: {gender}\n"
44
+ f"Age: {age}\n\n"
45
+ f"Presentation and Diagnosis:\n[Diagnosis data not provided in this snippet; assumed from related FHIR resources]\n\n"
46
+ f"Hospital Course:\n[Treatment data not provided in this snippet; assumed from related FHIR resources]\n\n"
47
+ f"Outcome:\n[Outcome data not provided in this snippet; assumed from related FHIR resources]"
48
+ )
49
+
50
+ # Define the prompt for the AI model
51
+ messages = [
52
+ {"role": "user", "content": ""},
53
+ {
54
+ "role": "assistant",
55
+ "content": (
56
+ "You are a senior expert medical health practitioner known for producing discharge papers. "
57
+ "You will receive patient information and treatment details. Produce a complete discharge summary "
58
+ "based on the information provided."
59
+ )
60
+ },
61
+ {"role": "user", "content": patient_info}
62
+ ]
63
+
64
+ # Generate discharge summary using streaming
65
+ stream = client.chat.completions.create(
66
+ model=MODEL_NAME,
67
+ messages=messages,
68
+ temperature=0.4,
69
+ max_tokens=3584,
70
+ top_p=0.7,
71
+ stream=True
72
+ )
73
+
74
+ discharge_summary = ""
75
+ for chunk in stream:
76
+ content = chunk.choices[0].delta.content
77
+ if content:
78
+ discharge_summary += content
79
+
80
+ return discharge_summary.strip()
81
+
82
+ except Exception as e:
83
+ logger.error(f"Error generating AI discharge summary: {str(e)}")
84
+ return None
85
+
86
+ def calculate_age(birth_date: str) -> str:
87
+ """
88
+ Calculate age from birth date.
89
+
90
+ Args:
91
+ birth_date (str): Birth date in YYYY-MM-DD format.
92
+
93
+ Returns:
94
+ str: Calculated age or 'Unknown' if calculation fails.
95
+ """
96
+ try:
97
+ birth = datetime.strptime(birth_date, "%Y-%m-%d")
98
+ today = datetime.today()
99
+ age = today.year - birth.year - ((today.month, today.day) < (birth.month, birth.day))
100
+ return str(age)
101
+ except ValueError:
102
+ return "Unknown"
103
+
104
+ def generate_discharge_paper_one_click(
105
+ meldrx_api: MeldRxAPI,
106
+ patient_id: str = None,
107
+ first_name: str = None,
108
+ last_name: str = None
109
+ ) -> tuple[Optional[str], str]:
110
+ """
111
+ Generate a discharge paper with AI content in one click.
112
+
113
+ Args:
114
+ meldrx_api (MeldRxAPI): Initialized MeldRxAPI instance.
115
+ patient_id (str, optional): Patient ID to fetch specific patient data.
116
+ first_name (str, optional): First name for patient lookup if patient_id is not provided.
117
+ last_name (str, optional): Last name for patient lookup if patient_id is not provided.
118
+
119
+ Returns:
120
+ tuple[Optional[str], str]: (PDF file path, Status message)
121
+ """
122
+ try:
123
+ # Authenticate if not already authenticated
124
+ if not meldrx_api.access_token and not meldrx_api.authenticate():
125
+ return None, "Error: Authentication failed. Please authenticate first."
126
+
127
+ # Fetch patient data
128
+ if patient_id:
129
+ # Fetch specific patient by ID (assuming FHIR Patient resource endpoint supports this)
130
+ patient_data = meldrx_api.get_patients() # Simplified; assumes ID filtering in real API
131
+ if not patient_data or "entry" not in patient_data:
132
+ return None, "Error: Failed to fetch patient data by ID."
133
+ patients = [entry["resource"] for entry in patient_data.get("entry", [])]
134
+ patient = next((p for p in patients if p.get("id") == patient_id), None)
135
+ if not patient:
136
+ return None, f"Error: Patient with ID {patient_id} not found."
137
+ else:
138
+ # Fetch all patients and filter by name if provided
139
+ patient_data = meldrx_api.get_patients()
140
+ if not patient_data or "entry" not in patient_data:
141
+ return None, "Error: Failed to fetch patient data."
142
+ patients = [entry["resource"] for entry in patient_data.get("entry", [])]
143
+ if first_name and last_name:
144
+ patient = next(
145
+ (p for p in patients if
146
+ p.get("name", [{}])[0].get("given", [""])[0].lower() == first_name.lower() and
147
+ p.get("name", [{}])[0].get("family", "").lower() == last_name.lower()),
148
+ None
149
+ )
150
+ if not patient:
151
+ return None, f"Error: Patient with name {first_name} {last_name} not found."
152
+ else:
153
+ # Default to first patient if no specific ID or name provided
154
+ patient = patients[0] if patients else None
155
+ if not patient:
156
+ return None, "Error: No patients found in the workspace."
157
+
158
+ # Generate AI discharge summary
159
+ ai_content = generate_ai_discharge_summary(patient)
160
+ if not ai_content:
161
+ return None, "Error: Failed to generate AI discharge summary."
162
+
163
+ # Generate PDF
164
+ pdf_generator = PDFGenerator()
165
+ pdf_path = pdf_generator.generate_pdf_from_text(
166
+ ai_content,
167
+ f"discharge_summary_{patient.get('id', 'unknown')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
168
+ )
169
+
170
+ if pdf_path:
171
+ return pdf_path, f"Success: Discharge paper generated for {patient.get('name', [{}])[0].get('given', ['Unknown'])[0]} {patient.get('name', [{}])[0].get('family', 'Unknown')}"
172
+ else:
173
+ return None, "Error: Failed to generate PDF."
174
+
175
+ except Exception as e:
176
+ logger.error(f"Error in one-click discharge generation: {str(e)}")
177
+ return None, f"Error: {str(e)}"