walaa2022 commited on
Commit
fe2050b
·
verified ·
1 Parent(s): c315239

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -484
app.py CHANGED
@@ -1,7 +1,7 @@
1
  #!/usr/bin/env python3
2
  """
3
- Gemini Vision Pro Medical Image Analysis - Gradio Interface
4
- Fixed version with HuggingFace Secrets support and better error handling
5
  """
6
 
7
  import gradio as gr
@@ -10,127 +10,48 @@ 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 get_api_key_from_secrets():
24
- """Try to get API key from HuggingFace secrets or environment variables"""
25
- # Try multiple possible secret names
26
- possible_keys = [
27
- 'GEMINI_API_KEY'
28
- ]
29
-
30
- for key_name in possible_keys:
31
- # First try HuggingFace secrets (if running on HF Spaces)
32
- try:
33
- from huggingface_hub import HfFolder
34
- token = HfFolder.get_token()
35
- if token:
36
- # This is a simplified approach - in HF Spaces, secrets are usually available as env vars
37
- api_key = os.getenv(key_name)
38
- if api_key:
39
- return api_key
40
- except:
41
- pass
42
-
43
- # Try regular environment variables
44
- api_key = os.getenv(key_name)
45
- if api_key:
46
- return api_key
47
-
48
- return None
49
 
50
- def setup_gemini(api_key: str = None):
51
- """Setup Gemini Vision Pro with API key"""
52
- global GEMINI_MODEL, API_KEY
53
-
54
- # Try to get API key from various sources
55
- if api_key and api_key.strip():
56
- API_KEY = api_key.strip()
57
- else:
58
- API_KEY = get_api_key_from_secrets()
59
-
60
- if not API_KEY:
61
- return False, "❌ No API key found. Please:\n1. Set GOOGLE_API_KEY in HuggingFace Spaces secrets"
62
-
63
  try:
64
- # Configure the API
65
- genai.configure(api_key=API_KEY)
66
-
67
-
68
- GEMINI_MODEL = genai.GenerativeModel(
69
- 'gemini-1.5-pro'
70
- )
71
-
72
- # Test the connection with a simple query
73
- test_response = GEMINI_MODEL.generate_content(
74
- "Respond with just 'OK' to confirm you can analyze medical images.",
75
- generation_config=genai.types.GenerationConfig(
76
- temperature=0.1,
77
- max_output_tokens=10
78
- )
79
- )
80
-
81
  if test_response and test_response.text:
82
  return True, "✅ Gemini Vision Pro connected successfully!"
83
  else:
84
- return False, "❌ Failed to get response from Gemini API"
85
-
86
  except Exception as e:
87
- error_msg = f"❌ Gemini setup failed: {str(e)}"
88
-
89
- # Provide specific guidance based on error type
90
- if "429" in str(e) or "quota" in str(e).lower():
91
- error_msg += "\n\n💡 **Quota Exceeded Solutions:**\n"
92
- error_msg += "• Check your Google Cloud Console billing\n"
93
- error_msg += "• Verify your API key has sufficient quota\n"
94
- error_msg += "• Try again in a few minutes (rate limiting)\n"
95
- error_msg += "• Consider upgrading your Google AI plan\n"
96
- error_msg += "🔗 Check usage: https://console.cloud.google.com/"
97
-
98
- elif "403" in str(e) or "permission" in str(e).lower():
99
- error_msg += "\n\n💡 **Permission Error Solutions:**\n"
100
- error_msg += "• Ensure Gemini API is enabled in your project\n"
101
- error_msg += "• Check if your API key has proper permissions\n"
102
- error_msg += "• Verify your Google Cloud project settings"
103
-
104
- elif "401" in str(e) or "unauthorized" in str(e).lower():
105
- error_msg += "\n\n💡 **Authentication Error:**\n"
106
- error_msg += "• Double-check your API key is correct\n"
107
- error_msg += "• Ensure no extra spaces in the API key\n"
108
- error_msg += "• Generate a new API key if needed"
109
-
110
- elif "safety" in str(e).lower() or "blocked" in str(e).lower():
111
- error_msg += "\n\n💡 **Content Safety Issue:**\n"
112
- error_msg += "• The image may have triggered safety filters\n"
113
- error_msg += "• Try a different medical image\n"
114
- error_msg += "• Ensure the image is clearly medical in nature"
115
-
116
- return False, error_msg
117
 
118
  def create_medical_prompt(clinical_data: Dict, analysis_type: str, focus_areas: str) -> str:
119
  """Create optimized medical analysis prompt for Gemini"""
120
-
121
- 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.
122
-
123
- **ANALYSIS INSTRUCTIONS:**
124
- Analyze this medical image systematically and professionally:
125
- - Use clear medical terminology with explanations for complex terms
126
- - Structure your response with clear sections and headers
127
- - Be thorough but concise
128
- - Always mention limitations and emphasize the need for professional medical consultation
129
- - Focus on observable findings rather than definitive diagnoses
130
- - This is for educational and research purposes only
131
- """
132
-
133
- # Add clinical context if provided
134
  clinical_context = ""
135
  if clinical_data and any(v.strip() for v in clinical_data.values() if v):
136
  clinical_context = "\n**CLINICAL CONTEXT:**\n"
@@ -140,87 +61,76 @@ Analyze this medical image systematically and professionally:
140
  if clinical_data.get("symptoms"): context_items.append(f"Presenting Symptoms: {clinical_data['symptoms']}")
141
  if clinical_data.get("history"): context_items.append(f"Medical History: {clinical_data['history']}")
142
  if clinical_data.get("medications"): context_items.append(f"Current Medications: {clinical_data['medications']}")
143
-
144
  clinical_context += "\n".join(f"• {item}" for item in context_items) + "\n"
145
-
146
- # Analysis type specific instructions
147
  analysis_instructions = {
148
  "Comprehensive": """
149
  **PROVIDE COMPREHENSIVE ANALYSIS WITH THESE SECTIONS:**
150
-
151
  ## 1. IMAGE ASSESSMENT
152
  - Image type, quality, and technical adequacy
153
  - Anatomical structures and regions visible
154
  - Any artifacts or limitations
155
-
156
  ## 2. CLINICAL FINDINGS
157
  - Normal anatomical structures observed
158
  - Abnormal findings or variations from normal
159
  - Specific measurements or quantitative observations if applicable
160
-
161
  ## 3. CLINICAL INTERPRETATION
162
  - Significance of the findings
163
  - Differential diagnostic considerations
164
  - Correlation with provided clinical history
165
-
166
  ## 4. RECOMMENDATIONS
167
  - Suggested next steps or additional imaging
168
  - Clinical correlation recommendations
169
  - Follow-up suggestions
170
-
171
  ## 5. LIMITATIONS & DISCLAIMERS
172
  - What cannot be determined from this image alone
173
  - Need for clinical correlation and professional evaluation
174
  """,
175
  "Quick Assessment": """
176
  **PROVIDE FOCUSED QUICK ASSESSMENT:**
177
-
178
  ## KEY FINDINGS
179
  - Most significant observations
180
  - Normal vs abnormal structures
181
-
182
  ## CLINICAL IMPRESSION
183
  - Primary considerations based on image
184
  - Any urgent findings that require immediate attention
185
-
186
  ## IMMEDIATE RECOMMENDATIONS
187
  - Essential next steps
188
  - Urgency level assessment
189
-
190
  ## LIMITATIONS
191
  - Important caveats about this assessment
192
  """,
193
  "Educational": """
194
  **PROVIDE EDUCATIONAL ANALYSIS:**
195
-
196
  ## LEARNING OBJECTIVES
197
  - Key educational points from this case
198
  - Important anatomical or pathological concepts
199
-
200
  ## NORMAL vs ABNORMAL
201
  - Clear explanation of what's normal in this image
202
  - Detailed description of any abnormal findings
203
-
204
  ## CLINICAL CORRELATION
205
  - How image findings relate to symptoms/history
206
  - Real-world clinical significance
207
-
208
  ## TEACHING PEARLS
209
  - Important concepts this case demonstrates
210
  - Common pitfalls or considerations
211
  """
212
  }
213
-
214
  focus_instruction = ""
215
  if focus_areas and focus_areas.strip():
216
  focus_instruction = f"\n**SPECIAL FOCUS AREAS**: Pay particular attention to: {focus_areas}\n"
217
-
218
- disclaimer = """
219
- **IMPORTANT MEDICAL DISCLAIMER**:
220
- 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.
221
- """
222
-
223
- return base_prompt + clinical_context + analysis_instructions.get(analysis_type, analysis_instructions["Comprehensive"]) + focus_instruction + disclaimer
 
 
 
 
 
224
 
225
  def analyze_medical_image_gemini(
226
  image: Image.Image,
@@ -231,397 +141,86 @@ def analyze_medical_image_gemini(
231
  medications: str,
232
  analysis_type: str,
233
  focus_areas: str,
234
- api_key: str,
235
  progress=gr.Progress()
236
  ) -> Tuple[str, str, str]:
237
  """Main analysis function using Gemini Vision Pro"""
238
-
239
  if image is None:
240
  return "❌ Please upload an image first.", "", "❌ No image provided"
241
-
242
- # Setup Gemini if needed
243
  progress(0.1, desc="Connecting to Gemini...")
244
- success, status = setup_gemini(api_key)
245
  if not success:
246
  return status, "", status
247
-
248
  try:
249
  progress(0.3, desc="Preparing analysis...")
250
-
251
- # Prepare clinical data
252
  clinical_data = {
253
- "age": age.strip() if age else "",
254
- "gender": gender if gender else "",
255
- "symptoms": symptoms.strip() if symptoms else "",
256
- "history": history.strip() if history else "",
257
- "medications": medications.strip() if medications else ""
258
  }
259
-
260
- # Create prompt
261
  prompt = create_medical_prompt(clinical_data, analysis_type, focus_areas)
262
-
263
  progress(0.5, desc="Analyzing image with Gemini...")
264
-
265
- # Configure generation parameters for better results
266
- generation_config = genai.types.GenerationConfig(
267
- temperature=0.3, # Lower temperature for more consistent medical analysis
268
- max_output_tokens=2048, # Sufficient for detailed analysis
269
- top_p=0.8,
270
- top_k=40
271
- )
272
-
273
- # Generate analysis using Gemini Vision Pro
274
- response = GEMINI_MODEL.generate_content(
275
- [prompt, image],
276
- generation_config=generation_config
277
- )
278
-
279
  if not response or not response.text:
280
- return "❌ No response received from Gemini API. The image may have been blocked by safety filters or there was a processing error.", "", "❌ Analysis failed"
281
-
282
  progress(0.9, desc="Preparing results...")
283
-
284
- # Create download content
285
  report_data = {
286
  "timestamp": time.strftime("%Y-%m-%d %H:%M:%S UTC"),
287
  "model": "Google Gemini-1.5-Pro Vision",
288
  "analysis_type": analysis_type,
289
  "clinical_data": clinical_data,
290
- "focus_areas": focus_areas if focus_areas else "None specified",
291
  "analysis": response.text
292
  }
293
-
294
  download_content = json.dumps(report_data, indent=2)
295
-
296
  progress(1.0, desc="Analysis complete!")
297
-
298
  return response.text, download_content, "✅ Analysis completed successfully"
299
-
300
  except Exception as e:
301
  error_msg = f"❌ Analysis failed: {str(e)}"
302
-
303
- # Provide specific error guidance
304
- if "429" in str(e) or "quota" in str(e).lower():
305
- error_msg += "\n\n💡 **Quota Issue:** You've exceeded your API limits. Please:\n"
306
- error_msg += " Check your Google Cloud Console billing\n"
307
- error_msg += " Wait a few minutes and try again\n"
308
- error_msg += "• Consider upgrading your plan"
309
-
310
- elif "safety" in str(e).lower() or "blocked" in str(e).lower():
311
- error_msg += "\n\n💡 **Safety Filter:** The image was blocked. Try:\n"
312
- error_msg += "• A different medical image\n"
313
- error_msg += "• Ensuring the image is clearly medical\n"
314
- error_msg += "• Removing any potentially sensitive content"
315
-
316
- elif "401" in str(e) or "403" in str(e):
317
- error_msg += "\n\n💡 **Authentication Error:** Check your API key"
318
-
319
  return error_msg, "", error_msg
320
 
321
  def create_interface():
322
  """Create the Gradio interface for Gemini Vision Pro"""
323
-
324
- # Custom CSS for medical theme
325
  css = """
326
- .gradio-container {
327
- max-width: 1400px !important;
328
- }
329
- .medical-header {
330
- text-align: center;
331
- color: #1a73e8;
332
- margin-bottom: 20px;
333
- }
334
- .api-section {
335
- background-color: #e8f0fe;
336
- padding: 15px;
337
- border-radius: 8px;
338
- margin: 10px 0;
339
- border-left: 4px solid #1a73e8;
340
- }
341
- .status-success {
342
- color: #137333;
343
- font-weight: 500;
344
- }
345
- .status-error {
346
- color: #d93025;
347
- font-weight: 500;
348
- }
349
- .quota-info {
350
- background-color: #fff3cd;
351
- padding: 10px;
352
- border-radius: 5px;
353
- margin: 10px 0;
354
- border-left: 3px solid #ffc107;
355
- }
356
  """
357
-
358
  with gr.Blocks(css=css, theme=gr.themes.Soft(), title="Gemini Medical AI") as interface:
359
-
360
- # Header
361
- gr.HTML("""
362
- <div class="medical-header">
363
- <h1>🏥 Medical Image AI Analyzer</h1>
364
- <h2>🤖 Powered by Google Gemini Vision Pro</h2>
365
- <p><em>Fast, efficient medical image analysis using Google's latest AI</em></p>
366
- </div>
367
- """)
368
-
369
- # Check for existing API key on startup
370
- initial_api_key = get_api_key_from_secrets()
371
-
372
- # API Configuration Section
373
- with gr.Accordion("🔑 API Configuration", open=not bool(initial_api_key)):
374
- if initial_api_key:
375
- gr.Markdown("""
376
- ### ✅ API Key Found in Secrets
377
- An API key was found in the environment/secrets.
378
- """)
379
- else:
380
- gr.Markdown("""
381
- ### 🔐 Google Gemini API Setup Required
382
- You need a Google API key to use Gemini Vision Pro.
383
-
384
- **For HuggingFace Spaces:** Add your API key as a secret named `GOOGLE_API_KEY`
385
- **For local use:** Set the `GOOGLE_API_KEY` environment variable or enter it below
386
-
387
- 🔗 Get your API key from: [Google AI Studio](https://makersuite.google.com/app/apikey)
388
- """)
389
-
390
- gr.HTML("""
391
- <div class="quota-info">
392
- <strong>💰 Important:</strong> Make sure your Google API key has sufficient quota and billing is set up.
393
- The 429 error indicates quota limits have been exceeded.
394
- </div>
395
- """)
396
-
397
- api_key_input = gr.Textbox(
398
- label="Google API Key (Optional Override)",
399
- type="password",
400
- placeholder="Enter your Google API key here to override secrets...",
401
- info="Leave empty to use API key from secrets/environment",
402
- value=""
403
- )
404
-
405
- status_display = gr.Textbox(
406
- label="Connection Status",
407
- value="⏳ Testing connection..." if initial_api_key else "⏳ Enter API key to connect",
408
- interactive=False
409
- )
410
-
411
  with gr.Row():
412
- # Left column - Inputs
413
- with gr.Column(scale=1):
414
- gr.Markdown("## 📤 Upload Medical Image")
415
-
416
- image_input = gr.Image(
417
- type="pil",
418
- label="Medical Image",
419
- height=300,
420
- sources=["upload", "clipboard", "webcam"]
421
- )
422
-
423
- gr.Markdown("*Supported: X-rays, CT, MRI, photographs, microscopy, dermatology images, etc.*")
424
-
425
- gr.Markdown("## 📋 Clinical Information")
426
-
427
- with gr.Group():
428
- with gr.Row():
429
- age_input = gr.Textbox(
430
- label="Patient Age",
431
- placeholder="e.g., 45 years",
432
- max_lines=1
433
- )
434
- gender_input = gr.Dropdown(
435
- choices=["", "Male", "Female", "Other"],
436
- label="Gender",
437
- value=""
438
- )
439
-
440
- symptoms_input = gr.Textbox(
441
- label="Chief Complaint / Symptoms",
442
- placeholder="e.g., Chest pain, shortness of breath for 3 days",
443
- lines=2
444
- )
445
-
446
- history_input = gr.Textbox(
447
- label="Medical History",
448
- placeholder="e.g., Hypertension, diabetes, previous surgeries",
449
- lines=2
450
- )
451
-
452
- medications_input = gr.Textbox(
453
- label="Current Medications",
454
- placeholder="e.g., Metformin, Lisinopril, Aspirin",
455
- lines=2
456
- )
457
-
458
- gr.Markdown("## ⚙️ Analysis Settings")
459
-
460
  analysis_type = gr.Radio(
461
  choices=["Comprehensive", "Quick Assessment", "Educational"],
462
- label="Analysis Type",
463
- value="Comprehensive",
464
- info="Choose the depth and focus of analysis"
465
- )
466
-
467
- focus_areas = gr.Textbox(
468
- label="Focus Areas (Optional)",
469
- placeholder="e.g., cardiac silhouette, lung fields, bone density",
470
- info="Specific areas to emphasize in analysis"
471
  )
472
-
473
- analyze_btn = gr.Button(
474
- "🔬 Analyze with Gemini",
475
- variant="primary",
476
- size="lg"
477
- )
478
-
479
- # Right column - Results
480
- with gr.Column(scale=1):
481
- gr.Markdown("## 🤖 AI Analysis Results")
482
-
483
- analysis_output = gr.Textbox(
484
- label="Medical Analysis",
485
- lines=25,
486
- max_lines=35,
487
- show_copy_button=True,
488
- placeholder="Analysis results will appear here after processing..."
489
- )
490
-
491
- download_file = gr.File(
492
- label="📥 Download Analysis Report",
493
- visible=False
494
- )
495
-
496
- # Hidden component to store download content
497
- download_content = gr.Textbox(visible=False)
498
-
499
- # Information sections
500
- with gr.Accordion("🔧 Troubleshooting Common Issues", open=False):
501
- gr.Markdown("""
502
- ### 🚨 **Error 429 - Quota Exceeded:**
503
- - **Check billing:** Ensure your Google Cloud project has billing enabled
504
- - **API limits:** You may have hit free tier limits - consider upgrading
505
- - **Rate limiting:** Wait a few minutes and try again
506
- - **Multiple keys:** Try generating a new API key
507
-
508
- ### 🔐 **For HuggingFace Spaces Users:**
509
- 1. Go to your Space settings
510
- 2. Add a new secret: `GOOGLE_API_KEY`
511
- 3. Paste your Google API key as the value
512
- 4. Restart your Space
513
-
514
- ### 📊 **Monitor Usage:**
515
- - [Google AI Studio Usage](https://makersuite.google.com/)
516
- - [Google Cloud Console](https://console.cloud.google.com/)
517
-
518
- ### 🔄 **If Still Having Issues:**
519
- - Try a different API key
520
- - Check if Gemini API is enabled in your project
521
- - Verify your Google Cloud project settings
522
- """)
523
-
524
- with gr.Accordion("💡 About Gemini Vision Pro", open=False):
525
- gr.Markdown("""
526
- ### 🚀 **Advantages of Gemini Vision Pro:**
527
- - **Fast Processing**: No local model loading - results in seconds
528
- - **Low Resource Usage**: Runs via API calls, minimal local computing needed
529
- - **High Quality**: Google's latest multimodal AI model
530
- - **Always Updated**: Access to the latest model improvements
531
- - **Reliable**: Enterprise-grade infrastructure
532
-
533
- ### 🔍 **Supported Medical Images:**
534
- - **Radiology**: X-rays, CT scans, MRI images, Ultrasound
535
- - **Pathology**: Histological slides, Cytology specimens
536
- - **Dermatology**: Skin lesions, Rashes, Clinical photos
537
- - **Ophthalmology**: Fundus photos, OCT images
538
- - **Clinical Photography**: Wound assessment, Physical findings
539
- - **Microscopy**: Cellular and tissue analysis
540
-
541
- ### 💰 **Cost Information:**
542
- - Gemini Vision Pro uses pay-per-use pricing
543
- - Typically very affordable for individual analyses
544
- - Check [Google AI Pricing](https://ai.google.dev/pricing) for current rates
545
- """)
546
-
547
- # Footer
548
- gr.HTML("""
549
- <div style="text-align: center; margin-top: 20px; padding: 15px; background-color: #fff3cd; border-radius: 8px;">
550
- <strong>⚠️ Medical Disclaimer:</strong> This AI tool is for educational and research purposes only.
551
- It should never replace professional medical diagnosis or treatment.
552
- Always consult qualified healthcare providers for medical decisions.
553
- </div>
554
- """)
555
-
556
- # Event handlers
557
- def create_download_file(content):
558
- if content:
559
- filename = f"gemini_medical_analysis_{int(time.time())}.json"
560
- with open(filename, "w") as f:
561
- f.write(content)
562
- return gr.File(value=filename, visible=True)
563
- return gr.File(visible=False)
564
-
565
- def test_api_connection(api_key_override):
566
- # Use override if provided, otherwise use secrets
567
- test_key = api_key_override if api_key_override.strip() else None
568
- success, status = setup_gemini(test_key)
569
- return status
570
-
571
- # Test connection on startup if we have an API key
572
- if initial_api_key:
573
- def initial_connection_test():
574
- return test_api_connection("")
575
-
576
- interface.load(
577
- fn=initial_connection_test,
578
- outputs=[status_display]
579
- )
580
-
581
- # API key testing
582
- api_key_input.change(
583
- fn=test_api_connection,
584
- inputs=[api_key_input],
585
- outputs=[status_display]
586
- )
587
-
588
- # Main analysis
589
  analyze_btn.click(
590
- fn=analyze_medical_image_gemini,
591
- inputs=[
592
- image_input, age_input, gender_input, symptoms_input,
593
- history_input, medications_input, analysis_type, focus_areas, api_key_input
594
- ],
595
- outputs=[analysis_output, download_content, status_display]
596
- ).then(
597
- fn=create_download_file,
598
- inputs=[download_content],
599
- outputs=[download_file]
600
  )
601
-
602
  return interface
603
 
604
  if __name__ == "__main__":
605
- print("🏥 Initializing Gemini Medical AI Analyzer...")
606
- print("🔍 Checking for API keys in secrets/environment...")
607
-
608
- # Check for API key
609
- api_key_found = get_api_key_from_secrets()
610
- if api_key_found:
611
- print("✅ API key found in environment/secrets")
612
- else:
613
- print("⚠️ No API key found - user will need to provide one")
614
-
615
- print("🚀 No local model loading required - using Google Gemini Vision Pro API")
616
-
617
- # Create and launch interface
618
- interface = create_interface()
619
-
620
- # Launch with optimized settings
621
- interface.launch(
622
- server_name="0.0.0.0",
623
- server_port=7860,
624
- share=False,
625
- show_error=True,
626
- quiet=False
627
- )
 
1
  #!/usr/bin/env python3
2
  """
3
+ Gemini Vision Pro Medical Image Analysis - Secure Gradio Interface
4
+ API key is loaded only from environment variables or .env file (never exposed to users)
5
  """
6
 
7
  import gradio as gr
 
10
  import json
11
  import time
12
  import os
13
+ from typing import Dict, Tuple
14
+ from dotenv import load_dotenv # pip install python-dotenv
 
15
  import warnings
16
+
17
  warnings.filterwarnings("ignore")
18
 
19
+ # Load environment variables from .env if present
20
+ load_dotenv()
 
21
 
22
+ # Global model instance
23
+ GEMINI_MODEL = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ def setup_gemini():
26
+ """Initialize Gemini Vision Pro using API key from environment (never exposed to users)"""
27
+ global GEMINI_MODEL
28
+ api_key = os.getenv('GOOGLE_API_KEY') or os.getenv('GEMINI_API_KEY')
29
+ if not api_key:
30
+ return False, "❌ No API key found. Please set GOOGLE_API_KEY or GEMINI_API_KEY in your environment or .env file."
 
 
 
 
 
 
 
31
  try:
32
+ genai.configure(api_key=api_key)
33
+ GEMINI_MODEL = genai.GenerativeModel('gemini-1.5-pro')
34
+ # Test connection
35
+ test_response = GEMINI_MODEL.generate_content("Hello, can you help with medical image analysis?")
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  if test_response and test_response.text:
37
  return True, "✅ Gemini Vision Pro connected successfully!"
38
  else:
39
+ return False, "❌ Failed to connect to Gemini API"
 
40
  except Exception as e:
41
+ return False, f"❌ Gemini setup failed: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
  def create_medical_prompt(clinical_data: Dict, analysis_type: str, focus_areas: str) -> str:
44
  """Create optimized medical analysis prompt for Gemini"""
45
+ base_prompt = (
46
+ "You are an expert medical AI assistant specializing in medical image analysis. "
47
+ "You have extensive training across radiology, pathology, dermatology, ophthalmology, and clinical medicine.\n"
48
+ "**ANALYSIS INSTRUCTIONS:**\n"
49
+ "- Use clear medical terminology with explanations for complex terms\n"
50
+ "- Structure your response with clear sections and headers\n"
51
+ "- Be thorough but concise\n"
52
+ "- Always mention limitations and emphasize the need for professional medical consultation\n"
53
+ "- Focus on observable findings rather than definitive diagnoses\n"
54
+ )
 
 
 
 
55
  clinical_context = ""
56
  if clinical_data and any(v.strip() for v in clinical_data.values() if v):
57
  clinical_context = "\n**CLINICAL CONTEXT:**\n"
 
61
  if clinical_data.get("symptoms"): context_items.append(f"Presenting Symptoms: {clinical_data['symptoms']}")
62
  if clinical_data.get("history"): context_items.append(f"Medical History: {clinical_data['history']}")
63
  if clinical_data.get("medications"): context_items.append(f"Current Medications: {clinical_data['medications']}")
 
64
  clinical_context += "\n".join(f"• {item}" for item in context_items) + "\n"
65
+
 
66
  analysis_instructions = {
67
  "Comprehensive": """
68
  **PROVIDE COMPREHENSIVE ANALYSIS WITH THESE SECTIONS:**
 
69
  ## 1. IMAGE ASSESSMENT
70
  - Image type, quality, and technical adequacy
71
  - Anatomical structures and regions visible
72
  - Any artifacts or limitations
 
73
  ## 2. CLINICAL FINDINGS
74
  - Normal anatomical structures observed
75
  - Abnormal findings or variations from normal
76
  - Specific measurements or quantitative observations if applicable
 
77
  ## 3. CLINICAL INTERPRETATION
78
  - Significance of the findings
79
  - Differential diagnostic considerations
80
  - Correlation with provided clinical history
 
81
  ## 4. RECOMMENDATIONS
82
  - Suggested next steps or additional imaging
83
  - Clinical correlation recommendations
84
  - Follow-up suggestions
 
85
  ## 5. LIMITATIONS & DISCLAIMERS
86
  - What cannot be determined from this image alone
87
  - Need for clinical correlation and professional evaluation
88
  """,
89
  "Quick Assessment": """
90
  **PROVIDE FOCUSED QUICK ASSESSMENT:**
 
91
  ## KEY FINDINGS
92
  - Most significant observations
93
  - Normal vs abnormal structures
 
94
  ## CLINICAL IMPRESSION
95
  - Primary considerations based on image
96
  - Any urgent findings that require immediate attention
 
97
  ## IMMEDIATE RECOMMENDATIONS
98
  - Essential next steps
99
  - Urgency level assessment
 
100
  ## LIMITATIONS
101
  - Important caveats about this assessment
102
  """,
103
  "Educational": """
104
  **PROVIDE EDUCATIONAL ANALYSIS:**
 
105
  ## LEARNING OBJECTIVES
106
  - Key educational points from this case
107
  - Important anatomical or pathological concepts
 
108
  ## NORMAL vs ABNORMAL
109
  - Clear explanation of what's normal in this image
110
  - Detailed description of any abnormal findings
 
111
  ## CLINICAL CORRELATION
112
  - How image findings relate to symptoms/history
113
  - Real-world clinical significance
 
114
  ## TEACHING PEARLS
115
  - Important concepts this case demonstrates
116
  - Common pitfalls or considerations
117
  """
118
  }
 
119
  focus_instruction = ""
120
  if focus_areas and focus_areas.strip():
121
  focus_instruction = f"\n**SPECIAL FOCUS AREAS**: Pay particular attention to: {focus_areas}\n"
122
+ disclaimer = (
123
+ "**IMPORTANT MEDICAL DISCLAIMER**: This AI-powered analysis is for educational and research purposes only. "
124
+ "It should never replace professional medical diagnosis, treatment, or consultation with qualified healthcare providers. "
125
+ "Always seek professional medical advice for any health concerns or medical decisions."
126
+ )
127
+ return (
128
+ base_prompt
129
+ + clinical_context
130
+ + analysis_instructions.get(analysis_type, analysis_instructions["Comprehensive"])
131
+ + focus_instruction
132
+ + disclaimer
133
+ )
134
 
135
  def analyze_medical_image_gemini(
136
  image: Image.Image,
 
141
  medications: str,
142
  analysis_type: str,
143
  focus_areas: str,
 
144
  progress=gr.Progress()
145
  ) -> Tuple[str, str, str]:
146
  """Main analysis function using Gemini Vision Pro"""
 
147
  if image is None:
148
  return "❌ Please upload an image first.", "", "❌ No image provided"
 
 
149
  progress(0.1, desc="Connecting to Gemini...")
150
+ success, status = setup_gemini()
151
  if not success:
152
  return status, "", status
 
153
  try:
154
  progress(0.3, desc="Preparing analysis...")
 
 
155
  clinical_data = {
156
+ "age": age.strip(),
157
+ "gender": gender,
158
+ "symptoms": symptoms.strip(),
159
+ "history": history.strip(),
160
+ "medications": medications.strip()
161
  }
 
 
162
  prompt = create_medical_prompt(clinical_data, analysis_type, focus_areas)
 
163
  progress(0.5, desc="Analyzing image with Gemini...")
164
+ response = GEMINI_MODEL.generate_content([prompt, image])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  if not response or not response.text:
166
+ return "❌ No response received from Gemini API", "", "❌ Analysis failed"
 
167
  progress(0.9, desc="Preparing results...")
 
 
168
  report_data = {
169
  "timestamp": time.strftime("%Y-%m-%d %H:%M:%S UTC"),
170
  "model": "Google Gemini-1.5-Pro Vision",
171
  "analysis_type": analysis_type,
172
  "clinical_data": clinical_data,
173
+ "focus_areas": focus_areas,
174
  "analysis": response.text
175
  }
 
176
  download_content = json.dumps(report_data, indent=2)
 
177
  progress(1.0, desc="Analysis complete!")
 
178
  return response.text, download_content, "✅ Analysis completed successfully"
 
179
  except Exception as e:
180
  error_msg = f"❌ Analysis failed: {str(e)}"
181
+ if "API_KEY" in str(e):
182
+ error_msg += "\n\n💡 Tip: Make sure your Google API key is valid and has access to Gemini API"
183
+ elif "quota" in str(e).lower():
184
+ error_msg += "\n\n💡 Tip: You may have exceeded your API quota. Check your Google Cloud Console"
185
+ elif "safety" in str(e).lower():
186
+ error_msg += "\n\n💡 Tip: The image may have been blocked by safety filters. Try a different medical image"
 
 
 
 
 
 
 
 
 
 
 
187
  return error_msg, "", error_msg
188
 
189
  def create_interface():
190
  """Create the Gradio interface for Gemini Vision Pro"""
 
 
191
  css = """
192
+ .gradio-container { max-width: 1400px !important; }
193
+ .medical-header { text-align: center; color: #1a73e8; margin-bottom: 20px; }
194
+ .status-success { color: #137333; font-weight: 500; }
195
+ .status-error { color: #d93025; font-weight: 500; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  """
 
197
  with gr.Blocks(css=css, theme=gr.themes.Soft(), title="Gemini Medical AI") as interface:
198
+ gr.HTML("<h1 class='medical-header'>Gemini Vision Pro Medical Image Analysis</h1><p>*Fast, efficient medical image analysis using Google's latest AI*</p>")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  with gr.Row():
200
+ with gr.Column():
201
+ image_input = gr.Image(type="pil", label="Upload a medical image")
202
+ age = gr.Textbox(label="Patient Age", placeholder="e.g. 47")
203
+ gender = gr.Dropdown(choices=["Male", "Female", "Other", "Unknown"], label="Gender", value="Unknown")
204
+ symptoms = gr.Textbox(label="Symptoms", placeholder="Describe presenting symptoms")
205
+ history = gr.Textbox(label="Medical History", placeholder="Relevant medical history")
206
+ medications = gr.Textbox(label="Current Medications", placeholder="List current medications")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  analysis_type = gr.Radio(
208
  choices=["Comprehensive", "Quick Assessment", "Educational"],
209
+ value="Comprehensive", label="Analysis Type"
 
 
 
 
 
 
 
 
210
  )
211
+ focus_areas = gr.Textbox(label="Special Focus Areas", placeholder="e.g. lung nodules, bone lesions")
212
+ analyze_btn = gr.Button("Analyze Image", variant="primary")
213
+ with gr.Column():
214
+ status = gr.Markdown(value="", elem_classes="status-success")
215
+ output = gr.Markdown(label="AI Medical Analysis")
216
+ download = gr.DownloadButton(label="Download Report", file_name="analysis_report.json")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  analyze_btn.click(
218
+ analyze_medical_image_gemini,
219
+ inputs=[image_input, age, gender, symptoms, history, medications, analysis_type, focus_areas],
220
+ outputs=[output, download, status]
 
 
 
 
 
 
 
221
  )
 
222
  return interface
223
 
224
  if __name__ == "__main__":
225
+ demo = create_interface()
226
+ demo.launch()