add callback manager , model app
Browse files- README.md +1 -1
- __pycache__/meldrx.cpython-312.pyc +0 -0
- callbackmanager.py +188 -0
- commandr.py +20 -0
- hospital.py +120 -0
- interfacehospital.py +63 -0
- llamaprompt.py +22 -0
- meldrx.py +361 -0
- meldrxtester.py +106 -0
- meldrxtester2.py +140 -0
- qwenprompt.py +22 -0
- requirements.txt +1 -0
- test_meldrx.py +160 -0
- wound.py +84 -0
README.md
CHANGED
@@ -5,7 +5,7 @@ colorFrom: gray
|
|
5 |
colorTo: pink
|
6 |
sdk: gradio
|
7 |
sdk_version: 5.19.0
|
8 |
-
app_file:
|
9 |
pinned: false
|
10 |
license: mit
|
11 |
short_description: Provides guardrails and discharge summaries with compliance
|
|
|
5 |
colorTo: pink
|
6 |
sdk: gradio
|
7 |
sdk_version: 5.19.0
|
8 |
+
app_file: callbackmanager.py
|
9 |
pinned: false
|
10 |
license: mit
|
11 |
short_description: Provides guardrails and discharge summaries with compliance
|
__pycache__/meldrx.cpython-312.pyc
ADDED
Binary file (12.6 kB). View file
|
|
callbackmanager.py
ADDED
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from meldrx import MeldRxAPI
|
3 |
+
import json
|
4 |
+
|
5 |
+
# CallbackManager class to handle OAuth callbacks
|
6 |
+
class CallbackManager:
|
7 |
+
def __init__(self, client_id: str, redirect_uri: str, workspace_id: str, client_secret: str = None):
|
8 |
+
"""
|
9 |
+
Initialize the CallbackManager with MeldRx API credentials.
|
10 |
+
|
11 |
+
Args:
|
12 |
+
client_id (str): The client ID from MeldRx Developer Portal.
|
13 |
+
redirect_uri (str): The redirect URI for the Gradio app (e.g., Space URL + /callback).
|
14 |
+
workspace_id (str): The workspace slug/ID.
|
15 |
+
client_secret (str, optional): The client secret (for confidential clients).
|
16 |
+
"""
|
17 |
+
self.api = MeldRxAPI(client_id, redirect_uri, workspace_id, client_secret)
|
18 |
+
self.auth_code = None
|
19 |
+
self.access_token = None
|
20 |
+
|
21 |
+
def get_auth_url(self) -> str:
|
22 |
+
"""Generate and return the SMART on FHIR authorization URL."""
|
23 |
+
return self.api.get_authorization_url()
|
24 |
+
|
25 |
+
def set_auth_code(self, code: str) -> str:
|
26 |
+
"""Set the authorization code and attempt to get an access token."""
|
27 |
+
self.auth_code = code
|
28 |
+
if self.api.authenticate_with_code(code):
|
29 |
+
self.access_token = self.api.access_token
|
30 |
+
return f"Authentication successful! Access Token: {self.access_token[:10]}... (truncated)"
|
31 |
+
return "Authentication failed. Please check the code."
|
32 |
+
|
33 |
+
def get_patient_data(self) -> str:
|
34 |
+
"""Retrieve patient data using the access token."""
|
35 |
+
if not self.access_token:
|
36 |
+
return "Not authenticated. Please provide a valid authorization code first."
|
37 |
+
patients = self.api.get_patients()
|
38 |
+
if patients is not None:
|
39 |
+
return json.dumps(patients, indent=2) if patients else "No patient data returned."
|
40 |
+
return "Failed to retrieve patient data."
|
41 |
+
|
42 |
+
# Discharge form display function
|
43 |
+
def display_form(
|
44 |
+
first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
|
45 |
+
doctor_first_name, doctor_last_name, doctor_middle_initial, hospital_name, doctor_address,
|
46 |
+
doctor_city, doctor_state, doctor_zip,
|
47 |
+
admission_date, referral_source, admission_method, discharge_date, discharge_reason, date_of_death,
|
48 |
+
diagnosis, procedures, medications, preparer_name, preparer_job_title
|
49 |
+
):
|
50 |
+
form = f"""
|
51 |
+
**Patient Discharge Form**
|
52 |
+
|
53 |
+
**Patient Details:**
|
54 |
+
- Name: {first_name} {middle_initial} {last_name}
|
55 |
+
- Date of Birth: {dob}, Age: {age}, Sex: {sex}
|
56 |
+
- Address: {address}, {city}, {state}, {zip_code}
|
57 |
+
|
58 |
+
**Primary Healthcare Professional Details:**
|
59 |
+
- Name: {doctor_first_name} {doctor_middle_initial} {doctor_last_name}
|
60 |
+
- Hospital/Clinic: {hospital_name}
|
61 |
+
- Address: {doctor_address}, {doctor_city}, {doctor_state}, {doctor_zip}
|
62 |
+
|
63 |
+
**Admission and Discharge Details:**
|
64 |
+
- Date of Admission: {admission_date}
|
65 |
+
- Source of Referral: {referral_source}
|
66 |
+
- Method of Admission: {admission_method}
|
67 |
+
- Date of Discharge: {discharge_date}
|
68 |
+
- Discharge Reason: {discharge_reason}
|
69 |
+
- Date of Death (if applicable): {date_of_death}
|
70 |
+
|
71 |
+
**Diagnosis & Procedures:**
|
72 |
+
- Diagnosis: {diagnosis}
|
73 |
+
- Procedures: {procedures}
|
74 |
+
|
75 |
+
**Medication Details:**
|
76 |
+
- Medications on Discharge: {medications}
|
77 |
+
|
78 |
+
**Prepared By:**
|
79 |
+
- Name: {preparer_name}, Job Title: {preparer_job_title}
|
80 |
+
"""
|
81 |
+
return form
|
82 |
+
|
83 |
+
# Initialize CallbackManager with your credentials
|
84 |
+
CALLBACK_MANAGER = CallbackManager(
|
85 |
+
client_id="your_client_id", # Replace with actual client ID
|
86 |
+
redirect_uri="https://multitransformer-discharge-guard.hf.space/callback",
|
87 |
+
workspace_id="your_workspace_id", # Replace with actual workspace ID
|
88 |
+
client_secret=None # Replace with actual secret if using a confidential client
|
89 |
+
)
|
90 |
+
|
91 |
+
# Gradio interface
|
92 |
+
with gr.Blocks() as demo:
|
93 |
+
gr.Markdown("# Patient Discharge Form with MeldRx Integration")
|
94 |
+
|
95 |
+
# Authentication Section
|
96 |
+
with gr.Tab("Authenticate with MeldRx"):
|
97 |
+
gr.Markdown("## SMART on FHIR Authentication")
|
98 |
+
auth_url_output = gr.Textbox(label="Authorization URL", value=CALLBACK_MANAGER.get_auth_url(), interactive=False)
|
99 |
+
gr.Markdown("Copy the URL above, open it in a browser, log in, and paste the 'code' from the redirect URL below.")
|
100 |
+
auth_code_input = gr.Textbox(label="Authorization Code")
|
101 |
+
auth_submit = gr.Button("Submit Code")
|
102 |
+
auth_result = gr.Textbox(label="Authentication Result")
|
103 |
+
patient_data_button = gr.Button("Fetch Patient Data")
|
104 |
+
patient_data_output = gr.Textbox(label="Patient Data")
|
105 |
+
|
106 |
+
auth_submit.click(
|
107 |
+
fn=CALLBACK_MANAGER.set_auth_code,
|
108 |
+
inputs=auth_code_input,
|
109 |
+
outputs=auth_result
|
110 |
+
)
|
111 |
+
patient_data_button.click(
|
112 |
+
fn=CALLBACK_MANAGER.get_patient_data,
|
113 |
+
inputs=None,
|
114 |
+
outputs=patient_data_output
|
115 |
+
)
|
116 |
+
|
117 |
+
# Discharge Form Section
|
118 |
+
with gr.Tab("Discharge Form"):
|
119 |
+
gr.Markdown("## Patient Details")
|
120 |
+
with gr.Row():
|
121 |
+
first_name = gr.Textbox(label="First Name")
|
122 |
+
last_name = gr.Textbox(label="Last Name")
|
123 |
+
middle_initial = gr.Textbox(label="Middle Initial")
|
124 |
+
|
125 |
+
with gr.Row():
|
126 |
+
dob = gr.Textbox(label="Date of Birth")
|
127 |
+
age = gr.Textbox(label="Age")
|
128 |
+
sex = gr.Textbox(label="Sex")
|
129 |
+
|
130 |
+
address = gr.Textbox(label="Address")
|
131 |
+
with gr.Row():
|
132 |
+
city = gr.Textbox(label="City")
|
133 |
+
state = gr.Textbox(label="State")
|
134 |
+
zip_code = gr.Textbox(label="Zip Code")
|
135 |
+
|
136 |
+
gr.Markdown("## Primary Healthcare Professional Details")
|
137 |
+
with gr.Row():
|
138 |
+
doctor_first_name = gr.Textbox(label="Doctor's First Name")
|
139 |
+
doctor_last_name = gr.Textbox(label="Doctor's Last Name")
|
140 |
+
doctor_middle_initial = gr.Textbox(label="Middle Initial")
|
141 |
+
|
142 |
+
hospital_name = gr.Textbox(label="Hospital/Clinic Name")
|
143 |
+
doctor_address = gr.Textbox(label="Address")
|
144 |
+
with gr.Row():
|
145 |
+
doctor_city = gr.Textbox(label="City")
|
146 |
+
doctor_state = gr.Textbox(label="State")
|
147 |
+
doctor_zip = gr.Textbox(label="Zip Code")
|
148 |
+
|
149 |
+
gr.Markdown("## Admission and Discharge Details")
|
150 |
+
with gr.Row():
|
151 |
+
admission_date = gr.Textbox(label="Date of Admission")
|
152 |
+
referral_source = gr.Textbox(label="Source of Referral")
|
153 |
+
|
154 |
+
admission_method = gr.Textbox(label="Method of Admission")
|
155 |
+
with gr.Row():
|
156 |
+
discharge_date = gr.Textbox(label="Date of Discharge")
|
157 |
+
discharge_reason = gr.Radio(["Treated", "Transferred", "Discharge Against Advice", "Patient Died"], label="Discharge Reason")
|
158 |
+
|
159 |
+
date_of_death = gr.Textbox(label="Date of Death (if applicable)")
|
160 |
+
|
161 |
+
gr.Markdown("## Diagnosis & Procedures")
|
162 |
+
diagnosis = gr.Textbox(label="Diagnosis")
|
163 |
+
procedures = gr.Textbox(label="Operation & Procedures")
|
164 |
+
|
165 |
+
gr.Markdown("## Medication Details")
|
166 |
+
medications = gr.Textbox(label="Medication on Discharge")
|
167 |
+
|
168 |
+
gr.Markdown("## Prepared By")
|
169 |
+
with gr.Row():
|
170 |
+
preparer_name = gr.Textbox(label="Name")
|
171 |
+
preparer_job_title = gr.Textbox(label="Job Title")
|
172 |
+
|
173 |
+
submit = gr.Button("Generate Form")
|
174 |
+
output = gr.Markdown()
|
175 |
+
|
176 |
+
submit.click(
|
177 |
+
display_form,
|
178 |
+
inputs=[
|
179 |
+
first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
|
180 |
+
doctor_first_name, doctor_last_name, doctor_middle_initial, hospital_name, doctor_address,
|
181 |
+
doctor_city, doctor_state, doctor_zip,
|
182 |
+
admission_date, referral_source, admission_method, discharge_date, discharge_reason, date_of_death,
|
183 |
+
diagnosis, procedures, medications, preparer_name, preparer_job_title
|
184 |
+
],
|
185 |
+
outputs=output
|
186 |
+
)
|
187 |
+
|
188 |
+
demo.launch()
|
commandr.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from huggingface_hub import InferenceClient
|
2 |
+
|
3 |
+
client = InferenceClient(api_key="YOUR_HF_TOKEN")
|
4 |
+
|
5 |
+
messages = [
|
6 |
+
{ "role": "user", "content": "you are a senior expert medical health practitioner known for their abilities to decide on clinical discharge . you will recieve a clinical case study for a fictional patient. you should respond with the following model { \"response\" : { \"discharge\" : True/False } } if the patient should be discharged or not. produce only your final answer:\n\nPatient Name: Patient 2 \nGender: Female \nAge: 72 years \n\n### Presentation and Diagnosis: \nThe patient presented to the emergency department in October 2024 with complaints of progressive shortness of breath, fatigue, and bilateral lower extremity edema persisting for three weeks. Initial evaluation revealed tachycardia, hypoxia (SpO2 88% on room air), and elevated blood pressure (168/94 mmHg). Laboratory findings demonstrated elevated brain natriuretic peptide (BNP) at 1,200 pg/mL, creatinine of 2.1 mg/dL (baseline 1.0 mg/dL), and a troponin I of 0.08 ng/mL. Chest X-ray showed bilateral pleural effusions and pulmonary congestion. An echocardiogram revealed a left ventricular ejection fraction (LVEF) of 25%, severe mitral regurgitation, and elevated pulmonary artery pressure (55 mmHg). Electrocardiogram (ECG) indicated sinus rhythm with left bundle branch block. The patient was diagnosed with acute decompensated heart failure (ADHF) secondary to ischemic cardiomyopathy, with concurrent stage IIIb chronic kidney disease (CKD) identified based on estimated glomerular filtration rate (eGFR) of 35 mL/min/1.73m². Coronary angiography performed subsequently confirmed triple-vessel coronary artery disease (CAD) with no immediate indication for revascularization due to high procedural risk.\n\n### Hospital Course: \nThe patient was admitted to the cardiac care unit (CCU) and initiated on intravenous furosemide (40 mg IV twice daily) and supplemental oxygen via nasal cannula. Nitroglycerin infusion was started for preload reduction but was discontinued after 24 hours due to hypotension (systolic BP dropping to 85 mmHg). She was transitioned to oral guideline-directed medical therapy (GDMT), including carvedilol (3.125 mg twice daily), sacubitril/valsartan (24/26 mg twice daily), and spironolactone (25 mg daily), with doses titrated cautiously due to renal impairment and borderline blood pressure. Despite initial improvement in dyspnea and reduction in edema, the patient developed worsening renal function (creatinine peaked at 2.8 mg/dL, eGFR 25 mL/min/1.73m²) by hospital day 5, prompting a temporary hold on diuretics and angiotensin receptor-neprilysin inhibitor (ARNI) therapy. Nephrology was consulted, and ultrafiltration was initiated for volume overload management, achieving a net fluid removal of 4 liters over 72 hours. \n\nBy hospital day 10, the patient stabilized hemodynamically (BP 110/70 mmHg, SpO2 94% on 2L oxygen), but attempts to wean oxygen supplementation resulted in recurrent hypoxia. Repeat echocardiography showed persistent LVEF of 25% with no improvement in mitral regurgitation. A multidisciplinary team discussion concluded that the patient’s advanced heart failure, compounded by CKD and frailty (Clinical Frailty Scale score of 6), precluded discharge to home. She was deemed high-risk for outpatient management due to recurrent decompensation risk, frequent monitoring needs, and inability to tolerate optimal GDMT dosing. A trial of inotropic support with dobutamine (2.5 mcg/kg/min) was initiated on hospital day 14 to improve cardiac output, with partial symptomatic relief but no significant change in LVEF or renal function. \n\nOn hospital day 20, the patient developed a hospital-acquired pneumonia, confirmed by chest X-ray (right lower lobe consolidation) and sputum culture positive for *Klebsiella pneumoniae*. She was started on piperacillin-tazobactam (adjusted for renal function), but her respiratory status deteriorated, requiring escalation to high-flow nasal cannula (HFNC) at 40 L/min with FiO2 of 60%. Infectious disease and pulmonology consultations recommended a 10-day antibiotic course and supportive care, but the patient’s frailty and poor cardiac reserve limited recovery. By hospital day 30, she remained oxygen-dependent, with persistent volume overload and worsening renal function (creatinine 3.2 mg/dL, eGFR 20 mL/min/1.73m²), necessitating ongoing ultrafiltration and inotropic support.\n\n### Current Status: \nAs of February 28, 2025, the patient remains hospitalized in a step-down unit, unable to be discharged due to chronic dependence on inotropic therapy (dobutamine 2.5 mcg/kg/min) and supplemental oxygen (HFNC at 30 L/min, FiO2 50%). Her advanced heart failure, compounded by recurrent infections, severe CKD, and poor functional status, renders her ineligible for home care or transfer to a lower-acuity facility. Palliative care has been engaged to discuss goals of care, but the patient and family have declined hospice transition, opting for continued aggressive management. She experiences intermittent dyspnea at rest, fatigue, and fluctuating mental status (likely due to hypoperfusion and medication effects), requiring constant nursing supervision. Long-term plans include evaluation for potential left ventricular assist device (LVAD) candidacy, though her comorbidities and frailty pose significant barriers." },
|
7 |
+
# { "role": "assistant", "content": "{\n \"response\": {\n \"discharge\": false\n }\n}" }
|
8 |
+
]
|
9 |
+
|
10 |
+
stream = client.chat.completions.create(
|
11 |
+
model="CohereForAI/c4ai-command-r-plus-08-2024",
|
12 |
+
messages=messages,
|
13 |
+
temperature=0.4,
|
14 |
+
max_tokens=1280,
|
15 |
+
top_p=0.7,
|
16 |
+
stream=True
|
17 |
+
)
|
18 |
+
|
19 |
+
for chunk in stream:
|
20 |
+
print(chunk.choices[0].delta.content)
|
hospital.py
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
def display_form(
|
4 |
+
first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
|
5 |
+
doctor_first_name, doctor_last_name, doctor_middle_initial, hospital_name, doctor_address,
|
6 |
+
doctor_city, doctor_state, doctor_zip,
|
7 |
+
admission_date, referral_source, admission_method, discharge_date, discharge_reason, date_of_death,
|
8 |
+
diagnosis, procedures, medications, preparer_name, preparer_job_title
|
9 |
+
):
|
10 |
+
form = f"""
|
11 |
+
**Patient Discharge Form**
|
12 |
+
|
13 |
+
**Patient Details:**
|
14 |
+
- Name: {first_name} {middle_initial} {last_name}
|
15 |
+
- Date of Birth: {dob}, Age: {age}, Sex: {sex}
|
16 |
+
- Address: {address}, {city}, {state}, {zip_code}
|
17 |
+
|
18 |
+
**Primary Healthcare Professional Details:**
|
19 |
+
- Name: {doctor_first_name} {doctor_middle_initial} {doctor_last_name}
|
20 |
+
- Hospital/Clinic: {hospital_name}
|
21 |
+
- Address: {doctor_address}, {doctor_city}, {doctor_state}, {doctor_zip}
|
22 |
+
|
23 |
+
**Admission and Discharge Details:**
|
24 |
+
- Date of Admission: {admission_date}
|
25 |
+
- Source of Referral: {referral_source}
|
26 |
+
- Method of Admission: {admission_method}
|
27 |
+
- Date of Discharge: {discharge_date}
|
28 |
+
- Discharge Reason: {discharge_reason}
|
29 |
+
- Date of Death (if applicable): {date_of_death}
|
30 |
+
|
31 |
+
**Diagnosis & Procedures:**
|
32 |
+
- Diagnosis: {diagnosis}
|
33 |
+
- Procedures: {procedures}
|
34 |
+
|
35 |
+
**Medication Details:**
|
36 |
+
- Medications on Discharge: {medications}
|
37 |
+
|
38 |
+
**Prepared By:**
|
39 |
+
- Name: {preparer_name}, Job Title: {preparer_job_title}
|
40 |
+
"""
|
41 |
+
return form
|
42 |
+
|
43 |
+
with gr.Blocks() as demo:
|
44 |
+
gr.Markdown("# Patient Discharge Form")
|
45 |
+
|
46 |
+
with gr.Row():
|
47 |
+
first_name = gr.Textbox(label="First Name")
|
48 |
+
last_name = gr.Textbox(label="Last Name")
|
49 |
+
middle_initial = gr.Textbox(label="Middle Initial")
|
50 |
+
|
51 |
+
with gr.Row():
|
52 |
+
dob = gr.Textbox(label="Date of Birth")
|
53 |
+
age = gr.Textbox(label="Age")
|
54 |
+
sex = gr.Textbox(label="Sex")
|
55 |
+
|
56 |
+
address = gr.Textbox(label="Address")
|
57 |
+
|
58 |
+
with gr.Row():
|
59 |
+
city = gr.Textbox(label="City")
|
60 |
+
state = gr.Textbox(label="State")
|
61 |
+
zip_code = gr.Textbox(label="Zip Code")
|
62 |
+
|
63 |
+
gr.Markdown("## Primary Healthcare Professional Details")
|
64 |
+
|
65 |
+
with gr.Row():
|
66 |
+
doctor_first_name = gr.Textbox(label="Doctor's First Name")
|
67 |
+
doctor_last_name = gr.Textbox(label="Doctor's Last Name")
|
68 |
+
doctor_middle_initial = gr.Textbox(label="Middle Initial")
|
69 |
+
|
70 |
+
hospital_name = gr.Textbox(label="Hospital/Clinic Name")
|
71 |
+
doctor_address = gr.Textbox(label="Address")
|
72 |
+
|
73 |
+
with gr.Row():
|
74 |
+
doctor_city = gr.Textbox(label="City")
|
75 |
+
doctor_state = gr.Textbox(label="State")
|
76 |
+
doctor_zip = gr.Textbox(label="Zip Code")
|
77 |
+
|
78 |
+
gr.Markdown("## Admission and Discharge Details")
|
79 |
+
|
80 |
+
with gr.Row():
|
81 |
+
admission_date = gr.Textbox(label="Date of Admission")
|
82 |
+
referral_source = gr.Textbox(label="Source of Referral")
|
83 |
+
|
84 |
+
admission_method = gr.Textbox(label="Method of Admission")
|
85 |
+
|
86 |
+
with gr.Row():
|
87 |
+
discharge_date = gr.Textbox(label="Date of Discharge")
|
88 |
+
discharge_reason = gr.Radio(["Treated", "Transferred", "Discharge Against Advice", "Patient Died"], label="Discharge Reason")
|
89 |
+
|
90 |
+
date_of_death = gr.Textbox(label="Date of Death (if applicable)")
|
91 |
+
|
92 |
+
gr.Markdown("## Diagnosis & Procedures")
|
93 |
+
diagnosis = gr.Textbox(label="Diagnosis")
|
94 |
+
procedures = gr.Textbox(label="Operation & Procedures")
|
95 |
+
|
96 |
+
gr.Markdown("## Medication Details")
|
97 |
+
medications = gr.Textbox(label="Medication on Discharge")
|
98 |
+
|
99 |
+
gr.Markdown("## Prepared By")
|
100 |
+
|
101 |
+
with gr.Row():
|
102 |
+
preparer_name = gr.Textbox(label="Name")
|
103 |
+
preparer_job_title = gr.Textbox(label="Job Title")
|
104 |
+
|
105 |
+
submit = gr.Button("Generate Form")
|
106 |
+
output = gr.Markdown()
|
107 |
+
|
108 |
+
submit.click(
|
109 |
+
display_form,
|
110 |
+
inputs=[
|
111 |
+
first_name, last_name, middle_initial, dob, age, sex, address, city, state, zip_code,
|
112 |
+
doctor_first_name, doctor_last_name, doctor_middle_initial, hospital_name, doctor_address,
|
113 |
+
doctor_city, doctor_state, doctor_zip,
|
114 |
+
admission_date, referral_source, admission_method, discharge_date, discharge_reason, date_of_death,
|
115 |
+
diagnosis, procedures, medications, preparer_name, preparer_job_title
|
116 |
+
],
|
117 |
+
outputs=output
|
118 |
+
)
|
119 |
+
|
120 |
+
demo.launch()
|
interfacehospital.py
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
def display_discharge_form(
|
4 |
+
patient_first, patient_last, patient_middle, dob, age, sex, address, city, state, zip_code,
|
5 |
+
doctor_first, doctor_last, doctor_middle, hospital, doctor_address, doctor_city, doctor_state, doctor_zip,
|
6 |
+
admission_date, referral_source, admission_method, discharge_date, discharge_reason, death_date,
|
7 |
+
diagnosis, procedures, medications, preparer_name, job_title, signature
|
8 |
+
):
|
9 |
+
|
10 |
+
form = f"""
|
11 |
+
**Patient Details:**
|
12 |
+
- **Name:** {patient_first} {patient_middle} {patient_last}
|
13 |
+
- **Date of Birth:** {dob}, **Age:** {age}, **Sex:** {sex}
|
14 |
+
- **Address:** {address}, {city}, {state} {zip_code}
|
15 |
+
|
16 |
+
**Primary Healthcare Professional Details:**
|
17 |
+
- **Name:** {doctor_first} {doctor_middle} {doctor_last}
|
18 |
+
- **Hospital/Clinic:** {hospital}
|
19 |
+
- **Address:** {doctor_address}, {doctor_city}, {doctor_state} {doctor_zip}
|
20 |
+
|
21 |
+
**Admission and Discharge Details:**
|
22 |
+
- **Date of Admission:** {admission_date}
|
23 |
+
- **Source of Referral:** {referral_source}
|
24 |
+
- **Method of Admission:** {admission_method}
|
25 |
+
- **Date of Discharge:** {discharge_date}
|
26 |
+
- **Discharge Reason:** {discharge_reason}
|
27 |
+
- **Date of Death:** {death_date if discharge_reason == 'Patient Died' else 'N/A'}
|
28 |
+
|
29 |
+
**Diagnosis & Procedures:**
|
30 |
+
- **Diagnosis:** {diagnosis}
|
31 |
+
- **Operations & Procedures:** {procedures}
|
32 |
+
|
33 |
+
**Medication Details:**
|
34 |
+
- **Medication on Discharge:** {medications}
|
35 |
+
|
36 |
+
**Prepared By:**
|
37 |
+
- **Name:** {preparer_name}, **Job Title:** {job_title}
|
38 |
+
- **Signature:** {signature}
|
39 |
+
"""
|
40 |
+
return form
|
41 |
+
|
42 |
+
discharge_interface = gr.Interface(
|
43 |
+
fn=display_discharge_form,
|
44 |
+
inputs=[
|
45 |
+
gr.Textbox(label="Patient First Name"), gr.Textbox(label="Patient Last Name"), gr.Textbox(label="Patient Middle Initial"),
|
46 |
+
gr.Textbox(label="Date of Birth"), gr.Textbox(label="Age"), gr.Textbox(label="Sex"),
|
47 |
+
gr.Textbox(label="Address"), gr.Textbox(label="City"), gr.Textbox(label="State"), gr.Textbox(label="Zip Code"),
|
48 |
+
gr.Textbox(label="Doctor First Name"), gr.Textbox(label="Doctor Last Name"), gr.Textbox(label="Doctor Middle Initial"),
|
49 |
+
gr.Textbox(label="Hospital/Clinic Name"), gr.Textbox(label="Doctor Address"),
|
50 |
+
gr.Textbox(label="Doctor City"), gr.Textbox(label="Doctor State"), gr.Textbox(label="Doctor Zip Code"),
|
51 |
+
gr.Textbox(label="Date of Admission"), gr.Textbox(label="Source of Referral"), gr.Textbox(label="Method of Admission"),
|
52 |
+
gr.Textbox(label="Date of Discharge"), gr.Radio(["Treated", "Transferred", "Discharge Against Advice", "Patient Died"], label="Discharge Reason"),
|
53 |
+
gr.Textbox(label="Date of Death (if applicable)"),
|
54 |
+
gr.Textbox(label="Diagnosis"), gr.Textbox(label="Operations & Procedures"),
|
55 |
+
gr.Textbox(label="Medication on Discharge"),
|
56 |
+
gr.Textbox(label="Prepared By (Name)"), gr.Textbox(label="Job Title"), gr.Textbox(label="Signature"),
|
57 |
+
],
|
58 |
+
outputs=gr.Markdown(),
|
59 |
+
title="Patient Discharge Form",
|
60 |
+
description="Fill in the required fields to generate a complete patient discharge summary."
|
61 |
+
)
|
62 |
+
|
63 |
+
discharge_interface.launch()
|
llamaprompt.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from huggingface_hub import InferenceClient
|
2 |
+
|
3 |
+
client = InferenceClient(api_key="YOUR_HF_TOKEN")
|
4 |
+
|
5 |
+
messages = [
|
6 |
+
{ "role": "user", "content": "" },
|
7 |
+
{ "role": "assistant", "content": "you are a senior expert medical health practitioner known for their abilities to produce discharge papers. you will recieve patient information and treatment cursus. Produce a complete discharge summary based on the information provided. produce complete discharge summary." },
|
8 |
+
{ "role": "user", "content": "Patient Name: Patient 1\nGender: Male\nAge: 65 years\n\nPresentation and Diagnosis:\nThe patient was diagnosed with acute myeloid leukemia (AML) in January 2020 based on leukocytosis, thrombocytopenia and anemia. Bone marrow aspiration revealed a hypercellular bone marrow with 50% blasts. The patient was further assessed using flow cytometry and cytogenetics, and molecular panel testing showed aberrations in ASXL1, CEBPA, JAK2, and RUNX1. AML with adverse risk was diagnosed according to genetic risk stratification.\n\nHospital Course:\nAfter one course of induction treatment with the IA regimen, the patient achieved complete remission with low minimal residual disease. Genetic analyses showed negative gene mutations, and the patient received consolidation therapies with the IA regimen and high-dose Ara-c (HiDAC) regimen. However, remission duration only lasted for 11 months, and in November 2020, relapsed BM morphology was detected, indicating relapsed AML with concurrent molecular aberration recurrence. The patient underwent several treatment regimens, including venetoclax combined with azacitidine and chidamide with venetoclax and azacitidine regimen. He achieved complete remission after one course of the chidamide combined regimen.\n\nOutcome:\nThe patient passed away due to disease progression three months after the completion of therapy." },
|
9 |
+
# { "role": "assistant", "content": "**DISCHARGE SUMMARY**\n\n**Patient Name:** Patient 1\n**Gender:** Male\n**Age:** 65 years\n**Medical Record Number:** [Insert MRN]\n**Date of Admission:** [Insert Date]\n**Date of Discharge:** [Insert Date]\n**Discharge Diagnosis:**\n1. Acute Myeloid Leukemia (AML) with adverse risk\n2. Relapsed AML with molecular aberration recurrence\n\n**History of Present Illness:**\nThe patient was initially diagnosed with Acute Myeloid Leukemia (AML) in January 2020, characterized by leukocytosis, thrombocytopenia, and anemia. Bone marrow aspiration revealed a hypercellular bone marrow with 50% blasts. Further genetic and molecular testing identified aberrations in ASXL1, CEBPA, JAK2, and RUNX1, categorizing the AML as high risk.\n\n**Treatment Course:**\n- The patient underwent induction therapy with the IA regimen, achieving complete remission with minimal residual disease.\n- Consolidation therapies included the IA regimen and high-dose Ara-c (HiDAC) regimen.\n- Despite initial remission, the patient relapsed 11 months later, with detection of relapsed BM morphology and concurrent molecular aberration recurrence.\n- Subsequent treatments included venetoclax combined with azacitidine and a regimen of chidamide with venetoclax and azacitidine, with the latter resulting in complete remission.\n\n**Outcome:**\nUnfortunately, the patient's disease progressed, and he passed away three months after completing the last therapy regimen.\n\n**Discharge Condition:**\nThe patient was discharged in a terminal condition due to disease progression.\n\n**Medications at Discharge:**\n[Insert list of medications the patient was on at the time of discharge, including dosages and frequencies]\n\n**Follow-Up Care:**\nGiven the patient's demise, follow-up care was not applicable. However, the family was counseled regarding the disease progression and the options for bereavement support.\n\n**Instructions to Patient/Family:**\nAt the time of discharge, the patient and family were informed about the terminal nature of the disease and the focus was shifted to palliative care. They were provided with information on hospice care services and bereavement counseling.\n\n**Condition at Time of Discharge:**\nThe patient's condition at discharge was terminal, with evidence of disease progression despite aggressive treatment.\n\n**Certification:**\nI, [Your Name], hereby certify that the information contained in this discharge summary is accurate and complete to the best of my knowledge. I can be reached at [Your Contact Information] for any further questions or clarifications.\n\n**Signature:** [Your Signature]\n**Date:** [Current Date]\n**Title:** Senior Expert Medical Health Practitioner" }
|
10 |
+
]
|
11 |
+
|
12 |
+
stream = client.chat.completions.create(
|
13 |
+
model="meta-llama/Llama-3.3-70B-Instruct",
|
14 |
+
messages=messages,
|
15 |
+
temperature=0.4,
|
16 |
+
max_tokens=3584,
|
17 |
+
top_p=0.7,
|
18 |
+
stream=True
|
19 |
+
)
|
20 |
+
|
21 |
+
for chunk in stream:
|
22 |
+
print(chunk.choices[0].delta.content)
|
meldrx.py
ADDED
@@ -0,0 +1,361 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import json
|
3 |
+
from typing import Optional, Dict, Any
|
4 |
+
|
5 |
+
class MeldRxAPI:
|
6 |
+
"""
|
7 |
+
A Python class to interact with the MeldRx API, including the MIPS API.
|
8 |
+
Provides methods to authenticate, retrieve/update patients, create virtual workspaces,
|
9 |
+
and interact with encounter data.
|
10 |
+
"""
|
11 |
+
|
12 |
+
def __init__(self, client_id: str, client_secret: str, workspace_id: str):
|
13 |
+
"""
|
14 |
+
Initialize the MeldRxAPI class with client credentials and workspace ID.
|
15 |
+
|
16 |
+
Args:
|
17 |
+
client_id (str): The client ID (App ID) obtained from MeldRx Developer Portal.
|
18 |
+
client_secret (str): The client secret for authentication.
|
19 |
+
workspace_id (str): The workspace slug/ID to interact with.
|
20 |
+
"""
|
21 |
+
self.base_url = "https://app.meldrx.com"
|
22 |
+
self.api_base_url = f"{self.base_url}/api"
|
23 |
+
self.fhir_base_url = f"{self.api_base_url}/fhir/{workspace_id}"
|
24 |
+
self.mips_base_url = f"{self.base_url}/mms-api" # MIPS API base URL
|
25 |
+
self.token_url = f"{self.base_url}/connect/token"
|
26 |
+
self.client_id = client_id
|
27 |
+
self.client_secret = client_secret
|
28 |
+
self.workspace_id = workspace_id
|
29 |
+
self.access_token = None
|
30 |
+
self.session = requests.Session()
|
31 |
+
|
32 |
+
def authenticate(self) -> bool:
|
33 |
+
"""
|
34 |
+
Authenticate with the MeldRx API to obtain an access token.
|
35 |
+
|
36 |
+
Returns:
|
37 |
+
bool: True if authentication is successful, False otherwise.
|
38 |
+
"""
|
39 |
+
payload = {
|
40 |
+
"grant_type": "client_credentials",
|
41 |
+
"client_id": self.client_id,
|
42 |
+
"client_secret": self.client_secret
|
43 |
+
}
|
44 |
+
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
45 |
+
|
46 |
+
try:
|
47 |
+
response = self.session.post(self.token_url, data=payload, headers=headers)
|
48 |
+
response.raise_for_status()
|
49 |
+
token_data = response.json()
|
50 |
+
self.access_token = token_data.get("access_token")
|
51 |
+
if not self.access_token:
|
52 |
+
raise ValueError("No access token received from the server.")
|
53 |
+
return True
|
54 |
+
except requests.RequestException as e:
|
55 |
+
print(f"Authentication failed: {e}")
|
56 |
+
return False
|
57 |
+
except ValueError as e:
|
58 |
+
print(f"Authentication error: {e}")
|
59 |
+
return False
|
60 |
+
|
61 |
+
def _get_headers(self) -> Dict[str, str]:
|
62 |
+
"""
|
63 |
+
Generate headers with the Bearer token for authenticated requests.
|
64 |
+
|
65 |
+
Returns:
|
66 |
+
Dict[str, str]: Headers dictionary with Authorization token if available.
|
67 |
+
"""
|
68 |
+
headers = {"Content-Type": "application/json"}
|
69 |
+
if self.access_token:
|
70 |
+
headers["Authorization"] = f"Bearer {self.access_token}"
|
71 |
+
return headers
|
72 |
+
|
73 |
+
def get_patients(self) -> Optional[Dict[str, Any]]:
|
74 |
+
"""
|
75 |
+
Retrieve a list of patients from the specified workspace (FHIR API).
|
76 |
+
|
77 |
+
Returns:
|
78 |
+
Optional[Dict[str, Any]]: Patient data as a dictionary if successful, None otherwise.
|
79 |
+
"""
|
80 |
+
url = f"{self.fhir_base_url}/Patient"
|
81 |
+
|
82 |
+
if not self.access_token and not self.authenticate():
|
83 |
+
print("Cannot proceed without authentication.")
|
84 |
+
return None
|
85 |
+
|
86 |
+
try:
|
87 |
+
response = self.session.get(url, headers=self._get_headers())
|
88 |
+
response.raise_for_status()
|
89 |
+
return response.json() if response.text else {}
|
90 |
+
except requests.RequestException as e:
|
91 |
+
print(f"Failed to retrieve patients: {e}")
|
92 |
+
return None
|
93 |
+
|
94 |
+
def get_authorization_url(self, scope: str = "patient/*.read openid profile", state: str = "random_state") -> str:
|
95 |
+
"""
|
96 |
+
Generate the SMART on FHIR authorization URL for patient login.
|
97 |
+
|
98 |
+
Args:
|
99 |
+
scope (str): The requested scopes (default: patient/*.read openid profile).
|
100 |
+
state (str): A random state string for security (default: random_state).
|
101 |
+
|
102 |
+
Returns:
|
103 |
+
str: The authorization URL to open in a browser.
|
104 |
+
"""
|
105 |
+
params = {
|
106 |
+
"response_type": "code",
|
107 |
+
"client_id": self.client_id,
|
108 |
+
"redirect_uri": self.redirect_uri,
|
109 |
+
"scope": scope,
|
110 |
+
"state": state,
|
111 |
+
"aud": self.fhir_base_url
|
112 |
+
}
|
113 |
+
query_string = "&".join(f"{k}={v}" for k, v in params.items())
|
114 |
+
return f"{self.authorize_url}?{query_string}"
|
115 |
+
|
116 |
+
def authenticate_with_code(self, auth_code: str) -> bool:
|
117 |
+
"""
|
118 |
+
Exchange an authorization code for an access token.
|
119 |
+
|
120 |
+
Args:
|
121 |
+
auth_code (str): The authorization code from the redirect URI.
|
122 |
+
|
123 |
+
Returns:
|
124 |
+
bool: True if authentication is successful, False otherwise.
|
125 |
+
"""
|
126 |
+
payload = {
|
127 |
+
"grant_type": "authorization_code",
|
128 |
+
"code": auth_code,
|
129 |
+
"redirect_uri": self.redirect_uri,
|
130 |
+
"client_id": self.client_id
|
131 |
+
}
|
132 |
+
if self.client_secret:
|
133 |
+
payload["client_secret"] = self.client_secret
|
134 |
+
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
135 |
+
|
136 |
+
try:
|
137 |
+
response = self.session.post(self.token_url, data=payload, headers=headers)
|
138 |
+
response.raise_for_status()
|
139 |
+
token_data = response.json()
|
140 |
+
self.access_token = token_data.get("access_token")
|
141 |
+
if not self.access_token:
|
142 |
+
raise ValueError("No access token received from the server.")
|
143 |
+
return True
|
144 |
+
except requests.RequestException as e:
|
145 |
+
print(f"Authentication failed: {e}")
|
146 |
+
return False
|
147 |
+
except ValueError as e:
|
148 |
+
print(f"Authentication error: {e}")
|
149 |
+
return False
|
150 |
+
def create_virtual_workspace(self, snapshot: str = "patient-prefetch",
|
151 |
+
patient_id: str = "AutoPopulatedIfNotManuallySet",
|
152 |
+
hook: str = "patient-view") -> bool:
|
153 |
+
"""
|
154 |
+
Create a virtual workspace in the specified workspace (FHIR API).
|
155 |
+
|
156 |
+
Args:
|
157 |
+
snapshot (str): The snapshot type (default: "patient-prefetch").
|
158 |
+
patient_id (str): The patient ID (default: "AutoPopulatedIfNotManuallySet").
|
159 |
+
hook (str): The hook type (default: "patient-view").
|
160 |
+
|
161 |
+
Returns:
|
162 |
+
bool: True if the virtual workspace is created successfully, False otherwise.
|
163 |
+
"""
|
164 |
+
url = f"{self.fhir_base_url}/$virtual-workspace"
|
165 |
+
|
166 |
+
if not self.access_token and not self.authenticate():
|
167 |
+
print("Cannot proceed without authentication.")
|
168 |
+
return False
|
169 |
+
|
170 |
+
payload = {"snapshot": snapshot, "patientId": patient_id, "hook": hook}
|
171 |
+
|
172 |
+
try:
|
173 |
+
response = self.session.post(url, data=json.dumps(payload), headers=self._get_headers())
|
174 |
+
response.raise_for_status()
|
175 |
+
return True
|
176 |
+
except requests.RequestException as e:
|
177 |
+
print(f"Failed to create virtual workspace: {e}")
|
178 |
+
return False
|
179 |
+
|
180 |
+
def get_mips_patients(self) -> Optional[Dict[str, Any]]:
|
181 |
+
"""
|
182 |
+
Retrieve a list of patients from the MIPS API.
|
183 |
+
|
184 |
+
Returns:
|
185 |
+
Optional[Dict[str, Any]]: Patient data as a dictionary if successful, None otherwise.
|
186 |
+
"""
|
187 |
+
url = f"{self.mips_base_url}/Patient"
|
188 |
+
|
189 |
+
if not self.access_token and not self.authenticate():
|
190 |
+
print("Cannot proceed without authentication.")
|
191 |
+
return None
|
192 |
+
|
193 |
+
try:
|
194 |
+
response = self.session.get(url, headers=self._get_headers())
|
195 |
+
response.raise_for_status()
|
196 |
+
return response.json() if response.text else {}
|
197 |
+
except requests.RequestException as e:
|
198 |
+
print(f"Failed to retrieve MIPS patients: {e}")
|
199 |
+
return None
|
200 |
+
|
201 |
+
def get_mips_patient_by_id(self, patient_id: str) -> Optional[Dict[str, Any]]:
|
202 |
+
"""
|
203 |
+
Retrieve patient information by ID from the MIPS API.
|
204 |
+
|
205 |
+
Args:
|
206 |
+
patient_id (str): The ID of the patient to retrieve.
|
207 |
+
|
208 |
+
Returns:
|
209 |
+
Optional[Dict[str, Any]]: Patient data as a dictionary if successful, None otherwise.
|
210 |
+
"""
|
211 |
+
url = f"{self.mips_base_url}/Patient/{patient_id}"
|
212 |
+
|
213 |
+
if not self.access_token and not self.authenticate():
|
214 |
+
print("Cannot proceed without authentication.")
|
215 |
+
return None
|
216 |
+
|
217 |
+
try:
|
218 |
+
response = self.session.get(url, headers=self._get_headers())
|
219 |
+
response.raise_for_status()
|
220 |
+
return response.json() if response.text else {}
|
221 |
+
except requests.RequestException as e:
|
222 |
+
print(f"Failed to retrieve patient {patient_id}: {e}")
|
223 |
+
return None
|
224 |
+
|
225 |
+
def get_mips_encounters(self, patient_id: str = None) -> Optional[Dict[str, Any]]:
|
226 |
+
"""
|
227 |
+
Retrieve encounters from the MIPS API, optionally filtered by patient ID.
|
228 |
+
|
229 |
+
Args:
|
230 |
+
patient_id (str, optional): The ID of the patient to filter encounters by.
|
231 |
+
|
232 |
+
Returns:
|
233 |
+
Optional[Dict[str, Any]]: Encounter data as a dictionary if successful, None otherwise.
|
234 |
+
"""
|
235 |
+
url = f"{self.mips_base_url}/Encounter"
|
236 |
+
if patient_id:
|
237 |
+
url += f"?patient={patient_id}"
|
238 |
+
|
239 |
+
if not self.access_token and not self.authenticate():
|
240 |
+
print("Cannot proceed without authentication.")
|
241 |
+
return None
|
242 |
+
|
243 |
+
try:
|
244 |
+
response = self.session.get(url, headers=self._get_headers())
|
245 |
+
response.raise_for_status()
|
246 |
+
return response.json() if response.text else {}
|
247 |
+
except requests.RequestException as e:
|
248 |
+
print(f"Failed to retrieve encounters: {e}")
|
249 |
+
return None
|
250 |
+
|
251 |
+
def update_fhir_patient(self, patient_id: str, patient_data: Dict[str, Any]) -> bool:
|
252 |
+
"""
|
253 |
+
Update patient data in the FHIR API using a PUT request.
|
254 |
+
|
255 |
+
Args:
|
256 |
+
patient_id (str): The ID of the patient to update.
|
257 |
+
patient_data (Dict[str, Any]): The updated patient data in FHIR JSON format.
|
258 |
+
|
259 |
+
Returns:
|
260 |
+
bool: True if the patient is updated successfully, False otherwise.
|
261 |
+
"""
|
262 |
+
url = f"{self.fhir_base_url}/Patient/{patient_id}"
|
263 |
+
|
264 |
+
if not self.access_token and not self.authenticate():
|
265 |
+
print("Cannot proceed without authentication.")
|
266 |
+
return False
|
267 |
+
|
268 |
+
try:
|
269 |
+
response = self.session.put(url, data=json.dumps(patient_data), headers=self._get_headers())
|
270 |
+
response.raise_for_status()
|
271 |
+
return True
|
272 |
+
except requests.RequestException as e:
|
273 |
+
print(f"Failed to update FHIR patient {patient_id}: {e}")
|
274 |
+
return False
|
275 |
+
|
276 |
+
def update_mips_patient(self, patient_id: str, patient_data: Dict[str, Any]) -> bool:
|
277 |
+
"""
|
278 |
+
Update patient data in the MIPS API using a PUT request.
|
279 |
+
|
280 |
+
Args:
|
281 |
+
patient_id (str): The ID of the patient to update.
|
282 |
+
patient_data (Dict[str, Any]): The updated patient data in FHIR JSON format.
|
283 |
+
|
284 |
+
Returns:
|
285 |
+
bool: True if the patient is updated successfully, False otherwise.
|
286 |
+
"""
|
287 |
+
url = f"{self.mips_base_url}/Patient/{patient_id}"
|
288 |
+
|
289 |
+
if not self.access_token and not self.authenticate():
|
290 |
+
print("Cannot proceed without authentication.")
|
291 |
+
return False
|
292 |
+
|
293 |
+
try:
|
294 |
+
response = self.session.put(url, data=json.dumps(patient_data), headers=self._get_headers())
|
295 |
+
response.raise_for_status()
|
296 |
+
return True
|
297 |
+
except requests.RequestException as e:
|
298 |
+
print(f"Failed to update MIPS patient {patient_id}: {e}")
|
299 |
+
return False
|
300 |
+
|
301 |
+
def close(self):
|
302 |
+
"""Close the session to free up resources."""
|
303 |
+
self.session.close()
|
304 |
+
|
305 |
+
def __enter__(self):
|
306 |
+
"""Support for context manager entry."""
|
307 |
+
return self
|
308 |
+
|
309 |
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
310 |
+
"""Support for context manager exit, ensuring session is closed."""
|
311 |
+
self.close()
|
312 |
+
|
313 |
+
|
314 |
+
# # Example usage with patient update functionality
|
315 |
+
# if __name__ == "__main__":
|
316 |
+
# # Replace these with your actual credentials and workspace ID
|
317 |
+
# CLIENT_ID = "your_client_id"
|
318 |
+
# CLIENT_SECRET = "your_client_secret"
|
319 |
+
# WORKSPACE_ID = "your_workspace_id"
|
320 |
+
# PATIENT_ID = "example_patient_id" # Replace with an actual patient ID
|
321 |
+
|
322 |
+
# with MeldRxAPI(client_id=CLIENT_ID, client_secret=CLIENT_SECRET, workspace_id=WORKSPACE_ID) as meldrx:
|
323 |
+
# # Authenticate
|
324 |
+
# if meldrx.authenticate():
|
325 |
+
# print("Authentication successful!")
|
326 |
+
|
327 |
+
# # Retrieve specific patient information from MIPS API
|
328 |
+
# patient_info = meldrx.get_mips_patient_by_id(PATIENT_ID)
|
329 |
+
# if patient_info is not None:
|
330 |
+
# print(f"Original Patient {PATIENT_ID} Info:", json.dumps(patient_info, indent=2))
|
331 |
+
|
332 |
+
# # Example patient data to update (FHIR Patient resource format)
|
333 |
+
# updated_patient_data = {
|
334 |
+
# "resourceType": "Patient",
|
335 |
+
# "id": PATIENT_ID,
|
336 |
+
# "name": [{
|
337 |
+
# "family": "Doe",
|
338 |
+
# "given": ["John", "Updated"]
|
339 |
+
# }],
|
340 |
+
# "gender": "male",
|
341 |
+
# "birthDate": "1980-01-01"
|
342 |
+
# }
|
343 |
+
|
344 |
+
# # Update patient in FHIR API
|
345 |
+
# if meldrx.update_fhir_patient(PATIENT_ID, updated_patient_data):
|
346 |
+
# print(f"Successfully updated patient {PATIENT_ID} in FHIR API")
|
347 |
+
# updated_info = meldrx.get_mips_patient_by_id(PATIENT_ID)
|
348 |
+
# if updated_info:
|
349 |
+
# print(f"Updated Patient {PATIENT_ID} Info (FHIR):", json.dumps(updated_info, indent=2))
|
350 |
+
|
351 |
+
# # Update patient in MIPS API
|
352 |
+
# if meldrx.update_mips_patient(PATIENT_ID, updated_patient_data):
|
353 |
+
# print(f"Successfully updated patient {PATIENT_ID} in MIPS API")
|
354 |
+
# updated_info = meldrx.get_mips_patient_by_id(PATIENT_ID)
|
355 |
+
# if updated_info:
|
356 |
+
# print(f"Updated Patient {PATIENT_ID} Info (MIPS):", json.dumps(updated_info, indent=2))
|
357 |
+
|
358 |
+
# # Retrieve encounters for the patient from MIPS API
|
359 |
+
# encounters = meldrx.get_mips_encounters(patient_id=PATIENT_ID)
|
360 |
+
# if encounters is not None:
|
361 |
+
# print(f"Encounters for Patient {PATIENT_ID}:", json.dumps(encounters, indent=2))
|
meldrxtester.py
ADDED
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import json
|
3 |
+
from typing import Optional, Dict, Any
|
4 |
+
from meldrx import MeldRxAPI
|
5 |
+
|
6 |
+
# Testing class
|
7 |
+
class MeldRxAPITest:
|
8 |
+
"""A class to test the functionality of the MeldRxAPI class."""
|
9 |
+
|
10 |
+
def __init__(self):
|
11 |
+
# Placeholder variables (replace with real values for live testing)
|
12 |
+
self.client_id = "04bdc9f9a23d488a868b93d594ee5a4a"
|
13 |
+
self.client_secret = "test_client_secret"
|
14 |
+
self.workspace_id = "09ed4f76-b5ac-42bf-92d5-496933203dbe"
|
15 |
+
self.test_patient_id = "05f7c0c2-ebee-44db-ab71-2113e7a70acb"
|
16 |
+
self.api = MeldRxAPI(self.client_id, self.client_secret, self.workspace_id)
|
17 |
+
|
18 |
+
def test_authenticate(self):
|
19 |
+
"""Test the authentication method."""
|
20 |
+
print("\n=== Testing Authentication ===")
|
21 |
+
result = self.api.authenticate()
|
22 |
+
print(f"Authentication Result: {result}")
|
23 |
+
if result:
|
24 |
+
print(f"Access Token: {self.api.access_token[:10]}... (truncated for brevity)")
|
25 |
+
else:
|
26 |
+
print("Authentication failed. Subsequent tests may not work as expected.")
|
27 |
+
|
28 |
+
def test_get_patients(self):
|
29 |
+
"""Test retrieving patients from the FHIR API."""
|
30 |
+
print("\n=== Testing Get Patients (FHIR) ===")
|
31 |
+
patients = self.api.get_patients()
|
32 |
+
if patients is not None:
|
33 |
+
print("Patients Retrieved Successfully:")
|
34 |
+
print(json.dumps(patients, indent=2) if patients else "No data returned (expected per docs)")
|
35 |
+
else:
|
36 |
+
print("Failed to retrieve patients.")
|
37 |
+
|
38 |
+
def test_create_virtual_workspace(self):
|
39 |
+
"""Test creating a virtual workspace."""
|
40 |
+
print("\n=== Testing Create Virtual Workspace ===")
|
41 |
+
success = self.api.create_virtual_workspace(
|
42 |
+
snapshot="patient-prefetch",
|
43 |
+
patient_id=self.test_patient_id,
|
44 |
+
hook="patient-view"
|
45 |
+
)
|
46 |
+
print(f"Virtual Workspace Creation Result: {success}")
|
47 |
+
if success:
|
48 |
+
print("Virtual workspace created successfully (no response body expected).")
|
49 |
+
else:
|
50 |
+
print("Failed to create virtual workspace.")
|
51 |
+
|
52 |
+
def test_get_mips_patients(self):
|
53 |
+
"""Test retrieving patients from the MIPS API."""
|
54 |
+
print("\n=== Testing Get MIPS Patients ===")
|
55 |
+
patients = self.api.get_mips_patients()
|
56 |
+
if patients is not None:
|
57 |
+
print("MIPS Patients Retrieved Successfully:")
|
58 |
+
print(json.dumps(patients, indent=2) if patients else "No data returned")
|
59 |
+
else:
|
60 |
+
print("Failed to retrieve MIPS patients.")
|
61 |
+
|
62 |
+
def test_get_mips_patient_by_id(self):
|
63 |
+
"""Test retrieving a specific patient by ID from the MIPS API."""
|
64 |
+
print("\n=== Testing Get MIPS Patient by ID ===")
|
65 |
+
patient = self.api.get_mips_patient_by_id(self.test_patient_id)
|
66 |
+
if patient is not None:
|
67 |
+
print(f"Patient {self.test_patient_id} Retrieved Successfully:")
|
68 |
+
print(json.dumps(patient, indent=2) if patient else "No data returned")
|
69 |
+
else:
|
70 |
+
print(f"Failed to retrieve patient {self.test_patient_id}.")
|
71 |
+
|
72 |
+
def test_get_mips_encounters(self):
|
73 |
+
"""Test retrieving encounters from the MIPS API (with and without patient filter)."""
|
74 |
+
print("\n=== Testing Get MIPS Encounters (All) ===")
|
75 |
+
encounters = self.api.get_mips_encounters()
|
76 |
+
if encounters is not None:
|
77 |
+
print("All Encounters Retrieved Successfully:")
|
78 |
+
print(json.dumps(encounters, indent=2) if encounters else "No data returned")
|
79 |
+
else:
|
80 |
+
print("Failed to retrieve all encounters.")
|
81 |
+
|
82 |
+
print("\n=== Testing Get MIPS Encounters (Filtered by Patient) ===")
|
83 |
+
encounters_filtered = self.api.get_mips_encounters(self.test_patient_id)
|
84 |
+
if encounters_filtered is not None:
|
85 |
+
print(f"Encounters for Patient {self.test_patient_id} Retrieved Successfully:")
|
86 |
+
print(json.dumps(encounters_filtered, indent=2) if encounters_filtered else "No data returned")
|
87 |
+
else:
|
88 |
+
print(f"Failed to retrieve encounters for patient {self.test_patient_id}.")
|
89 |
+
|
90 |
+
def run_all_tests(self):
|
91 |
+
"""Run all test methods in sequence."""
|
92 |
+
print("Starting MeldRx API Tests...\n")
|
93 |
+
self.test_authenticate()
|
94 |
+
self.test_get_patients()
|
95 |
+
self.test_create_virtual_workspace()
|
96 |
+
self.test_get_mips_patients()
|
97 |
+
self.test_get_mips_patient_by_id()
|
98 |
+
self.test_get_mips_encounters()
|
99 |
+
print("\nAll tests completed.")
|
100 |
+
self.api.close()
|
101 |
+
|
102 |
+
|
103 |
+
# Run the tests
|
104 |
+
if __name__ == "__main__":
|
105 |
+
tester = MeldRxAPITest()
|
106 |
+
tester.run_all_tests()
|
meldrxtester2.py
ADDED
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import json
|
3 |
+
from typing import Optional, Dict, Any
|
4 |
+
from meldrx import MeldRxAPI # Assuming meldrx.py contains the updated MeldRxAPI with SMART on FHIR
|
5 |
+
|
6 |
+
class MeldRxAPITest:
|
7 |
+
"""A class to test the functionality of the MeldRxAPI class with SMART on FHIR and Gradio callback."""
|
8 |
+
|
9 |
+
def __init__(self):
|
10 |
+
# Placeholder variables (replace with real values for live testing)
|
11 |
+
self.client_id = "04bdc9f9a23d488a868b93d594ee5a4a" # Replace with your actual client ID
|
12 |
+
self.redirect_uri = "https://multitransformer-discharge-guard.hf.space/callback" # Gradio Space callback URL
|
13 |
+
self.workspace_id = "09ed4f76-b5ac-42bf-92d5-496933203dbe" # Replace with your workspace ID
|
14 |
+
self.test_patient_id = "05f7c0c2-ebee-44db-ab71-2113e7a70acb" # Replace with a valid patient ID
|
15 |
+
self.client_secret = None # Optional; set if using a confidential client
|
16 |
+
self.api = MeldRxAPI(self.client_id, self.redirect_uri, self.workspace_id, self.client_secret)
|
17 |
+
self.auth_code = None
|
18 |
+
self.access_token = None
|
19 |
+
|
20 |
+
def _print_section(self, title: str):
|
21 |
+
"""Helper method to print section headers."""
|
22 |
+
print(f"\n{'=' * 10} {title} {'=' * 10}")
|
23 |
+
|
24 |
+
def test_get_auth_url(self):
|
25 |
+
"""Test generating the SMART on FHIR authorization URL."""
|
26 |
+
self._print_section("Testing Get Authorization URL")
|
27 |
+
auth_url = self.api.get_authorization_url()
|
28 |
+
print(f"Generated Authorization URL:\n{auth_url}")
|
29 |
+
print("Action: Open this URL in a browser, log in, and copy the 'code' from the redirect URL.")
|
30 |
+
|
31 |
+
def test_authenticate_with_code(self):
|
32 |
+
"""Test authentication using an authorization code (simulating Gradio callback)."""
|
33 |
+
self._print_section("Testing Authenticate with Code")
|
34 |
+
self.auth_code = input("Enter the authorization code from the redirect URL (or press Enter to skip): ").strip()
|
35 |
+
if not self.auth_code:
|
36 |
+
print("No code provided. Skipping authentication test.")
|
37 |
+
return
|
38 |
+
result = self.api.authenticate_with_code(self.auth_code)
|
39 |
+
print(f"Authentication Result: {result}")
|
40 |
+
if result:
|
41 |
+
self.access_token = self.api.access_token
|
42 |
+
print(f"Access Token: {self.access_token[:10]}... (truncated for brevity)")
|
43 |
+
else:
|
44 |
+
print("Authentication failed. Subsequent tests may not work as expected.")
|
45 |
+
|
46 |
+
def test_get_patients(self):
|
47 |
+
"""Test retrieving patients from the FHIR API."""
|
48 |
+
self._print_section("Testing Get Patients (FHIR)")
|
49 |
+
if not self.access_token:
|
50 |
+
print("Not authenticated. Run test_authenticate_with_code first.")
|
51 |
+
return
|
52 |
+
patients = self.api.get_patients()
|
53 |
+
if patients is not None:
|
54 |
+
print("Patients Retrieved Successfully:")
|
55 |
+
print(json.dumps(patients, indent=2) if patients else "No data returned (expected per docs)")
|
56 |
+
else:
|
57 |
+
print("Failed to retrieve patients.")
|
58 |
+
|
59 |
+
def test_create_virtual_workspace(self):
|
60 |
+
"""Test creating a virtual workspace."""
|
61 |
+
self._print_section("Testing Create Virtual Workspace")
|
62 |
+
if not self.access_token:
|
63 |
+
print("Not authenticated. Run test_authenticate_with_code first.")
|
64 |
+
return
|
65 |
+
success = self.api.create_virtual_workspace(
|
66 |
+
snapshot="patient-prefetch",
|
67 |
+
patient_id=self.test_patient_id,
|
68 |
+
hook="patient-view"
|
69 |
+
)
|
70 |
+
print(f"Virtual Workspace Creation Result: {success}")
|
71 |
+
if success:
|
72 |
+
print("Virtual workspace created successfully (no response body expected).")
|
73 |
+
else:
|
74 |
+
print("Failed to create virtual workspace.")
|
75 |
+
|
76 |
+
def test_get_mips_patients(self):
|
77 |
+
"""Test retrieving patients from the MIPS API."""
|
78 |
+
self._print_section("Testing Get MIPS Patients")
|
79 |
+
if not self.access_token:
|
80 |
+
print("Not authenticated. Run test_authenticate_with_code first.")
|
81 |
+
return
|
82 |
+
patients = self.api.get_mips_patients()
|
83 |
+
if patients is not None:
|
84 |
+
print("MIPS Patients Retrieved Successfully:")
|
85 |
+
print(json.dumps(patients, indent=2) if patients else "No data returned")
|
86 |
+
else:
|
87 |
+
print("Failed to retrieve MIPS patients.")
|
88 |
+
|
89 |
+
def test_get_mips_patient_by_id(self):
|
90 |
+
"""Test retrieving a specific patient by ID from the MIPS API."""
|
91 |
+
self._print_section("Testing Get MIPS Patient by ID")
|
92 |
+
if not self.access_token:
|
93 |
+
print("Not authenticated. Run test_authenticate_with_code first.")
|
94 |
+
return
|
95 |
+
patient = self.api.get_mips_patient_by_id(self.test_patient_id)
|
96 |
+
if patient is not None:
|
97 |
+
print(f"Patient {self.test_patient_id} Retrieved Successfully:")
|
98 |
+
print(json.dumps(patient, indent=2) if patient else "No data returned")
|
99 |
+
else:
|
100 |
+
print(f"Failed to retrieve patient {self.test_patient_id}.")
|
101 |
+
|
102 |
+
def test_get_mips_encounters(self):
|
103 |
+
"""Test retrieving encounters from the MIPS API (with and without patient filter)."""
|
104 |
+
self._print_section("Testing Get MIPS Encounters (All)")
|
105 |
+
if not self.access_token:
|
106 |
+
print("Not authenticated. Run test_authenticate_with_code first.")
|
107 |
+
return
|
108 |
+
encounters = self.api.get_mips_encounters()
|
109 |
+
if encounters is not None:
|
110 |
+
print("All Encounters Retrieved Successfully:")
|
111 |
+
print(json.dumps(encounters, indent=2) if encounters else "No data returned")
|
112 |
+
else:
|
113 |
+
print("Failed to retrieve all encounters.")
|
114 |
+
|
115 |
+
self._print_section("Testing Get MIPS Encounters (Filtered by Patient)")
|
116 |
+
encounters_filtered = self.api.get_mips_encounters(self.test_patient_id)
|
117 |
+
if encounters_filtered is not None:
|
118 |
+
print(f"Encounters for Patient {self.test_patient_id} Retrieved Successfully:")
|
119 |
+
print(json.dumps(encounters_filtered, indent=2) if encounters_filtered else "No data returned")
|
120 |
+
else:
|
121 |
+
print(f"Failed to retrieve encounters for patient {self.test_patient_id}.")
|
122 |
+
|
123 |
+
def run_all_tests(self):
|
124 |
+
"""Run all test methods in sequence."""
|
125 |
+
print("Starting MeldRx API Tests with Gradio Callback Simulation...\n")
|
126 |
+
self.test_get_auth_url()
|
127 |
+
self.test_authenticate_with_code()
|
128 |
+
self.test_get_patients()
|
129 |
+
self.test_create_virtual_workspace()
|
130 |
+
self.test_get_mips_patients()
|
131 |
+
self.test_get_mips_patient_by_id()
|
132 |
+
self.test_get_mips_encounters()
|
133 |
+
print("\nAll tests completed.")
|
134 |
+
self.api.close()
|
135 |
+
|
136 |
+
|
137 |
+
# Run the tests
|
138 |
+
if __name__ == "__main__":
|
139 |
+
tester = MeldRxAPITest()
|
140 |
+
tester.run_all_tests()
|
qwenprompt.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from huggingface_hub import InferenceClient
|
2 |
+
|
3 |
+
client = InferenceClient(api_key="YOUR_HF_TOKEN")
|
4 |
+
|
5 |
+
messages = [
|
6 |
+
{ "role": "user", "content": "" },
|
7 |
+
{ "role": "assistant", "content": "you are a senior expert medical health practitioner known for their abilities to produce discharge papers. you will recieve patient information and treatment cursus. Produce a complete discharge summary based on the information provided. produce complete discharge summary." },
|
8 |
+
{ "role": "user", "content": "Patient Name: Patient 1\nGender: Male\nAge: 65 years\n\nPresentation and Diagnosis:\nThe patient was diagnosed with acute myeloid leukemia (AML) in January 2020 based on leukocytosis, thrombocytopenia and anemia. Bone marrow aspiration revealed a hypercellular bone marrow with 50% blasts. The patient was further assessed using flow cytometry and cytogenetics, and molecular panel testing showed aberrations in ASXL1, CEBPA, JAK2, and RUNX1. AML with adverse risk was diagnosed according to genetic risk stratification.\n\nHospital Course:\nAfter one course of induction treatment with the IA regimen, the patient achieved complete remission with low minimal residual disease. Genetic analyses showed negative gene mutations, and the patient received consolidation therapies with the IA regimen and high-dose Ara-c (HiDAC) regimen. However, remission duration only lasted for 11 months, and in November 2020, relapsed BM morphology was detected, indicating relapsed AML with concurrent molecular aberration recurrence. The patient underwent several treatment regimens, including venetoclax combined with azacitidine and chidamide with venetoclax and azacitidine regimen. He achieved complete remission after one course of the chidamide combined regimen.\n\nOutcome:\nThe patient passed away due to disease progression three months after the completion of therapy." },
|
9 |
+
# { "role": "assistant", "content": "### Discharge Summary\n\n**Patient Name:** Patient 1 \n**Gender:** Male \n**Age:** 65 years \n**Date of Admission:** January 2020 \n**Date of Discharge:** April 2021 \n**Attending Physician:** Dr. [Attending Physician's Name] \n**Discharge Diagnosis:** Acute Myeloid Leukemia (AML) with Adverse Risk\n\n#### Presentation and Diagnosis:\nThe patient, a 65-year-old male, was diagnosed with acute myeloid leukemia (AML) in January 2020. The initial presentation included leukocytosis, thrombocytopenia, and anemia. A bone marrow aspiration revealed a hypercellular bone marrow with 50% blasts. Further evaluation using flow cytometry, cytogenetics, and molecular panel testing identified aberrations in ASXL1, CEBPA, JAK2, and RUNX1. Based on these findings, the patient was diagnosed with AML with adverse risk according to genetic risk stratification.\n\n#### Hospital Course:\n- **Initial Treatment:**\n - The patient underwent one course of induction treatment with the IA (idarubicin and cytarabine) regimen.\n - After the induction treatment, the patient achieved complete remission with low minimal residual disease (MRD). Genetic analyses confirmed the absence of gene mutations.\n - The patient then received consolidation therapies, including additional courses of the IA regimen and a high-dose Ara-C (HiDAC) regimen.\n\n- **Relapse:**\n - Despite the initial success, the patient's remission lasted only 11 months. In November 2020, a bone marrow biopsy revealed relapsed AML with concurrent molecular aberration recurrence.\n - The patient was subsequently treated with several regimens, including venetoclax combined with azacitidine and a chidamide with venetoclax and azacitidine regimen.\n - After one course of the chidamide combined regimen, the patient achieved complete remission again.\n\n- **Disease Progression:**\n - Despite achieving remission, the patient's condition began to deteriorate three months after the completion of therapy.\n - The patient developed progressive disease, and despite supportive care and palliative measures, he passed away due to disease progression.\n\n#### Outcome:\nThe patient passed away on [Date of Death] due to disease progression and complications associated with relapsed AML. The family was provided with appropriate bereavement support and counseling.\n\n#### Discharge Instructions:\n- **Follow-Up:**\n - The patient's family was advised to follow up with the oncology team for any further questions or support.\n - The family was also provided with resources for grief counseling and support groups.\n\n- **Medications:**\n - The patient was not discharged on any medications due to the terminal nature of his condition.\n\n- **Diet and Activity:**\n - The patient was on a regular diet and was encouraged to maintain a comfortable level of activity as tolerated.\n\n- **Advance Directives:**\n - The patient had previously completed an advance directive, and his wishes were respected throughout his care.\n\n#### Summary:\nPatient 1, a 65-year-old male with AML with adverse risk, underwent multiple treatment regimens, including induction and consolidation therapies, and achieved remission twice. However, the disease ultimately progressed, leading to his passing. The family was provided with comprehensive support and resources to navigate this difficult time.\n\n**Signed:**\nDr. [Attending Physician's Name] \n[Contact Information] \n[Date]" }
|
10 |
+
]
|
11 |
+
|
12 |
+
stream = client.chat.completions.create(
|
13 |
+
model="Qwen/Qwen2.5-72B-Instruct",
|
14 |
+
messages=messages,
|
15 |
+
temperature=0.6,
|
16 |
+
max_tokens=4096,
|
17 |
+
top_p=0.7,
|
18 |
+
stream=True
|
19 |
+
)
|
20 |
+
|
21 |
+
for chunk in stream:
|
22 |
+
print(chunk.choices[0].delta.content)
|
requirements.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
openai
|
test_meldrx.py
ADDED
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import unittest
|
2 |
+
from unittest.mock import patch, Mock
|
3 |
+
import json
|
4 |
+
from io import StringIO
|
5 |
+
from contextlib import redirect_stdout
|
6 |
+
from meldrx import MeldRxAPI # Import the class from meldrx.py
|
7 |
+
|
8 |
+
class TestMeldRxAPI(unittest.TestCase):
|
9 |
+
def setUp(self):
|
10 |
+
"""Set up test fixtures before each test."""
|
11 |
+
self.client_id = "test_client_id"
|
12 |
+
self.client_secret = "test_client_secret"
|
13 |
+
self.workspace_id = "test_workspace_id"
|
14 |
+
self.patient_id = "test_patient_id"
|
15 |
+
self.api = MeldRxAPI(self.client_id, self.client_secret, self.workspace_id)
|
16 |
+
|
17 |
+
def tearDown(self):
|
18 |
+
"""Clean up after each test."""
|
19 |
+
self.api.close()
|
20 |
+
|
21 |
+
@patch('meldrx.requests.Session.post')
|
22 |
+
def test_authenticate_success(self, mock_post):
|
23 |
+
"""Test successful authentication."""
|
24 |
+
mock_response = Mock()
|
25 |
+
mock_response.status_code = 200
|
26 |
+
mock_response.json.return_value = {"access_token": "test_token"}
|
27 |
+
mock_post.return_value = mock_response
|
28 |
+
|
29 |
+
result = self.api.authenticate()
|
30 |
+
self.assertTrue(result)
|
31 |
+
self.assertEqual(self.api.access_token, "test_token")
|
32 |
+
|
33 |
+
@patch('meldrx.requests.Session.post')
|
34 |
+
def test_authenticate_failure(self, mock_post):
|
35 |
+
"""Test authentication failure."""
|
36 |
+
mock_response = Mock()
|
37 |
+
mock_response.status_code = 401
|
38 |
+
mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError("Unauthorized")
|
39 |
+
mock_post.return_value = mock_response
|
40 |
+
|
41 |
+
with redirect_stdout(StringIO()) as output:
|
42 |
+
result = self.api.authenticate()
|
43 |
+
self.assertFalse(result)
|
44 |
+
self.assertIsNone(self.api.access_token)
|
45 |
+
self.assertIn("Authentication failed: Unauthorized", output.getvalue())
|
46 |
+
|
47 |
+
@patch('meldrx.requests.Session.get')
|
48 |
+
@patch('meldrx.MeldRxAPI.authenticate', return_value=True)
|
49 |
+
def test_get_patients_success(self, mock_auth, mock_get):
|
50 |
+
"""Test successful retrieval of patients from FHIR API."""
|
51 |
+
mock_response = Mock()
|
52 |
+
mock_response.status_code = 200
|
53 |
+
mock_response.text = json.dumps({"resourceType": "Bundle", "entry": [{"resource": {"id": self.patient_id}}]})
|
54 |
+
mock_response.json.return_value = json.loads(mock_response.text)
|
55 |
+
mock_get.return_value = mock_response
|
56 |
+
|
57 |
+
result = self.api.get_patients()
|
58 |
+
self.assertIsNotNone(result)
|
59 |
+
self.assertEqual(result["entry"][0]["resource"]["id"], self.patient_id)
|
60 |
+
|
61 |
+
@patch('meldrx.requests.Session.get')
|
62 |
+
@patch('meldrx.MeldRxAPI.authenticate', return_value=False)
|
63 |
+
def test_get_patients_auth_failure(self, mock_auth, mock_get):
|
64 |
+
"""Test patient retrieval fails due to authentication."""
|
65 |
+
with redirect_stdout(StringIO()) as output:
|
66 |
+
result = self.api.get_patients()
|
67 |
+
self.assertIsNone(result)
|
68 |
+
mock_get.assert_not_called()
|
69 |
+
self.assertIn("Cannot proceed without authentication", output.getvalue())
|
70 |
+
|
71 |
+
@patch('meldrx.requests.Session.post')
|
72 |
+
@patch('meldrx.MeldRxAPI.authenticate', return_value=True)
|
73 |
+
def test_create_virtual_workspace_success(self, mock_auth, mock_post):
|
74 |
+
"""Test successful creation of a virtual workspace."""
|
75 |
+
mock_response = Mock()
|
76 |
+
mock_response.status_code = 201
|
77 |
+
mock_post.return_value = mock_response
|
78 |
+
|
79 |
+
result = self.api.create_virtual_workspace()
|
80 |
+
self.assertTrue(result)
|
81 |
+
|
82 |
+
@patch('meldrx.requests.Session.get')
|
83 |
+
@patch('meldrx.MeldRxAPI.authenticate', return_value=True)
|
84 |
+
def test_get_mips_patients_success(self, mock_auth, mock_get):
|
85 |
+
"""Test successful retrieval of patients from MIPS API."""
|
86 |
+
mock_response = Mock()
|
87 |
+
mock_response.status_code = 200
|
88 |
+
mock_response.text = json.dumps({"resourceType": "Bundle", "entry": [{"resource": {"id": self.patient_id}}]})
|
89 |
+
mock_response.json.return_value = json.loads(mock_response.text)
|
90 |
+
mock_get.return_value = mock_response
|
91 |
+
|
92 |
+
result = self.api.get_mips_patients()
|
93 |
+
self.assertIsNotNone(result)
|
94 |
+
self.assertEqual(result["entry"][0]["resource"]["id"], self.patient_id)
|
95 |
+
|
96 |
+
@patch('meldrx.requests.Session.get')
|
97 |
+
@patch('meldrx.MeldRxAPI.authenticate', return_value=True)
|
98 |
+
def test_get_mips_patient_by_id_success(self, mock_auth, mock_get):
|
99 |
+
"""Test successful retrieval of a patient by ID from MIPS API."""
|
100 |
+
mock_response = Mock()
|
101 |
+
mock_response.status_code = 200
|
102 |
+
mock_response.text = json.dumps({"resourceType": "Patient", "id": self.patient_id})
|
103 |
+
mock_response.json.return_value = json.loads(mock_response.text)
|
104 |
+
mock_get.return_value = mock_response
|
105 |
+
|
106 |
+
result = self.api.get_mips_patient_by_id(self.patient_id)
|
107 |
+
self.assertIsNotNone(result)
|
108 |
+
self.assertEqual(result["id"], self.patient_id)
|
109 |
+
|
110 |
+
@patch('meldrx.requests.Session.get')
|
111 |
+
@patch('meldrx.MeldRxAPI.authenticate', return_value=True)
|
112 |
+
def test_get_mips_encounters_success(self, mock_auth, mock_get):
|
113 |
+
"""Test successful retrieval of encounters from MIPS API."""
|
114 |
+
mock_response = Mock()
|
115 |
+
mock_response.status_code = 200
|
116 |
+
mock_response.text = json.dumps({"resourceType": "Bundle", "entry": [{"resource": {"id": "enc1"}}]})
|
117 |
+
mock_response.json.return_value = json.loads(mock_response.text)
|
118 |
+
mock_get.return_value = mock_response
|
119 |
+
|
120 |
+
result = self.api.get_mips_encounters(self.patient_id)
|
121 |
+
self.assertIsNotNone(result)
|
122 |
+
self.assertEqual(result["entry"][0]["resource"]["id"], "enc1")
|
123 |
+
|
124 |
+
@patch('meldrx.requests.Session.put')
|
125 |
+
@patch('meldrx.MeldRxAPI.authenticate', return_value=True)
|
126 |
+
def test_update_fhir_patient_success(self, mock_auth, mock_put):
|
127 |
+
"""Test successful update of patient data in FHIR API."""
|
128 |
+
mock_response = Mock()
|
129 |
+
mock_response.status_code = 200
|
130 |
+
mock_put.return_value = mock_response
|
131 |
+
|
132 |
+
patient_data = {"resourceType": "Patient", "id": self.patient_id, "name": [{"family": "Doe"}]}
|
133 |
+
result = self.api.update_fhir_patient(self.patient_id, patient_data)
|
134 |
+
self.assertTrue(result)
|
135 |
+
|
136 |
+
@patch('meldrx.requests.Session.put')
|
137 |
+
@patch('meldrx.MeldRxAPI.authenticate', return_value=True)
|
138 |
+
def test_update_mips_patient_success(self, mock_auth, mock_put):
|
139 |
+
"""Test successful update of patient data in MIPS API."""
|
140 |
+
mock_response = Mock()
|
141 |
+
mock_response.status_code = 200
|
142 |
+
mock_put.return_value = mock_response
|
143 |
+
|
144 |
+
patient_data = {"resourceType": "Patient", "id": self.patient_id, "name": [{"family": "Doe"}]}
|
145 |
+
result = self.api.update_mips_patient(self.patient_id, patient_data)
|
146 |
+
self.assertTrue(result)
|
147 |
+
|
148 |
+
@patch('meldrx.requests.Session.put')
|
149 |
+
@patch('meldrx.MeldRxAPI.authenticate', return_value=False)
|
150 |
+
def test_update_fhir_patient_auth_failure(self, mock_auth, mock_put):
|
151 |
+
"""Test patient update fails due to authentication in FHIR API."""
|
152 |
+
patient_data = {"resourceType": "Patient", "id": self.patient_id}
|
153 |
+
with redirect_stdout(StringIO()) as output:
|
154 |
+
result = self.api.update_fhir_patient(self.patient_id, patient_data)
|
155 |
+
self.assertFalse(result)
|
156 |
+
mock_put.assert_not_called()
|
157 |
+
self.assertIn("Cannot proceed without authentication", output.getvalue())
|
158 |
+
|
159 |
+
if __name__ == "__main__":
|
160 |
+
unittest.main(verbosity=2) # Increased verbosity for detailed output
|
wound.py
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
def submit_form(
|
4 |
+
patient_name, dob, ssn, goal_met, goal_reason,
|
5 |
+
discharge_date, wound1_location, wound1_status, wound1_measure_date, wound1_length, wound1_width, wound1_depth,
|
6 |
+
wound2_location, wound2_status, wound2_measure_date, wound2_length, wound2_width, wound2_depth,
|
7 |
+
provider_name, provider_phone, info_date
|
8 |
+
):
|
9 |
+
result = f"""
|
10 |
+
Patient Information:
|
11 |
+
Name: {patient_name}
|
12 |
+
DOB: {dob}
|
13 |
+
SSN: {ssn}
|
14 |
+
|
15 |
+
Physician's Goal Met: {'Yes' if goal_met else 'No'}
|
16 |
+
Reason (if no): {goal_reason}
|
17 |
+
|
18 |
+
Discharge Date: {discharge_date}
|
19 |
+
|
20 |
+
Wound #1:
|
21 |
+
Location: {wound1_location}
|
22 |
+
Status: {', '.join(wound1_status)}
|
23 |
+
Measurement Date: {wound1_measure_date}
|
24 |
+
Length: {wound1_length} cm, Width: {wound1_width} cm, Depth: {wound1_depth} cm
|
25 |
+
|
26 |
+
Wound #2:
|
27 |
+
Location: {wound2_location}
|
28 |
+
Status: {', '.join(wound2_status)}
|
29 |
+
Measurement Date: {wound2_measure_date}
|
30 |
+
Length: {wound2_length} cm, Width: {wound2_width} cm, Depth: {wound2_depth} cm
|
31 |
+
|
32 |
+
Provider Information:
|
33 |
+
Name: {provider_name}
|
34 |
+
Phone: {provider_phone}
|
35 |
+
Information Date: {info_date}
|
36 |
+
"""
|
37 |
+
return result
|
38 |
+
|
39 |
+
with gr.Blocks() as app:
|
40 |
+
gr.Markdown("### Discharge Form")
|
41 |
+
with gr.Row():
|
42 |
+
patient_name = gr.Textbox(label="Patient's Name (Last, First, MI)")
|
43 |
+
dob = gr.Textbox(label="Date of Birth (MM/DD/YYYY)")
|
44 |
+
ssn = gr.Textbox(label="Social Security Number (XXX-XX-XXXX)")
|
45 |
+
|
46 |
+
goal_met = gr.Checkbox(label="Was the Physician’s Goal Met?")
|
47 |
+
goal_reason = gr.Textbox(label="If No, Explain Why")
|
48 |
+
discharge_date = gr.Textbox(label="Therapy Discharge Date (MM/DD/YYYY)")
|
49 |
+
|
50 |
+
gr.Markdown("### Wound #1")
|
51 |
+
with gr.Row():
|
52 |
+
wound1_location = gr.Textbox(label="Wound Location")
|
53 |
+
wound1_status = gr.CheckboxGroup(["Adequate granulation", "Patient in hospital", "Wound unresponsive", "Pain", "Wound healed", "Delayed primary closure", "Patient non-compliant", "Patient expired", "Wound sutured closed", "Tunnel dimensions decreased or closed", "Undermining improved or resolved", "4 months of treatment completed", "Other"], label="Wound Status")
|
54 |
+
wound1_measure_date = gr.Textbox(label="Final Measurement Date (MM/DD/YYYY)")
|
55 |
+
with gr.Row():
|
56 |
+
wound1_length = gr.Number(label="Length (cm)")
|
57 |
+
wound1_width = gr.Number(label="Width (cm)")
|
58 |
+
wound1_depth = gr.Number(label="Depth (cm)")
|
59 |
+
|
60 |
+
gr.Markdown("### Wound #2 (if applicable)")
|
61 |
+
with gr.Row():
|
62 |
+
wound2_location = gr.Textbox(label="Wound Location")
|
63 |
+
wound2_status = gr.CheckboxGroup(["Adequate granulation", "Patient in hospital", "Wound unresponsive", "Pain", "Wound healed", "Delayed primary closure", "Patient non-compliant", "Patient expired", "Wound sutured closed", "Tunnel dimensions decreased or closed", "Undermining improved or resolved", "4 months of treatment completed", "Other"], label="Wound Status")
|
64 |
+
wound2_measure_date = gr.Textbox(label="Final Measurement Date (MM/DD/YYYY)")
|
65 |
+
with gr.Row():
|
66 |
+
wound2_length = gr.Number(label="Length (cm)")
|
67 |
+
wound2_width = gr.Number(label="Width (cm)")
|
68 |
+
wound2_depth = gr.Number(label="Depth (cm)")
|
69 |
+
|
70 |
+
gr.Markdown("### Provider Information")
|
71 |
+
provider_name = gr.Textbox(label="Print Name, Title, Employer")
|
72 |
+
provider_phone = gr.Textbox(label="Phone Number")
|
73 |
+
info_date = gr.Textbox(label="Information Date (MM/DD/YYYY)")
|
74 |
+
|
75 |
+
submit = gr.Button("Submit")
|
76 |
+
output = gr.Textbox(label="Form Output", interactive=False)
|
77 |
+
submit.click(submit_form, inputs=[
|
78 |
+
patient_name, dob, ssn, goal_met, goal_reason,
|
79 |
+
discharge_date, wound1_location, wound1_status, wound1_measure_date, wound1_length, wound1_width, wound1_depth,
|
80 |
+
wound2_location, wound2_status, wound2_measure_date, wound2_length, wound2_width, wound2_depth,
|
81 |
+
provider_name, provider_phone, info_date
|
82 |
+
], outputs=output)
|
83 |
+
|
84 |
+
app.launch()
|