sujataprakashdatycs commited on
Commit
cd663d5
ยท
verified ยท
1 Parent(s): f9e1a87

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +113 -172
app.py CHANGED
@@ -15,13 +15,13 @@ from PatientInfoExtractionEngine import PatientInfoExtractionEngine
15
  load_dotenv()
16
  APP_TITLE = "Risk Adjustment (HCC Chart Validation)"
17
  CSV_PATH = "hcc_mapping.csv"
18
- SAMPLE_PDF = "sample_patient_chart.pdf" # Place a sample PDF in the same folder
19
 
20
 
21
  # ---------- JSON to Markdown ----------
22
  def json_to_markdown(data) -> str:
23
  try:
24
- if isinstance(data, dict) and "final_analysis" in data:
25
  file_name = data.get("file_name", "Unknown Patient")
26
  hcc_code = data.get("hcc_code", "N/A")
27
  model_version = data.get("model_version", "N/A")
@@ -35,20 +35,13 @@ def json_to_markdown(data) -> str:
35
  address = data.get("address", "")
36
  phone = data.get("phone", "")
37
  patient_identifier = data.get("patient_identifier", "")
38
-
39
- elif isinstance(data, list):
40
- file_name = "N/A"
41
- hcc_code = "N/A"
42
- model_version = "N/A"
43
- analyses = data
44
- patient_name = dob = age = gender = address = phone = patient_identifier = ""
45
  else:
46
  return "<div style='color:red; font-weight:bold;'>โš ๏ธ Invalid data format for report.</div>"
47
 
48
  md = f"""
49
  <div style="border:2px solid #4CAF50; padding:15px; border-radius:10px; background:#f9fdf9;">
50
  <h2 style="color:#2e7d32;">๐Ÿ“‹ HCC Chart Validation Report </h2>
51
- <p><b>๐Ÿงพ Patient ID:</b> {file_name}</p>
52
  <p><b>๐Ÿท๏ธ HCC Code:</b> {hcc_code}</p>
53
  <p><b>โš™๏ธ Model Version:</b> {model_version}</p>
54
  """
@@ -67,215 +60,184 @@ def json_to_markdown(data) -> str:
67
 
68
  md += "</div><br/>"
69
 
70
- # Render analyses
71
- for idx, diag in enumerate(analyses, 1):
72
- md += f"""
 
73
  <div style="border:1px solid #ccc; padding:12px; border-radius:8px; margin-bottom:12px;">
74
  <h3 style="color:#1565c0;">{idx}. {diag.get("diagnosis", "Unknown Diagnosis")}</h3>
75
  <p><b>ICD-10:</b> {diag.get("icd10", "N/A")}</p>
76
  <p><b>Reference:</b> <a href="{diag.get("reference","")}" target="_blank">{diag.get("reference","")}</a></p>
77
  """
78
- explicit_ans = diag.get("answer_explicit", "N/A")
79
- explicit_rat = diag.get("rationale_explicit", "")
80
- implicit_ans = diag.get("answer_implicit", "N/A")
81
- implicit_rat = diag.get("rationale_implicit", "")
82
 
83
- if explicit_ans.lower() == "yes":
84
- md += f"<p><b>Explicit:</b> {explicit_ans} โ€” {explicit_rat}</p>"
85
- else:
86
- md += f"<p><b>Implicit:</b> {implicit_ans} โ€” {implicit_rat}</p>"
87
 
88
- md += f"""
89
  <p><b>Clinical Status:</b> {diag.get("clinical_status","N/A")}</p>
90
  <p><b>Status Rationale:</b> {diag.get("status_rationale","")}</p>
91
  """
92
- if "tests" in diag:
93
- md += "<details><summary><b>๐Ÿงช Tests & Procedures</b></summary><ul>"
94
- tests = diag["tests"]
95
- if "vitals" in tests:
96
- md += "<li><b>Vitals:</b><ul>"
97
- for k, v in tests["vitals"].items():
98
- md += f"<li>{k}: {v}</li>"
99
- md += "</ul></li>"
100
- if "procedures" in tests:
101
- md += "<li><b>Procedures:</b><ul>"
102
- for k, v in tests["procedures"].items():
103
- md += f"<li>{k}: {v}</li>"
104
- md += "</ul></li>"
105
- if "lab_test" in tests:
106
- md += "<li><b>Lab Tests:</b><ul>"
107
- for k, v in tests["lab_test"].items():
108
- md += f"<li>{k}: {v}</li>"
109
- md += "</ul></li>"
110
- md += "</ul></details>"
111
-
112
- if "meat" in diag:
113
- md += "<details><summary><b>๐Ÿ– MEAT Validation</b></summary><ul>"
114
- for k, v in diag["meat"].items():
115
- emoji = "โœ…" if v else "โŒ"
116
- md += f"<li>{k.capitalize()}: {emoji}</li>"
117
- md += "</ul>"
118
- md += f"<p><b>MEAT Rationale:</b> {diag.get('meat_rationale','')}</p>"
119
- md += "</details>"
120
-
121
- if "comorbidities" in diag and diag["comorbidities"]:
122
- md += "<details><summary><b>๐Ÿฉบ Comorbidities</b></summary><ul>"
123
- for c in diag["comorbidities"]:
124
- emoji = "โœ…" if c.get("is_present") else "โŒ"
125
- md += f"<li>{emoji} <b>{c.get('condition')}</b><br/><i>{c.get('rationale')}</i></li>"
126
- md += "</ul></details>"
127
-
128
- md += "</div>"
129
-
130
  return md
131
-
132
  except Exception as e:
133
  return f"<div style='color:red; font-weight:bold;'>โš ๏ธ Error rendering report: {e}</div>"
134
 
135
 
136
- # ---------- Processing Pipeline Functions ----------
137
-
138
- def extract_demographics_only(pdf_file):
139
- """Step 1: Extracts and displays only the demographic information."""
140
- if pdf_file is None:
141
- return {
142
- gr.Markdown(value="<div style='color:orange;'>โš ๏ธ Please upload a patient chart PDF to begin.</div>"): gr.update(),
143
- gr.State(): gr.update(),
144
- gr.Button(): gr.update(visible=False)
145
- }
146
-
147
- pdf_path = pdf_file.name
148
- file_name = os.path.splitext(os.path.basename(pdf_path))[0]
149
-
150
- demographics_engine = PatientInfoExtractionEngine(pdf_path)
151
- demographics_info = demographics_engine.run()
152
-
153
- # Store info for the next step
154
- stored_data = {
155
- "file_name": file_name,
156
- "pdf_path": pdf_path,
157
- "demographics_info": demographics_info
158
- }
159
-
160
- # Create a partial report with just demographics
161
- report_data = {
162
- "file_name": file_name,
163
- "hcc_code": "N/A",
164
- "model_version": "N/A",
165
- "final_analysis": [],
166
- **demographics_info
167
- }
168
-
169
- md_output = json_to_markdown(report_data)
170
-
171
- return {
172
- gr.Markdown(value=md_output): gr.update(),
173
- gr.State(value=stored_data): gr.update(),
174
- gr.Button(value="โœ… Demographics Confirmed. Run Full Validation.", visible=True): gr.update()
175
- }
176
-
177
- def run_full_validation(stored_data, hcc_code, model_version, progress=gr.Progress()):
178
- """Step 2: Runs the rest of the validation pipeline."""
179
  try:
180
  start = time.time()
181
- # Start from step 2, since step 1 (demographics) is done
182
- step = 1
183
- total_steps = 7 # 8 total steps minus the first one
184
-
185
- pdf_path = stored_data["pdf_path"]
186
- file_name = stored_data["file_name"]
187
- demographics_info = stored_data["demographics_info"]
188
 
189
  def log(msg, current_step=0):
190
- # The progress bar will show steps 2 through 8
191
- # We add 1 to current_step for display purposes
192
- display_step = current_step + 1
193
  elapsed = time.time() - start
194
  bar_html = '<div style="display: flex; width: 100%; gap: 2px; height: 12px; margin: 8px 0 5px 0;">'
195
- for i in range(2, total_steps + 2):
196
- if i < display_step: color = "#1e40af"
197
- elif i == display_step: color = "#3b82f6"
198
  else: color = "#e5e7eb"
199
  bar_html += f'<div style="flex-grow: 1; background-color: {color}; border-radius: 3px;"></div>'
200
  bar_html += '</div>'
201
  return f"{msg}{bar_html}<small>โณ Elapsed: {elapsed:.1f} sec</small>"
202
-
 
 
 
203
  hcc_code_str = str(hcc_code or "").strip()
204
  if not hcc_code_str:
205
- yield "โš ๏ธ Please enter a valid HCC Code before running validation."
206
  return
207
 
208
- # Initial Markdown with demographics
209
- initial_md = json_to_markdown({
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  "file_name": file_name,
211
  "hcc_code": hcc_code_str,
212
  "model_version": model_version,
213
  "final_analysis": [],
214
  **demographics_info
215
- })
 
 
 
 
 
 
216
 
217
  # Step 2: Diagnoses
218
  step += 1
219
- progress((step-1, total_steps), desc="Extracting diagnoses")
220
- yield initial_md + log(f"๐Ÿ” Step {step}/{total_steps+1}: Extracting possible HCC Diagnoses...", step)
221
- diagnoses = HCCDiagnosisListEngine(hcc_code_str, model_version, CSV_PATH).run()
222
  if not diagnoses:
223
- yield initial_md + log(f"โŒ No diagnoses found for HCC {hcc_code_str}.", step)
224
  return
225
 
226
  # Step 3: Chart checking
227
  step += 1
228
- progress((step-1, total_steps), desc="Checking chart")
229
- yield initial_md + log(f"๐Ÿ“„ Step {step}/{total_steps+1}: Checking diagnoses in patient chart...", step)
230
  all_checked_results = ChartDiagnosisChecker(pdf_path).run(diagnoses)
231
  confirmed_diagnoses = [d for d in all_checked_results if d.get("answer_explicit", "").lower() == "yes" or d.get("answer_implicit", "").lower() == "yes"]
232
  if not confirmed_diagnoses:
233
- yield initial_md + log(f"โŒ No confirmed diagnoses for HCC {hcc_code_str} in {file_name}.", step)
234
  return
235
 
236
  # Step 4: Tests
237
  step += 1
238
- progress((step-1, total_steps), desc="Finding tests")
239
- yield initial_md + log(f"๐Ÿงช Step {step}/{total_steps+1}: Finding relevant tests...", step)
240
  diagnoses_with_tests = TestFindingAgent(hcc_code=hcc_code_str, model_version=model_version).run(confirmed_diagnoses)
241
 
242
  # Step 5: Clinical Status
243
  step += 1
244
- progress((step-1, total_steps), desc="Determining clinical status")
245
- yield initial_md + log(f"โš•๏ธ Step {step}/{total_steps+1}: Determining clinical status...", step)
246
  diagnoses_with_status = ClinicalStatusAgent().run(diagnoses_with_tests)
247
  active_diagnoses = [d for d in diagnoses_with_status if d.get("clinical_status") == "ACTIVE"]
248
 
249
  # Step 6: MEAT
250
  step += 1
251
- progress((step-1, total_steps), desc="Validating MEAT")
252
  if active_diagnoses:
253
- yield initial_md + log(f"๐Ÿ– Step {step}/{total_steps+1}: Validating MEAT...", step)
254
  validated_meat_diagnoses = MEATValidatorAgent().run(active_diagnoses)
255
  else:
256
  validated_meat_diagnoses = []
257
- yield initial_md + log("โ„น๏ธ No ACTIVE diagnoses found. Skipping MEAT/Comorbidity.", step)
258
 
259
  # Step 7: Comorbidities
260
  step += 1
261
- progress((step-1, total_steps), desc="Checking comorbidities")
262
  diagnoses_passed_meat = [d for d in validated_meat_diagnoses if any(d.get("meat", {}).values())]
263
  if diagnoses_passed_meat:
264
- yield initial_md + log(f"๐Ÿค Step {step}/{total_steps+1}: Checking comorbidities...", step)
265
  comorbidity_results = ComorbidityCheckerAgent(pdf_path, hcc_code_str, model_version).run(diagnoses_passed_meat)
266
  else:
267
  comorbidity_results = []
268
 
269
  # Step 8: Final Report
270
  step += 1
271
- progress((step-1, total_steps), desc="Generating report")
272
- yield initial_md + log(f"โœ… Step {step}/{total_steps+1}: Generating final report...", step)
273
 
274
- # Merge results
275
  status_map = {d["diagnosis"]: d for d in diagnoses_with_status}
276
  meat_map = {d["diagnosis"]: d for d in validated_meat_diagnoses}
277
  comorbidity_map = {d["diagnosis"]: d for d in comorbidity_results}
278
-
279
  final_analysis = []
280
  for entry in all_checked_results:
281
  diag_name = entry["diagnosis"]
@@ -302,6 +264,7 @@ def run_full_validation(stored_data, hcc_code, model_version, progress=gr.Progre
302
  print(f"[ERROR] {e}")
303
  yield f"<div style='color:red; font-weight:bold;'>โš ๏ธ Error: {e}</div>"
304
 
 
305
  # ---------- Gradio Theme and Helpers ----------
306
  simple_theme = gr.themes.Soft(
307
  primary_hue=gr.themes.colors.blue,
@@ -332,6 +295,7 @@ def pdf_to_iframe(file):
332
  except Exception as e:
333
  return f"<p style='color:red;'>Failed to display PDF: {e}</p>"
334
 
 
335
  # ---------- Gradio UI ----------
336
  with gr.Blocks(theme=simple_theme, title=APP_TITLE) as interface:
337
  gr.HTML(f"""
@@ -340,18 +304,12 @@ with gr.Blocks(theme=simple_theme, title=APP_TITLE) as interface:
340
  Upload a chart, set HCC + model version, and validate MEAT criteria.
341
  </p>
342
  """)
343
-
344
- # Store data between steps
345
- stored_data = gr.State()
346
 
347
  with gr.Row():
348
  pdf_upload = gr.File(label="Upload Patient Chart (PDF)", file_types=[".pdf"], scale=1)
349
  hcc_code = gr.Textbox(label="HCC Code (e.g., 12)", placeholder="Enter HCC code", scale=1)
350
  model_version = gr.Dropdown(choices=["V24", "V28"], label="Model Version", value="V24", scale=1)
351
-
352
- with gr.Row():
353
- run_demographics_btn = gr.Button("๐Ÿ” Extract Demographics", variant="primary", scale=1)
354
- run_full_validation_btn = gr.Button("๐Ÿš€ Run Full Validation", variant="primary", scale=1, visible=False)
355
 
356
  with gr.Row():
357
  with gr.Column(scale=2):
@@ -359,43 +317,26 @@ with gr.Blocks(theme=simple_theme, title=APP_TITLE) as interface:
359
  with gr.Column(scale=2):
360
  output_md = gr.Markdown(
361
  label="Validation Report",
362
- value="<div style='border:2px solid #1e40af; border-radius:12px; padding:15px; background-color:#f0f9ff;'>๐Ÿ“„ Upload a PDF and click <b>Extract Demographics</b> to start.</div>",
363
  )
364
 
365
  pdf_upload.change(fn=pdf_to_iframe, inputs=pdf_upload, outputs=pdf_preview)
366
 
367
- run_demographics_btn.click(
368
- fn=extract_demographics_only,
369
- inputs=[pdf_upload],
370
- outputs=[output_md, stored_data, run_full_validation_btn],
371
- )
372
-
373
- run_full_validation_btn.click(
374
- fn=run_full_validation,
375
- inputs=[stored_data, hcc_code, model_version],
376
  outputs=[output_md],
377
  )
378
-
379
- # Example loader needs to be adapted for the two-step process
380
- def load_and_run_example(pdf_path):
381
- sample_pdf = load_sample_pdf()
382
- # Step 1
383
- demographics_result = extract_demographics_only(sample_pdf)
384
- # We need to yield updates to the UI, which is complex in gr.Examples
385
- # For simplicity, we can just show the final result
386
- # A better approach would be a custom example function that triggers both buttons.
387
- # This is a simplified version for demonstration.
388
- return "Examples are loaded. Please click the buttons to process."
389
 
390
  gr.Examples(
391
  examples=[[SAMPLE_PDF]],
392
  inputs=[pdf_upload],
393
- # The output of an example click is now just a message.
394
  outputs=[output_md],
395
- fn=load_and_run_example,
396
  cache_examples=False
397
  )
398
 
 
399
  if __name__ == "__main__":
400
  interface.queue().launch(
401
  server_name="0.0.0.0",
 
15
  load_dotenv()
16
  APP_TITLE = "Risk Adjustment (HCC Chart Validation)"
17
  CSV_PATH = "hcc_mapping.csv"
18
+ SAMPLE_PDF = "sample_patient_chart.pdf" # Place a sample PDF in the same folder
19
 
20
 
21
  # ---------- JSON to Markdown ----------
22
  def json_to_markdown(data) -> str:
23
  try:
24
+ if isinstance(data, dict):
25
  file_name = data.get("file_name", "Unknown Patient")
26
  hcc_code = data.get("hcc_code", "N/A")
27
  model_version = data.get("model_version", "N/A")
 
35
  address = data.get("address", "")
36
  phone = data.get("phone", "")
37
  patient_identifier = data.get("patient_identifier", "")
 
 
 
 
 
 
 
38
  else:
39
  return "<div style='color:red; font-weight:bold;'>โš ๏ธ Invalid data format for report.</div>"
40
 
41
  md = f"""
42
  <div style="border:2px solid #4CAF50; padding:15px; border-radius:10px; background:#f9fdf9;">
43
  <h2 style="color:#2e7d32;">๐Ÿ“‹ HCC Chart Validation Report </h2>
44
+ <p><b>๐Ÿงพ File Name:</b> {file_name}</p>
45
  <p><b>๐Ÿท๏ธ HCC Code:</b> {hcc_code}</p>
46
  <p><b>โš™๏ธ Model Version:</b> {model_version}</p>
47
  """
 
60
 
61
  md += "</div><br/>"
62
 
63
+ # Render analyses if they exist
64
+ if analyses:
65
+ for idx, diag in enumerate(analyses, 1):
66
+ md += f"""
67
  <div style="border:1px solid #ccc; padding:12px; border-radius:8px; margin-bottom:12px;">
68
  <h3 style="color:#1565c0;">{idx}. {diag.get("diagnosis", "Unknown Diagnosis")}</h3>
69
  <p><b>ICD-10:</b> {diag.get("icd10", "N/A")}</p>
70
  <p><b>Reference:</b> <a href="{diag.get("reference","")}" target="_blank">{diag.get("reference","")}</a></p>
71
  """
72
+ explicit_ans = diag.get("answer_explicit", "N/A")
73
+ explicit_rat = diag.get("rationale_explicit", "")
74
+ implicit_ans = diag.get("answer_implicit", "N/A")
75
+ implicit_rat = diag.get("rationale_implicit", "")
76
 
77
+ if explicit_ans.lower() == "yes":
78
+ md += f"<p><b>Explicit:</b> {explicit_ans} โ€” {explicit_rat}</p>"
79
+ else:
80
+ md += f"<p><b>Implicit:</b> {implicit_ans} โ€” {implicit_rat}</p>"
81
 
82
+ md += f"""
83
  <p><b>Clinical Status:</b> {diag.get("clinical_status","N/A")}</p>
84
  <p><b>Status Rationale:</b> {diag.get("status_rationale","")}</p>
85
  """
86
+ if "tests" in diag:
87
+ md += "<details><summary><b>๐Ÿงช Tests & Procedures</b></summary><ul>"
88
+ tests = diag["tests"]
89
+ if "vitals" in tests:
90
+ md += "<li><b>Vitals:</b><ul>"
91
+ for k, v in tests["vitals"].items(): md += f"<li>{k}: {v}</li>"
92
+ md += "</ul></li>"
93
+ if "procedures" in tests:
94
+ md += "<li><b>Procedures:</b><ul>"
95
+ for k, v in tests["procedures"].items(): md += f"<li>{k}: {v}</li>"
96
+ md += "</ul></li>"
97
+ if "lab_test" in tests:
98
+ md += "<li><b>Lab Tests:</b><ul>"
99
+ for k, v in tests["lab_test"].items(): md += f"<li>{k}: {v}</li>"
100
+ md += "</ul></li>"
101
+ md += "</ul></details>"
102
+
103
+ if "meat" in diag:
104
+ md += "<details><summary><b>๐Ÿ– MEAT Validation</b></summary><ul>"
105
+ for k, v in diag["meat"].items():
106
+ emoji = "โœ…" if v else "โŒ"
107
+ md += f"<li>{k.capitalize()}: {emoji}</li>"
108
+ md += "</ul>"
109
+ md += f"<p><b>MEAT Rationale:</b> {diag.get('meat_rationale','')}</p>"
110
+ md += "</details>"
111
+
112
+ if "comorbidities" in diag and diag["comorbidities"]:
113
+ md += "<details><summary><b>๐Ÿฉบ Comorbidities</b></summary><ul>"
114
+ for c in diag["comorbidities"]:
115
+ emoji = "โœ…" if c.get("is_present") else "โŒ"
116
+ md += f"<li>{emoji} <b>{c.get('condition')}</b><br/><i>{c.get('rationale')}</i></li>"
117
+ md += "</ul></details>"
118
+
119
+ md += "</div>"
 
 
 
 
120
  return md
 
121
  except Exception as e:
122
  return f"<div style='color:red; font-weight:bold;'>โš ๏ธ Error rendering report: {e}</div>"
123
 
124
 
125
+ # ---------- Processing Pipeline with Gradio Progress ----------
126
+ def process_pipeline(pdf_file, hcc_code, model_version, csv_path=CSV_PATH, output_folder="outputs", progress=gr.Progress()):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  try:
128
  start = time.time()
129
+ step = 0
130
+ total_steps = 8 # Total number of steps in the pipeline
 
 
 
 
 
131
 
132
  def log(msg, current_step=0):
 
 
 
133
  elapsed = time.time() - start
134
  bar_html = '<div style="display: flex; width: 100%; gap: 2px; height: 12px; margin: 8px 0 5px 0;">'
135
+ for i in range(1, total_steps + 1):
136
+ if i < current_step: color = "#1e40af"
137
+ elif i == current_step: color = "#3b82f6"
138
  else: color = "#e5e7eb"
139
  bar_html += f'<div style="flex-grow: 1; background-color: {color}; border-radius: 3px;"></div>'
140
  bar_html += '</div>'
141
  return f"{msg}{bar_html}<small>โณ Elapsed: {elapsed:.1f} sec</small>"
142
+
143
+ if pdf_file is None:
144
+ yield log("โš ๏ธ Please upload a patient chart PDF.", 0)
145
+ return
146
  hcc_code_str = str(hcc_code or "").strip()
147
  if not hcc_code_str:
148
+ yield log("โš ๏ธ Please enter a valid HCC Code before running validation.", 0)
149
  return
150
 
151
+ os.makedirs(output_folder, exist_ok=True)
152
+ pdf_path = pdf_file.name
153
+ file_name = os.path.splitext(os.path.basename(pdf_path))[0]
154
+ print(f"[PROCESSING] {file_name}")
155
+
156
+ # --- MODIFICATION: Extract and show demographics first ---
157
+ # Step 1: Extract Demographics
158
+ step += 1
159
+ progress((step, total_steps), desc="Extracting demographics")
160
+ yield log(f"๐Ÿง Step {step}/{total_steps}: Extracting patient demographics...", step)
161
+ demographics_engine = PatientInfoExtractionEngine(pdf_path)
162
+ demographics_info = demographics_engine.run()
163
+ print(f"[DEMOGRAPHICS] Extracted: {demographics_info}")
164
+
165
+ # Create and yield the initial report with only demographics
166
+ initial_report_data = {
167
  "file_name": file_name,
168
  "hcc_code": hcc_code_str,
169
  "model_version": model_version,
170
  "final_analysis": [],
171
  **demographics_info
172
+ }
173
+ demographics_md = json_to_markdown(initial_report_data)
174
+ yield demographics_md
175
+ time.sleep(1) # Pause for a moment to show the demographics
176
+ # --- END OF MODIFICATION ---
177
+
178
+ # Subsequent steps will append progress below the initial demographic display
179
 
180
  # Step 2: Diagnoses
181
  step += 1
182
+ progress((step, total_steps), desc="Extracting diagnoses")
183
+ yield demographics_md + log(f"๐Ÿ” Step {step}/{total_steps}: Extracting possible HCC Diagnoses...", step)
184
+ diagnoses = HCCDiagnosisListEngine(hcc_code_str, model_version, csv_path).run()
185
  if not diagnoses:
186
+ yield demographics_md + log(f"โŒ No diagnoses found for HCC {hcc_code_str}.", step)
187
  return
188
 
189
  # Step 3: Chart checking
190
  step += 1
191
+ progress((step, total_steps), desc="Checking chart")
192
+ yield demographics_md + log(f"๐Ÿ“„ Step {step}/{total_steps}: Checking diagnoses in patient chart...", step)
193
  all_checked_results = ChartDiagnosisChecker(pdf_path).run(diagnoses)
194
  confirmed_diagnoses = [d for d in all_checked_results if d.get("answer_explicit", "").lower() == "yes" or d.get("answer_implicit", "").lower() == "yes"]
195
  if not confirmed_diagnoses:
196
+ yield demographics_md + log(f"โŒ No confirmed diagnoses for HCC {hcc_code_str} in {file_name}.", step)
197
  return
198
 
199
  # Step 4: Tests
200
  step += 1
201
+ progress((step, total_steps), desc="Finding tests")
202
+ yield demographics_md + log(f"๐Ÿงช Step {step}/{total_steps}: Finding relevant tests...", step)
203
  diagnoses_with_tests = TestFindingAgent(hcc_code=hcc_code_str, model_version=model_version).run(confirmed_diagnoses)
204
 
205
  # Step 5: Clinical Status
206
  step += 1
207
+ progress((step, total_steps), desc="Determining clinical status")
208
+ yield demographics_md + log(f"โš•๏ธ Step {step}/{total_steps}: Determining clinical status...", step)
209
  diagnoses_with_status = ClinicalStatusAgent().run(diagnoses_with_tests)
210
  active_diagnoses = [d for d in diagnoses_with_status if d.get("clinical_status") == "ACTIVE"]
211
 
212
  # Step 6: MEAT
213
  step += 1
214
+ progress((step, total_steps), desc="Validating MEAT")
215
  if active_diagnoses:
216
+ yield demographics_md + log(f"๐Ÿ– Step {step}/{total_steps}: Validating MEAT...", step)
217
  validated_meat_diagnoses = MEATValidatorAgent().run(active_diagnoses)
218
  else:
219
  validated_meat_diagnoses = []
220
+ yield demographics_md + log("โ„น๏ธ No ACTIVE diagnoses found. Skipping MEAT/Comorbidity.", step)
221
 
222
  # Step 7: Comorbidities
223
  step += 1
224
+ progress((step, total_steps), desc="Checking comorbidities")
225
  diagnoses_passed_meat = [d for d in validated_meat_diagnoses if any(d.get("meat", {}).values())]
226
  if diagnoses_passed_meat:
227
+ yield demographics_md + log(f"๐Ÿค Step {step}/{total_steps}: Checking comorbidities...", step)
228
  comorbidity_results = ComorbidityCheckerAgent(pdf_path, hcc_code_str, model_version).run(diagnoses_passed_meat)
229
  else:
230
  comorbidity_results = []
231
 
232
  # Step 8: Final Report
233
  step += 1
234
+ progress((step, total_steps), desc="Generating report")
235
+ yield demographics_md + log(f"โœ… Step {step}/{total_steps}: Generating final report...", step)
236
 
237
+ # Merge results for final output
238
  status_map = {d["diagnosis"]: d for d in diagnoses_with_status}
239
  meat_map = {d["diagnosis"]: d for d in validated_meat_diagnoses}
240
  comorbidity_map = {d["diagnosis"]: d for d in comorbidity_results}
 
241
  final_analysis = []
242
  for entry in all_checked_results:
243
  diag_name = entry["diagnosis"]
 
264
  print(f"[ERROR] {e}")
265
  yield f"<div style='color:red; font-weight:bold;'>โš ๏ธ Error: {e}</div>"
266
 
267
+
268
  # ---------- Gradio Theme and Helpers ----------
269
  simple_theme = gr.themes.Soft(
270
  primary_hue=gr.themes.colors.blue,
 
295
  except Exception as e:
296
  return f"<p style='color:red;'>Failed to display PDF: {e}</p>"
297
 
298
+
299
  # ---------- Gradio UI ----------
300
  with gr.Blocks(theme=simple_theme, title=APP_TITLE) as interface:
301
  gr.HTML(f"""
 
304
  Upload a chart, set HCC + model version, and validate MEAT criteria.
305
  </p>
306
  """)
 
 
 
307
 
308
  with gr.Row():
309
  pdf_upload = gr.File(label="Upload Patient Chart (PDF)", file_types=[".pdf"], scale=1)
310
  hcc_code = gr.Textbox(label="HCC Code (e.g., 12)", placeholder="Enter HCC code", scale=1)
311
  model_version = gr.Dropdown(choices=["V24", "V28"], label="Model Version", value="V24", scale=1)
312
+ run_btn = gr.Button("๐Ÿš€ Run Validation", variant="primary", scale=1)
 
 
 
313
 
314
  with gr.Row():
315
  with gr.Column(scale=2):
 
317
  with gr.Column(scale=2):
318
  output_md = gr.Markdown(
319
  label="Validation Report",
320
+ value="<div style='border:2px solid #1e40af; border-radius:12px; padding:15px; background-color:#f0f9ff;'>๐Ÿ“„ Upload a PDF and click <b>Run Validation</b> to start.</div>",
321
  )
322
 
323
  pdf_upload.change(fn=pdf_to_iframe, inputs=pdf_upload, outputs=pdf_preview)
324
 
325
+ run_btn.click(
326
+ fn=process_pipeline,
327
+ inputs=[pdf_upload, hcc_code, model_version],
 
 
 
 
 
 
328
  outputs=[output_md],
329
  )
 
 
 
 
 
 
 
 
 
 
 
330
 
331
  gr.Examples(
332
  examples=[[SAMPLE_PDF]],
333
  inputs=[pdf_upload],
 
334
  outputs=[output_md],
335
+ fn=lambda x: process_pipeline(load_sample_pdf(), hcc_code="12", model_version="V24"),
336
  cache_examples=False
337
  )
338
 
339
+
340
  if __name__ == "__main__":
341
  interface.queue().launch(
342
  server_name="0.0.0.0",