"""The Gradio interface. Run locally with: python -m doccompass.app The result is drawn like a hospital wayfinding sign: one plaque naming the door to knock on, with the router's top three and the explanation kept quiet underneath. """ import argparse from html import escape import gradio as gr from .explain import QwenExplainer from .labels import GP, SCOPE from .pipeline import load_router, route_concern EXAMPLES = [ # made up by us; never real posts "I've had an itchy red rash on both shins for about three weeks and creams from the pharmacy haven't helped.", "My right knee swells and hurts after I run, and it clicks when I climb stairs.", "I've been feeling very sad and anxious for weeks and I can't focus on anything.", "My ears have been ringing for a week and my throat is sore when I swallow.", "I get a burning feeling when I pee and I have to go all the time.", "I suddenly have crushing chest pain and my left arm feels numb.", ] EXAMPLE_LABELS = ["Itchy rash", "Sore knee", "Feeling low", "Ringing ears", "Burning when I pee", "Crushing chest pain"] DISCLAIMER = ("Doc Compass suggests which kind of doctor to book. It does not diagnose, and it is not medical advice. " "Nothing you type is stored. In an emergency call 911.") # Atkinson Hyperlegible was drawn for readers with low vision; it suits a health tool. THEME = gr.themes.Base( font=[gr.themes.GoogleFont("Atkinson Hyperlegible"), "system-ui", "sans-serif"], radius_size=gr.themes.sizes.radius_sm, ).set( body_background_fill="#F4F7FA", body_background_fill_dark="#0F1820", block_shadow="none", block_border_width="1px", button_primary_background_fill="#1B4F8F", button_primary_background_fill_dark="#1B4F8F", button_primary_background_fill_hover="#163F73", button_primary_text_color="#FFFFFF", input_border_color_focus="#1B4F8F", ) CSS = """ .gradio-container {max-width: 1080px !important; --dc-ink: #13212C; --dc-muted: #586A78; --dc-line: #D3DDE6; --dc-card: #FFFFFF; --dc-blue: #1B4F8F; --dc-amber: #F2B441; --dc-red: #B3261E;} .dark .gradio-container, .gradio-container.dark {--dc-ink: #E6EDF3; --dc-muted: #9AAAB7; --dc-line: #2A3A47; --dc-card: #16222C;} .dc-header h1 {margin: 0; font-size: 2rem; font-weight: 700; letter-spacing: -0.01em; color: var(--dc-ink);} .dc-header p {margin: 4px 0 0; font-size: 1.05rem; color: var(--dc-muted); max-width: 60ch;} /* The sign: the one loud element on the page. */ .dc-sign {display: flex; gap: 18px; align-items: center; padding: 22px 24px; border-radius: 6px; background: var(--dc-blue); color: #FFFFFF;} .dc-sign svg {flex: none; width: 54px; height: 54px;} .dc-sign p {margin: 0; color: inherit;} .dc-sign .dc-small {font-size: 0.98rem; opacity: 0.92;} .dc-sign .dc-big {font-size: 2.1rem; line-height: 1.12; font-weight: 700; letter-spacing: -0.01em; margin: 2px 0 4px;} .dc-sign .dc-sub {font-size: 0.98rem; opacity: 0.92; max-width: 46ch;} .dc-sign.dc-junction {background: var(--dc-amber); color: #1C1503;} .dc-sign.dc-emergency {background: var(--dc-red);} .dc-sign.dc-empty {background: transparent; color: var(--dc-muted); border: 1.5px dashed var(--dc-line);} .dc-sign.dc-empty .dc-big {font-size: 1.25rem; color: var(--dc-ink);} /* The router's top three, as a quiet directory under the sign. */ .dc-doors {margin: 14px 0 0; padding: 14px 18px; border: 1px solid var(--dc-line); border-radius: 6px; background: var(--dc-card);} .dc-doors h2 {margin: 0 0 8px; font-size: 0.95rem; font-weight: 400; color: var(--dc-muted);} .dc-door {display: grid; grid-template-columns: minmax(9rem, 13rem) 1fr 3.2rem; gap: 12px; align-items: center; padding: 5px 0; color: var(--dc-ink); font-size: 1rem;} .dc-door .dc-track {height: 8px; border-radius: 4px; background: var(--dc-line); overflow: hidden;} .dc-door .dc-fill {display: block; height: 100%; background: var(--dc-blue); border-radius: 4px;} .dark .dc-door .dc-fill {background: #6FA8EA;} .dc-door .dc-pct {text-align: right; font-variant-numeric: tabular-nums; color: var(--dc-muted);} .dc-explain {padding: 2px 4px; font-size: 1.02rem; line-height: 1.55;} .dc-explain p, .dc-explain li {max-width: 62ch;} .dc-note, .dc-note p {font-size: 0.92rem; color: var(--dc-muted) !important;} .dc-footer p {margin: 8px 0 0; font-size: 0.9rem; color: var(--dc-muted); max-width: 80ch;} @media (max-width: 640px) {.dc-sign .dc-big {font-size: 1.6rem;} .dc-door {grid-template-columns: 8rem 1fr 3rem;}} """ _ARROW = ('') _FORK = ('') _ALERT = ('') def _sign(kind: str, icon: str, small: str, big: str, sub: str = "") -> str: sub_html = f"
{sub}
" if sub else "" return (f"{small}
" f"{big}
{sub_html}Tell us what's going on in your own words. We'll point you to the kind of doctor to book.