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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +288 -215
app.py CHANGED
@@ -1,226 +1,299 @@
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
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, 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"
58
- context_items = []
59
- if clinical_data.get("age"): context_items.append(f"Patient Age: {clinical_data['age']}")
60
- if clinical_data.get("gender"): context_items.append(f"Gender: {clinical_data['gender']}")
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,
137
- age: str,
138
- gender: str,
139
- symptoms: str,
140
- history: str,
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()
 
 
 
 
 
 
 
1
  import gradio as gr
2
  import google.generativeai as genai
3
  from PIL import Image
4
  import json
5
+ from typing import List, Dict, Any
6
  import os
7
+ from datetime import datetime
8
+
9
+ # Configure Gemini API
10
+ # You'll need to set this as an environment variable in Hugging Face Spaces
11
+ GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
12
+
13
+ class MedicalAssistant:
14
+ def __init__(self):
15
+ if not GOOGLE_API_KEY:
16
+ raise ValueError("Please set GOOGLE_API_KEY environment variable")
17
+
18
+ genai.configure(api_key=GOOGLE_API_KEY)
19
+
20
+ # Use Gemini Pro Vision for multimodal capabilities
21
+ self.model = genai.GenerativeModel('gemini-1.5-pro-latest')
22
+
23
+ # Medical analysis prompt template
24
+ self.medical_prompt_template = """
25
+ You are an expert medical AI assistant with comprehensive training in medical imaging, diagnostics, and clinical decision support. Your analysis should be thorough, evidence-based, and clinically relevant.
26
+
27
+ **IMPORTANT DISCLAIMERS:**
28
+ - This analysis is for educational and assistive purposes only
29
+ - It does not replace professional medical consultation
30
+ - All findings should be verified by qualified healthcare providers
31
+ - Emergency cases require immediate medical attention
32
+
33
+ **PATIENT INFORMATION:**
34
+ {patient_info}
35
+
36
+ **CHIEF COMPLAINTS:**
37
+ {complaints}
38
+
39
+ **MEDICAL IMAGES PROVIDED:**
40
+ {image_count} image(s) uploaded for analysis
41
+
42
+ **TASK:**
43
+ Please provide a comprehensive medical analysis including:
44
+
45
+ 1. **IMAGE ANALYSIS** (if images provided):
46
+ - Systematic description of visible findings
47
+ - Anatomical structures identified
48
+ - Any abnormalities, lesions, or pathological changes
49
+ - Image quality and limitations assessment
50
+
51
+ 2. **CLINICAL CORRELATION:**
52
+ - How imaging findings relate to patient symptoms
53
+ - Differential diagnoses based on presentation
54
+ - Risk factors and red flags identified
55
+
56
+ 3. **DIFFERENTIAL DIAGNOSES:**
57
+ - List 3-5 most likely diagnoses with reasoning
58
+ - Include probability assessment if possible
59
+ - Consider both common and critical conditions
60
+
61
+ 4. **RECOMMENDED INVESTIGATIONS:**
62
+ - Additional imaging studies if needed
63
+ - Laboratory tests to consider
64
+ - Specialist consultations advised
65
+
66
+ 5. **IMMEDIATE CONCERNS:**
67
+ - Any findings requiring urgent attention
68
+ - Red flags or emergency indicators
69
+
70
+ 6. **MANAGEMENT SUGGESTIONS:**
71
+ - Initial treatment considerations
72
+ - Follow-up recommendations
73
+ - Patient education points
74
+
75
+ 7. **LIMITATIONS & CONSIDERATIONS:**
76
+ - Limitations of the current analysis
77
+ - Information gaps that need addressing
78
+ - Quality of provided data
79
+
80
+ Please structure your response clearly with appropriate medical terminology while ensuring it's understandable. Use evidence-based medicine principles and cite relevant clinical guidelines where applicable.
81
+
82
+ Remember to maintain a professional, empathetic tone and emphasize the importance of professional medical consultation for definitive diagnosis and treatment.
83
+ """
84
+
85
+ def format_patient_info(self, age, gender, medical_history, current_medications, allergies, vital_signs):
86
+ """Format patient information for the prompt"""
87
+ info = []
88
+ if age:
89
+ info.append(f"Age: {age}")
90
+ if gender:
91
+ info.append(f"Gender: {gender}")
92
+ if medical_history:
93
+ info.append(f"Medical History: {medical_history}")
94
+ if current_medications:
95
+ info.append(f"Current Medications: {current_medications}")
96
+ if allergies:
97
+ info.append(f"Allergies: {allergies}")
98
+ if vital_signs:
99
+ info.append(f"Vital Signs: {vital_signs}")
100
+
101
+ return "\n".join(info) if info else "No patient information provided"
102
+
103
+ def analyze_medical_case(self, images, age, gender, medical_history,
104
+ current_medications, allergies, vital_signs, complaints):
105
+ """Analyze medical case with Gemini"""
106
+ try:
107
+ # Format patient information
108
+ patient_info = self.format_patient_info(
109
+ age, gender, medical_history, current_medications,
110
+ allergies, vital_signs
111
+ )
112
+
113
+ # Prepare the prompt
114
+ prompt = self.medical_prompt_template.format(
115
+ patient_info=patient_info,
116
+ complaints=complaints if complaints else "No specific complaints provided",
117
+ image_count=len(images) if images else 0
118
+ )
119
+
120
+ # Prepare content for Gemini
121
+ content = [prompt]
122
+
123
+ # Add images if provided
124
+ if images:
125
+ for img_path in images:
126
+ try:
127
+ img = Image.open(img_path)
128
+ content.append(img)
129
+ except Exception as e:
130
+ return f"Error loading image {img_path}: {str(e)}"
131
+
132
+ # Generate response
133
+ response = self.model.generate_content(content)
134
+
135
+ # Add timestamp and disclaimer
136
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
137
+ output = f"**Analysis Generated on: {timestamp}**\n\n"
138
+ output += "⚠️ **MEDICAL DISCLAIMER**: This is an AI-generated analysis for educational purposes only. "
139
+ output += "It is not a substitute for professional medical advice, diagnosis, or treatment. "
140
+ output += "Always seek the advice of qualified healthcare providers.\n\n"
141
+ output += "---\n\n"
142
+ output += response.text
143
+
144
+ return output
145
+
146
+ except Exception as e:
147
+ return f"Error during analysis: {str(e)}\n\nPlease check your API key and inputs."
148
+
149
+ # Initialize the assistant
150
+ assistant = MedicalAssistant()
151
+
152
+ # Create Gradio interface
153
+ def process_medical_case(images, age, gender, medical_history,
154
+ current_medications, allergies, vital_signs, complaints):
155
+ """Process medical case through Gradio interface"""
156
+
157
+ # Validate inputs
158
+ if not complaints and not images:
159
+ return "Please provide either medical images or patient complaints for analysis."
160
+
161
+ # Get image paths if images uploaded
162
+ image_paths = []
163
+ if images:
164
+ if isinstance(images, list):
165
+ image_paths = [img.name if hasattr(img, 'name') else img for img in images]
166
  else:
167
+ image_paths = [images.name if hasattr(images, 'name') else images]
168
+
169
+ # Run analysis
170
+ result = assistant.analyze_medical_case(
171
+ image_paths, age, gender, medical_history,
172
+ current_medications, allergies, vital_signs, complaints
 
 
 
 
 
 
 
 
 
173
  )
174
+
175
+ return result
176
+
177
+ # Create Gradio interface
178
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
179
+ gr.Markdown(
180
+ """
181
+ # 🏥 Medical AI Assistant powered by Gemini
182
+
183
+ This AI assistant analyzes medical images and patient data to provide clinical insights.
184
+ Upload medical images and enter patient information for comprehensive analysis.
185
+
186
+ **Note**: Ensure you have set the GOOGLE_API_KEY environment variable in your Hugging Face Space settings.
187
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  )
189
+
190
+ with gr.Row():
191
+ with gr.Column(scale=1):
192
+ gr.Markdown("### 📋 Patient Information")
193
+ age = gr.Number(label="Age", precision=0)
194
+ gender = gr.Dropdown(
195
+ label="Gender",
196
+ choices=["Male", "Female", "Other", "Prefer not to say"],
197
+ value="Prefer not to say"
198
+ )
199
+ medical_history = gr.Textbox(
200
+ label="Medical History",
201
+ placeholder="Previous diagnoses, surgeries, chronic conditions...",
202
+ lines=3
203
+ )
204
+ current_medications = gr.Textbox(
205
+ label="Current Medications",
206
+ placeholder="List all current medications and dosages...",
207
+ lines=2
208
+ )
209
+ allergies = gr.Textbox(
210
+ label="Allergies",
211
+ placeholder="Drug allergies, food allergies, etc...",
212
+ lines=2
213
+ )
214
+ vital_signs = gr.Textbox(
215
+ label="Vital Signs",
216
+ placeholder="BP: 120/80, HR: 72, Temp: 98.6°F, etc...",
217
+ lines=2
218
+ )
219
+
220
+ with gr.Column(scale=1):
221
+ gr.Markdown("### 🏥 Clinical Data")
222
+ complaints = gr.Textbox(
223
+ label="Chief Complaints & Symptoms",
224
+ placeholder="Describe main symptoms, duration, severity, associated factors...",
225
+ lines=6
226
+ )
227
+ images = gr.File(
228
+ label="Medical Images",
229
+ file_count="multiple",
230
+ file_types=["image"],
231
+ type="filepath"
232
+ )
233
+ gr.Markdown(
234
+ """
235
+ **Supported formats**: X-rays, CT scans, MRI, ultrasound, clinical photos
236
+
237
+ **Privacy Note**: Ensure all images are properly anonymized
238
+ """
239
+ )
240
+
241
+ submit_btn = gr.Button("🔬 Analyze Case", variant="primary", size="lg")
242
+
243
+ output = gr.Markdown(label="Analysis Results")
244
+
245
+ # Examples
246
+ gr.Examples(
247
+ examples=[
248
+ [
249
+ None, # images
250
+ 45, # age
251
+ "Male", # gender
252
+ "Hypertension for 5 years, Type 2 diabetes", # medical history
253
+ "Metformin 500mg BD, Amlodipine 5mg OD", # medications
254
+ "None known", # allergies
255
+ "BP: 140/90, HR: 78, RR: 16", # vital signs
256
+ "Chest pain for 2 days, radiating to left arm, associated with shortness of breath" # complaints
257
+ ],
258
+ [
259
+ None,
260
+ 28,
261
+ "Female",
262
+ "Migraine headaches",
263
+ "None",
264
+ "Penicillin - rash",
265
+ "BP: 110/70, HR: 68",
266
+ "Severe headache, photophobia, nausea for 6 hours"
267
+ ]
268
+ ],
269
+ inputs=[images, age, gender, medical_history, current_medications,
270
+ allergies, vital_signs, complaints]
271
+ )
272
+
273
+ submit_btn.click(
274
+ fn=process_medical_case,
275
+ inputs=[images, age, gender, medical_history, current_medications,
276
+ allergies, vital_signs, complaints],
277
+ outputs=output
278
+ )
279
+
280
+ gr.Markdown(
281
+ """
282
+ ---
283
+ ### ⚕️ Important Information:
284
+ - This tool is for educational and assistive purposes only
285
+ - Always consult qualified healthcare professionals for medical decisions
286
+ - Ensure patient privacy and HIPAA compliance when using this tool
287
+ - Report any issues or feedback to improve the system
288
+
289
+ ### 🔧 Setup Instructions for Hugging Face:
290
+ 1. Create a Space on Hugging Face
291
+ 2. Add your Google API key as a secret: GOOGLE_API_KEY
292
+ 3. Install requirements: `google-generativeai gradio pillow`
293
+ 4. Deploy this code
294
+ """
295
  )
296
 
297
+ # Launch the app
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  if __name__ == "__main__":
299
+ demo.launch()