Bonosa2 commited on
Commit
62027fa
Β·
verified Β·
1 Parent(s): 3c2dfdd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +326 -0
app.py CHANGED
@@ -2,10 +2,336 @@ import gradio as gr
2
  import torch
3
  import numpy as np
4
  from PIL import Image
 
 
 
 
5
  import time
6
  import io
7
  import subprocess
8
  import sys
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  import cv2
10
 
11
  # Install required packages
 
2
  import torch
3
  import numpy as np
4
  from PIL import Image
5
+ import timeimport gradio as gr
6
+ import torch
7
+ import numpy as np
8
+ from PIL import Image
9
  import time
10
  import io
11
  import subprocess
12
  import sys
13
+
14
+ # Install required packages
15
+ def install_packages():
16
+ packages = [
17
+ "transformers",
18
+ "accelerate",
19
+ "timm",
20
+ "easyocr"
21
+ ]
22
+ for package in packages:
23
+ try:
24
+ subprocess.check_call([sys.executable, "-m", "pip", "install", package])
25
+ except:
26
+ print(f"Warning: Could not install {package}")
27
+
28
+ # Install packages at startup
29
+ install_packages()
30
+
31
+ from transformers import AutoProcessor, AutoModelForImageTextToText, AutoConfig
32
+
33
+ # Global variables for model
34
+ processor = None
35
+ model = None
36
+ config = None
37
+ ocr_reader = None
38
+
39
+ def load_model():
40
+ """Load the Gemma 3n model"""
41
+ global processor, model, config, ocr_reader
42
+
43
+ try:
44
+ print("πŸš€ Loading Gemma 3n model...")
45
+ GEMMA_PATH = "google/gemma-3n-e2b-it"
46
+
47
+ # Load configuration
48
+ config = AutoConfig.from_pretrained(GEMMA_PATH, trust_remote_code=True)
49
+ print("βœ… Config loaded")
50
+
51
+ # Load processor
52
+ processor = AutoProcessor.from_pretrained(GEMMA_PATH, trust_remote_code=True)
53
+ print("βœ… Processor loaded")
54
+
55
+ # Load model
56
+ model = AutoModelForImageTextToText.from_pretrained(
57
+ GEMMA_PATH,
58
+ config=config,
59
+ torch_dtype="auto",
60
+ device_map="auto",
61
+ trust_remote_code=True
62
+ )
63
+ print("βœ… Model loaded successfully!")
64
+
65
+ # Set up compilation fix
66
+ import torch._dynamo
67
+ torch._dynamo.config.suppress_errors = True
68
+
69
+ # Initialize OCR
70
+ try:
71
+ import easyocr
72
+ ocr_reader = easyocr.Reader(['en'], gpu=False, verbose=False)
73
+ print("βœ… EasyOCR initialized")
74
+ except Exception as e:
75
+ print(f"⚠️ EasyOCR not available: {e}")
76
+ ocr_reader = None
77
+
78
+ return True
79
+
80
+ except Exception as e:
81
+ print(f"❌ Model loading failed: {e}")
82
+ return False
83
+
84
+ def generate_soap_note(text):
85
+ """Generate SOAP note using Gemma 3n"""
86
+ if model is None or processor is None:
87
+ return "❌ Model not loaded. Please wait for initialization."
88
+
89
+ soap_prompt = f"""You are a medical AI assistant. Convert the following medical notes into a properly formatted SOAP note.
90
+
91
+ Medical notes:
92
+ {text}
93
+
94
+ Please format as:
95
+ S - SUBJECTIVE: (chief complaint, history of present illness, past medical history, medications, allergies)
96
+ O - OBJECTIVE: (vital signs, physical examination findings)
97
+ A - ASSESSMENT: (diagnosis/clinical impression)
98
+ P - PLAN: (treatment plan, follow-up instructions)
99
+
100
+ Generate a complete, professional SOAP note:"""
101
+
102
+ messages = [{
103
+ "role": "system",
104
+ "content": [{"type": "text", "text": "You are an expert medical AI assistant specialized in creating SOAP notes from medical documentation."}]
105
+ }, {
106
+ "role": "user",
107
+ "content": [{"type": "text", "text": soap_prompt}]
108
+ }]
109
+
110
+ try:
111
+ inputs = processor.apply_chat_template(
112
+ messages,
113
+ add_generation_prompt=True,
114
+ tokenize=True,
115
+ return_dict=True,
116
+ return_tensors="pt"
117
+ ).to(model.device)
118
+
119
+ input_len = inputs["input_ids"].shape[-1]
120
+
121
+ with torch.no_grad():
122
+ outputs = model.generate(
123
+ **inputs,
124
+ max_new_tokens=400,
125
+ do_sample=True,
126
+ temperature=0.1,
127
+ top_p=0.95,
128
+ pad_token_id=processor.tokenizer.eos_token_id,
129
+ disable_compile=True
130
+ )
131
+
132
+ response = processor.batch_decode(
133
+ outputs[:, input_len:],
134
+ skip_special_tokens=True
135
+ )[0].strip()
136
+
137
+ return response
138
+
139
+ except Exception as e:
140
+ return f"❌ SOAP generation failed: {str(e)}"
141
+
142
+ def extract_text_from_image(image):
143
+ """Extract text using EasyOCR - fast processing"""
144
+ if ocr_reader is None:
145
+ return "❌ OCR not available"
146
+
147
+ try:
148
+ if hasattr(image, 'convert'):
149
+ image = image.convert('RGB')
150
+ img_array = np.array(image)
151
+
152
+ results = ocr_reader.readtext(img_array, detail=0, paragraph=True)
153
+ if results:
154
+ return ' '.join(results).strip()
155
+ else:
156
+ return "❌ No text detected in image"
157
+
158
+ except Exception as e:
159
+ return f"❌ OCR failed: {str(e)}"
160
+
161
+ def process_medical_input(image, text):
162
+ """Main processing function for the Gradio interface"""
163
+
164
+ if image is not None and text.strip():
165
+ return "⚠️ Please provide either an image OR text, not both.", ""
166
+
167
+ if image is not None:
168
+ # Process image
169
+ print("πŸ” Extracting text from image...")
170
+ extracted_text = extract_text_from_image(image)
171
+
172
+ if extracted_text.startswith('❌'):
173
+ return extracted_text, ""
174
+
175
+ print("πŸ€– Generating SOAP note...")
176
+ soap_note = generate_soap_note(extracted_text)
177
+
178
+ return extracted_text, soap_note
179
+
180
+ elif text.strip():
181
+ # Process text directly
182
+ print("πŸ€– Generating SOAP note from text...")
183
+ soap_note = generate_soap_note(text.strip())
184
+ return text.strip(), soap_note
185
+
186
+ else:
187
+ return "❌ Please provide either an image or text input.", ""
188
+
189
+ def create_demo():
190
+ """Create the Gradio demo interface"""
191
+
192
+ # Sample text for demonstration
193
+ sample_text = """Patient: John Smith, 45yo male
194
+ CC: Chest pain
195
+ Vitals: BP 140/90, HR 88, RR 16, O2 98%, Temp 98.6F
196
+ HPI: Patient reports crushing chest pain x 2 hours, radiating to left arm
197
+ PMH: HTN, DM Type 2
198
+ Current Meds: Lisinopril 10mg daily, Metformin 500mg BID
199
+ PE: Diaphoretic, anxious appearance
200
+ EKG: ST elevation in leads II, III, aVF"""
201
+
202
+ with gr.Blocks(title="Medical OCR SOAP Generator", theme=gr.themes.Soft()) as demo:
203
+
204
+ gr.HTML("""
205
+ <h1>πŸ₯ Medical OCR SOAP Generator - LIVE DEMO</h1>
206
+ <h2>🎯 For Competition Judges - Quick 2-Minute Demo:</h2>
207
+
208
+ <div style="background-color: #e6f3ff; padding: 15px; border-radius: 10px; margin: 10px 0;">
209
+ <h3>πŸ“‹ SAMPLE IMAGE PROVIDED:</h3>
210
+ <p><strong>πŸ‘† Download "docs-note-to-upload.jpg" from the Files tab above, then upload it below</strong></p>
211
+ <p><strong>OR</strong> click "Try Sample Medical Text" button for instant text demo</p>
212
+ </div>
213
+
214
+ <h3>Demo Steps:</h3>
215
+ <ol>
216
+ <li><strong>Upload the sample image</strong> (docs-note-to-upload.jpg from Files tab) <strong>OR</strong> click sample text button</li>
217
+ <li><strong>Click "Generate SOAP Note"</strong></li>
218
+ <li><strong>Wait ~2 minutes</strong> for AI processing (first time only)</li>
219
+ <li><strong>See professional SOAP note</strong> generated by Gemma 3n</li>
220
+ </ol>
221
+
222
+ <h3>βœ… What This Demo Shows:</h3>
223
+ <ul>
224
+ <li><strong>Real OCR</strong> extraction from handwritten medical notes</li>
225
+ <li><strong>AI-powered medical reasoning</strong> with Gemma 3n</li>
226
+ <li><strong>Professional SOAP formatting</strong> (Subjective, Objective, Assessment, Plan)</li>
227
+ <li><strong>HIPAA-compliant</strong> local processing</li>
228
+ </ul>
229
+
230
+ <p><strong>⚠️ Note:</strong> First generation takes ~2 minutes as model loads. Subsequent ones are faster.</p>
231
+ <hr>
232
+ """)
233
+
234
+ with gr.Row():
235
+ with gr.Column():
236
+ image_input = gr.Image(
237
+ type="pil",
238
+ label="πŸ“· Upload Medical Image",
239
+ height=300
240
+ )
241
+
242
+ text_input = gr.Textbox(
243
+ label="πŸ“ Or Enter Medical Text",
244
+ placeholder=sample_text,
245
+ lines=8,
246
+ max_lines=15
247
+ )
248
+
249
+ submit_btn = gr.Button(
250
+ "Generate SOAP Note",
251
+ variant="primary",
252
+ size="lg"
253
+ )
254
+
255
+ with gr.Column():
256
+ extracted_output = gr.Textbox(
257
+ label="πŸ“‹ Extracted/Input Text",
258
+ lines=6,
259
+ max_lines=10
260
+ )
261
+
262
+ soap_output = gr.Textbox(
263
+ label="πŸ₯ Generated SOAP Note",
264
+ lines=12,
265
+ max_lines=20
266
+ )
267
+
268
+ # Example section
269
+ gr.Markdown("### πŸ“‹ Quick Test Example")
270
+ example_btn = gr.Button("Try Sample Medical Text", variant="secondary")
271
+
272
+ def load_example():
273
+ return sample_text, None
274
+
275
+ example_btn.click(
276
+ load_example,
277
+ outputs=[text_input, image_input]
278
+ )
279
+
280
+ # Process function
281
+ submit_btn.click(
282
+ process_medical_input,
283
+ inputs=[image_input, text_input],
284
+ outputs=[extracted_output, soap_output]
285
+ )
286
+
287
+ gr.Markdown("""
288
+ ---
289
+ **About:** This application uses Google's Gemma 3n model for medical text understanding and EasyOCR for handwriting recognition.
290
+ All processing is done locally for HIPAA compliance.
291
+
292
+ **Competition Entry:** Medical AI Innovation Challenge 2024
293
+ """)
294
+
295
+ return demo
296
+
297
+ # Initialize the application
298
+ if __name__ == "__main__":
299
+ print("πŸš€ Starting Medical OCR SOAP Generator...")
300
+
301
+ # Load model
302
+ model_loaded = load_model()
303
+
304
+ if model_loaded:
305
+ print("βœ… All systems ready!")
306
+ demo = create_demo()
307
+ demo.launch(
308
+ share=True,
309
+ server_name="0.0.0.0",
310
+ server_port=7860
311
+ )
312
+ else:
313
+ print("❌ Failed to load model. Creating fallback demo...")
314
+
315
+ def fallback_demo():
316
+ return "❌ Model loading failed. Please check the logs.", "❌ Model not available."
317
+
318
+ demo = gr.Interface(
319
+ fn=fallback_demo,
320
+ inputs=[
321
+ gr.Image(type="pil", label="Upload Medical Image"),
322
+ gr.Textbox(label="Enter Medical Text", lines=5)
323
+ ],
324
+ outputs=[
325
+ gr.Textbox(label="Status"),
326
+ gr.Textbox(label="Error Message")
327
+ ],
328
+ title="❌ Medical OCR - Model Loading Failed"
329
+ )
330
+
331
+ demo.launch(share=True)
332
+ import io
333
+ import subprocess
334
+ import sys
335
  import cv2
336
 
337
  # Install required packages