sujataprakashdatycs commited on
Commit
0e3414f
Β·
verified Β·
1 Parent(s): eac4c73

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +389 -9
app.py CHANGED
@@ -10,7 +10,7 @@ from ComorbidityCheckerAgent import ComorbidityCheckerAgent
10
  from HCCDiagnosisListEngine import HCCDiagnosisListEngine
11
  from chartdiagnosischecker import ChartDiagnosisChecker
12
  from MeatValidatorAgent import MEATValidatorAgent
13
- from typing import Optional
14
 
15
  load_dotenv()
16
  APP_TITLE = "Risk Adjustment (HCC Chart Validation)"
@@ -26,11 +26,22 @@ def json_to_markdown(data) -> str:
26
  hcc_code = data.get("hcc_code", "N/A")
27
  model_version = data.get("model_version", "N/A")
28
  analyses = data.get("final_analysis", [])
 
 
 
 
 
 
 
 
 
 
29
  elif isinstance(data, list):
30
  patient_id = "N/A"
31
  hcc_code = "N/A"
32
  model_version = "N/A"
33
  analyses = data
 
34
  else:
35
  return "<div style='color:red; font-weight:bold;'>⚠️ Invalid data format for report.</div>"
36
 
@@ -40,9 +51,23 @@ def json_to_markdown(data) -> str:
40
  <p><b>🧾 Patient ID:</b> {patient_id}</p>
41
  <p><b>🏷️ HCC Code:</b> {hcc_code}</p>
42
  <p><b>βš™οΈ Model Version:</b> {model_version}</p>
43
- </div>
44
- <br/>
45
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  for idx, diag in enumerate(analyses, 1):
47
  md += f"""
48
  <div style="border:1px solid #ccc; padding:12px; border-radius:8px; margin-bottom:12px;">
@@ -113,7 +138,7 @@ def process_pipeline(pdf_file, hcc_code, model_version, csv_path=CSV_PATH, outpu
113
  try:
114
  start = time.time()
115
  step = 0
116
- total_steps = 7
117
 
118
  def log(msg, step_progress=None):
119
  elapsed = time.time() - start
@@ -139,6 +164,14 @@ def process_pipeline(pdf_file, hcc_code, model_version, csv_path=CSV_PATH, outpu
139
  patient_name = os.path.splitext(os.path.basename(pdf_path))[0]
140
  print(f"[PROCESSING] {patient_name}")
141
 
 
 
 
 
 
 
 
 
142
  # Step 1: Diagnoses
143
  step += 1
144
  progress((step, total_steps), desc="Extracting diagnoses")
@@ -223,10 +256,18 @@ def process_pipeline(pdf_file, hcc_code, model_version, csv_path=CSV_PATH, outpu
223
  or e.get("answer_implicit", "").lower() == "yes"
224
  ]
225
 
 
226
  output_data = {
227
  "patient_id": patient_name,
228
  "hcc_code": hcc_code_str,
229
  "model_version": model_version,
 
 
 
 
 
 
 
230
  "final_analysis": filtered_final_analysis
231
  }
232
 
@@ -281,7 +322,6 @@ def pdf_to_iframe(file):
281
  return f"<p style='color:red;'>Failed to display PDF: {e}</p>"
282
 
283
 
284
-
285
  # ---------- Gradio UI ----------
286
  with gr.Blocks(theme=simple_theme, title=APP_TITLE) as interface:
287
  gr.HTML(f"""
@@ -306,10 +346,8 @@ with gr.Blocks(theme=simple_theme, title=APP_TITLE) as interface:
306
  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>",
307
  )
308
 
309
- # Connect PDF upload to preview
310
  pdf_upload.change(fn=pdf_to_iframe, inputs=pdf_upload, outputs=pdf_preview)
311
 
312
- # Connect run button with progress
313
  run_btn.click(
314
  fn=process_pipeline,
315
  inputs=[pdf_upload, hcc_code, model_version],
@@ -322,8 +360,7 @@ with gr.Blocks(theme=simple_theme, title=APP_TITLE) as interface:
322
  outputs=[output_md],
323
  fn=lambda x: process_pipeline(load_sample_pdf(), hcc_code="12", model_version="V24"),
324
  cache_examples=False
325
- )
326
-
327
 
328
 
329
  if __name__ == "__main__":
@@ -333,3 +370,346 @@ if __name__ == "__main__":
333
  )
334
 
335
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  from HCCDiagnosisListEngine import HCCDiagnosisListEngine
11
  from chartdiagnosischecker import ChartDiagnosisChecker
12
  from MeatValidatorAgent import MEATValidatorAgent
13
+ from PatientInfoExtractionEngine import PatientInfoExtractionEngine
14
 
15
  load_dotenv()
16
  APP_TITLE = "Risk Adjustment (HCC Chart Validation)"
 
26
  hcc_code = data.get("hcc_code", "N/A")
27
  model_version = data.get("model_version", "N/A")
28
  analyses = data.get("final_analysis", [])
29
+
30
+ # Demographics
31
+ patient_name = data.get("patient_name", "")
32
+ dob = data.get("dob", "")
33
+ age = data.get("age", "")
34
+ gender = data.get("gender", "")
35
+ address = data.get("address", "")
36
+ phone = data.get("phone", "")
37
+ patient_identifier = data.get("patient_identifier", "")
38
+
39
  elif isinstance(data, list):
40
  patient_id = "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
 
 
51
  <p><b>🧾 Patient ID:</b> {patient_id}</p>
52
  <p><b>🏷️ HCC Code:</b> {hcc_code}</p>
53
  <p><b>βš™οΈ Model Version:</b> {model_version}</p>
 
 
54
  """
55
+
56
+ # Add demographics
57
+ if any([patient_name, dob, age, gender, address, phone, patient_identifier]):
58
+ md += "<hr style='border:0;border-top:1px solid #c8e6c9;margin:10px 0;'/>"
59
+ md += "<h3 style='color:#1b5e20;'>πŸ‘€ Patient Demographics</h3>"
60
+ if patient_name: md += f"<p><b>Name:</b> {patient_name}</p>"
61
+ if patient_identifier: md += f"<p><b>Patient Identifier:</b> {patient_identifier}</p>"
62
+ if dob: md += f"<p><b>Date of Birth:</b> {dob}</p>"
63
+ if age: md += f"<p><b>Age:</b> {age}</p>"
64
+ if gender: md += f"<p><b>Gender:</b> {gender}</p>"
65
+ if address: md += f"<p><b>Address:</b> {address}</p>"
66
+ if phone: md += f"<p><b>Phone:</b> {phone}</p>"
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;">
 
138
  try:
139
  start = time.time()
140
  step = 0
141
+ total_steps = 8 # Step 0 added for demographics
142
 
143
  def log(msg, step_progress=None):
144
  elapsed = time.time() - start
 
164
  patient_name = os.path.splitext(os.path.basename(pdf_path))[0]
165
  print(f"[PROCESSING] {patient_name}")
166
 
167
+ # Step 0: Extract Demographics
168
+ step += 1
169
+ progress((step, total_steps), desc="Extracting demographics")
170
+ yield log(f"🧍 Step {step}/{total_steps}: Extracting patient demographics...", step/total_steps)
171
+ demographics_engine = PatientInfoExtractionEngine(pdf_path)
172
+ demographics_info = demographics_engine.run()
173
+ print(f"[DEMOGRAPHICS] Extracted: {demographics_info}")
174
+
175
  # Step 1: Diagnoses
176
  step += 1
177
  progress((step, total_steps), desc="Extracting diagnoses")
 
256
  or e.get("answer_implicit", "").lower() == "yes"
257
  ]
258
 
259
+ # Include demographics in output
260
  output_data = {
261
  "patient_id": patient_name,
262
  "hcc_code": hcc_code_str,
263
  "model_version": model_version,
264
+ "patient_name": demographics_info.get("name", ""),
265
+ "dob": demographics_info.get("dob", ""),
266
+ "age": demographics_info.get("age", ""),
267
+ "gender": demographics_info.get("gender", ""),
268
+ "address": demographics_info.get("address", ""),
269
+ "phone": demographics_info.get("phone", ""),
270
+ "patient_identifier": demographics_info.get("patient_identifier", ""),
271
  "final_analysis": filtered_final_analysis
272
  }
273
 
 
322
  return f"<p style='color:red;'>Failed to display PDF: {e}</p>"
323
 
324
 
 
325
  # ---------- Gradio UI ----------
326
  with gr.Blocks(theme=simple_theme, title=APP_TITLE) as interface:
327
  gr.HTML(f"""
 
346
  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>",
347
  )
348
 
 
349
  pdf_upload.change(fn=pdf_to_iframe, inputs=pdf_upload, outputs=pdf_preview)
350
 
 
351
  run_btn.click(
352
  fn=process_pipeline,
353
  inputs=[pdf_upload, hcc_code, model_version],
 
360
  outputs=[output_md],
361
  fn=lambda x: process_pipeline(load_sample_pdf(), hcc_code="12", model_version="V24"),
362
  cache_examples=False
363
+ )
 
364
 
365
 
366
  if __name__ == "__main__":
 
370
  )
371
 
372
 
373
+
374
+
375
+
376
+
377
+
378
+
379
+
380
+ # import os
381
+ # import gradio as gr
382
+ # import json
383
+ # import time
384
+ # import base64
385
+ # from dotenv import load_dotenv
386
+ # from ClinicalStatusAgent import ClinicalStatusAgent
387
+ # from TestFindingAgent import TestFindingAgent
388
+ # from ComorbidityCheckerAgent import ComorbidityCheckerAgent
389
+ # from HCCDiagnosisListEngine import HCCDiagnosisListEngine
390
+ # from chartdiagnosischecker import ChartDiagnosisChecker
391
+ # from MeatValidatorAgent import MEATValidatorAgent
392
+ # from PatientInfoExtractionEngine import PatientInfoExtractionEngine
393
+ # from typing import Optional
394
+
395
+ # load_dotenv()
396
+ # APP_TITLE = "Risk Adjustment (HCC Chart Validation)"
397
+ # CSV_PATH = "hcc_mapping.csv"
398
+ # SAMPLE_PDF = "sample_patient_chart.pdf" # Place a sample PDF in the same folder
399
+
400
+
401
+ # # ---------- JSON to Markdown ----------
402
+ # def json_to_markdown(data) -> str:
403
+ # try:
404
+ # if isinstance(data, dict) and "final_analysis" in data:
405
+ # patient_id = data.get("patient_id", "Unknown Patient")
406
+ # hcc_code = data.get("hcc_code", "N/A")
407
+ # model_version = data.get("model_version", "N/A")
408
+ # analyses = data.get("final_analysis", [])
409
+ # elif isinstance(data, list):
410
+ # patient_id = "N/A"
411
+ # hcc_code = "N/A"
412
+ # model_version = "N/A"
413
+ # analyses = data
414
+ # else:
415
+ # return "<div style='color:red; font-weight:bold;'>⚠️ Invalid data format for report.</div>"
416
+
417
+ # md = f"""
418
+ # <div style="border:2px solid #4CAF50; padding:15px; border-radius:10px; background:#f9fdf9;">
419
+ # <h2 style="color:#2e7d32;">πŸ“‹ HCC Chart Validation Report </h2>
420
+ # <p><b>🧾 Patient ID:</b> {patient_id}</p>
421
+ # <p><b>🏷️ HCC Code:</b> {hcc_code}</p>
422
+ # <p><b>βš™οΈ Model Version:</b> {model_version}</p>
423
+ # </div>
424
+ # <br/>
425
+ # """
426
+ # for idx, diag in enumerate(analyses, 1):
427
+ # md += f"""
428
+ # <div style="border:1px solid #ccc; padding:12px; border-radius:8px; margin-bottom:12px;">
429
+ # <h3 style="color:#1565c0;">{idx}. {diag.get("diagnosis", "Unknown Diagnosis")}</h3>
430
+ # <p><b>ICD-10:</b> {diag.get("icd10", "N/A")}</p>
431
+ # <p><b>Reference:</b> <a href="{diag.get("reference","")}" target="_blank">{diag.get("reference","")}</a></p>
432
+ # """
433
+ # explicit_ans = diag.get("answer_explicit", "N/A")
434
+ # explicit_rat = diag.get("rationale_explicit", "")
435
+ # implicit_ans = diag.get("answer_implicit", "N/A")
436
+ # implicit_rat = diag.get("rationale_implicit", "")
437
+
438
+ # if explicit_ans.lower() == "yes":
439
+ # md += f"<p><b>Explicit:</b> {explicit_ans} β€” {explicit_rat}</p>"
440
+ # else:
441
+ # md += f"<p><b>Implicit:</b> {implicit_ans} β€” {implicit_rat}</p>"
442
+
443
+ # md += f"""
444
+ # <p><b>Clinical Status:</b> {diag.get("clinical_status","N/A")}</p>
445
+ # <p><b>Status Rationale:</b> {diag.get("status_rationale","")}</p>
446
+ # """
447
+ # if "tests" in diag:
448
+ # md += "<details><summary><b>πŸ§ͺ Tests & Procedures</b></summary><ul>"
449
+ # tests = diag["tests"]
450
+ # if "vitals" in tests:
451
+ # md += "<li><b>Vitals:</b><ul>"
452
+ # for k, v in tests["vitals"].items():
453
+ # md += f"<li>{k}: {v}</li>"
454
+ # md += "</ul></li>"
455
+ # if "procedures" in tests:
456
+ # md += "<li><b>Procedures:</b><ul>"
457
+ # for k, v in tests["procedures"].items():
458
+ # md += f"<li>{k}: {v}</li>"
459
+ # md += "</ul></li>"
460
+ # if "lab_test" in tests:
461
+ # md += "<li><b>Lab Tests:</b><ul>"
462
+ # for k, v in tests["lab_test"].items():
463
+ # md += f"<li>{k}: {v}</li>"
464
+ # md += "</ul></li>"
465
+ # md += "</ul></details>"
466
+
467
+ # if "meat" in diag:
468
+ # md += "<details><summary><b>πŸ– MEAT Validation</b></summary><ul>"
469
+ # for k, v in diag["meat"].items():
470
+ # emoji = "βœ…" if v else "❌"
471
+ # md += f"<li>{k.capitalize()}: {emoji}</li>"
472
+ # md += "</ul>"
473
+ # md += f"<p><b>MEAT Rationale:</b> {diag.get('meat_rationale','')}</p>"
474
+ # md += "</details>"
475
+
476
+ # if "comorbidities" in diag and diag["comorbidities"]:
477
+ # md += "<details><summary><b>🩺 Comorbidities</b></summary><ul>"
478
+ # for c in diag["comorbidities"]:
479
+ # emoji = "βœ…" if c.get("is_present") else "❌"
480
+ # md += f"<li>{emoji} <b>{c.get('condition')}</b><br/><i>{c.get('rationale')}</i></li>"
481
+ # md += "</ul></details>"
482
+
483
+ # md += "</div>"
484
+
485
+ # return md
486
+
487
+ # except Exception as e:
488
+ # return f"<div style='color:red; font-weight:bold;'>⚠️ Error rendering report: {e}</div>"
489
+
490
+
491
+ # # ---------- Processing Pipeline with Gradio Progress ----------
492
+ # def process_pipeline(pdf_file, hcc_code, model_version, csv_path=CSV_PATH, output_folder="outputs", progress=gr.Progress()):
493
+ # try:
494
+ # start = time.time()
495
+ # step = 0
496
+ # total_steps = 7
497
+
498
+ # def log(msg, step_progress=None):
499
+ # elapsed = time.time() - start
500
+ # progress_html = ""
501
+ # if step_progress is not None:
502
+ # progress_html = f"""
503
+ # <div style="width:100%; background:#eee; border-radius:6px; margin:5px 0;">
504
+ # <div style="width:{step_progress*100}%; background:#1e40af; height:12px; border-radius:6px;"></div>
505
+ # </div>
506
+ # """
507
+ # return f"{progress_html}{msg}<br/><small>⏳ Elapsed: {elapsed:.1f} sec</small>"
508
+
509
+ # if pdf_file is None:
510
+ # yield log("⚠️ Please upload a patient chart PDF.", 0)
511
+ # return
512
+ # hcc_code_str = str(hcc_code or "").strip()
513
+ # if not hcc_code_str:
514
+ # yield log("⚠️ Please enter a valid HCC Code before running validation.", 0)
515
+ # return
516
+
517
+ # os.makedirs(output_folder, exist_ok=True)
518
+ # pdf_path = pdf_file.name
519
+ # patient_name = os.path.splitext(os.path.basename(pdf_path))[0]
520
+ # print(f"[PROCESSING] {patient_name}")
521
+
522
+ # # Step 1: Diagnoses
523
+ # step += 1
524
+ # progress((step, total_steps), desc="Extracting diagnoses")
525
+ # yield log(f"πŸ” Step {step}/{total_steps}: Extracting possible HCC Diagnoses...", step/total_steps)
526
+ # diagnoses = HCCDiagnosisListEngine(hcc_code_str, model_version, csv_path).run()
527
+ # if not diagnoses:
528
+ # yield log(f"❌ No diagnoses found for HCC {hcc_code_str}.", step/total_steps)
529
+ # return
530
+
531
+ # # Step 2: Chart checking
532
+ # step += 1
533
+ # progress((step, total_steps), desc="Checking chart")
534
+ # yield log(f"πŸ“„ Step {step}/{total_steps}: Checking diagnoses in patient chart...", step/total_steps)
535
+ # all_checked_results = ChartDiagnosisChecker(pdf_path).run(diagnoses)
536
+ # confirmed_diagnoses = [
537
+ # d for d in all_checked_results
538
+ # if d.get("answer_explicit", "").lower() == "yes"
539
+ # or d.get("answer_implicit", "").lower() == "yes"
540
+ # ]
541
+ # if not confirmed_diagnoses:
542
+ # yield log(f"❌ No confirmed diagnoses for HCC {hcc_code_str} in {patient_name}.", step/total_steps)
543
+ # return
544
+
545
+ # # Step 3: Tests
546
+ # step += 1
547
+ # progress((step, total_steps), desc="Finding tests")
548
+ # yield log(f"πŸ§ͺ Step {step}/{total_steps}: Finding relevant tests...", step/total_steps)
549
+ # diagnoses_with_tests = TestFindingAgent(hcc_code=hcc_code_str, model_version=model_version).run(confirmed_diagnoses)
550
+
551
+ # # Step 4: Clinical Status
552
+ # step += 1
553
+ # progress((step, total_steps), desc="Determining clinical status")
554
+ # yield log(f"βš•οΈ Step {step}/{total_steps}: Determining clinical status...", step/total_steps)
555
+ # diagnoses_with_status = ClinicalStatusAgent().run(diagnoses_with_tests)
556
+ # active_diagnoses = [d for d in diagnoses_with_status if d.get("clinical_status") == "ACTIVE"]
557
+
558
+ # # Step 5: MEAT
559
+ # step += 1
560
+ # progress((step, total_steps), desc="Validating MEAT")
561
+ # if active_diagnoses:
562
+ # yield log(f"πŸ– Step {step}/{total_steps}: Validating MEAT...", step/total_steps)
563
+ # validated_meat_diagnoses = MEATValidatorAgent().run(active_diagnoses)
564
+ # else:
565
+ # validated_meat_diagnoses = []
566
+ # yield log("ℹ️ No ACTIVE diagnoses found. Skipping MEAT/Comorbidity.", step/total_steps)
567
+
568
+ # # Step 6: Comorbidities
569
+ # step += 1
570
+ # progress((step, total_steps), desc="Checking comorbidities")
571
+ # diagnoses_passed_meat = [d for d in validated_meat_diagnoses if any(d.get("meat", {}).values())]
572
+ # if diagnoses_passed_meat:
573
+ # yield log(f"🀝 Step {step}/{total_steps}: Checking comorbidities...", step/total_steps)
574
+ # comorbidity_results = ComorbidityCheckerAgent(pdf_path, hcc_code_str, model_version).run(diagnoses_passed_meat)
575
+ # else:
576
+ # comorbidity_results = []
577
+
578
+ # # Step 7: Final Report
579
+ # step += 1
580
+ # progress((step, total_steps), desc="Generating report")
581
+ # yield log(f"βœ… Step {step}/{total_steps}: Generating final report...", step/total_steps)
582
+
583
+ # # Merge results
584
+ # status_map = {d["diagnosis"]: d for d in diagnoses_with_status}
585
+ # meat_map = {d["diagnosis"]: d for d in validated_meat_diagnoses}
586
+ # comorbidity_map = {d["diagnosis"]: d for d in comorbidity_results}
587
+
588
+ # final_analysis = []
589
+ # for entry in all_checked_results:
590
+ # diag_name = entry["diagnosis"]
591
+ # updated_entry = entry.copy()
592
+ # if diag_name in status_map:
593
+ # updated_entry.update(status_map[diag_name])
594
+ # if diag_name in meat_map:
595
+ # updated_entry.update(meat_map[diag_name])
596
+ # if diag_name in comorbidity_map:
597
+ # updated_entry.update(comorbidity_map[diag_name])
598
+ # final_analysis.append(updated_entry)
599
+
600
+ # filtered_final_analysis = [
601
+ # e for e in final_analysis
602
+ # if e.get("answer_explicit", "").lower() == "yes"
603
+ # or e.get("answer_implicit", "").lower() == "yes"
604
+ # ]
605
+
606
+ # output_data = {
607
+ # "patient_id": patient_name,
608
+ # "hcc_code": hcc_code_str,
609
+ # "model_version": model_version,
610
+ # "final_analysis": filtered_final_analysis
611
+ # }
612
+
613
+ # elapsed = time.time() - start
614
+ # yield json_to_markdown(output_data) + f"<br/><div style='color:green;'>βœ… Completed in {elapsed:.1f} sec</div>"
615
+
616
+ # except Exception as e:
617
+ # print(f"[ERROR] {e}")
618
+ # yield f"<div style='color:red; font-weight:bold;'>⚠️ Error: {e}</div>"
619
+
620
+
621
+ # # ---------- Gradio Theme ----------
622
+ # simple_theme = gr.themes.Soft(
623
+ # primary_hue=gr.themes.colors.blue,
624
+ # secondary_hue=gr.themes.colors.slate,
625
+ # neutral_hue=gr.themes.colors.slate,
626
+ # ).set(
627
+ # button_primary_background_fill="#1e40af",
628
+ # button_primary_background_fill_hover="#1d4ed8",
629
+ # button_primary_text_color="white",
630
+ # background_fill_primary="white",
631
+ # background_fill_secondary="#f8fafc",
632
+ # )
633
+
634
+
635
+ # # ---------- Helper for Sample PDF ----------
636
+ # def load_sample_pdf():
637
+ # if not os.path.exists(SAMPLE_PDF):
638
+ # raise FileNotFoundError(f"Sample PDF not found at {SAMPLE_PDF}")
639
+ # class PDFWrapper:
640
+ # def __init__(self, path):
641
+ # self.name = path
642
+ # return PDFWrapper(SAMPLE_PDF)
643
+
644
+
645
+ # # ---------- Helper for PDF Preview ----------
646
+ # def pdf_to_iframe(file):
647
+ # if file is None:
648
+ # return "<p style='color:orange;'>No PDF uploaded.</p>"
649
+ # try:
650
+ # with open(file.name, "rb") as f:
651
+ # pdf_bytes = f.read()
652
+ # encoded = base64.b64encode(pdf_bytes).decode("utf-8")
653
+ # return f"""
654
+ # <iframe
655
+ # src="data:application/pdf;base64,{encoded}"
656
+ # width="100%" height="600px"
657
+ # style="border:1px solid #ccc;"
658
+ # ></iframe>
659
+ # """
660
+ # except Exception as e:
661
+ # return f"<p style='color:red;'>Failed to display PDF: {e}</p>"
662
+
663
+
664
+
665
+ # # ---------- Gradio UI ----------
666
+ # with gr.Blocks(theme=simple_theme, title=APP_TITLE) as interface:
667
+ # gr.HTML(f"""
668
+ # <h1 style='text-align:center;color:#1e40af;'> 🏩 {APP_TITLE}</h1>
669
+ # <p style='text-align:center;color:#64748b;'>
670
+ # Upload a chart, set HCC + model version, and validate MEAT criteria.
671
+ # </p>
672
+ # """)
673
+
674
+ # with gr.Row():
675
+ # pdf_upload = gr.File(label="Upload Patient Chart (PDF)", file_types=[".pdf"], scale=1)
676
+ # hcc_code = gr.Textbox(label="HCC Code (e.g., 12)", placeholder="Enter HCC code", scale=1)
677
+ # model_version = gr.Dropdown(choices=["V24", "V28"], label="Model Version", value="V24", scale=1)
678
+ # run_btn = gr.Button("πŸš€ Run Validation", variant="primary", scale=1)
679
+
680
+ # with gr.Row():
681
+ # with gr.Column(scale=2):
682
+ # pdf_preview = gr.HTML(label="πŸ“‘ PDF Preview", value="<p>Upload a PDF to preview</p>")
683
+ # with gr.Column(scale=2):
684
+ # output_md = gr.Markdown(
685
+ # label="Validation Report",
686
+ # 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>",
687
+ # )
688
+
689
+ # # Connect PDF upload to preview
690
+ # pdf_upload.change(fn=pdf_to_iframe, inputs=pdf_upload, outputs=pdf_preview)
691
+
692
+ # # Connect run button with progress
693
+ # run_btn.click(
694
+ # fn=process_pipeline,
695
+ # inputs=[pdf_upload, hcc_code, model_version],
696
+ # outputs=[output_md],
697
+ # )
698
+
699
+ # gr.Examples(
700
+ # examples=[[SAMPLE_PDF]],
701
+ # inputs=[pdf_upload],
702
+ # outputs=[output_md],
703
+ # fn=lambda x: process_pipeline(load_sample_pdf(), hcc_code="12", model_version="V24"),
704
+ # cache_examples=False
705
+ # )
706
+
707
+
708
+
709
+ # if __name__ == "__main__":
710
+ # interface.queue().launch(
711
+ # server_name="0.0.0.0",
712
+ # server_port=int(os.environ.get("PORT", 7860))
713
+ # )
714
+
715
+