Distopia22 commited on
Commit
7d58419
·
1 Parent(s): 2101408

Update: Change name, dark cyan sidebar, 3 examples, file upload, GPT-style prompt

Browse files
Files changed (2) hide show
  1. app.py +128 -15
  2. assets/styles.css +80 -25
app.py CHANGED
@@ -61,10 +61,99 @@ def analyze_provider_notes(provider_notes, api_url, progress=gr.Progress()):
61
  except Exception as e:
62
  return f"❌ **Unexpected Error**\n\n{str(e)}"
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  def generate_empty_response():
65
  """Generate empty response message"""
66
  return """
67
- ### 💬 Welcome to ICD-10 & CPT Coding Assistant
68
 
69
  Please enter provider notes in the text box below and click **Send** to analyze.
70
 
@@ -75,9 +164,10 @@ Please enter provider notes in the text box below and click **Send** to analyze.
75
 
76
  **How to use:**
77
  1. Select an example from the sidebar, or
78
- 2. Type your own clinical notes below
79
- 3. Click the **Send** button
80
- 4. Review the ICD-10 and CPT codes generated
 
81
  """
82
 
83
  def format_complete_response(result):
@@ -114,7 +204,7 @@ def format_complete_response(result):
114
 
115
  return output
116
 
117
- # ==================== Example Notes ====================
118
 
119
  EXAMPLES = {
120
  "Acute Bronchitis": """Patient presents with acute bronchitis. Cough for 5 days, productive with yellow sputum. Lung exam reveals diffuse wheezing. Prescribed azithromycin 500mg.""",
@@ -122,10 +212,6 @@ EXAMPLES = {
122
  "Type 2 Diabetes": """Patient with type 2 diabetes mellitus, uncontrolled. HbA1c 9.2%. Discussed diet and medication compliance. Adjusted insulin dosing. Referred to diabetes educator.""",
123
 
124
  "Hypertension Follow-up": """Follow-up visit for hypertension. Blood pressure 145/92. Patient reports good medication compliance. Continue current antihypertensive regimen. Return in 3 months.""",
125
-
126
- "Annual Physical": """Annual physical examination for 45-year-old patient. Comprehensive metabolic panel ordered. Discussed preventive health measures. No acute concerns. Patient in good health.""",
127
-
128
- "Acute Pharyngitis": """Patient with sore throat for 3 days, fever 101.5°F. Physical exam shows erythematous pharynx with exudate. Rapid strep test positive. Prescribed amoxicillin 500mg TID for 10 days.""",
129
  }
130
 
131
  def load_example(example_name):
@@ -146,7 +232,7 @@ def load_css():
146
 
147
  # ==================== Gradio Interface ====================
148
 
149
- with gr.Blocks(css=load_css(), theme=gr.themes.Soft(), title="ICD-10 & CPT Coding Assistant") as demo:
150
 
151
  # Hidden state for API URL
152
  api_url_state = gr.State(value="https://Distopia22-icd-cpt-coding-api.hf.space")
@@ -154,7 +240,7 @@ with gr.Blocks(css=load_css(), theme=gr.themes.Soft(), title="ICD-10 & CPT Codin
154
  # Header
155
  gr.HTML("""
156
  <div class="header-container">
157
- <h1>🏥 ICD-10 & CPT Coding Assistant</h1>
158
  <p>AI-Powered Medical Coding Analysis using Groq LLaMA 3.3 70B</p>
159
  </div>
160
  """)
@@ -166,7 +252,7 @@ with gr.Blocks(css=load_css(), theme=gr.themes.Soft(), title="ICD-10 & CPT Codin
166
  with gr.Column(scale=1, min_width=280, elem_classes="sidebar"):
167
  gr.HTML('<div class="sidebar-title">📚 Example Cases</div>')
168
 
169
- # Example buttons with event handlers
170
  example_buttons = {}
171
  for example_name in EXAMPLES.keys():
172
  btn = gr.Button(
@@ -177,6 +263,25 @@ with gr.Blocks(css=load_css(), theme=gr.themes.Soft(), title="ICD-10 & CPT Codin
177
 
178
  gr.Markdown("---")
179
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  # API Configuration
181
  with gr.Accordion("⚙️ API Configuration", open=False, elem_classes="api-config"):
182
  api_url_input = gr.Textbox(
@@ -199,7 +304,7 @@ with gr.Blocks(css=load_css(), theme=gr.themes.Soft(), title="ICD-10 & CPT Codin
199
  label=""
200
  )
201
 
202
- # Input Area (Prompt Box)
203
  with gr.Group(elem_classes="input-container"):
204
  with gr.Row():
205
  provider_notes_input = gr.Textbox(
@@ -207,7 +312,8 @@ with gr.Blocks(css=load_css(), theme=gr.themes.Soft(), title="ICD-10 & CPT Codin
207
  placeholder="Enter clinical provider notes here...",
208
  lines=3,
209
  max_lines=5,
210
- show_label=False
 
211
  )
212
 
213
  with gr.Row():
@@ -218,7 +324,7 @@ with gr.Blocks(css=load_css(), theme=gr.themes.Soft(), title="ICD-10 & CPT Codin
218
  gr.HTML("""
219
  <div class="footer">
220
  <p>Powered by <strong>Groq LLaMA 3.3 70B</strong> | <strong>FastAPI</strong> | <strong>Gradio</strong></p>
221
- <p>© 2025 ICD-CPT Coding Assistant - Secure & HIPAA Compliant</p>
222
  </div>
223
  """)
224
 
@@ -231,6 +337,13 @@ with gr.Blocks(css=load_css(), theme=gr.themes.Soft(), title="ICD-10 & CPT Codin
231
  outputs=[provider_notes_input]
232
  )
233
 
 
 
 
 
 
 
 
234
  # Send button - Analyze notes
235
  send_btn.click(
236
  fn=analyze_provider_notes,
 
61
  except Exception as e:
62
  return f"❌ **Unexpected Error**\n\n{str(e)}"
63
 
64
+ def upload_file_analysis(file, api_url, progress=gr.Progress()):
65
+ """Upload TXT file to backend API for analysis"""
66
+ if file is None:
67
+ return "⚠️ Please upload a TXT file first."
68
+
69
+ progress(0, desc="Uploading file...")
70
+
71
+ try:
72
+ # Read file content
73
+ file_content = file.read()
74
+
75
+ progress(0.3, desc="Sending file to API...")
76
+
77
+ # Prepare multipart form data
78
+ files = {
79
+ 'file': (file.name, file_content, 'text/plain')
80
+ }
81
+
82
+ response = requests.post(
83
+ f"{api_url}/api/v1/upload-file",
84
+ files=files,
85
+ timeout=60
86
+ )
87
+
88
+ progress(0.6, desc="Processing file...")
89
+
90
+ response.raise_for_status()
91
+ result = response.json()
92
+
93
+ progress(0.9, desc="Formatting results...")
94
+
95
+ # Format file upload response
96
+ formatted_response = format_file_upload_response(result)
97
+
98
+ progress(1.0, desc="Complete!")
99
+
100
+ return formatted_response
101
+
102
+ except requests.exceptions.Timeout:
103
+ return "❌ **Request Timeout**\n\nThe API is taking too long to process the file. Please try again."
104
+ except requests.exceptions.HTTPError as e:
105
+ return f"❌ **HTTP Error {e.response.status_code}**\n\n{e.response.text}"
106
+ except requests.exceptions.RequestException as e:
107
+ return f"❌ **Request Error**\n\n{str(e)}"
108
+ except Exception as e:
109
+ return f"❌ **Unexpected Error**\n\n{str(e)}"
110
+
111
+ def format_file_upload_response(result):
112
+ """Format file upload response"""
113
+ output = "---\n\n"
114
+
115
+ # File info
116
+ output += f"### 📁 File Information\n\n"
117
+ output += f"**Filename:** {result.get('filename', 'N/A')}\n\n"
118
+ output += f"**Text Length:** {result.get('extracted_text_length', 0)} characters\n\n"
119
+
120
+ if result.get('pii_removed'):
121
+ output += f"**PII Removed:** ✅ Yes ({result.get('pii_count', 0)} entities removed)\n\n"
122
+ else:
123
+ output += f"**PII Removed:** ❌ No\n\n"
124
+
125
+ output += "---\n\n"
126
+
127
+ # CPT Codes
128
+ output += "### 💼 CPT Procedure Codes\n\n"
129
+ cpt_codes = result.get("cpt_codes", [])
130
+
131
+ if cpt_codes:
132
+ for idx, code in enumerate(cpt_codes, 1):
133
+ output += f"**{idx}.** `{code}`\n\n"
134
+ output += f"\n**Explanation:** {result.get('cpt_explanation', 'N/A')}\n\n"
135
+ else:
136
+ output += "*No CPT codes identified*\n\n"
137
+
138
+ output += "---\n\n"
139
+
140
+ # ICD Codes
141
+ output += "### 🏥 ICD-10 Diagnostic Codes\n\n"
142
+ icd_codes = result.get("icd_codes", [])
143
+
144
+ if icd_codes:
145
+ for idx, code in enumerate(icd_codes, 1):
146
+ output += f"**{idx}.** `{code}`\n\n"
147
+ output += f"\n**Explanation:** {result.get('icd_explanation', 'N/A')}\n\n"
148
+ else:
149
+ output += "*No ICD-10 codes identified*\n\n"
150
+
151
+ return output
152
+
153
  def generate_empty_response():
154
  """Generate empty response message"""
155
  return """
156
+ ### 💬 Welcome to Medical Coding (ICD-10) Assistant
157
 
158
  Please enter provider notes in the text box below and click **Send** to analyze.
159
 
 
164
 
165
  **How to use:**
166
  1. Select an example from the sidebar, or
167
+ 2. Upload a TXT file with clinical notes, or
168
+ 3. Type your own clinical notes below
169
+ 4. Click the **Send** button
170
+ 5. Review the ICD-10 and CPT codes generated
171
  """
172
 
173
  def format_complete_response(result):
 
204
 
205
  return output
206
 
207
+ # ==================== Example Notes (Only 3) ====================
208
 
209
  EXAMPLES = {
210
  "Acute Bronchitis": """Patient presents with acute bronchitis. Cough for 5 days, productive with yellow sputum. Lung exam reveals diffuse wheezing. Prescribed azithromycin 500mg.""",
 
212
  "Type 2 Diabetes": """Patient with type 2 diabetes mellitus, uncontrolled. HbA1c 9.2%. Discussed diet and medication compliance. Adjusted insulin dosing. Referred to diabetes educator.""",
213
 
214
  "Hypertension Follow-up": """Follow-up visit for hypertension. Blood pressure 145/92. Patient reports good medication compliance. Continue current antihypertensive regimen. Return in 3 months.""",
 
 
 
 
215
  }
216
 
217
  def load_example(example_name):
 
232
 
233
  # ==================== Gradio Interface ====================
234
 
235
+ with gr.Blocks(css=load_css(), theme=gr.themes.Soft(), title="Medical Coding (ICD-10) Assistant") as demo:
236
 
237
  # Hidden state for API URL
238
  api_url_state = gr.State(value="https://Distopia22-icd-cpt-coding-api.hf.space")
 
240
  # Header
241
  gr.HTML("""
242
  <div class="header-container">
243
+ <h1>🏥 Medical Coding (ICD-10) Assistant</h1>
244
  <p>AI-Powered Medical Coding Analysis using Groq LLaMA 3.3 70B</p>
245
  </div>
246
  """)
 
252
  with gr.Column(scale=1, min_width=280, elem_classes="sidebar"):
253
  gr.HTML('<div class="sidebar-title">📚 Example Cases</div>')
254
 
255
+ # Example buttons (Only 3)
256
  example_buttons = {}
257
  for example_name in EXAMPLES.keys():
258
  btn = gr.Button(
 
263
 
264
  gr.Markdown("---")
265
 
266
+ # File Upload Section
267
+ gr.HTML('<div class="sidebar-title">📤 Upload Document</div>')
268
+
269
+ file_upload = gr.File(
270
+ label="Upload TXT File",
271
+ file_types=[".txt"],
272
+ type="binary",
273
+ elem_classes="file-upload"
274
+ )
275
+
276
+ upload_btn = gr.Button(
277
+ "📁 Analyze Uploaded File",
278
+ elem_classes="upload-btn"
279
+ )
280
+
281
+ gr.Markdown("*Only .txt files are supported*", elem_classes="upload-info")
282
+
283
+ gr.Markdown("---")
284
+
285
  # API Configuration
286
  with gr.Accordion("⚙️ API Configuration", open=False, elem_classes="api-config"):
287
  api_url_input = gr.Textbox(
 
304
  label=""
305
  )
306
 
307
+ # Input Area (Prompt Box) - GPT Style
308
  with gr.Group(elem_classes="input-container"):
309
  with gr.Row():
310
  provider_notes_input = gr.Textbox(
 
312
  placeholder="Enter clinical provider notes here...",
313
  lines=3,
314
  max_lines=5,
315
+ show_label=False,
316
+ elem_classes="prompt-input"
317
  )
318
 
319
  with gr.Row():
 
324
  gr.HTML("""
325
  <div class="footer">
326
  <p>Powered by <strong>Groq LLaMA 3.3 70B</strong> | <strong>FastAPI</strong> | <strong>Gradio</strong></p>
327
+ <p>© 2025 Medical Coding Assistant - Secure & HIPAA Compliant</p>
328
  </div>
329
  """)
330
 
 
337
  outputs=[provider_notes_input]
338
  )
339
 
340
+ # Upload button - Analyze uploaded file
341
+ upload_btn.click(
342
+ fn=upload_file_analysis,
343
+ inputs=[file_upload, api_url_state],
344
+ outputs=[output_area]
345
+ )
346
+
347
  # Send button - Analyze notes
348
  send_btn.click(
349
  fn=analyze_provider_notes,
assets/styles.css CHANGED
@@ -43,20 +43,20 @@
43
  overflow: hidden;
44
  }
45
 
46
- /* ==================== Left Sidebar ==================== */
47
  .sidebar {
48
- background: #ffffff !important;
49
- border-right: 2px solid #e0e7ef !important;
50
  padding: 20px !important;
51
  width: 280px !important;
52
  min-width: 280px !important;
53
  height: 100% !important;
54
  overflow-y: auto !important;
55
- box-shadow: 2px 0 8px rgba(0, 0, 0, 0.05) !important;
56
  }
57
 
58
  .sidebar-title {
59
- color: #00a896 !important;
60
  font-size: 1.2rem !important;
61
  font-weight: 600 !important;
62
  margin-bottom: 15px !important;
@@ -78,13 +78,47 @@
78
  transition: all 0.3s ease !important;
79
  width: 100% !important;
80
  text-align: left !important;
81
- box-shadow: 0 2px 5px rgba(0, 212, 170, 0.2) !important;
82
  }
83
 
84
  .example-btn:hover {
85
  background: linear-gradient(135deg, #00ffcc 0%, #00d4aa 100%) !important;
86
  transform: translateX(5px) !important;
87
- box-shadow: 0 4px 12px rgba(0, 212, 170, 0.3) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  }
89
 
90
  /* ==================== Right Chat Area ==================== */
@@ -129,34 +163,38 @@
129
  }
130
 
131
  .output-area p {
132
- color: #2d3748 !important;
133
  line-height: 1.6 !important;
134
  margin: 8px 0 !important;
135
  }
136
 
137
- /* ==================== Input Area (Prompt Box) ==================== */
 
 
 
 
138
  .input-container {
139
  background: white !important;
140
- border: 2px solid #00d4aa !important;
141
  border-radius: 12px !important;
142
  padding: 15px !important;
143
- box-shadow: 0 4px 12px rgba(0, 212, 170, 0.15) !important;
144
  }
145
 
146
- .input-container textarea {
147
- background: #fafbfc !important;
148
- color: #2d3748 !important;
149
- border: 1px solid #e0e7ef !important;
150
  border-radius: 8px !important;
151
  font-size: 0.95rem !important;
152
  padding: 12px !important;
153
  resize: none !important;
154
  }
155
 
156
- .input-container textarea:focus {
157
- border-color: #00d4aa !important;
158
  outline: none !important;
159
- box-shadow: 0 0 0 3px rgba(0, 212, 170, 0.1) !important;
160
  background: white !important;
161
  }
162
 
@@ -184,7 +222,7 @@
184
  .clear-button {
185
  background: white !important;
186
  color: #718096 !important;
187
- border: 1px solid #e0e7ef !important;
188
  border-radius: 8px !important;
189
  padding: 10px 28px !important;
190
  font-size: 0.95rem !important;
@@ -203,15 +241,15 @@
203
 
204
  /* ==================== API Configuration ==================== */
205
  .api-config {
206
- background: #f7fafc !important;
207
- border: 1px solid #e0e7ef !important;
208
  border-radius: 8px !important;
209
  padding: 12px !important;
210
  margin-bottom: 12px !important;
211
  }
212
 
213
  .api-config input {
214
- background: white !important;
215
  color: #2d3748 !important;
216
  border: 1px solid #e0e7ef !important;
217
  border-radius: 6px !important;
@@ -225,6 +263,10 @@
225
  box-shadow: 0 0 0 3px rgba(0, 212, 170, 0.1) !important;
226
  }
227
 
 
 
 
 
228
  .check-api-button {
229
  background: linear-gradient(135deg, #00a896 0%, #008577 100%) !important;
230
  color: white !important;
@@ -263,16 +305,29 @@
263
  background: #00a896;
264
  }
265
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  /* ==================== Accordion Styling ==================== */
267
  .accordion {
268
- background: white !important;
269
- border: 1px solid #e0e7ef !important;
270
  border-radius: 8px !important;
271
  margin-bottom: 10px !important;
272
  }
273
 
274
  .accordion summary {
275
- color: #00a896 !important;
276
  font-weight: 600 !important;
277
  font-size: 0.9rem !important;
278
  padding: 10px !important;
 
43
  overflow: hidden;
44
  }
45
 
46
+ /* ==================== Left Sidebar (Dark Cyan) ==================== */
47
  .sidebar {
48
+ background: linear-gradient(180deg, #008b8b 0%, #006666 100%) !important;
49
+ border-right: 2px solid #005555 !important;
50
  padding: 20px !important;
51
  width: 280px !important;
52
  min-width: 280px !important;
53
  height: 100% !important;
54
  overflow-y: auto !important;
55
+ box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15) !important;
56
  }
57
 
58
  .sidebar-title {
59
+ color: #ffffff !important;
60
  font-size: 1.2rem !important;
61
  font-weight: 600 !important;
62
  margin-bottom: 15px !important;
 
78
  transition: all 0.3s ease !important;
79
  width: 100% !important;
80
  text-align: left !important;
81
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2) !important;
82
  }
83
 
84
  .example-btn:hover {
85
  background: linear-gradient(135deg, #00ffcc 0%, #00d4aa 100%) !important;
86
  transform: translateX(5px) !important;
87
+ box-shadow: 0 4px 12px rgba(0, 212, 170, 0.4) !important;
88
+ }
89
+
90
+ /* ==================== File Upload Section ==================== */
91
+ .file-upload {
92
+ margin: 10px 0 !important;
93
+ }
94
+
95
+ .upload-btn {
96
+ background: linear-gradient(135deg, #ff8c00 0%, #ff6b00 100%) !important;
97
+ color: white !important;
98
+ border: none !important;
99
+ border-radius: 10px !important;
100
+ padding: 12px 15px !important;
101
+ margin: 10px 0 !important;
102
+ font-weight: 500 !important;
103
+ font-size: 0.9rem !important;
104
+ cursor: pointer !important;
105
+ transition: all 0.3s ease !important;
106
+ width: 100% !important;
107
+ text-align: center !important;
108
+ box-shadow: 0 2px 5px rgba(255, 140, 0, 0.3) !important;
109
+ }
110
+
111
+ .upload-btn:hover {
112
+ background: linear-gradient(135deg, #ffa500 0%, #ff8c00 100%) !important;
113
+ transform: translateY(-2px) !important;
114
+ box-shadow: 0 4px 12px rgba(255, 140, 0, 0.4) !important;
115
+ }
116
+
117
+ .upload-info {
118
+ color: #e0f7f4 !important;
119
+ font-size: 0.75rem !important;
120
+ font-style: italic !important;
121
+ margin-top: 5px !important;
122
  }
123
 
124
  /* ==================== Right Chat Area ==================== */
 
163
  }
164
 
165
  .output-area p {
166
+ color: #000000 !important;
167
  line-height: 1.6 !important;
168
  margin: 8px 0 !important;
169
  }
170
 
171
+ .output-area li {
172
+ color: #000000 !important;
173
+ }
174
+
175
+ /* ==================== Input Area (GPT-Style Prompt Box) ==================== */
176
  .input-container {
177
  background: white !important;
178
+ border: 1px solid #d1d5db !important;
179
  border-radius: 12px !important;
180
  padding: 15px !important;
181
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08) !important;
182
  }
183
 
184
+ .prompt-input textarea {
185
+ background: white !important;
186
+ color: #000000 !important;
187
+ border: none !important;
188
  border-radius: 8px !important;
189
  font-size: 0.95rem !important;
190
  padding: 12px !important;
191
  resize: none !important;
192
  }
193
 
194
+ .prompt-input textarea:focus {
195
+ border: none !important;
196
  outline: none !important;
197
+ box-shadow: none !important;
198
  background: white !important;
199
  }
200
 
 
222
  .clear-button {
223
  background: white !important;
224
  color: #718096 !important;
225
+ border: 1px solid #d1d5db !important;
226
  border-radius: 8px !important;
227
  padding: 10px 28px !important;
228
  font-size: 0.95rem !important;
 
241
 
242
  /* ==================== API Configuration ==================== */
243
  .api-config {
244
+ background: rgba(255, 255, 255, 0.1) !important;
245
+ border: 1px solid rgba(255, 255, 255, 0.2) !important;
246
  border-radius: 8px !important;
247
  padding: 12px !important;
248
  margin-bottom: 12px !important;
249
  }
250
 
251
  .api-config input {
252
+ background: rgba(255, 255, 255, 0.9) !important;
253
  color: #2d3748 !important;
254
  border: 1px solid #e0e7ef !important;
255
  border-radius: 6px !important;
 
263
  box-shadow: 0 0 0 3px rgba(0, 212, 170, 0.1) !important;
264
  }
265
 
266
+ .api-config label {
267
+ color: #ffffff !important;
268
+ }
269
+
270
  .check-api-button {
271
  background: linear-gradient(135deg, #00a896 0%, #008577 100%) !important;
272
  color: white !important;
 
305
  background: #00a896;
306
  }
307
 
308
+ /* Sidebar scrollbar */
309
+ .sidebar::-webkit-scrollbar-track {
310
+ background: rgba(0, 0, 0, 0.2);
311
+ }
312
+
313
+ .sidebar::-webkit-scrollbar-thumb {
314
+ background: rgba(255, 255, 255, 0.3);
315
+ }
316
+
317
+ .sidebar::-webkit-scrollbar-thumb:hover {
318
+ background: rgba(255, 255, 255, 0.5);
319
+ }
320
+
321
  /* ==================== Accordion Styling ==================== */
322
  .accordion {
323
+ background: rgba(255, 255, 255, 0.1) !important;
324
+ border: 1px solid rgba(255, 255, 255, 0.2) !important;
325
  border-radius: 8px !important;
326
  margin-bottom: 10px !important;
327
  }
328
 
329
  .accordion summary {
330
+ color: #ffffff !important;
331
  font-weight: 600 !important;
332
  font-size: 0.9rem !important;
333
  padding: 10px !important;