FastMedExtract / app.py
Umong's picture
Upload folder using huggingface_hub
ad74c90 verified
import time
import gradio as gr
from gliner import GLiNER
model = GLiNER.from_pretrained("Ihor/gliner-biomed-base-v1.0")
MAX_LABELS = 12
PALETTE = [
"#FF6B6B", "#4ECDC4", "#45B7D1", "#FFA07A", "#98D8C8", "#F7DC6F",
"#BB8FCE", "#85C1E9", "#F0B27A", "#76D7C4", "#F1948A", "#82E0AA",
]
DEFAULT_LABELS = ["patient_name", "age", "sex", "symptom", "diagnosis", "medication", "vital_sign", "procedure"]
def filter_choices(selected):
return gr.Dropdown(choices=[l for l in DEFAULT_LABELS if l not in selected])
def extract(text, labels_list, threshold):
labels = [l for l in labels_list if l][:MAX_LABELS]
if not labels or not text.strip():
return None, [], ""
color_map = {l: PALETTE[i % len(PALETTE)] for i, l in enumerate(labels)}
start = time.perf_counter()
entities = model.predict_entities(text, labels, threshold=threshold)
latency_ms = (time.perf_counter() - start) * 1000
entities = sorted(entities, key=lambda e: e["start"])
hl_entities = [{"entity": e["label"], "start": e["start"], "end": e["end"]} for e in entities]
table = [[e["label"], e["text"], f"{e['score']:.2f}"] for e in entities]
return (
gr.HighlightedText(value={"text": text, "entities": hl_entities}, color_map=color_map),
table,
f"{latency_ms:.1f} ms | {len(entities)} entities",
)
EXAMPLES = [
[
"""Patient: Jane Doe, 58-year-old female.
Chief Complaint: Chest pain and shortness of breath for 2 days.
History of Present Illness:
Patient presents with substernal chest pain radiating to the left arm,
rated 7/10, worsening with exertion. She reports associated dyspnea and
diaphoresis. She has a history of Type 2 Diabetes Mellitus diagnosed in
2015 and Hypertension diagnosed in 2018.
Current Medications:
- Metformin 1000mg PO BID for diabetes
- Lisinopril 20mg PO daily for hypertension
- Aspirin 81mg PO daily for cardiac prophylaxis
Vitals: BP 158/92, HR 96, SpO2 94%, Temp 98.6F
Assessment:
1. Acute coronary syndrome - rule out myocardial infarction
2. Uncontrolled hypertension
3. Type 2 Diabetes Mellitus - stable on current regimen
Plan:
- Stat ECG and troponin levels
- Start Heparin drip 18 units/kg/hr IV
- Nitroglycerin 0.4mg sublingual PRN chest pain
- Cardiology consult
- Continue home medications""",
DEFAULT_LABELS,
0.4,
],
[
"""DISCHARGE SUMMARY
Patient: Robert Chen, 72-year-old male.
Admission Date: 2024-01-15. Discharge Date: 2024-01-19.
Principal Diagnosis: Community-acquired pneumonia, right lower lobe.
Secondary Diagnoses: COPD, Atrial fibrillation.
Hospital Course:
Patient admitted with fever 101.8F, productive cough with purulent sputum,
and oxygen saturation of 88% on room air. Chest X-ray confirmed right lower
lobe consolidation. Started on Ceftriaxone 1g IV daily and Azithromycin
500mg PO daily. Supplemental O2 via nasal cannula at 3L/min.
Discharge Medications:
- Amoxicillin-Clavulanate 875mg PO BID x 5 days
- Albuterol inhaler 2 puffs q4-6h PRN
- Warfarin 5mg PO daily
- Metoprolol 50mg PO BID
Follow-up: Pulmonology clinic in 2 weeks. Repeat chest X-ray in 6 weeks.""",
DEFAULT_LABELS,
0.4,
],
[
"""ED Note - 03/10/2024 22:45
Chief Complaint: Laceration to right hand.
HPI: 34-year-old male presents after cutting his right palm on broken glass
approximately 1 hour ago. Reports moderate bleeding controlled with direct
pressure. Denies numbness or weakness in fingers. No foreign body sensation.
Tetanus up to date.
Exam: 3cm linear laceration to right thenar eminence, clean edges, no tendon
involvement, neurovascular intact distally.
Procedure: Wound irrigated with normal saline. Repaired with 4-0 nylon,
5 interrupted sutures. Sterile dressing applied.
Disposition: Home with wound care instructions. Suture removal in 10 days.""",
DEFAULT_LABELS + ["body_part", "wound"],
0.4,
],
]
with gr.Blocks(title="GLiNER Biomedical NER") as demo:
gr.Markdown("# GLiNER Biomedical NER\nZero-shot named entity recognition with `gliner-biomed-base-v1.0`")
with gr.Row():
with gr.Column(scale=2):
text_input = gr.Textbox(label="Clinical Text", lines=12)
labels_input = gr.Dropdown(
label="Entity Labels",
choices=DEFAULT_LABELS,
value=DEFAULT_LABELS,
multiselect=True,
allow_custom_value=True,
max_choices=MAX_LABELS,
)
threshold = gr.Slider(0.0, 1.0, value=0.4, step=0.05, label="Confidence Threshold")
run_btn = gr.Button("Extract", variant="primary")
with gr.Column(scale=3):
latency_output = gr.Textbox(label="Latency")
highlight_output = gr.HighlightedText(label="Entities", combine_adjacent=False, show_legend=True)
table_output = gr.Dataframe(headers=["Label", "Text", "Score"], label="Extracted Entities")
labels_input.change(filter_choices, inputs=[labels_input], outputs=[labels_input])
run_btn.click(extract, inputs=[text_input, labels_input, threshold], outputs=[highlight_output, table_output, latency_output])
gr.Examples(EXAMPLES, inputs=[text_input, labels_input, threshold])
demo.launch()