try to fix the response parser , fingers crossed
Browse files- docs/Ada662_Sari509_Balistreri607_dbc4a3f7-9c69-4435-3ce3-4e1988ab6b91.json +0 -0
- templates/index.html +77 -2
- utils/meldrx.py +8 -12
- utils/oneclick.py +10 -0
- utils/responseparser.py +16 -0
docs/Ada662_Sari509_Balistreri607_dbc4a3f7-9c69-4435-3ce3-4e1988ab6b91.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
templates/index.html
CHANGED
@@ -1,5 +1,80 @@
|
|
1 |
{% extends "base.html" %}
|
2 |
{% block content %}
|
3 |
-
<
|
4 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
{% endblock %}
|
|
|
1 |
{% extends "base.html" %}
|
2 |
{% block content %}
|
3 |
+
<div class="container my-5">
|
4 |
+
<div class="row">
|
5 |
+
<div class="col-12">
|
6 |
+
<h2 class="text-center mb-4">Welcome to Discharge Guard</h2>
|
7 |
+
<div class="card shadow-sm mb-4">
|
8 |
+
<div class="card-body">
|
9 |
+
<h3 class="card-title">💡 Inspiration</h3>
|
10 |
+
<p class="card-text">
|
11 |
+
Busy clinics are often overwhelmed with administrative tasks, and generating discharge papers
|
12 |
+
manually is time-consuming and prone to errors.
|
13 |
+
We were inspired to create a solution that streamlines this process, freeing up valuable time
|
14 |
+
for healthcare professionals to focus on patient care.
|
15 |
+
We saw the potential of MeldRX to access and leverage patient data securely and compliantly,
|
16 |
+
making automated discharge paper generation a reality. 🏥 ⏱️ ➡️ 🧑⚕️
|
17 |
+
</p>
|
18 |
+
</div>
|
19 |
+
</div>
|
20 |
+
|
21 |
+
<div class="card shadow-sm mb-4">
|
22 |
+
<div class="card-body">
|
23 |
+
<h3 class="card-title">✨ What it does</h3>
|
24 |
+
<p class="card-text">
|
25 |
+
Discharge Guard is a single-button solution for generating compliant and comprehensive medical
|
26 |
+
discharge papers directly within busy clinic workflows.
|
27 |
+
By connecting to MeldRX, it automatically pulls necessary patient information and formats it
|
28 |
+
into a professional discharge document.
|
29 |
+
This eliminates manual data entry, reduces errors, and ensures adherence to healthcare
|
30 |
+
standards, all with just one click! 🖱️ ✅ 📄
|
31 |
+
</p>
|
32 |
+
</div>
|
33 |
+
</div>
|
34 |
+
|
35 |
+
<div class="card shadow-sm mb-4">
|
36 |
+
<div class="card-body">
|
37 |
+
<h3 class="card-title">🛠️ How we built it</h3>
|
38 |
+
<p class="card-text">
|
39 |
+
We built Discharge Guard using a combination of powerful and user-friendly technologies. The
|
40 |
+
front-end is developed with MultiTransformer huggingface, providing a simple and intuitive
|
41 |
+
interface for clinic staff.
|
42 |
+
Behind the scenes, we leverage the MeldRX API to securely access patient data in FHIR format.
|
43 |
+
</p>
|
44 |
+
<p class="card-text">
|
45 |
+
Our prototype implements the following key steps:
|
46 |
+
</p>
|
47 |
+
<ul>
|
48 |
+
<li><strong>Produce patient data download by ID:</strong> Clinic staff can input a patient ID,
|
49 |
+
and the application retrieves the corresponding patient data from MeldRX using the API.</li>
|
50 |
+
<li><strong>Parse patient data:</strong> The fetched FHIR data is processed to extract essential
|
51 |
+
details like patient demographics, diagnoses, and treatment plans needed for discharge
|
52 |
+
papers.</li>
|
53 |
+
<li><strong>Produce prompts for discharge papers:</strong> Using the parsed data, the
|
54 |
+
application generates the content for discharge papers, including medical information and
|
55 |
+
post-discharge instructions tailored to the patient.</li>
|
56 |
+
<li><strong>Create patient data in MeldRX:</strong> The generated discharge papers are uploaded
|
57 |
+
back to MeldRX as new resources, ensuring the patient's record stays complete and up to
|
58 |
+
date.</li>
|
59 |
+
</ul>
|
60 |
+
</div>
|
61 |
+
</div>
|
62 |
+
|
63 |
+
<div class="card shadow-sm">
|
64 |
+
<div class="card-body">
|
65 |
+
<h3 class="card-title">🚀 Next Steps</h3>
|
66 |
+
<p class="card-text">
|
67 |
+
We're continuously improving Discharge Guard with more features including customizable
|
68 |
+
templates, additional clinic system integrations, and refinements based on user feedback.
|
69 |
+
Our goal is to make Discharge Guard a widely adopted tool that empowers clinics to provide
|
70 |
+
better patient care by streamlining administrative processes.
|
71 |
+
</p>
|
72 |
+
<div class="text-center mt-4">
|
73 |
+
<a href="/generate" class="btn btn-primary btn-lg">Try Discharge Guard Now</a>
|
74 |
+
</div>
|
75 |
+
</div>
|
76 |
+
</div>
|
77 |
+
</div>
|
78 |
+
</div>
|
79 |
+
</div>
|
80 |
{% endblock %}
|
utils/meldrx.py
CHANGED
@@ -59,18 +59,14 @@ class MeldRxAPI:
|
|
59 |
headers["Authorization"] = f"Bearer {self.access_token}"
|
60 |
return headers
|
61 |
|
62 |
-
def get_patients(self)
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
return response.json() if response.text else {}
|
71 |
-
except requests.RequestException as e:
|
72 |
-
print(f"Failed to retrieve patients: {e}")
|
73 |
-
return None
|
74 |
|
75 |
def get_authorization_url(self, scope: str = "patient/*.read openid profile", state: str = "random_state") -> str:
|
76 |
code_verifier = self._generate_code_verifier()
|
|
|
59 |
headers["Authorization"] = f"Bearer {self.access_token}"
|
60 |
return headers
|
61 |
|
62 |
+
def get_patients(self):
|
63 |
+
# This should return the FHIR Bundle as per your sample output
|
64 |
+
headers = {"Authorization": f"Bearer {self.access_token}"}
|
65 |
+
response = requests.get(
|
66 |
+
f"https://app.meldrx.com/api/fhir/{self.workspace_id}/Patient",
|
67 |
+
headers=headers
|
68 |
+
)
|
69 |
+
return response.json() if response.status_code == 200 else None
|
|
|
|
|
|
|
|
|
70 |
|
71 |
def get_authorization_url(self, scope: str = "patient/*.read openid profile", state: str = "random_state") -> str:
|
72 |
code_verifier = self._generate_code_verifier()
|
utils/oneclick.py
CHANGED
@@ -102,6 +102,7 @@ def generate_discharge_paper_one_click(
|
|
102 |
logger.debug(f"Processing patient {i}: {patient_data}") # Add debug log
|
103 |
patient_id_from_data = str(patient_data.get('id', '')).strip().lower()
|
104 |
|
|
|
105 |
if patient_id_input and patient_id_from_data == patient_id_input:
|
106 |
matching_patient = patient_data
|
107 |
logger.info(f"Exact match found for patient ID: {patient_id_from_data}")
|
@@ -120,9 +121,13 @@ def generate_discharge_paper_one_click(
|
|
120 |
logger.info(f"Match found by name: {first_name_from_data} {last_name_from_data}")
|
121 |
break
|
122 |
|
|
|
123 |
if not matching_patient:
|
124 |
search_criteria = f"ID: {patient_id or 'N/A'}, First: {first_name or 'N/A'}, Last: {last_name or 'N/A'}"
|
125 |
all_patient_ids = [str(p.get('id', '')) for p in extractor.get_all_patients()]
|
|
|
|
|
|
|
126 |
all_patient_names = [f"{p.get('first_name', '')} {p.get('last_name', '')}".strip()
|
127 |
for p in extractor.get_all_patients()]
|
128 |
logger.warning(f"No patients matched criteria: {search_criteria}")
|
@@ -131,7 +136,11 @@ def generate_discharge_paper_one_click(
|
|
131 |
f"Available Names: {', '.join(all_patient_names)}"), None, None, None
|
132 |
|
133 |
logger.info(f"Selected patient data: {matching_patient}")
|
|
|
|
|
134 |
|
|
|
|
|
135 |
basic_summary = format_discharge_summary(matching_patient)
|
136 |
ai_summary, verified_summary = generate_ai_discharge_summary(matching_patient, client)
|
137 |
|
@@ -140,6 +149,7 @@ def generate_discharge_paper_one_click(
|
|
140 |
|
141 |
pdf_gen = PDFGenerator()
|
142 |
filename = f"discharge_{matching_patient.get('id', 'unknown')}_{matching_patient.get('last_name', 'patient')}.pdf"
|
|
|
143 |
pdf_path = pdf_gen.generate_pdf_from_text(ai_summary, filename)
|
144 |
|
145 |
if pdf_path:
|
|
|
102 |
logger.debug(f"Processing patient {i}: {patient_data}") # Add debug log
|
103 |
patient_id_from_data = str(patient_data.get('id', '')).strip().lower()
|
104 |
|
105 |
+
|
106 |
if patient_id_input and patient_id_from_data == patient_id_input:
|
107 |
matching_patient = patient_data
|
108 |
logger.info(f"Exact match found for patient ID: {patient_id_from_data}")
|
|
|
121 |
logger.info(f"Match found by name: {first_name_from_data} {last_name_from_data}")
|
122 |
break
|
123 |
|
124 |
+
if not matching_patient:
|
125 |
if not matching_patient:
|
126 |
search_criteria = f"ID: {patient_id or 'N/A'}, First: {first_name or 'N/A'}, Last: {last_name or 'N/A'}"
|
127 |
all_patient_ids = [str(p.get('id', '')) for p in extractor.get_all_patients()]
|
128 |
+
all_patient_names = [f"{p.get('first_name', '')} {p.get('last_name', '')}".strip()
|
129 |
+
for p in extractor.get_all_patients()]
|
130 |
+
all_patient_ids = [str(p.get('id', '')) for p in extractor.get_all_patients()]
|
131 |
all_patient_names = [f"{p.get('first_name', '')} {p.get('last_name', '')}".strip()
|
132 |
for p in extractor.get_all_patients()]
|
133 |
logger.warning(f"No patients matched criteria: {search_criteria}")
|
|
|
136 |
f"Available Names: {', '.join(all_patient_names)}"), None, None, None
|
137 |
|
138 |
logger.info(f"Selected patient data: {matching_patient}")
|
139 |
+
|
140 |
+
logger.info(f"Selected patient data: {matching_patient}")
|
141 |
|
142 |
+
basic_summary = format_discharge_summary(matching_patient)
|
143 |
+
ai_summary, verified_summary = generate_ai_discharge_summary(matching_patient, client)
|
144 |
basic_summary = format_discharge_summary(matching_patient)
|
145 |
ai_summary, verified_summary = generate_ai_discharge_summary(matching_patient, client)
|
146 |
|
|
|
149 |
|
150 |
pdf_gen = PDFGenerator()
|
151 |
filename = f"discharge_{matching_patient.get('id', 'unknown')}_{matching_patient.get('last_name', 'patient')}.pdf"
|
152 |
+
filename = f"discharge_{matching_patient.get('id', 'unknown')}_{matching_patient.get('last_name', 'patient')}.pdf"
|
153 |
pdf_path = pdf_gen.generate_pdf_from_text(ai_summary, filename)
|
154 |
|
155 |
if pdf_path:
|
utils/responseparser.py
CHANGED
@@ -269,6 +269,7 @@ class PatientDataExtractor:
|
|
269 |
# Format medications as a string
|
270 |
medications_str = "; ".join([m["description"] for m in data["medications"] if m["description"]]) or "None specified"
|
271 |
|
|
|
272 |
# Safely extract fields with defaults to avoid KeyError
|
273 |
return {
|
274 |
"id": data.get("id", "Unknown"),
|
@@ -283,6 +284,21 @@ class PatientDataExtractor:
|
|
283 |
"state": data.get("state", "Unknown"),
|
284 |
"zip_code": data.get("zip_code", "Unknown"),
|
285 |
"phone": data.get("phone", "Unknown"),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
286 |
"admission_date": admission_date,
|
287 |
"discharge_date": discharge_date,
|
288 |
"diagnosis": diagnosis,
|
|
|
269 |
# Format medications as a string
|
270 |
medications_str = "; ".join([m["description"] for m in data["medications"] if m["description"]]) or "None specified"
|
271 |
|
272 |
+
<<<<<<< HEAD
|
273 |
# Safely extract fields with defaults to avoid KeyError
|
274 |
return {
|
275 |
"id": data.get("id", "Unknown"),
|
|
|
284 |
"state": data.get("state", "Unknown"),
|
285 |
"zip_code": data.get("zip_code", "Unknown"),
|
286 |
"phone": data.get("phone", "Unknown"),
|
287 |
+
=======
|
288 |
+
return {
|
289 |
+
"id": data["id"],
|
290 |
+
"first_name": data["first_name"],
|
291 |
+
"last_name": data["last_name"],
|
292 |
+
"name_prefix": data["name_prefix"],
|
293 |
+
"dob": data["dob"],
|
294 |
+
"age": data["age"],
|
295 |
+
"sex": data["gender"],
|
296 |
+
"address": data["address_line"],
|
297 |
+
"city": data["city"],
|
298 |
+
"state": data["state"],
|
299 |
+
"zip_code": data["zip_code"],
|
300 |
+
"phone": data["phone"],
|
301 |
+
>>>>>>> 9690499f96401745e214013c8a9267b332a69778
|
302 |
"admission_date": admission_date,
|
303 |
"discharge_date": discharge_date,
|
304 |
"diagnosis": diagnosis,
|