mgbam commited on
Commit
81dc1a4
ยท
verified ยท
1 Parent(s): 9059159

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -106
app.py CHANGED
@@ -12,50 +12,66 @@ st.set_page_config(
12
  initial_sidebar_state="expanded"
13
  )
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  # --- Configuration and Initialization ---
16
 
17
- # Securely load API key
18
- # Prioritize Streamlit secrets, fall back to environment variable for flexibility
19
  GEMINI_API_KEY = st.secrets.get("GEMINI_API_KEY", os.environ.get("GEMINI_API_KEY"))
20
 
21
- # Configure Gemini Client (only if key is found)
22
  genai_client_configured = False
23
  if GEMINI_API_KEY:
24
  try:
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:
33
- st.error("โš ๏ธ Gemini API Key not found. Please configure `GEMINI_API_KEY` in Streamlit secrets or environment variables.")
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
 
40
- if genai_client_configured:
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
 
55
 
56
  # --- Core AI Interaction Functions ---
57
 
58
- # AGENTIC prompt for Text Analysis
59
  AGENTIC_TEXT_ANALYSIS_PROMPT_TEMPLATE = """
60
  **Simulated Clinical Reasoning Agent Task:**
61
 
@@ -63,6 +79,8 @@ AGENTIC_TEXT_ANALYSIS_PROMPT_TEMPLATE = """
63
 
64
  **Input Data:** Unstructured clinical information (e.g., symptoms, history, basic findings).
65
 
 
 
66
  **Simulated Agentic Steps (Perform sequentially):**
67
 
68
  1. **Information Extraction & Structuring:**
@@ -94,17 +112,21 @@ AGENTIC_TEXT_ANALYSIS_PROMPT_TEMPLATE = """
94
  **Agentic Analysis:**
95
  """
96
 
97
- # Standard prompt for Image Analysis
98
  IMAGE_ANALYSIS_PROMPT_TEMPLATE = """
99
  **Medical Image Analysis Request:**
100
 
101
  **Context:** Analyze the provided medical image. User may provide additional context or questions.
 
 
 
102
  **Task:**
 
103
  1. **Describe Visible Structures:** Briefly describe main anatomical structures.
104
- 2. **Identify Potential Anomalies:** Point out areas that *appear* abnormal or deviate from typical presentation (e.g., "potential opacity," "altered signal intensity," "possible asymmetry"). Use cautious, descriptive language.
105
- 3. **Correlate with User Prompt (if provided):** Address specific user questions based *only* on visual information.
106
- 4. **Limitations:** State that image quality, view, and lack of clinical context limit analysis.
107
- 5. **Disclaimer:** Explicitly state this is AI visual analysis, not radiological interpretation or diagnosis, requiring review by a qualified professional with clinical context.
108
 
109
  **User's Additional Context/Question (if any):**
110
  ---
@@ -115,21 +137,15 @@ IMAGE_ANALYSIS_PROMPT_TEMPLATE = """
115
  """
116
 
117
  def run_agentic_text_analysis(text_input: str) -> Tuple[Optional[str], Optional[str]]:
118
- """
119
- Sends clinical text to the Gemini text model for simulated agentic analysis.
120
-
121
- Args:
122
- text_input: The clinical text provided by the user.
123
-
124
- Returns:
125
- Tuple: (analysis_text, error_message)
126
- """
127
  if not text_input or not text_input.strip():
128
  return None, "Input text cannot be empty."
 
 
 
129
  try:
130
  prompt = AGENTIC_TEXT_ANALYSIS_PROMPT_TEMPLATE.format(text_input=text_input)
131
- # Using the designated text model
132
- response = text_model.generate_content(prompt)
133
 
134
  if response.parts:
135
  return response.text, None
@@ -143,41 +159,34 @@ def run_agentic_text_analysis(text_input: str) -> Tuple[Optional[str], Optional[
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
- """
153
- Sends a medical image (and optional prompt) to the Gemini Vision model for analysis.
154
-
155
- Args:
156
- image_file: Uploaded image file object from Streamlit.
157
- user_prompt: Optional text context/questions from the user.
158
-
159
- Returns:
160
- Tuple: (analysis_text, error_message)
161
- """
162
  if not image_file:
163
  return None, "Image file cannot be empty."
 
 
 
164
  try:
165
  try:
166
  image = Image.open(image_file)
 
167
  if image.mode != 'RGB':
168
  image = image.convert('RGB')
169
  except Exception as img_e:
170
- return None, f"Error opening or processing image file: {img_e}"
171
 
172
  prompt_text = IMAGE_ANALYSIS_PROMPT_TEMPLATE.format(user_prompt=user_prompt if user_prompt else "N/A")
173
  model_input = [prompt_text, image]
174
- # Using the designated vision model
175
- response = vision_model.generate_content(model_input)
176
 
177
  if response.parts:
178
  return response.text, None
179
  elif response.prompt_feedback.block_reason:
180
- return None, f"Image analysis blocked by safety filters: {response.prompt_feedback.block_reason.name}. May relate to sensitive content policies."
181
  else:
182
  candidate = response.candidates[0] if response.candidates else None
183
  if candidate and candidate.finish_reason != "STOP":
@@ -186,22 +195,20 @@ def analyze_medical_image(image_file: Any, user_prompt: str = "") -> Tuple[Optio
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})")
202
- st.markdown("---")
203
 
204
  # --- CRITICAL DISCLAIMER ---
 
205
  st.warning(
206
  """
207
  **๐Ÿ”ด IMPORTANT SAFETY & USE DISCLAIMER ๐Ÿ”ด**
@@ -210,13 +217,13 @@ def main():
210
  * **Image Analysis:** Provides observations on images. Output is **NOT** a radiological interpretation.
211
  * AI analysis lacks full clinical context, may be inaccurate, and **CANNOT** replace professional judgment.
212
  * **ALWAYS consult qualified healthcare professionals** for diagnosis and treatment.
213
- * **PRIVACY:** Do **NOT** upload identifiable patient information (PHI) without explicit consent and adherence to all privacy laws (e.g., HIPAA).
214
  """,
215
  icon="โš ๏ธ"
216
  )
217
  st.markdown("---")
218
 
219
-
220
  st.sidebar.header("Analysis Options")
221
  input_method = st.sidebar.radio(
222
  "Select Analysis Type:",
@@ -226,26 +233,31 @@ def main():
226
  )
227
  st.sidebar.markdown("---") # Visual separator
228
 
 
229
  col1, col2 = st.columns(2)
230
 
 
 
 
 
 
231
  with col1:
232
  st.header("Input Data")
233
- analysis_result = None # Initialize results variables
234
- error_message = None
235
- output_header = "Analysis Results" # Default header for the output column
236
 
237
- # --- Agentic Text Analysis Input ---
238
  if input_method == "Agentic Text Analysis":
239
  st.subheader("Clinical Text for Agentic Analysis")
 
240
  text_input = st.text_area(
241
- "Paste de-identified clinical information (symptoms, history, findings):",
242
- height=350, # Slightly larger text area
243
  placeholder="Example: 68yo male, sudden SOB & pleuritic chest pain post-flight. HR 110, SpO2 92% RA. No known cardiac hx...",
244
  key="text_input_area"
245
  )
246
- analyze_button = st.button("โ–ถ๏ธ Run Agentic Text Analysis", key="analyze_text_button", type="primary")
 
247
 
248
- if analyze_button:
249
  if text_input:
250
  with st.spinner("๐Ÿง  Simulating agentic reasoning..."):
251
  analysis_result, error_message = run_agentic_text_analysis(text_input)
@@ -253,11 +265,11 @@ def main():
253
  else:
254
  st.warning("Please enter clinical text to analyze.", icon="โ˜๏ธ")
255
 
256
- # --- Medical Image Analysis Input ---
257
  elif input_method == "Medical Image Analysis":
258
  st.subheader("Medical Image for Analysis")
 
259
  image_file = st.file_uploader(
260
- "Upload a de-identified medical image (e.g., X-ray, CT slice). Supported: PNG, JPG, JPEG.",
261
  type=["png", "jpg", "jpeg"],
262
  key="image_uploader"
263
  )
@@ -266,60 +278,63 @@ def main():
266
  placeholder="Example: 'Describe findings in the lung fields' or 'Any visible fractures?'",
267
  key="image_prompt_input"
268
  )
269
- analyze_button = st.button("๐Ÿ–ผ๏ธ Analyze Medical Image", key="analyze_image_button", type="primary")
 
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)
277
  output_header = "Medical Image Analysis Output"
278
  else:
279
  st.warning("Please upload an image file to analyze.", icon="โ˜๏ธ")
280
 
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
 
305
  # --- Sidebar Explanations ---
306
  st.sidebar.markdown("---")
307
  st.sidebar.header("About The Prompts")
308
- with st.sidebar.expander("View Agentic Text Prompt Structure"):
309
  st.markdown(f"```plaintext\n{AGENTIC_TEXT_ANALYSIS_PROMPT_TEMPLATE.split('---')[0]} ... [Input Text] ...\n```")
310
  st.caption("Guides the AI through structured reasoning steps for text.")
311
- with st.sidebar.expander("View Image Analysis Prompt Structure"):
312
  st.markdown(f"```plaintext\n{IMAGE_ANALYSIS_PROMPT_TEMPLATE.split('---')[0]} ... [User Prompt] ...\n```")
313
  st.caption("Guides the AI to describe visual features and potential anomalies in images.")
314
 
315
  st.sidebar.markdown("---")
316
  st.sidebar.error(
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()
 
 
 
 
 
12
  initial_sidebar_state="expanded"
13
  )
14
 
15
+ # --- Introductory Explanation ---
16
+ st.markdown(
17
+ """
18
+ ### Welcome to the AI Clinical Support Demonstrator
19
+ This application demonstrates how Generative AI (Google Gemini) can be guided to assist with analyzing clinical information.
20
+ - **Agentic Text Analysis:** Simulates a structured reasoning process on clinical text to identify key findings, suggest considerations, and note information gaps.
21
+ - **Medical Image Analysis:** Provides descriptive observations of potential anomalies in medical images.
22
+
23
+ **Crucially, this tool is for demonstration purposes ONLY. It does NOT provide medical advice or diagnosis.**
24
+ """
25
+ )
26
+ st.markdown("---") # Visual separator
27
+
28
  # --- Configuration and Initialization ---
29
 
30
+ # Securely load API key (Secrets > Env Var)
 
31
  GEMINI_API_KEY = st.secrets.get("GEMINI_API_KEY", os.environ.get("GEMINI_API_KEY"))
32
 
33
+ # Configure Gemini Client
34
  genai_client_configured = False
35
  if GEMINI_API_KEY:
36
  try:
37
  genai.configure(api_key=GEMINI_API_KEY)
38
  genai_client_configured = True
39
  except Exception as e:
40
+ st.error(f"Fatal Error: Failed to configure Google Generative AI. Check API Key. Details: {e}", icon="๐Ÿšจ")
41
+ st.stop()
 
 
42
  else:
43
+ st.error("โš ๏ธ Gemini API Key not found. Please configure `GEMINI_API_KEY` in Streamlit secrets or environment variables.", icon="๐Ÿ”‘")
44
+ st.stop()
45
+
46
+ # Initialize models
47
+ TEXT_MODEL_NAME = 'gemini-1.5-pro-latest' # For agentic text reasoning
48
+ VISION_MODEL_NAME = 'gemini-1.5-flash' # For image analysis
49
 
50
+ # Use session state to initialize models only once
51
+ if 'models_initialized' not in st.session_state:
52
+ st.session_state.models_initialized = False
53
+ st.session_state.text_model = None
54
+ st.session_state.vision_model = None
55
 
56
+ if genai_client_configured and not st.session_state.models_initialized:
57
  try:
58
+ st.session_state.text_model = genai.GenerativeModel(TEXT_MODEL_NAME)
59
+ st.session_state.vision_model = genai.GenerativeModel(VISION_MODEL_NAME)
60
+ st.session_state.models_initialized = True
61
+ # Display success message subtly in sidebar perhaps, or remove if too noisy
62
+ # st.sidebar.success("AI Models Ready.", icon="โœ…")
63
  except Exception as e:
64
+ st.error(f"Fatal Error: Failed to initialize Gemini models. Text: {TEXT_MODEL_NAME}, Vision: {VISION_MODEL_NAME}. Details: {e}", icon="๐Ÿ’ฅ")
65
  st.stop()
66
+ elif not genai_client_configured:
67
+ # Should have stopped already, but defensive check
68
+ st.error("AI Models could not be initialized due to configuration issues.", icon="๐Ÿšซ")
 
69
  st.stop()
70
 
71
 
72
  # --- Core AI Interaction Functions ---
73
 
74
+ # Refined AGENTIC prompt for Text Analysis with formatting request
75
  AGENTIC_TEXT_ANALYSIS_PROMPT_TEMPLATE = """
76
  **Simulated Clinical Reasoning Agent Task:**
77
 
 
79
 
80
  **Input Data:** Unstructured clinical information (e.g., symptoms, history, basic findings).
81
 
82
+ **Output Format:** Please structure your response using Markdown headings for each step (e.g., `## 1. Information Extraction`).
83
+
84
  **Simulated Agentic Steps (Perform sequentially):**
85
 
86
  1. **Information Extraction & Structuring:**
 
112
  **Agentic Analysis:**
113
  """
114
 
115
+ # Refined prompt for Image Analysis with formatting request
116
  IMAGE_ANALYSIS_PROMPT_TEMPLATE = """
117
  **Medical Image Analysis Request:**
118
 
119
  **Context:** Analyze the provided medical image. User may provide additional context or questions.
120
+
121
+ **Output Format:** Please structure your response using Markdown headings for each step (e.g., `## 1. Visible Structures`).
122
+
123
  **Task:**
124
+
125
  1. **Describe Visible Structures:** Briefly describe main anatomical structures.
126
+ 2. **Identify Potential Anomalies:** Point out areas that *appear* abnormal or deviate from typical presentation (e.g., "potential opacity," "altered signal intensity," "possible asymmetry"). Use cautious, descriptive language. **This is not a definitive finding.**
127
+ 3. **Correlate with User Prompt (if provided):** Address specific user questions based *only* on visual information. State if the image cannot answer the question.
128
+ 4. **Limitations:** State that image quality, view, lack of clinical context, and the AI's nature limit analysis.
129
+ 5. **Mandatory Disclaimer:** Explicitly state this is AI visual analysis, not radiological interpretation or diagnosis, requiring review by a qualified professional with clinical context.
130
 
131
  **User's Additional Context/Question (if any):**
132
  ---
 
137
  """
138
 
139
  def run_agentic_text_analysis(text_input: str) -> Tuple[Optional[str], Optional[str]]:
140
+ """Sends clinical text to the configured text model for simulated agentic analysis."""
 
 
 
 
 
 
 
 
141
  if not text_input or not text_input.strip():
142
  return None, "Input text cannot be empty."
143
+ if not st.session_state.models_initialized or not st.session_state.text_model:
144
+ return None, "Text analysis model not initialized."
145
+
146
  try:
147
  prompt = AGENTIC_TEXT_ANALYSIS_PROMPT_TEMPLATE.format(text_input=text_input)
148
+ response = st.session_state.text_model.generate_content(prompt)
 
149
 
150
  if response.parts:
151
  return response.text, None
 
159
  return None, "Received an empty or unexpected response from the AI model."
160
 
161
  except Exception as e:
162
+ print(f"ERROR in run_agentic_text_analysis: {e}") # Basic server-side log
163
+ st.error("An error occurred during text analysis.", icon="๐Ÿšจ") # User-facing error
164
+ return None, "An internal error occurred during text analysis. Please try again later."
 
165
 
166
  def analyze_medical_image(image_file: Any, user_prompt: str = "") -> Tuple[Optional[str], Optional[str]]:
167
+ """Sends a medical image to the configured vision model for analysis."""
 
 
 
 
 
 
 
 
 
168
  if not image_file:
169
  return None, "Image file cannot be empty."
170
+ if not st.session_state.models_initialized or not st.session_state.vision_model:
171
+ return None, "Image analysis model not initialized."
172
+
173
  try:
174
  try:
175
  image = Image.open(image_file)
176
+ # Convert to RGB ensure compatibility, common requirement for vision models
177
  if image.mode != 'RGB':
178
  image = image.convert('RGB')
179
  except Exception as img_e:
180
+ return None, f"Error opening or processing the uploaded image file: {img_e}"
181
 
182
  prompt_text = IMAGE_ANALYSIS_PROMPT_TEMPLATE.format(user_prompt=user_prompt if user_prompt else "N/A")
183
  model_input = [prompt_text, image]
184
+ response = st.session_state.vision_model.generate_content(model_input)
 
185
 
186
  if response.parts:
187
  return response.text, None
188
  elif response.prompt_feedback.block_reason:
189
+ return None, f"Image analysis blocked by safety filters: {response.prompt_feedback.block_reason.name}. This may relate to sensitive content policies."
190
  else:
191
  candidate = response.candidates[0] if response.candidates else None
192
  if candidate and candidate.finish_reason != "STOP":
 
195
  return None, "Received an empty or unexpected response from the AI model for image analysis."
196
 
197
  except Exception as e:
198
+ print(f"ERROR in analyze_medical_image: {e}") # Basic server-side log
199
+ st.error("An error occurred during image analysis.", icon="๐Ÿ–ผ๏ธ") # User-facing error
200
+ return None, "An internal error occurred during image analysis. Please try again later."
 
201
 
202
 
203
  # --- Streamlit User Interface ---
204
 
205
  def main():
206
+ # Page title and model info
 
207
  st.title("๐Ÿค– AI Clinical Support Demonstrator")
208
+ st.caption(f"Utilizing: Text Model ({TEXT_MODEL_NAME}), Vision Model ({VISION_MODEL_NAME})")
 
209
 
210
  # --- CRITICAL DISCLAIMER ---
211
+ # Positioned prominently after title/intro
212
  st.warning(
213
  """
214
  **๐Ÿ”ด IMPORTANT SAFETY & USE DISCLAIMER ๐Ÿ”ด**
 
217
  * **Image Analysis:** Provides observations on images. Output is **NOT** a radiological interpretation.
218
  * AI analysis lacks full clinical context, may be inaccurate, and **CANNOT** replace professional judgment.
219
  * **ALWAYS consult qualified healthcare professionals** for diagnosis and treatment.
220
+ * **PRIVACY:** Do **NOT** upload identifiable patient information (PHI) without explicit consent and adherence to all privacy laws (e.g., HIPAA). You are responsible for the data you input.
221
  """,
222
  icon="โš ๏ธ"
223
  )
224
  st.markdown("---")
225
 
226
+ # --- Sidebar Controls ---
227
  st.sidebar.header("Analysis Options")
228
  input_method = st.sidebar.radio(
229
  "Select Analysis Type:",
 
233
  )
234
  st.sidebar.markdown("---") # Visual separator
235
 
236
+ # --- Main Area Layout (Input and Output Columns) ---
237
  col1, col2 = st.columns(2)
238
 
239
+ analysis_result = None # Initialize results variables for this run
240
+ error_message = None
241
+ output_header = "Analysis Results" # Default header
242
+
243
+ # --- Column 1: Input Area ---
244
  with col1:
245
  st.header("Input Data")
 
 
 
246
 
247
+ # Conditional Input UI based on selection
248
  if input_method == "Agentic Text Analysis":
249
  st.subheader("Clinical Text for Agentic Analysis")
250
+ st.caption("Please ensure data is de-identified before pasting.")
251
  text_input = st.text_area(
252
+ "Paste clinical information:",
253
+ height=350,
254
  placeholder="Example: 68yo male, sudden SOB & pleuritic chest pain post-flight. HR 110, SpO2 92% RA. No known cardiac hx...",
255
  key="text_input_area"
256
  )
257
+ analyze_button_key = "analyze_text_button"
258
+ analyze_button_label = "โ–ถ๏ธ Run Agentic Text Analysis"
259
 
260
+ if st.button(analyze_button_label, key=analyze_button_key, type="primary"):
261
  if text_input:
262
  with st.spinner("๐Ÿง  Simulating agentic reasoning..."):
263
  analysis_result, error_message = run_agentic_text_analysis(text_input)
 
265
  else:
266
  st.warning("Please enter clinical text to analyze.", icon="โ˜๏ธ")
267
 
 
268
  elif input_method == "Medical Image Analysis":
269
  st.subheader("Medical Image for Analysis")
270
+ st.caption("Upload a de-identified medical image (PNG, JPG, JPEG).")
271
  image_file = st.file_uploader(
272
+ "Choose an image file:",
273
  type=["png", "jpg", "jpeg"],
274
  key="image_uploader"
275
  )
 
278
  placeholder="Example: 'Describe findings in the lung fields' or 'Any visible fractures?'",
279
  key="image_prompt_input"
280
  )
281
+ analyze_button_key = "analyze_image_button"
282
+ analyze_button_label = "๐Ÿ–ผ๏ธ Analyze Medical Image"
283
 
284
+ if image_file:
285
+ # Display preview immediately after upload inside the input column
286
+ st.image(image_file, caption="Uploaded Image Preview", use_column_width=True)
287
+
288
+ if st.button(analyze_button_label, key=analyze_button_key, type="primary"):
289
  if image_file:
 
 
290
  with st.spinner("๐Ÿ‘๏ธ Analyzing image..."):
291
  analysis_result, error_message = analyze_medical_image(image_file, user_image_prompt)
292
  output_header = "Medical Image Analysis Output"
293
  else:
294
  st.warning("Please upload an image file to analyze.", icon="โ˜๏ธ")
295
 
296
+ # --- Column 2: Output Area ---
297
  with col2:
298
  st.header(output_header)
299
+
300
+ # Display results or errors if an analysis was attempted
301
+ # Check if button was pressed and corresponding result/error exists
302
+ button_pressed = st.session_state.get(analyze_button_key, False) if 'analyze_button_key' in locals() else False
303
+
304
+ if button_pressed and (analysis_result or error_message):
305
+ if error_message:
 
 
306
  st.error(f"Analysis Failed: {error_message}", icon="โŒ")
307
+ elif analysis_result:
308
+ # Use st.markdown to render potential formatting from AI
309
+ st.markdown(analysis_result)
310
+ elif not button_pressed :
 
 
 
 
311
  st.info("Analysis results will appear here after providing input and clicking the corresponding analysis button.")
312
+ # Add a condition for button pressed but no input provided (already handled by st.warning in col1)
313
 
314
 
315
  # --- Sidebar Explanations ---
316
  st.sidebar.markdown("---")
317
  st.sidebar.header("About The Prompts")
318
+ with st.sidebar.expander("View Agentic Text Prompt Structure", icon="๐Ÿ“„"):
319
  st.markdown(f"```plaintext\n{AGENTIC_TEXT_ANALYSIS_PROMPT_TEMPLATE.split('---')[0]} ... [Input Text] ...\n```")
320
  st.caption("Guides the AI through structured reasoning steps for text.")
321
+ with st.sidebar.expander("View Image Analysis Prompt Structure", icon="๐Ÿ–ผ๏ธ"):
322
  st.markdown(f"```plaintext\n{IMAGE_ANALYSIS_PROMPT_TEMPLATE.split('---')[0]} ... [User Prompt] ...\n```")
323
  st.caption("Guides the AI to describe visual features and potential anomalies in images.")
324
 
325
  st.sidebar.markdown("---")
326
  st.sidebar.error(
327
+ "**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.",
328
+ icon = "โš•๏ธ"
329
  )
330
 
331
  # --- Main Execution Guard ---
332
  if __name__ == "__main__":
333
+ # Check if models are initialized before running the main UI components
334
+ if st.session_state.models_initialized:
335
+ main()
336
+ else:
337
+ # If models failed to initialize, errors would have been shown already.
338
+ # We might add a placeholder or further message here if needed.
339
+ st.info("Waiting for model initialization...") # Or check specific errors if needed
340
+ # The script might stop earlier if initialization fails critically.