multimodalart HF Staff commited on
Commit
25f27da
·
verified ·
1 Parent(s): c714e3b

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. README.md +30 -7
  2. app.py +186 -0
  3. requirements.txt +2 -0
README.md CHANGED
@@ -1,13 +1,36 @@
1
  ---
2
- title: Cliniguard Diagnosis Icd Ner
3
- emoji: 📈
4
  colorFrom: blue
5
- colorTo: blue
6
  sdk: gradio
7
- sdk_version: 6.20.0
8
- python_version: '3.12'
9
  app_file: app.py
10
- pinned: false
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: CliniGuard Diagnosis ICD NER
3
+ emoji: 🏥
4
  colorFrom: blue
5
+ colorTo: green
6
  sdk: gradio
7
+ sdk_version: 6.15.1
 
8
  app_file: app.py
9
+ short_description: PubMedBERT clinical diagnosis entity extraction NER
10
+ python_version: "3.12"
11
+ startup_duration_timeout: 30m
12
  ---
13
 
14
+ # CliniGuard Diagnosis ICD NER
15
+
16
+ Interactive demo for [genzeonplatform/cliniguard-diagnosis-icd-ner](https://huggingface.co/genzeonplatform/cliniguard-diagnosis-icd-ner),
17
+ a transformer-based clinical Named Entity Recognition model built on **PubMedBERT** (`BertForTokenClassification`)
18
+ for automated extraction of diagnoses, conditions, and coding-support entities from unstructured clinical text.
19
+
20
+ The model recognizes **9 diagnosis and coding entity types** (19 BIO labels):
21
+
22
+ | Entity | Description |
23
+ |--------|-------------|
24
+ | `PRIMARY_DIAGNOSIS` | Principal reason for encounter |
25
+ | `SECONDARY_DIAGNOSIS` | Additional diagnoses |
26
+ | `DIFFERENTIAL_DIAGNOSIS` | Diagnoses under consideration |
27
+ | `COMORBIDITY` | Co-existing conditions |
28
+ | `COMPLICATION` | Hospital-acquired or treatment complications |
29
+ | `CHRONIC_CONDITION` | Long-term conditions |
30
+ | `ACUTE_CONDITION` | Acute episodes or events |
31
+ | `DIAGNOSIS_STATUS` | Current clinical status (active, resolved, improving) |
32
+ | `DIAGNOSIS_DATE` | Date of diagnosis or onset |
33
+
34
+ Enter clinical text (discharge summaries, progress notes, clinical narratives) and the model will
35
+ highlight and structure the recognized diagnosis entities using the standard HuggingFace
36
+ `token-classification` pipeline with `aggregation_strategy="simple"`.
app.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import spaces # MUST be first — ZeroGPU patches torch.cuda before transformers imports torch
2
+ import torch
3
+ import gradio as gr
4
+ import json
5
+ from transformers import pipeline as hf_pipeline
6
+
7
+ MODEL_ID = "genzeonplatform/cliniguard-diagnosis-icd-ner"
8
+
9
+ # Entity type -> human-readable description (9 diagnosis/coding categories)
10
+ ENTITY_INFO = {
11
+ "PRIMARY_DIAGNOSIS": "Principal reason for encounter",
12
+ "SECONDARY_DIAGNOSIS": "Additional diagnoses",
13
+ "DIFFERENTIAL_DIAGNOSIS": "Diagnoses under consideration",
14
+ "COMORBIDITY": "Co-existing conditions",
15
+ "COMPLICATION": "Hospital-acquired or treatment complications",
16
+ "CHRONIC_CONDITION": "Long-term conditions",
17
+ "ACUTE_CONDITION": "Acute episodes or events",
18
+ "DIAGNOSIS_STATUS": "Current clinical status (active, resolved, improving)",
19
+ "DIAGNOSIS_DATE": "Date of diagnosis or onset",
20
+ }
21
+
22
+ # Color map for HighlightedText (9 distinct colors)
23
+ COLOR_MAP = {
24
+ "PRIMARY_DIAGNOSIS": "#ef4444",
25
+ "SECONDARY_DIAGNOSIS": "#f97316",
26
+ "DIFFERENTIAL_DIAGNOSIS": "#eab308",
27
+ "COMORBIDITY": "#22c55e",
28
+ "COMPLICATION": "#3b82f6",
29
+ "CHRONIC_CONDITION": "#a855f7",
30
+ "ACUTE_CONDITION": "#ec4899",
31
+ "DIAGNOSIS_STATUS": "#14b8a6",
32
+ "DIAGNOSIS_DATE": "#6b7280",
33
+ }
34
+
35
+ # Load the token-classification pipeline at module scope.
36
+ # aggregation_strategy="simple" merges B-/I- subword tokens into full entity spans,
37
+ # exactly as documented in the model card.
38
+ nlp = hf_pipeline(
39
+ "token-classification",
40
+ model=MODEL_ID,
41
+ aggregation_strategy="simple",
42
+ )
43
+ # Move the underlying model to CUDA eagerly (ZeroGPU hijack intercepts this).
44
+ nlp.model.to("cuda")
45
+
46
+
47
+ @spaces.GPU(duration=60)
48
+ def extract_entities(text: str):
49
+ """Extract diagnosis entities from unstructured clinical text.
50
+
51
+ Recognizes 9 diagnosis/coding entity types: PRIMARY_DIAGNOSIS,
52
+ SECONDARY_DIAGNOSIS, DIFFERENTIAL_DIAGNOSIS, COMORBIDITY, COMPLICATION,
53
+ CHRONIC_CONDITION, ACUTE_CONDITION, DIAGNOSIS_STATUS, and DIAGNOSIS_DATE.
54
+
55
+ Args:
56
+ text: Clinical text to analyze (discharge summaries, progress notes, etc.)
57
+
58
+ Returns:
59
+ A tuple of (highlighted_text, structured_json, entity_summary_table).
60
+ """
61
+ # Run inference; pipeline handles tokenization + aggregation
62
+ raw_entities = nlp(text)
63
+
64
+ # Build HighlightedText format: {"text": ..., "entities": [{"start","end","entity"}]}
65
+ entities = [
66
+ {
67
+ "start": ent["start"],
68
+ "end": ent["end"],
69
+ "entity": ent["entity_group"],
70
+ }
71
+ for ent in raw_entities
72
+ ]
73
+ highlighted = {"text": text, "entities": entities}
74
+
75
+ # Build structured JSON output
76
+ structured = [
77
+ {
78
+ "text": ent["word"],
79
+ "type": ent["entity_group"],
80
+ "description": ENTITY_INFO.get(ent["entity_group"], ""),
81
+ "score": round(float(ent["score"]), 4),
82
+ "start": ent["start"],
83
+ "end": ent["end"],
84
+ }
85
+ for ent in raw_entities
86
+ ]
87
+
88
+ # Build entity summary table (type, count, examples, description)
89
+ summary = {}
90
+ for ent in raw_entities:
91
+ label = ent["entity_group"]
92
+ if label not in summary:
93
+ summary[label] = []
94
+ summary[label].append(ent["word"])
95
+
96
+ table_data = []
97
+ for label, mentions in sorted(summary.items()):
98
+ table_data.append([
99
+ label,
100
+ len(mentions),
101
+ ", ".join(mentions[:5]) + ("..." if len(mentions) > 5 else ""),
102
+ ENTITY_INFO.get(label, ""),
103
+ ])
104
+
105
+ return highlighted, json.dumps(structured, indent=2), table_data
106
+
107
+
108
+ # --- Gradio UI ---
109
+
110
+ CSS = """
111
+ #col-container { max-width: 1100px; margin: 0 auto; }
112
+ .dark .gradio-container { color: var(--body-text-color); }
113
+ """
114
+
115
+ EXAMPLES = [
116
+ ["Discharge Diagnosis: Primary: acute myocardial infarction. "
117
+ "Secondary: type 2 diabetes mellitus, essential hypertension. "
118
+ "Status: improving. Complication: acute kidney injury."],
119
+ ["Patient admitted with community-acquired pneumonia. "
120
+ "PMH: COPD, coronary artery disease, hyperlipidemia. "
121
+ "Differential: pulmonary embolism vs pneumonia. Status: suspected. Date: 03/15/2024."],
122
+ ["Assessment: sepsis is worsening with acute respiratory failure. "
123
+ "Chronic conditions include type 2 diabetes and chronic kidney disease stage 3. "
124
+ "Comorbidity: obesity. Complication: hospital-acquired pneumonia."],
125
+ ["Principal Dx: congestive heart failure with acute respiratory failure. "
126
+ "Secondary: atrial fibrillation, chronic kidney disease. "
127
+ "Status: active. Date of onset: 01/20/2024."],
128
+ ]
129
+
130
+ with gr.Blocks(theme=gr.themes.Citrus(), css=CSS) as demo:
131
+ gr.Markdown(
132
+ """
133
+ # 🏥 CliniGuard Diagnosis ICD NER
134
+
135
+ Extract diagnosis entities — primary/secondary/differential diagnoses, comorbidities,
136
+ complications, chronic/acute conditions, status, and dates — from unstructured clinical text
137
+ using a **PubMedBERT**-based token-classification model
138
+ ([genzeonplatform/cliniguard-diagnosis-icd-ner](https://huggingface.co/genzeonplatform/cliniguard-diagnosis-icd-ner)).
139
+ """
140
+ )
141
+
142
+ with gr.Column(elem_id="col-container"):
143
+ with gr.Row():
144
+ input_text = gr.Textbox(
145
+ label="Clinical Text",
146
+ placeholder="Enter clinical text (discharge summaries, progress notes, clinical narratives)...",
147
+ lines=8,
148
+ scale=4,
149
+ )
150
+ run_btn = gr.Button("Extract Entities", variant="primary", scale=1)
151
+
152
+ highlighted_output = gr.HighlightedText(
153
+ label="Annotated Clinical Text",
154
+ combine_adjacent=True,
155
+ show_legend=True,
156
+ color_map=COLOR_MAP,
157
+ )
158
+
159
+ with gr.Accordion("Structured Output", open=False):
160
+ json_output = gr.JSON(label="Extracted Entities (JSON)")
161
+
162
+ entity_table = gr.Dataframe(
163
+ headers=["Entity Type", "Count", "Examples", "Description"],
164
+ label="Entity Summary",
165
+ interactive=False,
166
+ wrap=True,
167
+ )
168
+
169
+ gr.Examples(
170
+ examples=EXAMPLES,
171
+ inputs=[input_text],
172
+ outputs=[highlighted_output, json_output, entity_table],
173
+ fn=extract_entities,
174
+ cache_examples=True,
175
+ cache_mode="lazy",
176
+ )
177
+
178
+ run_btn.click(
179
+ fn=extract_entities,
180
+ inputs=[input_text],
181
+ outputs=[highlighted_output, json_output, entity_table],
182
+ api_name="extract_entities",
183
+ )
184
+
185
+ if __name__ == "__main__":
186
+ demo.launch(mcp_server=True)
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ transformers
2
+ torch