walaa2022 commited on
Commit
deed5ef
Β·
verified Β·
1 Parent(s): e7ca87e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +230 -221
app.py CHANGED
@@ -1,84 +1,68 @@
1
  #!/usr/bin/env python3
2
  """
3
- Qwen-VL Medical Image Analysis - Gradio Interface for Hugging Face Spaces
4
- Optimized for Hugging Face deployment with efficient resource usage
5
  """
6
 
7
  import gradio as gr
8
- import torch
9
- from transformers import Qwen2_5_VLForConditionalGeneration, AutoTokenizer, AutoProcessor
10
- from qwen_vl_utils import process_vision_info
11
  from PIL import Image
12
  import json
13
  import time
14
  import os
15
  from typing import Dict, List, Optional, Tuple
 
 
16
  import warnings
17
  warnings.filterwarnings("ignore")
18
 
19
- # Global variables for model caching
20
- MODEL = None
21
- PROCESSOR = None
22
- DEVICE = None
23
 
24
- os.environ['TOKENIZERS_PARALLELISM'] = 'false'
25
- os.environ['TRANSFORMERS_CACHE'] = '/tmp/transformers_cache'
26
-
27
- def get_device():
28
- """Determine the best available device"""
29
- if torch.cuda.is_available():
30
- return "cuda"
31
  else:
32
- return "cpu"
33
-
34
- def load_model_cached(model_name: str = "Qwen/Qwen2-VL-2B-Instruct"):
35
- """Load and cache model - optimized for HF Spaces"""
36
- global MODEL, PROCESSOR, DEVICE
37
 
38
- if MODEL is None:
39
- print(f"Loading {model_name}...")
40
- DEVICE = get_device()
41
- print(f"Using device: {DEVICE}")
42
 
43
- try:
44
- # Load with memory optimization for HF Spaces
45
- MODEL = Qwen2_5_VLForConditionalGeneration.from_pretrained(
46
- model_name,
47
- torch_dtype='auto',
48
- device_map="auto" if DEVICE == "cuda" else None,
49
- trust_remote_code=True,
50
- attn_implementation="eager", # More stable for HF Spaces
51
- low_cpu_mem_usage=True
52
- )
53
-
54
- PROCESSOR = AutoProcessor.from_pretrained(
55
- model_name,
56
- trust_remote_code=True
57
- )
58
-
59
- if DEVICE == "cpu":
60
- MODEL = MODEL.to(DEVICE)
61
-
62
- print("Model loaded successfully!")
63
- return True
64
 
65
- except Exception as e:
66
- print(f"Error loading model: {str(e)}")
67
- return False
68
-
69
- return True
70
 
71
  def create_medical_prompt(clinical_data: Dict, analysis_type: str, focus_areas: str) -> str:
72
- """Create optimized medical analysis prompt"""
73
 
74
- base_prompt = """You are an expert medical AI assistant specializing in medical image analysis with training across radiology, pathology, dermatology, and clinical medicine.
75
 
76
  **ANALYSIS INSTRUCTIONS:**
77
- Provide a systematic, professional medical image analysis following these guidelines:
78
- - Use clear medical terminology with explanations
79
- - Structure your response with clear sections
80
  - Be thorough but concise
81
- - Always mention limitations and need for professional consultation
 
82
  """
83
 
84
  # Add clinical context if provided
@@ -86,51 +70,94 @@ Provide a systematic, professional medical image analysis following these guidel
86
  if clinical_data and any(v.strip() for v in clinical_data.values() if v):
87
  clinical_context = "\n**CLINICAL CONTEXT:**\n"
88
  context_items = []
89
- if clinical_data.get("age"): context_items.append(f"Age: {clinical_data['age']}")
90
  if clinical_data.get("gender"): context_items.append(f"Gender: {clinical_data['gender']}")
91
- if clinical_data.get("symptoms"): context_items.append(f"Symptoms: {clinical_data['symptoms']}")
92
- if clinical_data.get("history"): context_items.append(f"History: {clinical_data['history']}")
93
- if clinical_data.get("medications"): context_items.append(f"Medications: {clinical_data['medications']}")
94
 
95
  clinical_context += "\n".join(f"β€’ {item}" for item in context_items) + "\n"
96
 
97
  # Analysis type specific instructions
98
  analysis_instructions = {
99
  "Comprehensive": """
100
- **PROVIDE COMPREHENSIVE ANALYSIS:**
101
- 1. **Image Description**: Type, quality, anatomical structures visible
102
- 2. **Clinical Findings**: Normal and abnormal observations
103
- 3. **Interpretation**: Clinical significance and differential diagnosis
104
- 4. **Recommendations**: Next steps and follow-up suggestions
105
- 5. **Limitations**: What cannot be determined from this image alone
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  """,
107
  "Quick Assessment": """
108
- **PROVIDE QUICK ASSESSMENT:**
109
- 1. **Key Findings**: Most important observations
110
- 2. **Clinical Impression**: Primary diagnostic considerations
111
- 3. **Urgent Concerns**: Any findings requiring immediate attention
112
- 4. **Next Steps**: Essential recommendations
 
 
 
 
 
 
 
 
 
 
 
113
  """,
114
  "Educational": """
115
  **PROVIDE EDUCATIONAL ANALYSIS:**
116
- 1. **Learning Points**: Key educational aspects of this case
117
- 2. **Normal vs Abnormal**: Clear explanation of findings
118
- 3. **Clinical Correlation**: How image relates to symptoms/history
119
- 4. **Teaching Insights**: Important concepts demonstrated
 
 
 
 
 
 
 
 
 
 
 
 
120
  """
121
  }
122
 
123
  focus_instruction = ""
124
  if focus_areas and focus_areas.strip():
125
- focus_instruction = f"\n**SPECIAL FOCUS**: Pay particular attention to: {focus_areas}\n"
126
 
127
  disclaimer = """
128
- **MEDICAL DISCLAIMER**: This AI analysis is for educational purposes only. Always consult qualified healthcare professionals for medical diagnosis and treatment decisions.
 
129
  """
130
 
131
  return base_prompt + clinical_context + analysis_instructions.get(analysis_type, analysis_instructions["Comprehensive"]) + focus_instruction + disclaimer
132
 
133
- def analyze_medical_image(
134
  image: Image.Image,
135
  age: str,
136
  gender: str,
@@ -139,17 +166,19 @@ def analyze_medical_image(
139
  medications: str,
140
  analysis_type: str,
141
  focus_areas: str,
 
142
  progress=gr.Progress()
143
- ) -> Tuple[str, str]:
144
- """Main analysis function for Gradio interface"""
145
 
146
  if image is None:
147
- return "❌ Please upload an image first.", ""
148
 
149
- # Load model if needed
150
- progress(0.1, desc="Loading model...")
151
- if not load_model_cached():
152
- return "❌ Failed to load model. Please try again.", ""
 
153
 
154
  try:
155
  progress(0.3, desc="Preparing analysis...")
@@ -166,110 +195,104 @@ def analyze_medical_image(
166
  # Create prompt
167
  prompt = create_medical_prompt(clinical_data, analysis_type, focus_areas)
168
 
169
- progress(0.5, desc="Processing image...")
170
-
171
- # Prepare messages for model
172
- messages = [
173
- {
174
- "role": "user",
175
- "content": [
176
- {"type": "image", "image": image},
177
- {"type": "text", "text": prompt}
178
- ]
179
- }
180
- ]
181
-
182
- # Process inputs
183
- text = PROCESSOR.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
184
- image_inputs, video_inputs = process_vision_info(messages)
185
-
186
- inputs = PROCESSOR(
187
- text=[text],
188
- images=image_inputs,
189
- videos=video_inputs,
190
- padding=True,
191
- return_tensors="pt",
192
- )
193
-
194
- inputs = inputs.to(DEVICE)
195
-
196
- progress(0.7, desc="Generating analysis...")
197
-
198
- # Generate response with optimized parameters for HF Spaces
199
- with torch.no_grad():
200
- generated_ids = MODEL.generate(
201
- **inputs,
202
- max_new_tokens=1024, # Reduced for faster processing
203
- do_sample=True,
204
- temperature=0.3,
205
- top_p=0.8,
206
- repetition_penalty=1.1,
207
- pad_token_id=PROCESSOR.tokenizer.eos_token_id,
208
- eos_token_id=PROCESSOR.tokenizer.eos_token_id,
209
- )
210
 
211
- generated_ids_trimmed = [
212
- out_ids[len(in_ids):]
213
- for in_ids, out_ids in zip(inputs.input_ids, generated_ids)
214
- ]
215
 
216
- response = PROCESSOR.batch_decode(
217
- generated_ids_trimmed,
218
- skip_special_tokens=True,
219
- clean_up_tokenization_spaces=False
220
- )[0]
221
 
222
- progress(1.0, desc="Analysis complete!")
223
 
224
  # Create download content
225
  report_data = {
226
  "timestamp": time.strftime("%Y-%m-%d %H:%M:%S UTC"),
227
- "model": "Qwen2.5-VL-3B-Instruct",
228
  "analysis_type": analysis_type,
229
  "clinical_data": clinical_data,
230
  "focus_areas": focus_areas,
231
- "analysis": response
232
  }
233
 
234
  download_content = json.dumps(report_data, indent=2)
235
 
236
- return response, download_content
 
 
237
 
238
  except Exception as e:
239
- return f"❌ Analysis failed: {str(e)}\n\nPlease try again or contact support.", ""
 
 
 
 
 
 
 
 
240
 
241
  def create_interface():
242
- """Create the Gradio interface"""
243
 
244
  # Custom CSS for medical theme
245
  css = """
246
  .gradio-container {
247
- max-width: 1200px !important;
248
  }
249
  .medical-header {
250
  text-align: center;
251
- color: #2c5aa0;
252
  margin-bottom: 20px;
253
  }
254
- .clinical-section {
255
- background-color: #f8f9fa;
256
  padding: 15px;
257
  border-radius: 8px;
258
  margin: 10px 0;
 
 
 
 
 
 
 
 
 
259
  }
260
  """
261
 
262
- with gr.Blocks(css=css, theme=gr.themes.Soft(), title="Medical AI Analyzer") as interface:
263
 
264
  # Header
265
  gr.HTML("""
266
  <div class="medical-header">
267
  <h1>πŸ₯ Medical Image AI Analyzer</h1>
268
- <h3>Advanced Medical Image Analysis using Qwen-VL</h3>
269
- <p><em>Upload medical images and provide clinical context for AI-powered analysis</em></p>
270
  </div>
271
  """)
272
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  with gr.Row():
274
  # Left column - Inputs
275
  with gr.Column(scale=1):
@@ -279,10 +302,10 @@ def create_interface():
279
  type="pil",
280
  label="Medical Image",
281
  height=300,
282
- sources=["upload", "clipboard"]
283
  )
284
 
285
- gr.Markdown("*Supported: X-rays, CT, MRI, photographs, microscopy, etc.*")
286
 
287
  gr.Markdown("## πŸ“‹ Clinical Information")
288
 
@@ -328,12 +351,12 @@ def create_interface():
328
 
329
  focus_areas = gr.Textbox(
330
  label="Focus Areas (Optional)",
331
- placeholder="e.g., cardiac, pulmonary, neurological",
332
  info="Specific areas to emphasize in analysis"
333
  )
334
 
335
  analyze_btn = gr.Button(
336
- "πŸ”¬ Analyze Medical Image",
337
  variant="primary",
338
  size="lg"
339
  )
@@ -344,8 +367,8 @@ def create_interface():
344
 
345
  analysis_output = gr.Textbox(
346
  label="Medical Analysis",
347
- lines=20,
348
- max_lines=30,
349
  show_copy_button=True,
350
  placeholder="Analysis results will appear here after processing..."
351
  )
@@ -358,33 +381,49 @@ def create_interface():
358
  # Hidden component to store download content
359
  download_content = gr.Textbox(visible=False)
360
 
361
- # Example section
362
- with gr.Accordion("πŸ’‘ Example Use Cases & Tips", open=False):
363
  gr.Markdown("""
 
 
 
 
 
 
 
364
  ### πŸ” **Supported Medical Images:**
365
  - **Radiology**: X-rays, CT scans, MRI images, Ultrasound
366
- - **Pathology**: Histological slides, Cytology specimens
367
  - **Dermatology**: Skin lesions, Rashes, Clinical photos
368
  - **Ophthalmology**: Fundus photos, OCT images
369
  - **Clinical Photography**: Wound assessment, Physical findings
 
370
 
371
- ### πŸ“ **Tips for Better Analysis:**
372
- - **Provide clinical context**: Age, symptoms, and history improve accuracy
373
- - **Use specific focus areas**: "cardiac silhouette, lung fields" vs just "chest"
374
- - **Choose appropriate analysis type**: Comprehensive for complex cases, Quick for screening
375
- - **High-quality images**: Clear, well-lit images produce better results
 
 
 
 
 
 
 
 
 
376
 
377
- ### ⚠️ **Important Limitations:**
378
- - This AI tool is for educational and research purposes only
379
- - Always consult qualified healthcare professionals for medical decisions
380
- - AI cannot replace clinical expertise and physical examination
381
- - Results should be validated by medical professionals
382
  """)
383
 
384
  # Footer
385
  gr.HTML("""
386
  <div style="text-align: center; margin-top: 20px; padding: 15px; background-color: #fff3cd; border-radius: 8px;">
387
- <strong>⚠️ Medical Disclaimer:</strong> This AI tool is for educational purposes only.
388
  It should never replace professional medical diagnosis or treatment.
389
  Always consult qualified healthcare providers for medical decisions.
390
  </div>
@@ -393,19 +432,33 @@ def create_interface():
393
  # Event handlers
394
  def create_download_file(content):
395
  if content:
396
- filename = f"medical_analysis_{int(time.time())}.json"
397
  with open(filename, "w") as f:
398
  f.write(content)
399
  return gr.File(value=filename, visible=True)
400
  return gr.File(visible=False)
401
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
  analyze_btn.click(
403
- fn=analyze_medical_image,
404
  inputs=[
405
  image_input, age_input, gender_input, symptoms_input,
406
- history_input, medications_input, analysis_type, focus_areas
407
  ],
408
- outputs=[analysis_output, download_content]
409
  ).then(
410
  fn=create_download_file,
411
  inputs=[download_content],
@@ -415,61 +468,17 @@ def create_interface():
415
  return interface
416
 
417
  if __name__ == "__main__":
418
- # Pre-load model to reduce first-run latency
419
- print("Initializing Medical AI Analyzer...")
420
- load_model_cached()
421
 
422
  # Create and launch interface
423
  interface = create_interface()
424
 
425
- # Launch with settings optimized for HF Spaces
426
  interface.launch(
427
  server_name="0.0.0.0",
428
  server_port=7860,
429
  share=False,
430
  show_error=True,
431
  quiet=False
432
- )
433
-
434
- """
435
- HUGGING FACE SPACE CONFIGURATION:
436
-
437
- 1. Create requirements.txt:
438
- torch
439
- torchvision
440
- transformers>=4.37.0
441
- accelerate
442
- pillow
443
- gradio
444
- qwen-vl-utils
445
- spaces
446
-
447
- 2. Create app.py (this file)
448
-
449
- 3. Create README.md:
450
- ---
451
- title: Medical Image AI Analyzer
452
- emoji: πŸ₯
453
- colorFrom: blue
454
- colorTo: green
455
- sdk: gradio
456
- sdk_version: 4.44.0
457
- app_file: app.py
458
- pinned: false
459
- license: apache-2.0
460
- ---
461
-
462
- 4. Optional - Create .gitattributes:
463
- *.safetensors filter=lfs diff=lfs merge=lfs -text
464
- *.bin filter=lfs diff=lfs merge=lfs -text
465
-
466
- DEPLOYMENT FEATURES:
467
- βœ… Optimized for Hugging Face Spaces
468
- βœ… Efficient memory usage
469
- βœ… Progress indicators
470
- βœ… Professional medical interface
471
- βœ… Download analysis reports
472
- βœ… Mobile-responsive design
473
- βœ… Error handling and validation
474
- βœ… Medical disclaimer compliance
475
- """
 
1
  #!/usr/bin/env python3
2
  """
3
+ Gemini Vision Pro Medical Image Analysis - Gradio Interface
4
+ Lightweight alternative using Google's Gemini Vision Pro API
5
  """
6
 
7
  import gradio as gr
8
+ import google.generativeai as genai
 
 
9
  from PIL import Image
10
  import json
11
  import time
12
  import os
13
  from typing import Dict, List, Optional, Tuple
14
+ import base64
15
+ import io
16
  import warnings
17
  warnings.filterwarnings("ignore")
18
 
19
+ # Global configuration
20
+ GEMINI_MODEL = None
21
+ API_KEY = None
 
22
 
23
+ def setup_gemini(api_key: str = None):
24
+ """Setup Gemini Vision Pro with API key"""
25
+ global GEMINI_MODEL, API_KEY
26
+
27
+ # Try to get API key from environment or parameter
28
+ if api_key:
29
+ API_KEY = api_key
30
  else:
31
+ API_KEY = os.getenv('GOOGLE_API_KEY') or os.getenv('GEMINI_API_KEY')
32
+
33
+ if not API_KEY:
34
+ return False, "❌ No API key provided. Please set GOOGLE_API_KEY environment variable or enter it in the interface."
 
35
 
36
+ try:
37
+ # Configure the API
38
+ genai.configure(api_key=API_KEY)
 
39
 
40
+ # Initialize the model
41
+ GEMINI_MODEL = genai.GenerativeModel('gemini-1.5-pro')
42
+
43
+ # Test the connection
44
+ test_response = GEMINI_MODEL.generate_content("Hello, can you help with medical image analysis?")
45
+
46
+ if test_response and test_response.text:
47
+ return True, "βœ… Gemini Vision Pro connected successfully!"
48
+ else:
49
+ return False, "❌ Failed to connect to Gemini API"
 
 
 
 
 
 
 
 
 
 
 
50
 
51
+ except Exception as e:
52
+ return False, f"❌ Gemini setup failed: {str(e)}"
 
 
 
53
 
54
  def create_medical_prompt(clinical_data: Dict, analysis_type: str, focus_areas: str) -> str:
55
+ """Create optimized medical analysis prompt for Gemini"""
56
 
57
+ base_prompt = """You are an expert medical AI assistant specializing in medical image analysis. You have extensive training across radiology, pathology, dermatology, ophthalmology, and clinical medicine.
58
 
59
  **ANALYSIS INSTRUCTIONS:**
60
+ Analyze this medical image systematically and professionally:
61
+ - Use clear medical terminology with explanations for complex terms
62
+ - Structure your response with clear sections and headers
63
  - Be thorough but concise
64
+ - Always mention limitations and emphasize the need for professional medical consultation
65
+ - Focus on observable findings rather than definitive diagnoses
66
  """
67
 
68
  # Add clinical context if provided
 
70
  if clinical_data and any(v.strip() for v in clinical_data.values() if v):
71
  clinical_context = "\n**CLINICAL CONTEXT:**\n"
72
  context_items = []
73
+ if clinical_data.get("age"): context_items.append(f"Patient Age: {clinical_data['age']}")
74
  if clinical_data.get("gender"): context_items.append(f"Gender: {clinical_data['gender']}")
75
+ if clinical_data.get("symptoms"): context_items.append(f"Presenting Symptoms: {clinical_data['symptoms']}")
76
+ if clinical_data.get("history"): context_items.append(f"Medical History: {clinical_data['history']}")
77
+ if clinical_data.get("medications"): context_items.append(f"Current Medications: {clinical_data['medications']}")
78
 
79
  clinical_context += "\n".join(f"β€’ {item}" for item in context_items) + "\n"
80
 
81
  # Analysis type specific instructions
82
  analysis_instructions = {
83
  "Comprehensive": """
84
+ **PROVIDE COMPREHENSIVE ANALYSIS WITH THESE SECTIONS:**
85
+
86
+ ## 1. IMAGE ASSESSMENT
87
+ - Image type, quality, and technical adequacy
88
+ - Anatomical structures and regions visible
89
+ - Any artifacts or limitations
90
+
91
+ ## 2. CLINICAL FINDINGS
92
+ - Normal anatomical structures observed
93
+ - Abnormal findings or variations from normal
94
+ - Specific measurements or quantitative observations if applicable
95
+
96
+ ## 3. CLINICAL INTERPRETATION
97
+ - Significance of the findings
98
+ - Differential diagnostic considerations
99
+ - Correlation with provided clinical history
100
+
101
+ ## 4. RECOMMENDATIONS
102
+ - Suggested next steps or additional imaging
103
+ - Clinical correlation recommendations
104
+ - Follow-up suggestions
105
+
106
+ ## 5. LIMITATIONS & DISCLAIMERS
107
+ - What cannot be determined from this image alone
108
+ - Need for clinical correlation and professional evaluation
109
  """,
110
  "Quick Assessment": """
111
+ **PROVIDE FOCUSED QUICK ASSESSMENT:**
112
+
113
+ ## KEY FINDINGS
114
+ - Most significant observations
115
+ - Normal vs abnormal structures
116
+
117
+ ## CLINICAL IMPRESSION
118
+ - Primary considerations based on image
119
+ - Any urgent findings that require immediate attention
120
+
121
+ ## IMMEDIATE RECOMMENDATIONS
122
+ - Essential next steps
123
+ - Urgency level assessment
124
+
125
+ ## LIMITATIONS
126
+ - Important caveats about this assessment
127
  """,
128
  "Educational": """
129
  **PROVIDE EDUCATIONAL ANALYSIS:**
130
+
131
+ ## LEARNING OBJECTIVES
132
+ - Key educational points from this case
133
+ - Important anatomical or pathological concepts
134
+
135
+ ## NORMAL vs ABNORMAL
136
+ - Clear explanation of what's normal in this image
137
+ - Detailed description of any abnormal findings
138
+
139
+ ## CLINICAL CORRELATION
140
+ - How image findings relate to symptoms/history
141
+ - Real-world clinical significance
142
+
143
+ ## TEACHING PEARLS
144
+ - Important concepts this case demonstrates
145
+ - Common pitfalls or considerations
146
  """
147
  }
148
 
149
  focus_instruction = ""
150
  if focus_areas and focus_areas.strip():
151
+ focus_instruction = f"\n**SPECIAL FOCUS AREAS**: Pay particular attention to: {focus_areas}\n"
152
 
153
  disclaimer = """
154
+ **IMPORTANT MEDICAL DISCLAIMER**:
155
+ This AI-powered analysis is for educational and research purposes only. It should never replace professional medical diagnosis, treatment, or consultation with qualified healthcare providers. Always seek professional medical advice for any health concerns or medical decisions.
156
  """
157
 
158
  return base_prompt + clinical_context + analysis_instructions.get(analysis_type, analysis_instructions["Comprehensive"]) + focus_instruction + disclaimer
159
 
160
+ def analyze_medical_image_gemini(
161
  image: Image.Image,
162
  age: str,
163
  gender: str,
 
166
  medications: str,
167
  analysis_type: str,
168
  focus_areas: str,
169
+ api_key: str,
170
  progress=gr.Progress()
171
+ ) -> Tuple[str, str, str]:
172
+ """Main analysis function using Gemini Vision Pro"""
173
 
174
  if image is None:
175
+ return "❌ Please upload an image first.", "", "❌ No image provided"
176
 
177
+ # Setup Gemini if needed
178
+ progress(0.1, desc="Connecting to Gemini...")
179
+ success, status = setup_gemini(api_key)
180
+ if not success:
181
+ return status, "", status
182
 
183
  try:
184
  progress(0.3, desc="Preparing analysis...")
 
195
  # Create prompt
196
  prompt = create_medical_prompt(clinical_data, analysis_type, focus_areas)
197
 
198
+ progress(0.5, desc="Analyzing image with Gemini...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
+ # Generate analysis using Gemini Vision Pro
201
+ response = GEMINI_MODEL.generate_content([prompt, image])
 
 
202
 
203
+ if not response or not response.text:
204
+ return "❌ No response received from Gemini API", "", "❌ Analysis failed"
 
 
 
205
 
206
+ progress(0.9, desc="Preparing results...")
207
 
208
  # Create download content
209
  report_data = {
210
  "timestamp": time.strftime("%Y-%m-%d %H:%M:%S UTC"),
211
+ "model": "Google Gemini-1.5-Pro Vision",
212
  "analysis_type": analysis_type,
213
  "clinical_data": clinical_data,
214
  "focus_areas": focus_areas,
215
+ "analysis": response.text
216
  }
217
 
218
  download_content = json.dumps(report_data, indent=2)
219
 
220
+ progress(1.0, desc="Analysis complete!")
221
+
222
+ return response.text, download_content, "βœ… Analysis completed successfully"
223
 
224
  except Exception as e:
225
+ error_msg = f"❌ Analysis failed: {str(e)}"
226
+ if "API_KEY" in str(e):
227
+ error_msg += "\n\nπŸ’‘ Tip: Make sure your Google API key is valid and has access to Gemini API"
228
+ elif "quota" in str(e).lower():
229
+ error_msg += "\n\nπŸ’‘ Tip: You may have exceeded your API quota. Check your Google Cloud Console"
230
+ elif "safety" in str(e).lower():
231
+ error_msg += "\n\nπŸ’‘ Tip: The image may have been blocked by safety filters. Try a different medical image"
232
+
233
+ return error_msg, "", error_msg
234
 
235
  def create_interface():
236
+ """Create the Gradio interface for Gemini Vision Pro"""
237
 
238
  # Custom CSS for medical theme
239
  css = """
240
  .gradio-container {
241
+ max-width: 1400px !important;
242
  }
243
  .medical-header {
244
  text-align: center;
245
+ color: #1a73e8;
246
  margin-bottom: 20px;
247
  }
248
+ .api-section {
249
+ background-color: #e8f0fe;
250
  padding: 15px;
251
  border-radius: 8px;
252
  margin: 10px 0;
253
+ border-left: 4px solid #1a73e8;
254
+ }
255
+ .status-success {
256
+ color: #137333;
257
+ font-weight: 500;
258
+ }
259
+ .status-error {
260
+ color: #d93025;
261
+ font-weight: 500;
262
  }
263
  """
264
 
265
+ with gr.Blocks(css=css, theme=gr.themes.Soft(), title="Gemini Medical AI") as interface:
266
 
267
  # Header
268
  gr.HTML("""
269
  <div class="medical-header">
270
  <h1>πŸ₯ Medical Image AI Analyzer</h1>
271
+ <h2>πŸ€– Powered by Google Gemini Vision Pro</h2>
272
+ <p><em>Fast, efficient medical image analysis using Google's latest AI</em></p>
273
  </div>
274
  """)
275
 
276
+ # API Configuration Section
277
+ with gr.Accordion("πŸ”‘ API Configuration", open=True):
278
+ gr.Markdown("""
279
+ ### Google Gemini API Setup
280
+ You need a Google API key to use Gemini Vision Pro. Get one from [Google AI Studio](https://makersuite.google.com/app/apikey).
281
+ """)
282
+
283
+ api_key_input = gr.Textbox(
284
+ label="Google API Key",
285
+ type="password",
286
+ placeholder="Enter your Google API key here...",
287
+ info="Your API key is not stored and only used for this session"
288
+ )
289
+
290
+ status_display = gr.Textbox(
291
+ label="Connection Status",
292
+ value="⏳ Enter API key to connect",
293
+ interactive=False
294
+ )
295
+
296
  with gr.Row():
297
  # Left column - Inputs
298
  with gr.Column(scale=1):
 
302
  type="pil",
303
  label="Medical Image",
304
  height=300,
305
+ sources=["upload", "clipboard", "webcam"]
306
  )
307
 
308
+ gr.Markdown("*Supported: X-rays, CT, MRI, photographs, microscopy, dermatology images, etc.*")
309
 
310
  gr.Markdown("## πŸ“‹ Clinical Information")
311
 
 
351
 
352
  focus_areas = gr.Textbox(
353
  label="Focus Areas (Optional)",
354
+ placeholder="e.g., cardiac silhouette, lung fields, bone density",
355
  info="Specific areas to emphasize in analysis"
356
  )
357
 
358
  analyze_btn = gr.Button(
359
+ "πŸ”¬ Analyze with Gemini",
360
  variant="primary",
361
  size="lg"
362
  )
 
367
 
368
  analysis_output = gr.Textbox(
369
  label="Medical Analysis",
370
+ lines=25,
371
+ max_lines=35,
372
  show_copy_button=True,
373
  placeholder="Analysis results will appear here after processing..."
374
  )
 
381
  # Hidden component to store download content
382
  download_content = gr.Textbox(visible=False)
383
 
384
+ # Information sections
385
+ with gr.Accordion("πŸ’‘ About Gemini Vision Pro", open=False):
386
  gr.Markdown("""
387
+ ### πŸš€ **Advantages of Gemini Vision Pro:**
388
+ - **Fast Processing**: No local model loading - results in seconds
389
+ - **Low Resource Usage**: Runs via API calls, minimal local computing needed
390
+ - **High Quality**: Google's latest multimodal AI model
391
+ - **Always Updated**: Access to the latest model improvements
392
+ - **Reliable**: Enterprise-grade infrastructure
393
+
394
  ### πŸ” **Supported Medical Images:**
395
  - **Radiology**: X-rays, CT scans, MRI images, Ultrasound
396
+ - **Pathology**: Histological slides, Cytology specimens
397
  - **Dermatology**: Skin lesions, Rashes, Clinical photos
398
  - **Ophthalmology**: Fundus photos, OCT images
399
  - **Clinical Photography**: Wound assessment, Physical findings
400
+ - **Microscopy**: Cellular and tissue analysis
401
 
402
+ ### πŸ’° **Cost Information:**
403
+ - Gemini Vision Pro uses pay-per-use pricing
404
+ - Typically very affordable for individual analyses
405
+ - Check [Google AI Pricing](https://ai.google.dev/pricing) for current rates
406
+ """)
407
+
408
+ with gr.Accordion("πŸ“ Tips for Better Results", open=False):
409
+ gr.Markdown("""
410
+ ### 🎯 **Optimization Tips:**
411
+ - **Provide clinical context**: Age, symptoms, and history significantly improve accuracy
412
+ - **Use specific focus areas**: "cardiac silhouette, pulmonary vessels" vs just "chest"
413
+ - **High-quality images**: Clear, well-lit, properly oriented images work best
414
+ - **Appropriate image size**: Gemini works well with various image sizes
415
+ - **Choose right analysis type**: Comprehensive for complex cases, Quick for screening
416
 
417
+ ### πŸ” **API Key Security:**
418
+ - Your API key is only used for this session and not stored
419
+ - Consider using environment variables for production deployments
420
+ - Monitor your API usage in Google Cloud Console
 
421
  """)
422
 
423
  # Footer
424
  gr.HTML("""
425
  <div style="text-align: center; margin-top: 20px; padding: 15px; background-color: #fff3cd; border-radius: 8px;">
426
+ <strong>⚠️ Medical Disclaimer:</strong> This AI tool is for educational and research purposes only.
427
  It should never replace professional medical diagnosis or treatment.
428
  Always consult qualified healthcare providers for medical decisions.
429
  </div>
 
432
  # Event handlers
433
  def create_download_file(content):
434
  if content:
435
+ filename = f"gemini_medical_analysis_{int(time.time())}.json"
436
  with open(filename, "w") as f:
437
  f.write(content)
438
  return gr.File(value=filename, visible=True)
439
  return gr.File(visible=False)
440
 
441
+ def test_api_connection(api_key):
442
+ if not api_key:
443
+ return "⏳ Enter API key to connect"
444
+ success, status = setup_gemini(api_key)
445
+ return status
446
+
447
+ # API key testing
448
+ api_key_input.change(
449
+ fn=test_api_connection,
450
+ inputs=[api_key_input],
451
+ outputs=[status_display]
452
+ )
453
+
454
+ # Main analysis
455
  analyze_btn.click(
456
+ fn=analyze_medical_image_gemini,
457
  inputs=[
458
  image_input, age_input, gender_input, symptoms_input,
459
+ history_input, medications_input, analysis_type, focus_areas, api_key_input
460
  ],
461
+ outputs=[analysis_output, download_content, status_display]
462
  ).then(
463
  fn=create_download_file,
464
  inputs=[download_content],
 
468
  return interface
469
 
470
  if __name__ == "__main__":
471
+ print("πŸ₯ Initializing Gemini Medical AI Analyzer...")
472
+ print("πŸš€ No local model loading required - using Google Gemini Vision Pro API")
 
473
 
474
  # Create and launch interface
475
  interface = create_interface()
476
 
477
+ # Launch with optimized settings
478
  interface.launch(
479
  server_name="0.0.0.0",
480
  server_port=7860,
481
  share=False,
482
  show_error=True,
483
  quiet=False
484
+ )