Update app.py
Browse files
app.py
CHANGED
@@ -5,6 +5,13 @@ from PIL import Image
|
|
5 |
import io # Needed for handling image bytes
|
6 |
from typing import Optional, Tuple, Any # For type hinting
|
7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
# --- Configuration and Initialization ---
|
9 |
|
10 |
# Securely load API key
|
@@ -18,6 +25,8 @@ if GEMINI_API_KEY:
|
|
18 |
genai.configure(api_key=GEMINI_API_KEY)
|
19 |
genai_client_configured = True
|
20 |
except Exception as e:
|
|
|
|
|
21 |
st.error(f"Fatal Error: Failed to configure Google Generative AI. Check API Key. Details: {e}")
|
22 |
st.stop() # Stop execution if configuration fails
|
23 |
else:
|
@@ -25,7 +34,6 @@ else:
|
|
25 |
st.stop() # Stop execution if no API key
|
26 |
|
27 |
# Initialize models (Consider more powerful model for agentic reasoning if needed)
|
28 |
-
# Using 1.5 Pro for text (agentic) and 1.5 Flash for vision might be a good balance
|
29 |
TEXT_MODEL_NAME = 'gemini-1.5-pro-latest' # Model for agentic text reasoning
|
30 |
VISION_MODEL_NAME = 'gemini-1.5-flash' # Model for image analysis
|
31 |
|
@@ -33,11 +41,14 @@ if genai_client_configured:
|
|
33 |
try:
|
34 |
text_model = genai.GenerativeModel(TEXT_MODEL_NAME)
|
35 |
vision_model = genai.GenerativeModel(VISION_MODEL_NAME)
|
36 |
-
|
|
|
37 |
except Exception as e:
|
38 |
st.error(f"Fatal Error: Failed to initialize Gemini models. Text: {TEXT_MODEL_NAME}, Vision: {VISION_MODEL_NAME}. Details: {e}")
|
39 |
st.stop()
|
40 |
else:
|
|
|
|
|
41 |
st.error("AI Models could not be initialized due to configuration issues.")
|
42 |
st.stop()
|
43 |
|
@@ -132,8 +143,10 @@ def run_agentic_text_analysis(text_input: str) -> Tuple[Optional[str], Optional[
|
|
132 |
return None, "Received an empty or unexpected response from the AI model."
|
133 |
|
134 |
except Exception as e:
|
135 |
-
|
136 |
-
|
|
|
|
|
137 |
|
138 |
def analyze_medical_image(image_file: Any, user_prompt: str = "") -> Tuple[Optional[str], Optional[str]]:
|
139 |
"""
|
@@ -173,18 +186,16 @@ def analyze_medical_image(image_file: Any, user_prompt: str = "") -> Tuple[Optio
|
|
173 |
return None, "Received an empty or unexpected response from the AI model for image analysis."
|
174 |
|
175 |
except Exception as e:
|
176 |
-
|
177 |
-
|
|
|
|
|
178 |
|
179 |
|
180 |
# --- Streamlit User Interface ---
|
181 |
|
182 |
def main():
|
183 |
-
st.set_page_config(
|
184 |
-
page_title="AI Clinical Support Demonstrator",
|
185 |
-
layout="wide",
|
186 |
-
initial_sidebar_state="expanded"
|
187 |
-
)
|
188 |
|
189 |
st.title("π€ AI Clinical Support Demonstrator")
|
190 |
st.caption(f"Agentic Text Analysis ({TEXT_MODEL_NAME}) & Image Analysis ({VISION_MODEL_NAME})")
|
@@ -259,6 +270,7 @@ def main():
|
|
259 |
|
260 |
if analyze_button:
|
261 |
if image_file:
|
|
|
262 |
st.image(image_file, caption="Uploaded Image Preview", use_column_width=True)
|
263 |
with st.spinner("ποΈ Analyzing image..."):
|
264 |
analysis_result, error_message = analyze_medical_image(image_file, user_image_prompt)
|
@@ -269,17 +281,24 @@ def main():
|
|
269 |
# --- Output Column ---
|
270 |
with col2:
|
271 |
st.header(output_header)
|
272 |
-
#
|
273 |
-
#
|
274 |
-
button_pressed = st.session_state.get('analyze_text_button', False) or
|
275 |
-
|
276 |
-
|
|
|
|
|
|
|
277 |
if error_message:
|
278 |
st.error(f"Analysis Failed: {error_message}", icon="β")
|
279 |
elif analysis_result:
|
280 |
st.markdown(analysis_result) # Display the successful result
|
281 |
-
#
|
282 |
-
|
|
|
|
|
|
|
|
|
283 |
st.info("Analysis results will appear here after providing input and clicking the corresponding analysis button.")
|
284 |
|
285 |
|
@@ -298,5 +317,9 @@ def main():
|
|
298 |
"**Ethical Use Reminder:** AI in medicine requires extreme caution. This tool is for demonstration and education, not clinical practice. Verify all information and rely on professional expertise."
|
299 |
)
|
300 |
|
|
|
301 |
if __name__ == "__main__":
|
|
|
|
|
|
|
302 |
main()
|
|
|
5 |
import io # Needed for handling image bytes
|
6 |
from typing import Optional, Tuple, Any # For type hinting
|
7 |
|
8 |
+
# --- Page Configuration (MUST BE THE FIRST STREAMLIT COMMAND) ---
|
9 |
+
st.set_page_config(
|
10 |
+
page_title="AI Clinical Support Demonstrator",
|
11 |
+
layout="wide",
|
12 |
+
initial_sidebar_state="expanded"
|
13 |
+
)
|
14 |
+
|
15 |
# --- Configuration and Initialization ---
|
16 |
|
17 |
# Securely load API key
|
|
|
25 |
genai.configure(api_key=GEMINI_API_KEY)
|
26 |
genai_client_configured = True
|
27 |
except Exception as e:
|
28 |
+
# Use st.exception() for a more detailed error in the app if needed during debugging
|
29 |
+
# st.exception(e)
|
30 |
st.error(f"Fatal Error: Failed to configure Google Generative AI. Check API Key. Details: {e}")
|
31 |
st.stop() # Stop execution if configuration fails
|
32 |
else:
|
|
|
34 |
st.stop() # Stop execution if no API key
|
35 |
|
36 |
# Initialize models (Consider more powerful model for agentic reasoning if needed)
|
|
|
37 |
TEXT_MODEL_NAME = 'gemini-1.5-pro-latest' # Model for agentic text reasoning
|
38 |
VISION_MODEL_NAME = 'gemini-1.5-flash' # Model for image analysis
|
39 |
|
|
|
41 |
try:
|
42 |
text_model = genai.GenerativeModel(TEXT_MODEL_NAME)
|
43 |
vision_model = genai.GenerativeModel(VISION_MODEL_NAME)
|
44 |
+
# Optional: Display success message (won't violate the rule as set_page_config was first)
|
45 |
+
# st.sidebar.success(f"Models Initialized ({TEXT_MODEL_NAME}, {VISION_MODEL_NAME})", icon="β
")
|
46 |
except Exception as e:
|
47 |
st.error(f"Fatal Error: Failed to initialize Gemini models. Text: {TEXT_MODEL_NAME}, Vision: {VISION_MODEL_NAME}. Details: {e}")
|
48 |
st.stop()
|
49 |
else:
|
50 |
+
# This state should not be reached due to earlier st.stop() calls,
|
51 |
+
# but included for completeness.
|
52 |
st.error("AI Models could not be initialized due to configuration issues.")
|
53 |
st.stop()
|
54 |
|
|
|
143 |
return None, "Received an empty or unexpected response from the AI model."
|
144 |
|
145 |
except Exception as e:
|
146 |
+
# Log error for debugging purposes server-side if possible
|
147 |
+
print(f"ERROR in run_agentic_text_analysis: {e}") # Simple print for demo
|
148 |
+
st.error(f"Error during agentic text analysis. Check logs if possible.", icon="π¨") # Keep UI error generic
|
149 |
+
return None, f"An internal error occurred during text analysis." # Generic message to user
|
150 |
|
151 |
def analyze_medical_image(image_file: Any, user_prompt: str = "") -> Tuple[Optional[str], Optional[str]]:
|
152 |
"""
|
|
|
186 |
return None, "Received an empty or unexpected response from the AI model for image analysis."
|
187 |
|
188 |
except Exception as e:
|
189 |
+
# Log error for debugging purposes server-side if possible
|
190 |
+
print(f"ERROR in analyze_medical_image: {e}") # Simple print for demo
|
191 |
+
st.error(f"Error during image analysis. Check logs if possible.", icon="πΌοΈ") # Keep UI error generic
|
192 |
+
return None, f"An internal error occurred during image analysis." # Generic message to user
|
193 |
|
194 |
|
195 |
# --- Streamlit User Interface ---
|
196 |
|
197 |
def main():
|
198 |
+
# REMOVED st.set_page_config() FROM HERE
|
|
|
|
|
|
|
|
|
199 |
|
200 |
st.title("π€ AI Clinical Support Demonstrator")
|
201 |
st.caption(f"Agentic Text Analysis ({TEXT_MODEL_NAME}) & Image Analysis ({VISION_MODEL_NAME})")
|
|
|
270 |
|
271 |
if analyze_button:
|
272 |
if image_file:
|
273 |
+
# Using st.image within the column context
|
274 |
st.image(image_file, caption="Uploaded Image Preview", use_column_width=True)
|
275 |
with st.spinner("ποΈ Analyzing image..."):
|
276 |
analysis_result, error_message = analyze_medical_image(image_file, user_image_prompt)
|
|
|
281 |
# --- Output Column ---
|
282 |
with col2:
|
283 |
st.header(output_header)
|
284 |
+
# Determine if analysis was attempted in this run
|
285 |
+
# Use session state keys which are set when buttons are clicked
|
286 |
+
button_pressed = st.session_state.get('analyze_text_button', False) or \
|
287 |
+
st.session_state.get('analyze_image_button', False)
|
288 |
+
|
289 |
+
if button_pressed:
|
290 |
+
# Check if the button was clicked AND we have results or an error from that action
|
291 |
+
# analysis_result and error_message are set within the button's if block in col1
|
292 |
if error_message:
|
293 |
st.error(f"Analysis Failed: {error_message}", icon="β")
|
294 |
elif analysis_result:
|
295 |
st.markdown(analysis_result) # Display the successful result
|
296 |
+
# If button was pressed but neither error nor result is set, maybe input was invalid
|
297 |
+
# The warnings for empty input are handled in col1, so this case might not be needed
|
298 |
+
# else:
|
299 |
+
# st.info("Provide valid input and click Analyze.") # Fallback?
|
300 |
+
|
301 |
+
else: # No button pressed in this run
|
302 |
st.info("Analysis results will appear here after providing input and clicking the corresponding analysis button.")
|
303 |
|
304 |
|
|
|
317 |
"**Ethical Use Reminder:** AI in medicine requires extreme caution. This tool is for demonstration and education, not clinical practice. Verify all information and rely on professional expertise."
|
318 |
)
|
319 |
|
320 |
+
# --- Main Execution Guard ---
|
321 |
if __name__ == "__main__":
|
322 |
+
# Ensure configuration happens before main UI logic runs
|
323 |
+
# NOTE: The config/init code now runs automatically when the script is imported/run,
|
324 |
+
# BEFORE the main() function is called here. This is correct.
|
325 |
main()
|