Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,47 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
-
from sentence_transformers import SentenceTransformer, util
|
| 3 |
-
from transformers import pipeline
|
| 4 |
|
| 5 |
-
# ---
|
| 6 |
-
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
|
| 9 |
-
|
| 10 |
-
def
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
return "❌ Anaemia not detected (no keyword match)"
|
| 15 |
|
| 16 |
-
#
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
| 19 |
|
| 20 |
-
def ml_based(text):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
emb = embedder.encode(text, convert_to_tensor=True)
|
| 22 |
-
score = util.cos_sim(emb, ref_emb).item()
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
rb_output = gr.Textbox(label="Rule-Based Result")
|
| 37 |
-
ml_output = gr.Textbox(label="Machine Learning Result")
|
| 38 |
-
ai_output = gr.Textbox(label="AI (LLM) Result")
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
|
|
|
|
|
|
| 42 |
|
| 43 |
-
|
| 44 |
-
|
|
|
|
|
|
|
| 45 |
|
| 46 |
-
demo
|
| 47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import re
|
| 3 |
+
from functools import lru_cache
|
| 4 |
+
|
| 5 |
import gradio as gr
|
|
|
|
|
|
|
| 6 |
|
| 7 |
+
# --- Space-friendly settings ---
|
| 8 |
+
# Keep caches persistent if you enabled Space storage
|
| 9 |
+
os.environ.setdefault("HF_HOME", "/data/huggingface")
|
| 10 |
+
os.environ.setdefault("GRADIO_ANALYTICS_ENABLED", "false")
|
| 11 |
+
|
| 12 |
+
# ---------- Lazy model loaders (no heavy work at import time) ----------
|
| 13 |
+
@lru_cache(maxsize=1)
|
| 14 |
+
def get_embedder():
|
| 15 |
+
# lazy import to avoid blocking the frontend
|
| 16 |
+
from sentence_transformers import SentenceTransformer
|
| 17 |
+
return SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
|
| 18 |
+
|
| 19 |
+
@lru_cache(maxsize=1)
|
| 20 |
+
def get_ref_emb():
|
| 21 |
+
from sentence_transformers import util # imported where needed
|
| 22 |
+
embedder = get_embedder()
|
| 23 |
+
reference_text = "Patient diagnosed with anaemia and low haemoglobin."
|
| 24 |
+
return embedder.encode(reference_text, convert_to_tensor=True)
|
| 25 |
|
| 26 |
+
@lru_cache(maxsize=1)
|
| 27 |
+
def get_llm():
|
| 28 |
+
from transformers import pipeline
|
| 29 |
+
# keep it light; GPT-2 works on CPU
|
| 30 |
+
return pipeline("text-generation", model="gpt2", max_new_tokens=80)
|
|
|
|
| 31 |
|
| 32 |
+
# ------------------------ Functions per approach ------------------------
|
| 33 |
+
def rule_based(text: str) -> str:
|
| 34 |
+
if re.search(r"\banae?mia\b", text, flags=re.IGNORECASE):
|
| 35 |
+
return "Anaemia detected (keyword match)"
|
| 36 |
+
return "Anaemia not detected (no keyword match)"
|
| 37 |
|
| 38 |
+
def ml_based(text: str) -> str:
|
| 39 |
+
# load lazily (first call)
|
| 40 |
+
from sentence_transformers import util
|
| 41 |
+
embedder = get_embedder()
|
| 42 |
+
ref_emb = get_ref_emb()
|
| 43 |
emb = embedder.encode(text, convert_to_tensor=True)
|
| 44 |
+
score = float(util.cos_sim(emb, ref_emb).item())
|
| 45 |
+
verdict = "Anaemia likely" if score > 0.45 else "Anaemia unlikely"
|
| 46 |
+
return f"Similarity: {score:.2f}\n{verdict}"
|
| 47 |
+
|
| 48 |
+
def ai_based(text: str) -> str:
|
| 49 |
+
llm = get_llm()
|
| 50 |
+
prompt = (
|
| 51 |
+
"Determine if the following clinical note suggests anaemia. "
|
| 52 |
+
"Answer clearly in one short paragraph with reasoning.\n\n"
|
| 53 |
+
f"{text}\n"
|
| 54 |
+
)
|
| 55 |
+
out = llm(prompt)[0]["generated_text"]
|
| 56 |
+
return out
|
| 57 |
+
|
| 58 |
+
# ----------------------------- UI -----------------------------
|
| 59 |
+
def build_ui():
|
| 60 |
+
with gr.Blocks(title="RB vs ML vs AI — Anaemia Demo", theme=gr.themes.Soft()) as demo:
|
| 61 |
+
gr.Markdown("## Clinical Text Understanding — Three Approaches")
|
| 62 |
+
with gr.Row():
|
| 63 |
+
default_note = "The patient presents with fatigue and very low haemoglobin."
|
| 64 |
+
input_box = gr.Textbox(value=default_note, label="Clinical note", lines=4)
|
| 65 |
|
| 66 |
+
with gr.Tabs():
|
| 67 |
+
with gr.Tab("Rule-Based"):
|
| 68 |
+
rb_btn = gr.Button("Run Rule-Based")
|
| 69 |
+
rb_out = gr.Textbox(label="Result", lines=3)
|
| 70 |
+
rb_btn.click(fn=rule_based, inputs=input_box, outputs=rb_out)
|
| 71 |
|
| 72 |
+
with gr.Tab("Machine Learning (Embeddings)"):
|
| 73 |
+
ml_btn = gr.Button("Run ML")
|
| 74 |
+
ml_out = gr.Textbox(label="Result", lines=4)
|
| 75 |
+
ml_btn.click(fn=ml_based, inputs=input_box, outputs=ml_out)
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
+
with gr.Tab("AI / Foundation Model"):
|
| 78 |
+
ai_btn = gr.Button("Run AI")
|
| 79 |
+
ai_out = gr.Textbox(label="Result", lines=8)
|
| 80 |
+
ai_btn.click(fn=ai_based, inputs=input_box, outputs=ai_out)
|
| 81 |
|
| 82 |
+
gr.Markdown(
|
| 83 |
+
"Notes: models are loaded lazily on first run to keep the UI responsive in Spaces."
|
| 84 |
+
)
|
| 85 |
+
return demo
|
| 86 |
|
| 87 |
+
demo = build_ui()
|
| 88 |
|
| 89 |
+
# Queue + launch: SSR off is important for Spaces that show a blank/broken view.
|
| 90 |
+
demo.queue(concurrency_count=1, max_size=10).launch(
|
| 91 |
+
server_name="0.0.0.0",
|
| 92 |
+
server_port=7860,
|
| 93 |
+
ssr_mode=False,
|
| 94 |
+
show_error=True,
|
| 95 |
+
inbrowser=False,
|
| 96 |
+
share=False,
|
| 97 |
+
)
|