Milad96 commited on
Commit
dce8a1b
·
verified ·
1 Parent(s): fd1b6ae

[BIOBERT-FTM] Add/Update Space files (2025-10-17T20:54:49.835623+00:00)

Browse files
Files changed (4) hide show
  1. README.md +17 -6
  2. app.py +129 -0
  3. requirements.txt +6 -0
  4. space_env_hints.json +5 -0
README.md CHANGED
@@ -1,12 +1,23 @@
1
  ---
2
- title: BIOBERT FTM Demo
3
- emoji: 🏢
4
- colorFrom: yellow
5
- colorTo: pink
6
  sdk: gradio
7
- sdk_version: 5.49.1
 
8
  app_file: app.py
9
  pinned: false
 
 
 
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
1
  ---
2
+ title: BIOBERT-FTM Demo
3
+ emoji: 🧬
4
+ colorFrom: green
5
+ colorTo: blue
6
  sdk: gradio
7
+ sdk_version: 4.44.0
8
+ python_version: 3.10
9
  app_file: app.py
10
  pinned: false
11
+ license: apache-2.0
12
+ models:
13
+ - Milad96/BIOBERT-FTM-mlm
14
+ - Milad96/BIOBERT-FTM-tasks
15
  ---
16
 
17
+ # BIOBERT-FTM — Gradio Space
18
+
19
+ Interactive demo for **Fill‑Mask (MLM)** and **Bio‑NER (genes)** powered by:
20
+ - Tokenizer/MLM: `Milad96/BIOBERT-FTM-mlm`
21
+ - NER model: `Milad96/BIOBERT-FTM-tasks/ner-spyysalo_bc2gm_corpus`
22
+
23
+ > Tip: GPU is optional but recommended. This Space reads public model weights from the Hub.
app.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # BIOBERT-FTM — Gradio Space App
2
+ import os, json
3
+ import torch
4
+ import gradio as gr
5
+ from transformers import AutoTokenizer, AutoConfig, AutoModelForTokenClassification, pipeline
6
+
7
+ # ---- Model sources (override via Space Secrets or env) ----
8
+ TOKENIZER_REPO = os.getenv("MLM_MODEL_REPO_ID", "Milad96/BIOBERT-FTM-mlm")
9
+ TASK_MODEL_REPO = os.getenv("TASK_MODEL_REPO_ID", "Milad96/BIOBERT-FTM-tasks")
10
+ NER_SUBFOLDER = os.getenv("NER_SUBFOLDER", "ner-spyysalo_bc2gm_corpus")
11
+
12
+ DEVICE = 0 if torch.cuda.is_available() else -1
13
+
14
+ tokenizer = AutoTokenizer.from_pretrained(TOKENIZER_REPO, use_fast=True)
15
+ config = AutoConfig.from_pretrained(TASK_MODEL_REPO, subfolder=NER_SUBFOLDER)
16
+ model = AutoModelForTokenClassification.from_pretrained(
17
+ TASK_MODEL_REPO, subfolder=NER_SUBFOLDER, torch_dtype=torch.float32
18
+ )
19
+
20
+ ner = pipeline(
21
+ "token-classification",
22
+ model=model,
23
+ tokenizer=tokenizer,
24
+ device=DEVICE,
25
+ aggregation_strategy="simple"
26
+ )
27
+
28
+ fill_mask = pipeline(
29
+ "fill-mask",
30
+ model=TOKENIZER_REPO,
31
+ tokenizer=TOKENIZER_REPO,
32
+ device=DEVICE
33
+ )
34
+
35
+ EXAMPLE_TEXTS = [
36
+ "Mutations in BRCA1 and TP53 are frequently reported in breast cancer.",
37
+ "The expression of EGFR and KRAS was quantified by qPCR.",
38
+ "BRCA2 interacts with RAD51 during homologous recombination.",
39
+ ]
40
+
41
+ MASK_EXAMPLES = [
42
+ "SARS-CoV-2 infects [MASK] epithelial cells in the respiratory tract.",
43
+ "Dexamethasone is commonly used to treat [MASK] inflammation.",
44
+ ]
45
+
46
+ def run_fill_mask(text: str, topk: int = 5):
47
+ if not text or "[MASK]" not in text:
48
+ return "Input must contain [MASK] token.", f"Device: {'cuda' if DEVICE==0 else 'cpu'}"
49
+ try:
50
+ res = fill_mask(text, top_k=int(topk))
51
+ if isinstance(res, dict): # older transformers may return dict for top_k=1
52
+ res = [res]
53
+ lines = []
54
+ for p in res:
55
+ seq = p.get("sequence", "")
56
+ score = float(p.get("score", 0.0))
57
+ lines.append(f"→ {seq} (score={score:.4f})")
58
+ return "\n".join(lines), f"Device: {'cuda' if DEVICE==0 else 'cpu'}"
59
+ except Exception as e:
60
+ return f"⚠️ Error: {e}", f"Device: {'cuda' if DEVICE==0 else 'cpu'}"
61
+
62
+
63
+ def run_ner(text: str, score_threshold: float = 0.50):
64
+ if not text:
65
+ return "", "[]"
66
+ try:
67
+ preds = ner(text)
68
+ if not isinstance(preds, list):
69
+ preds = []
70
+ spans = []
71
+ for s in preds:
72
+ try:
73
+ sc = float(s.get("score", 0.0))
74
+ if sc < float(score_threshold):
75
+ continue
76
+ start = int(s.get("start", 0))
77
+ end = int(s.get("end", 0))
78
+ spans.append({
79
+ "entity": s.get("entity_group") or s.get("entity") or "",
80
+ "start": start,
81
+ "end": end,
82
+ "text": text[start:end],
83
+ "score": sc
84
+ })
85
+ except Exception:
86
+ # Skip any malformed span safely
87
+ continue
88
+ # Markdown summary
89
+ if spans:
90
+ lines = [f"Found {len(spans)} spans:"]
91
+ for sp in spans:
92
+ lines.append(
93
+ f"- [{sp['entity']}] {sp['text']} (start={sp['start']}, end={sp['end']}, score={sp['score']:.4f})"
94
+ )
95
+ md = "\n".join(lines)
96
+ else:
97
+ md = "No spans above threshold."
98
+ return md, json.dumps(spans, ensure_ascii=False, indent=2)
99
+ except Exception as e:
100
+ return f"⚠️ Error: {e}", "[]"
101
+
102
+ with gr.Blocks(title="BIOBERT-FTM Demo", theme=gr.themes.Default()) as demo:
103
+ gr.Markdown("""
104
+ # 🧬 BIOBERT-FTM — Demo
105
+ **Fill‑Mask** (MLM) and **Bio‑NER** (Gene) demo powered by your fine‑tuned checkpoints.
106
+ """)
107
+
108
+ with gr.Tabs():
109
+ with gr.TabItem("Fill-Mask"):
110
+ inp_mask = gr.Textbox(label="Input (must contain [MASK])", value=MASK_EXAMPLES[0])
111
+ topk = gr.Slider(1, 10, value=5, step=1, label="Top‑K")
112
+ btn = gr.Button("Run Fill-Mask")
113
+ out_txt = gr.Textbox(label="Predictions", lines=6)
114
+ out_meta = gr.Textbox(label="Meta")
115
+ btn.click(run_fill_mask, inputs=[inp_mask, topk], outputs=[out_txt, out_meta])
116
+ gr.Examples(MASK_EXAMPLES, inputs=[inp_mask])
117
+
118
+ with gr.TabItem("NER (Genes)"):
119
+ inp = gr.Textbox(label="Input text", value=EXAMPLE_TEXTS[0])
120
+ thr = gr.Slider(0, 1, value=0.50, step=0.01, label="Score threshold")
121
+ go = gr.Button("Run NER")
122
+ out_md = gr.Markdown()
123
+ out_json = gr.JSON()
124
+ go.click(run_ner, inputs=[inp, thr], outputs=[out_md, out_json])
125
+ gr.Examples(EXAMPLE_TEXTS, inputs=[inp])
126
+
127
+ if __name__ == "__main__":
128
+ # When running inside Spaces, just `python app.py` is enough.
129
+ demo.queue().launch()
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ transformers==4.57.1
2
+ torch>=2.3
3
+ accelerate>=0.28.0
4
+ gradio>=4.29.0,<5
5
+ huggingface_hub>=0.23.0
6
+ numpy
space_env_hints.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "MLM_MODEL_REPO_ID": "Milad96/BIOBERT-FTM-mlm",
3
+ "TASK_MODEL_REPO_ID": "Milad96/BIOBERT-FTM-tasks",
4
+ "NER_SUBFOLDER": "ner-spyysalo_bc2gm_corpus"
5
+ }