Vaibhavi53 commited on
Commit
a46b965
Β·
verified Β·
1 Parent(s): d324d15

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +225 -143
src/streamlit_app.py CHANGED
@@ -1,156 +1,238 @@
 
 
 
1
  import streamlit as st
2
- import pandas as pd
3
- import numpy as np
4
- import joblib
5
- from scipy.special import softmax
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
- # ── Load Models ─────────────────────────────────────
8
- @st.cache_resource
9
- def load_models():
10
- svm = joblib.load("tfidf_svm_pipeline.joblib")
11
- label_map = joblib.load("label_to_code.joblib")
12
 
13
- # Import torch-based models safely
14
- try:
15
- from utils.models import predict_b2, predict_longformer
16
- TORCH_OK = True
17
- except Exception as e:
18
- TORCH_OK = False
19
- predict_b2 = None
20
- predict_longformer = None
21
-
22
- return svm, label_map, predict_b2, predict_longformer, TORCH_OK
23
-
24
-
25
- svm, label_map, predict_b2, predict_longformer, TORCH_OK = load_models()
26
 
27
- # ── SVM Prediction ───────────────────────────────────
28
- def predict_svm(text):
29
- scores = svm.decision_function([text])[0]
30
- probs = softmax(scores)
31
- pred = int(np.argmax(probs))
32
- return pred, probs
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
- # ── UI ──────────────────────────────────────────────
36
- st.title("πŸ₯ ICD-10 Model Comparison System")
37
 
38
  # ═══════════════════════════════════════════════════
39
- # πŸ”¬ SINGLE INPUT
40
  # ═══════════════════════════════════════════════════
41
- st.markdown("## πŸ”¬ Single Clinical Note")
42
-
43
- text_input = st.text_area("Enter clinical note")
44
-
45
- if st.button("Run Prediction"):
46
-
47
- if not text_input.strip():
48
- st.warning("Enter text first")
49
- else:
50
- # SVM
51
- svm_pred, _ = predict_svm(text_input)
52
- svm_code = label_map[svm_pred]
53
-
54
- # BERT
55
- if TORCH_OK:
56
- try:
57
- bert_pred, _ = predict_b2(text_input)
58
- bert_code = label_map[bert_pred]
59
- except:
60
- bert_code = "ERROR"
61
- else:
62
- bert_code = "NOT AVAILABLE"
63
-
64
- # Longformer
65
- if TORCH_OK:
66
- try:
67
- long_pred, _ = predict_longformer(text_input)
68
- long_code = label_map[long_pred]
69
- except:
70
- long_code = "ERROR"
71
- else:
72
- long_code = "NOT AVAILABLE"
73
-
74
- # Display
75
- st.markdown("### 🎯 Predictions")
76
- st.write(f"SVM β†’ {svm_code}")
77
- st.write(f"ClinicalBERT β†’ {bert_code}")
78
- st.write(f"Longformer β†’ {long_code}")
79
-
80
- # AGREEMENT
81
- codes = [svm_code, bert_code, long_code]
82
- valid_codes = [c for c in codes if c not in ["ERROR", "NOT AVAILABLE"]]
83
-
84
- if len(set(valid_codes)) == 1:
85
- st.success("βœ… All models agree")
86
- elif len(set(valid_codes)) == 2:
87
- st.warning("⚠️ Partial agreement")
88
- else:
89
- st.error("❌ No agreement")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
 
92
  # ═══════════════════════════════════════════════════
93
- # πŸ“‚ CSV BATCH MODE
94
  # ═══════════════════════════════════════════════════
95
- st.markdown("## πŸ“‚ Batch Testing (CSV)")
96
-
97
- uploaded_file = st.file_uploader("Upload CSV", type=["csv"])
98
-
99
- if uploaded_file:
100
- df = pd.read_csv(uploaded_file)
101
-
102
- if "text" not in df.columns:
103
- st.error("CSV must contain 'text' column")
104
- else:
105
- results = []
106
-
107
- for text in df["text"].astype(str):
108
-
109
- # SVM
110
- svm_pred, _ = predict_svm(text)
111
- svm_code = label_map[svm_pred]
112
-
113
- # BERT
114
- if TORCH_OK:
115
- try:
116
- bert_pred, _ = predict_b2(text)
117
- bert_code = label_map[bert_pred]
118
- except:
119
- bert_code = "ERR"
120
- else:
121
- bert_code = "NA"
122
-
123
- # Longformer
124
- if TORCH_OK:
125
- try:
126
- long_pred, _ = predict_longformer(text)
127
- long_code = label_map[long_pred]
128
- except:
129
- long_code = "ERR"
130
- else:
131
- long_code = "NA"
132
-
133
- # Agreement
134
- codes = [svm_code, bert_code, long_code]
135
- valid = [c for c in codes if c not in ["ERR", "NA"]]
136
- agree = len(set(valid)) == 1
137
-
138
- results.append({
139
- "text": text[:80],
140
- "svm": svm_code,
141
- "bert": bert_code,
142
- "longformer": long_code,
143
- "agree": agree
144
- })
145
-
146
- res_df = pd.DataFrame(results)
147
-
148
- st.dataframe(res_df)
149
-
150
- # Metrics
151
- agreement_rate = res_df["agree"].mean() * 100
152
- st.markdown(f"### πŸ“Š Agreement Rate: {agreement_rate:.2f}%")
153
-
154
- # Download
155
- csv = res_df.to_csv(index=False).encode('utf-8')
156
- st.download_button("Download Results", csv, "results.csv", "text/csv")
 
 
 
 
 
1
+ """
2
+ 🏠 ICD-10 Automated Clinical Coding System β€” Dashboard
3
+ """
4
  import streamlit as st
5
+ import os
6
+
7
+ # ── Page Config ──
8
+ st.set_page_config(
9
+ page_title="ICD-10 AutoCoder",
10
+ page_icon="πŸ₯",
11
+ layout="wide",
12
+ initial_sidebar_state="expanded",
13
+ )
14
+
15
+ # ── Load CSS ──
16
+ css_path = os.path.join(os.path.dirname(__file__), "assets", "style.css")
17
+ if os.path.exists(css_path):
18
+ with open(css_path, encoding="utf-8") as f:
19
+ st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True)
20
+
21
+ from utils.config import DATASET_STATS, TOP_20_CODES
22
+
23
+ # ── Sidebar ──
24
+ with st.sidebar:
25
+ st.markdown("## πŸ₯ ICD-10 AutoCoder")
26
+ st.markdown("---")
27
+ st.markdown("""
28
+ **Navigation**
29
+ - 🏠 Dashboard (this page)
30
+ - πŸ”¬ Live ICD Coding
31
+ - πŸ“Š Model Comparison
32
+ - πŸ“– ICD-10 Browser
33
+ - πŸ“ˆ Dataset Explorer
34
+ - πŸ“‚ Batch Prediction
35
+ - βš™οΈ About
36
+ """)
37
+ st.markdown("---")
38
+ st.markdown(
39
+ '<p style="color: #64748b; font-size: 0.75rem;">'
40
+ 'Built for clinical NLP research<br>'
41
+ 'RTX 4050 Β· 6GB VRAM Β· LoRA</p>',
42
+ unsafe_allow_html=True
43
+ )
44
 
 
 
 
 
 
45
 
46
+ # ═══════════════════════════════════════════════════
47
+ # HERO SECTION
48
+ # ═══════════════════════════════════════════════════
49
+ st.markdown("""
50
+ <div class="hero-container">
51
+ <div class="hero-title">ICD-10 Automated Clinical Coding</div>
52
+ <div class="hero-subtitle">
53
+ A hierarchical retrieval and biomedical re-ranking system for automated
54
+ ICD-10 diagnosis code assignment from clinical discharge notes.
55
+ Bilingual output (English + Traditional Chinese) across 2,863 codes.
56
+ </div>
57
+ </div>
58
+ """, unsafe_allow_html=True)
59
 
 
 
 
 
 
 
60
 
61
+ # ═══════════════════════════════════════════════════
62
+ # STAT CARDS
63
+ # ═══════════════════════════════════════════════════
64
+ st.markdown('<div class="section-header"><div class="section-accent"></div>Project at a Glance</div>',
65
+ unsafe_allow_html=True)
66
+
67
+ c1, c2, c3, c4 = st.columns(4)
68
+
69
+ with c1:
70
+ st.markdown(f"""
71
+ <div class="stat-card">
72
+ <div class="stat-number">{DATASET_STATS['raw_records']:,}</div>
73
+ <div class="stat-label">Clinical Records</div>
74
+ </div>
75
+ """, unsafe_allow_html=True)
76
+
77
+ with c2:
78
+ st.markdown(f"""
79
+ <div class="stat-card">
80
+ <div class="stat-number">{DATASET_STATS['unique_encounters']:,}</div>
81
+ <div class="stat-label">Patient Encounters</div>
82
+ </div>
83
+ """, unsafe_allow_html=True)
84
+
85
+ with c3:
86
+ st.markdown(f"""
87
+ <div class="stat-card">
88
+ <div class="stat-number">{DATASET_STATS['unique_codes']:,}</div>
89
+ <div class="stat-label">ICD-10 Codes</div>
90
+ </div>
91
+ """, unsafe_allow_html=True)
92
+
93
+ with c4:
94
+ st.markdown("""
95
+ <div class="stat-card">
96
+ <div class="stat-number">4</div>
97
+ <div class="stat-label">Trained Models</div>
98
+ </div>
99
+ """, unsafe_allow_html=True)
100
 
 
 
101
 
102
  # ═══════════════════════════════════════════════════
103
+ # ARCHITECTURE PIPELINE
104
  # ═══════════════════════════════════════════════════
105
+ st.markdown("")
106
+ st.markdown('<div class="section-header"><div class="section-accent"></div>Three-Layer Pipeline Architecture</div>',
107
+ unsafe_allow_html=True)
108
+
109
+ col_l, col_r = st.columns([3, 2])
110
+
111
+ with col_l:
112
+ st.markdown("""
113
+ <div class="pipeline-step">
114
+ <span class="badge badge-teal">LAYER 1</span>
115
+ <div style="margin-top:0.5rem; font-size:1.05rem; font-weight:600; color:#e8ecf4;">
116
+ Hierarchical TF-IDF Retriever
117
+ </div>
118
+ <div style="font-size:0.85rem; color:#94a3b8; margin-top:0.3rem;">
119
+ Chapter β†’ Category β†’ Full code scoring<br>
120
+ Reduces 2,863 codes β†’ top-100 candidates
121
+ </div>
122
+ </div>
123
+ <div class="pipeline-arrow">β–Ό</div>
124
+ <div class="pipeline-step">
125
+ <span class="badge badge-blue">LAYER 2</span>
126
+ <div style="margin-top:0.5rem; font-size:1.05rem; font-weight:600; color:#e8ecf4;">
127
+ ClinicalBERT Re-Ranker (LoRA)
128
+ </div>
129
+ <div style="font-size:0.85rem; color:#94a3b8; margin-top:0.3rem;">
130
+ Pairwise relevance scoring: (note, ICD description) β†’ score<br>
131
+ 92.5% pairwise F1 accuracy
132
+ </div>
133
+ </div>
134
+ <div class="pipeline-arrow">β–Ό</div>
135
+ <div class="pipeline-step">
136
+ <span class="badge badge-purple">LAYER 3</span>
137
+ <div style="margin-top:0.5rem; font-size:1.05rem; font-weight:600; color:#e8ecf4;">
138
+ Bilingual Prediction Output
139
+ </div>
140
+ <div style="font-size:0.85rem; color:#94a3b8; margin-top:0.3rem;">
141
+ Ranked ICD codes with confidence scores<br>
142
+ English + Traditional Chinese descriptions
143
+ </div>
144
+ </div>
145
+ """, unsafe_allow_html=True)
146
+
147
+ with col_r:
148
+ st.markdown("""
149
+ <div class="model-card" style="margin-bottom:1rem;">
150
+ <div class="model-card-label">BEST BASELINE</div>
151
+ <div class="model-card-title">TF-IDF + LinearSVC</div>
152
+ <div class="model-card-metric">0.516</div>
153
+ <div class="model-card-label">Micro-F1 (Top-100)</div>
154
+ </div>
155
+ <div class="model-card" style="margin-bottom:1rem;">
156
+ <div class="model-card-label">BEST TRANSFORMER</div>
157
+ <div class="model-card-title">ClinicalBERT (LoRA)</div>
158
+ <div class="model-card-metric">0.397</div>
159
+ <div class="model-card-label">Micro-F1 (Full 2,863)</div>
160
+ </div>
161
+ <div class="model-card">
162
+ <div class="model-card-label">PROPOSED PIPELINE</div>
163
+ <div class="model-card-title">Hierarchical Re-Ranker</div>
164
+ <div class="model-card-metric">0.925</div>
165
+ <div class="model-card-label">Pairwise Re-ranking F1</div>
166
+ </div>
167
+ """, unsafe_allow_html=True)
168
 
169
 
170
  # ═══════════════════════════════════════════════════
171
+ # QUICK ACCESS
172
  # ═══════════════════════════════════════════════════
173
+ st.markdown("")
174
+ st.markdown('<div class="section-header"><div class="section-accent"></div>Quick Access</div>',
175
+ unsafe_allow_html=True)
176
+
177
+ qa1, qa2, qa3, qa4 = st.columns(4)
178
+
179
+ with qa1:
180
+ st.markdown("""
181
+ <div class="stat-card">
182
+ <div style="font-size:2rem;">πŸ”¬</div>
183
+ <div style="font-size:1.05rem; font-weight:600; color:#e8ecf4; margin-top:0.5rem;">
184
+ Live ICD Coding
185
+ </div>
186
+ <div style="font-size:0.8rem; color:#94a3b8; margin-top:0.3rem;">
187
+ Paste a clinical note and get instant ICD-10 predictions
188
+ </div>
189
+ </div>
190
+ """, unsafe_allow_html=True)
191
+
192
+ with qa2:
193
+ st.markdown("""
194
+ <div class="stat-card">
195
+ <div style="font-size:2rem;">πŸ“Š</div>
196
+ <div style="font-size:1.05rem; font-weight:600; color:#e8ecf4; margin-top:0.5rem;">
197
+ Model Comparison
198
+ </div>
199
+ <div style="font-size:0.8rem; color:#94a3b8; margin-top:0.3rem;">
200
+ Compare all 4 models with interactive charts
201
+ </div>
202
+ </div>
203
+ """, unsafe_allow_html=True)
204
+
205
+ with qa3:
206
+ st.markdown("""
207
+ <div class="stat-card">
208
+ <div style="font-size:2rem;">πŸ“–</div>
209
+ <div style="font-size:1.05rem; font-weight:600; color:#e8ecf4; margin-top:0.5rem;">
210
+ ICD-10 Browser
211
+ </div>
212
+ <div style="font-size:0.8rem; color:#94a3b8; margin-top:0.3rem;">
213
+ Search and explore all 2,863 ICD-10 codes
214
+ </div>
215
+ </div>
216
+ """, unsafe_allow_html=True)
217
+
218
+ with qa4:
219
+ st.markdown("""
220
+ <div class="stat-card">
221
+ <div style="font-size:2rem;">πŸ“‚</div>
222
+ <div style="font-size:1.05rem; font-weight:600; color:#e8ecf4; margin-top:0.5rem;">
223
+ Batch Prediction
224
+ </div>
225
+ <div style="font-size:0.8rem; color:#94a3b8; margin-top:0.3rem;">
226
+ Upload CSV files for bulk ICD-10 coding with multi-model comparison
227
+ </div>
228
+ </div>
229
+ """, unsafe_allow_html=True)
230
+
231
+
232
+ # ── Footer ──
233
+ st.markdown("""
234
+ <div class="footer">
235
+ ICD-10 Automated Coding System Β· Biomedical NLP Research Β· 2026<br>
236
+ Built with ClinicalBERT Β· Longformer Β· LoRA Β· PyTorch Β· Streamlit
237
+ </div>
238
+ """, unsafe_allow_html=True)