| |
| """Gradio UI for query entity export on Hugging Face Spaces.""" |
|
|
| from __future__ import annotations |
|
|
| import gradio as gr |
|
|
| from space_service import format_entry_json, get_service |
|
|
|
|
| def run_single_query(query: str) -> tuple[str, str]: |
| query = (query or "").strip() |
| if not query: |
| return "", "Enter a clinical evidence query." |
|
|
| try: |
| entry = get_service().process_query(query) |
| except FileNotFoundError as exc: |
| return "", f"Service not ready: {exc}" |
| except Exception as exc: |
| return "", f"Error: {exc}" |
|
|
| entities = entry.get("entities", []) |
| summary = ( |
| f"Detected {len(entities)} entity/entities for query " |
| f"({len(query)} characters)." |
| ) |
| return format_entry_json(entry), summary |
|
|
|
|
| def run_split_export( |
| split: str, |
| limit: int, |
| pretty: bool, |
| progress=gr.Progress(track_tqdm=False), |
| ) -> tuple[str, str | None]: |
| if limit <= 0: |
| return "Limit must be at least 1.", None |
|
|
| try: |
| svc = get_service() |
| except FileNotFoundError as exc: |
| return f"Service not ready: {exc}", None |
|
|
| def _progress(done: int, total: int) -> None: |
| progress(done / total, desc=f"Processing {done}/{total}") |
|
|
| try: |
| output_path, summary = svc.process_split( |
| split, |
| limit=limit, |
| pretty=pretty, |
| progress_callback=_progress, |
| ) |
| except Exception as exc: |
| return f"Error: {exc}", None |
|
|
| return summary, str(output_path) |
|
|
|
|
| DESCRIPTION = """ |
| Detect UMLS concepts in clinical query text with **QuickUMLS**, then map each CUI |
| to the best graph **AUI** using the bundled parquet cache. |
| |
| **Modes** |
| - **Single query** β paste one evidence string and get entities immediately. |
| - **Dataset split** β run `train`, `val`, or `test` JSONL (bundled). Use a limit for |
| quick checks; full test (~17k rows) can take 10β15 minutes after QuickUMLS loads. |
| |
| First cold start downloads ~5 GB QuickUMLS data from S3 (configured via Space secrets). |
| """ |
|
|
| with gr.Blocks(title="Query Entity Export") as demo: |
| gr.Markdown("# Query Entity Export") |
| gr.Markdown(DESCRIPTION) |
|
|
| with gr.Tab("Single query"): |
| query_input = gr.Textbox( |
| label="Clinical evidence / query text", |
| placeholder="Type II Diabetes Mellitus Uncontrolled", |
| lines=3, |
| ) |
| single_btn = gr.Button("Detect entities", variant="primary") |
| single_summary = gr.Textbox(label="Status", interactive=False) |
| single_output = gr.Code(label="Result JSON", language="json") |
|
|
| single_btn.click( |
| fn=run_single_query, |
| inputs=query_input, |
| outputs=[single_output, single_summary], |
| ) |
| gr.Examples( |
| examples=[ |
| ["Type II Diabetes Mellitus Uncontrolled"], |
| ["Mild intermittent asthma without complication"], |
| ["Patient with acute kidney injury stage 3"], |
| ], |
| inputs=query_input, |
| ) |
|
|
| with gr.Tab("Dataset split"): |
| split_input = gr.Dropdown( |
| choices=["test", "val", "train"], |
| value="test", |
| label="Split", |
| ) |
| limit_input = gr.Number( |
| value=10, |
| precision=0, |
| minimum=1, |
| label="Row limit", |
| info="Full test split has 17,243 rows (~10β15 min). Start small.", |
| ) |
| pretty_input = gr.Checkbox(label="Pretty-print JSON", value=False) |
| split_btn = gr.Button("Run export", variant="primary") |
| split_status = gr.Textbox(label="Status", interactive=False) |
| split_file = gr.File(label="Download results JSON") |
|
|
| split_btn.click( |
| fn=run_split_export, |
| inputs=[split_input, limit_input, pretty_input], |
| outputs=[split_status, split_file], |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch(server_name="0.0.0.0", server_port=7860) |
|
|