""" ClaimReady — pre-submission claim checker (Gradio UI). Pre-checks hospital insurance claim / pre-auth document sets against the Standard Treatment Guidelines before they're uploaded to the government portal. OCR + content verification run inside the Space on Gemma 3 12B via transformers (GPU), with no cloud inference API. """ import gradio as gr from llm import LLMConfigError, verify, _file_to_images from packages import ( STAGE_PREAUTH, STAGE_CLAIM, STAGE_LABELS, dropdown_choices, get_package, required_documents, ) STAGE_RADIO_CHOICES = [ (STAGE_LABELS[STAGE_PREAUTH], STAGE_PREAUTH), (STAGE_LABELS[STAGE_CLAIM], STAGE_CLAIM), ] # Synthetic (fictional-patient) sample claims — safe to publish, let judges try # the app in one click. NO real patient data. # (label, package_code, stage, files) — synthetic, fictional-patient sample claims. SAMPLES = [ ("🤒 Enteric Fever · Pre-Auth · EN+हिन्दी", "MG006A", STAGE_PREAUTH, ["samples/enteric_clinical_notes.png", "samples/enteric_cbc.png"]), ("🤒 Enteric Fever · Claim · EN+हिन्दी", "MG006A", STAGE_CLAIM, ["samples/enteric_indoor_case.png", "samples/enteric_post_cbc.png", "samples/enteric_discharge.png"]), ("🩸 Severe Anemia · Pre-Auth · EN+తెలుగు", "MG064A", STAGE_PREAUTH, ["samples/anemia_clinical_notes.png", "samples/anemia_cbc_hb.png"]), ("🩸 Severe Anemia · Claim · EN+తెలుగు", "MG064A", STAGE_CLAIM, ["samples/anemia_indoor_case.png", "samples/anemia_post_cbc.png", "samples/anemia_discharge.png"]), ] def package_info_md(code): pkg = get_package(code) if not pkg: return "" return ( f"**{pkg['code']} — {pkg['name']}** \n" f"Procedure: {pkg.get('procedure', '—')} \n" f"Specialty: {pkg.get('specialty', '—')} \n" f"Package price: {pkg.get('price', '—')}" ) def checklist_md(code, stage): if not code or not stage: return "_Select a package and stage to see the required documents._" pkg = get_package(code) docs = required_documents(code, stage) if not docs: return "_No documents configured for this selection._" lines = [ f"### Required documents — {STAGE_LABELS[stage]}", f"_{pkg['name']} ({pkg['code']})_", "", ] for i, doc in enumerate(docs, 1): line = f"{i}. **{doc['label']}** — {doc['verify']}" if doc.get("note"): line += f" \n _Note: {doc['note']}_" lines.append(line) rules = pkg.get("rules", []) if rules: lines.append("") lines.append("**Compliance checks (content):**") for r in rules: lines.append(f"- {r['check']}") return "\n".join(lines) def on_package_change(code, stage): return package_info_md(code), checklist_md(code, stage) def on_stage_change(code, stage): return checklist_md(code, stage) def show_documents(files): """Render the uploaded/sample files (PDF pages too) into gallery images.""" images = [] for f in files or []: path = getattr(f, "name", f) try: images.extend(_file_to_images(path)) except Exception: pass return images def run_verification(code, stage, files): if not code: yield "⚠️ Please select a package code first." return if not stage: yield "⚠️ Please select a stage (Pre-Auth or Claim)." return if not files: yield "⚠️ Please upload at least one document to verify." return pkg = get_package(code) docs = required_documents(code, stage) paths = [getattr(f, "name", f) for f in files] yield ( f"⏳ **Analyzing {len(paths)} document(s)…** " "Reading each page and checking it against the guidelines — " "the assistive review will appear here shortly." ) try: result = verify(pkg, STAGE_LABELS[stage], docs, pkg.get("rules", []), paths) except LLMConfigError as e: yield f"## ⚠️ Configuration error\n\n{e}" return except Exception as e: yield ( "## ❌ Verification failed\n\n" f"The model did not complete: `{type(e).__name__}: {e}`" ) return yield result # --- Styling ------------------------------------------------------------------ THEME = gr.themes.Soft( primary_hue=gr.themes.colors.teal, secondary_hue=gr.themes.colors.blue, neutral_hue=gr.themes.colors.slate, font=[gr.themes.GoogleFont("Inter"), "system-ui", "sans-serif"], ).set( body_background_fill="#eef2f6", block_background_fill="#ffffff", block_border_width="1px", block_shadow="0 1px 3px rgba(16,24,40,.06)", block_radius="14px", ) CSS = """ .gradio-container {max-width: 1500px !important; width: 96% !important; margin: auto !important;} #hero { background: linear-gradient(135deg, #2563eb 0%, #06b6d4 100%); color: #fff; border-radius: 16px; padding: 28px 32px; margin-bottom: 6px; box-shadow: 0 10px 26px rgba(37,99,235,.28); } #hero h1 {margin: 0 0 8px 0; font-size: 31px; font-weight: 800; text-shadow: 0 1px 2px rgba(0,0,0,.18);} #hero p {margin: 0; color:#f0f9ff; opacity: 1; font-size: 15.5px; line-height: 1.55;} #hero p b {color:#ffffff;} #hero .pills {margin-top: 16px;} #hero .pill { display:inline-block; background: rgba(255,255,255,.22); border:1px solid rgba(255,255,255,.45); color:#fff; padding: 5px 13px; border-radius: 999px; font-size: 12.5px; margin: 0 8px 6px 0; font-weight: 500; } #run-btn {font-weight: 700; font-size: 16px;} #result-card .prose {font-size: 15px;} .step-label {font-weight: 700; color:#0f4c81; margin-bottom: 2px;} footer {display: none !important;} #foot {text-align:center; color:#64748b; font-size:12.5px; margin-top:10px;} /* keep text + list markers off the edge so the first glyph never clips */ .prose, .md, .prose *, .md * {overflow: visible !important;} .prose {padding: 2px 6px !important;} .prose ul, .prose ol {padding-left: 1.6em !important; margin-left: 0 !important;} .prose li {line-height: 1.6; margin: 4px 0;} .prose p, .prose h1, .prose h2, .prose h3, .prose h4 {line-height: 1.55;} #problem-sidebar {padding: 6px 18px 16px 22px !important;} #result-card {padding: 2px 18px !important;} """ HERO = """

🏥 ClaimReady

An assistive pre-check for hospital insurance claim and pre-authorization document sets. Before you upload to the government portal, ClaimReady reads each document and checks it against the Standard Treatment Guidelines, highlighting missing papers and possible compliance gaps so your team can fix them early and reduce rejections.

🩺 Decision-support 🔒 No cloud API — runs in the Space 🤖 Gemma 3 12B (≤32B open model) ⚡ GPU-accelerated
""" PROBLEM = """ Health-insurance claims — for example under India's **Ayushman Bharat / PMJAY** scheme — require a specific set of **supporting documents** that must satisfy the applicable **clinical / treatment guidelines** for each procedure and stage (pre-authorization / claim). **The problem** - Every claim must include **all mandatory documents** and meet defined **content conditions** for the procedure and stage. - A missing document — or a value that doesn't meet a condition — can lead to **claim rejection**, delays and rework. **What ClaimReady offers** - 📄 Reads every uploaded document with **on-device OCR** — images *and* PDFs. - ✅ Verifies the set against the **required-document checklist** for the selected package and stage. - 🔎 Evaluates **content rules** (thresholds, conditions) against the values it actually reads. - 🌐 Handles **mixed-language** documents (e.g. English + Hindi / Telugu). - ⚠️ Surfaces **missing documents and unmet conditions early**, with supporting evidence — as an **assistive** pre-check. """ with gr.Blocks(theme=THEME, css=CSS, title="ClaimReady — Claim Submission Check") as demo: with gr.Sidebar(label="ℹ️ The problem", open=False, position="left", width=400, elem_id="problem-sidebar"): gr.Markdown("### The problem ClaimReady solves") gr.Markdown(PROBLEM) gr.HTML(HERO) gr.Markdown("**▶ New here? Load a sample claim**  ·  " "_synthetic data, no real patients · mixed English + हिन्दी / తెలుగు_") with gr.Row(): sample_buttons = [gr.Button(s[0], size="sm") for s in SAMPLES] with gr.Row(equal_height=False): with gr.Column(scale=5): gr.Markdown("#### 1 · Select the package", elem_classes="step-label") package_dd = gr.Dropdown( choices=dropdown_choices(), label="Package code", info="The PMJAY Health Benefit Package being claimed", ) package_info = gr.Markdown() gr.Markdown("#### 2 · Select the stage", elem_classes="step-label") stage_radio = gr.Radio( choices=STAGE_RADIO_CHOICES, label="Stage", info="Pre-auth = before treatment · Claim = after treatment", ) gr.Markdown("#### 3 · Upload the documents", elem_classes="step-label") files_in = gr.File( label="Claim documents (images or PDF)", file_count="multiple", file_types=["image", ".pdf"], height=160, ) verify_btn = gr.Button("🔎 Run Assistive Check", variant="primary", elem_id="run-btn") with gr.Column(scale=5): with gr.Tabs(): with gr.Tab("📋 Required documents & checks"): checklist_out = gr.Markdown( "_Select a package and stage to see the required documents._" ) with gr.Tab("📎 View uploaded documents"): doc_gallery = gr.Gallery( label="Click any page to enlarge", columns=2, height=560, object_fit="contain", ) gr.Markdown("#### 🔎 Assistive review", elem_classes="step-label") with gr.Group(elem_id="result-card"): result_out = gr.Markdown( "_Run a check (or click a sample claim above) to see the assistive review here._" ) gr.HTML( "" ) package_dd.change( on_package_change, inputs=[package_dd, stage_radio], outputs=[package_info, checklist_out], ) stage_radio.change( on_stage_change, inputs=[package_dd, stage_radio], outputs=[checklist_out], ) files_in.change(show_documents, inputs=[files_in], outputs=[doc_gallery]) verify_btn.click( run_verification, inputs=[package_dd, stage_radio, files_in], outputs=[result_out], ) def _load_sample(code, stage, files): return ( code, stage, files, package_info_md(code), checklist_md(code, stage), show_documents(files), ) for _btn, _s in zip(sample_buttons, SAMPLES): _btn.click( (lambda c=_s[1], st=_s[2], fl=_s[3]: _load_sample(c, st, fl)), outputs=[package_dd, stage_radio, files_in, package_info, checklist_out, doc_gallery], ) demo.queue() if __name__ == "__main__": demo.launch()