mgbam commited on
Commit
2d84aa6
·
verified ·
1 Parent(s): 7280d57

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +67 -72
app.py CHANGED
@@ -4,11 +4,23 @@ import os
4
  import sys
5
  import subprocess
6
  import logging
7
- import copy # Keep copy import for state initialization if needed directly
8
 
9
- # --- Step 0: Setup Logging Early ---
10
- # Setup logging configuration first
11
- from config import setup_logging, LOG_LEVEL, APP_TITLE, FAVICON, LAYOUT, INITIAL_SIDEBAR_STATE, CUSTOM_CSS, LOGO_PATH, FOOTER_HTML
 
 
 
 
 
 
 
 
 
 
 
 
12
  logger = setup_logging() # Get the configured logger
13
 
14
  logger.info("--- RadVision AI Application Start ---")
@@ -17,11 +29,12 @@ logger.info(f"Logging Level: {LOG_LEVEL}")
17
 
18
  # --- Step 1: Handle Core Dependencies and Availability ---
19
  # Try importing essential libraries and set availability flags
 
 
20
 
21
  # Deep Translator (Attempt install if missing)
22
  try:
23
  from deep_translator import GoogleTranslator
24
- # Also try importing our translation wrapper
25
  from translation_models import translate, detect_language, LANGUAGE_CODES, AUTO_DETECT_INDICATOR
26
  TRANSLATION_AVAILABLE = True
27
  logger.info("Deep Translator and translation_models imported successfully.")
@@ -30,15 +43,14 @@ except ImportError:
30
  try:
31
  subprocess.check_call([sys.executable, "-m", "pip", "install", "deep-translator"])
32
  from deep_translator import GoogleTranslator
33
- # Re-try importing our wrapper after install
34
  from translation_models import translate, detect_language, LANGUAGE_CODES, AUTO_DETECT_INDICATOR
35
  TRANSLATION_AVAILABLE = True
36
  logger.info("Successfully installed and imported deep-translator and translation_models.")
37
  except Exception as e:
38
  logger.error(f"CRITICAL: Failed to install/import deep-translator or translation_models: {e}", exc_info=True)
39
- st.warning("Translation features will be disabled: Could not load 'deep-translator'.")
 
40
  TRANSLATION_AVAILABLE = False
41
- # Define fallbacks if translation module failed
42
  translate = None
43
  detect_language = None
44
  LANGUAGE_CODES = {"English": "en"}
@@ -51,7 +63,7 @@ try:
51
  DRAWABLE_CANVAS_AVAILABLE = True
52
  logger.info(f"Streamlit Drawable Canvas Version: {CANVAS_VERSION} available.")
53
  except ImportError:
54
- st.error("CRITICAL ERROR: streamlit-drawable-canvas is not installed. ROI drawing disabled. Run `pip install streamlit-drawable-canvas`.")
55
  logger.critical("streamlit-drawable-canvas not found. ROI functionality disabled.")
56
  DRAWABLE_CANVAS_AVAILABLE = False
57
 
@@ -62,13 +74,12 @@ try:
62
  PIL_VERSION = getattr(PIL, '__version__', 'Unknown')
63
  PIL_AVAILABLE = True
64
  logger.info(f"Pillow (PIL) Version: {PIL_VERSION} available.")
65
- # Make PIL Image available to utils module if needed
66
  import utils
67
  utils.Image = Image
68
  except ImportError:
69
- st.error("CRITICAL ERROR: Pillow (PIL) is not installed. Image handling disabled. Run `pip install Pillow`.")
70
  logger.critical("Pillow (PIL) not found. Application cannot function correctly.")
71
- PIL_AVAILABLE = False
72
  st.stop() # Stop execution if PIL is missing
73
 
74
  # Pydicom and related libraries
@@ -78,19 +89,16 @@ try:
78
  PYDICOM_VERSION = getattr(pydicom, '__version__', 'Unknown')
79
  PYDICOM_AVAILABLE = True
80
  logger.info(f"Pydicom Version: {PYDICOM_VERSION} available.")
81
- # Check for optional DICOM helpers
82
- try:
83
- import pylibjpeg; logger.info("pylibjpeg found (for extended DICOM decompression).")
84
- except ImportError: logger.info("pylibjpeg not found. Some DICOM decompression may fail.")
85
- try:
86
- import gdcm; logger.info("python-gdcm found (for improved DICOM compatibility).")
87
- except ImportError: logger.info("python-gdcm not found. Some DICOM features might be limited.")
88
  except ImportError:
89
  PYDICOM_AVAILABLE = False
90
  PYDICOM_VERSION = 'Not Installed'
91
  logger.warning("pydicom not found. DICOM file support will be disabled.")
92
- pydicom = None # Ensure pydicom object doesn't exist
93
-
94
 
95
  # Custom Utilities & Backend Modules
96
  try:
@@ -100,38 +108,43 @@ try:
100
  except ImportError as e:
101
  logger.error(f"Failed to import dicom_utils: {e}. DICOM specific features disabled.", exc_info=True)
102
  DICOM_UTILS_AVAILABLE = False
103
- if PYDICOM_AVAILABLE: # Only warn if pydicom *is* installed but utils are missing
104
- st.warning("DICOM processing utilities (dicom_utils.py) not found. DICOM handling may be limited.")
105
-
106
- try:
107
- from llm_interactions import run_initial_analysis, run_multimodal_qa, run_disease_analysis, estimate_ai_confidence
108
- LLM_INTERACTIONS_AVAILABLE = True
109
- logger.info("llm_interactions imported successfully.")
110
- except ImportError as e:
111
- st.error(f"Core AI module (llm_interactions.py) failed to import: {e}. Analysis functions disabled.")
112
- logger.critical(f"Failed to import llm_interactions: {e}", exc_info=True)
113
- LLM_INTERACTIONS_AVAILABLE = False
114
- # Consider st.stop() if core AI is essential and fails to load
115
- # st.stop()
116
 
117
  try:
 
118
  from report_utils import generate_pdf_report_bytes
119
  REPORT_UTILS_AVAILABLE = True
120
  logger.info("report_utils imported successfully.")
121
  except ImportError as e:
122
  logger.error(f"Failed to import report_utils: {e}. PDF reporting disabled.", exc_info=True)
123
  REPORT_UTILS_AVAILABLE = False
124
- st.warning("Report generation utility (report_utils.py) not found. PDF reporting disabled.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
  try:
127
  from ui_components import display_dicom_metadata, dicom_wl_sliders
128
  UI_COMPONENTS_AVAILABLE = True
129
  logger.info("ui_components imported successfully.")
130
  except ImportError as e:
131
- logger.warning(f"Failed to import ui_components: {e}. Custom UI elements (like sliders/metadata display) might use fallbacks.", exc_info=True)
132
  UI_COMPONENTS_AVAILABLE = False
133
 
134
-
135
  # HF Fallback Models (Optional)
136
  try:
137
  from hf_models import query_hf_vqa_inference_api, HF_VQA_MODEL_ID
@@ -142,34 +155,24 @@ except ImportError:
142
  HF_MODELS_AVAILABLE = False
143
  logger.warning("hf_models not found or failed to import. Fallback VQA disabled.")
144
 
145
- # --- Update config with availability flags (optional, if config needs them) ---
 
146
  import config
 
147
  config.DRAWABLE_CANVAS_AVAILABLE = DRAWABLE_CANVAS_AVAILABLE
148
- config.PIL_AVAILABLE = PIL_AVAILABLE
149
- config.PYDICOM_AVAILABLE = PYDICOM_AVAILABLE
150
- config.DICOM_UTILS_AVAILABLE = DICOM_UTILS_AVAILABLE
151
- config.LLM_INTERACTIONS_AVAILABLE = LLM_INTERACTIONS_AVAILABLE
152
- config.REPORT_UTILS_AVAILABLE = REPORT_UTILS_AVAILABLE
153
- config.UI_COMPONENTS_AVAILABLE = UI_COMPONENTS_AVAILABLE
154
- config.HF_MODELS_AVAILABLE = HF_MODELS_AVAILABLE
155
- config.TRANSLATION_AVAILABLE = TRANSLATION_AVAILABLE
156
-
157
 
158
  # --- Step 2: Configure Streamlit Page ---
159
- st.set_page_config(
160
- page_title=APP_TITLE,
161
- layout=LAYOUT,
162
- page_icon=FAVICON,
163
- initial_sidebar_state=INITIAL_SIDEBAR_STATE
164
- )
165
 
166
  # Apply Custom CSS
167
  st.markdown(CUSTOM_CSS, unsafe_allow_html=True)
168
 
169
  # --- Step 3: Apply Monkey Patches (Conditional) ---
170
  import streamlit.elements.image as st_image
171
- import utils # Import our utils module
172
- utils.apply_image_to_url_monkey_patch(st_image) # Call the patch function
173
 
174
  # --- Step 4: Initialize Session State ---
175
  from state import initialize_session_state
@@ -178,15 +181,12 @@ logger.debug(f"Session state verified/initialized for session ID: {st.session_st
178
 
179
  # --- Step 5: Display Logo ---
180
  if os.path.exists(LOGO_PATH):
181
- # Use columns to control logo width/position if needed
182
- logo_col, _ = st.columns([1, 3]) # Adjust ratio as needed
183
  with logo_col:
184
- st.image(LOGO_PATH, width=300) # Adjust width
185
  else:
186
  logger.warning(f"Hero logo not found at: {LOGO_PATH}")
187
- # Optionally display a placeholder text if logo is missing
188
- # st.warning("RadVision AI Logo missing.")
189
-
190
 
191
  # --- Step 6: Render Sidebar and Get Uploaded File ---
192
  from ui import render_sidebar
@@ -194,20 +194,17 @@ uploaded_file = render_sidebar(
194
  IS_DICOM=st.session_state.get("is_dicom", False),
195
  UI_COMPONENTS_AVAILABLE=UI_COMPONENTS_AVAILABLE,
196
  DICOM_UTILS_AVAILABLE=DICOM_UTILS_AVAILABLE,
197
- REPORT_UTILS_AVAILABLE=REPORT_UTILS_AVAILABLE
198
  )
199
 
200
-
201
  # --- Step 7: Handle File Upload Processing ---
202
  from file_handler import process_uploaded_file
203
- # Pass availability flags needed by the handler
204
  process_uploaded_file(uploaded_file, PYDICOM_AVAILABLE, DICOM_UTILS_AVAILABLE, PIL_AVAILABLE)
205
 
206
  # --- Step 8: Render Main Page Content ---
207
  st.markdown("---")
208
  st.title(f"⚕️ {APP_TITLE}: AI-Assisted Image Analysis")
209
 
210
- # User Guide/Disclaimer Expander
211
  with st.expander("User Guide & Disclaimer", expanded=False):
212
  st.warning("⚠️ **Disclaimer**: This tool is for research/educational purposes only and is **NOT** a substitute for professional medical advice or diagnosis.")
213
  st.markdown("""
@@ -223,13 +220,12 @@ with st.expander("User Guide & Disclaimer", expanded=False):
223
  6. **Review Results**: Check the tabs ('Initial Analysis', 'Q&A History', 'Condition Focus') for AI output.
224
  7. **(Optional) Translation**: Use the 'Translation' tab to translate AI-generated text.
225
  8. **(Optional) Confidence**: Use the 'Estimate AI Confidence' button (sidebar) after analysis.
226
- 9. **(Optional) Report**: Click 'Generate PDF Report Data' (sidebar) and then 'Download PDF Report' to save a summary.
227
- """)
228
 
229
  st.markdown("---")
230
 
231
- # Main layout columns
232
- col1, col2 = st.columns([2, 3]) # Image column wider slightly
233
 
234
  with col1:
235
  from ui import render_image_viewer
@@ -243,7 +239,6 @@ with col1:
243
 
244
  with col2:
245
  from ui import render_results_tabs
246
- # Pass the actual translation function if available
247
  translate_func = translate if TRANSLATION_AVAILABLE else None
248
  render_results_tabs(
249
  TRANSLATION_SERVICE_AVAILABLE=TRANSLATION_AVAILABLE,
@@ -251,11 +246,11 @@ with col2:
251
  )
252
 
253
  # --- Step 9: Handle Button Actions ---
254
- # This logic is now encapsulated in actions.py
255
  from actions import handle_actions
 
 
256
  handle_actions(LLM_INTERACTIONS_AVAILABLE, REPORT_UTILS_AVAILABLE)
257
 
258
-
259
  # --- Step 10: Render Footer ---
260
  from ui import render_footer
261
  render_footer(st.session_state.get("session_id"))
 
4
  import sys
5
  import subprocess
6
  import logging
7
+ import copy
8
 
9
+ # --- Step 0: Setup Logging and Page Config EARLY ---
10
+ from config import (
11
+ setup_logging, LOG_LEVEL, APP_TITLE, FAVICON, LAYOUT,
12
+ INITIAL_SIDEBAR_STATE, CUSTOM_CSS, LOGO_PATH, FOOTER_HTML
13
+ )
14
+
15
+ # !!! IMPORTANT: Set page config as the VERY FIRST Streamlit command !!!
16
+ st.set_page_config(
17
+ page_title=APP_TITLE,
18
+ layout=LAYOUT,
19
+ page_icon=FAVICON,
20
+ initial_sidebar_state=INITIAL_SIDEBAR_STATE
21
+ )
22
+
23
+ # Now, setup logging
24
  logger = setup_logging() # Get the configured logger
25
 
26
  logger.info("--- RadVision AI Application Start ---")
 
29
 
30
  # --- Step 1: Handle Core Dependencies and Availability ---
31
  # Try importing essential libraries and set availability flags
32
+ # (Error/Warning messages using st.* inside these blocks are now OK,
33
+ # because set_page_config has already run)
34
 
35
  # Deep Translator (Attempt install if missing)
36
  try:
37
  from deep_translator import GoogleTranslator
 
38
  from translation_models import translate, detect_language, LANGUAGE_CODES, AUTO_DETECT_INDICATOR
39
  TRANSLATION_AVAILABLE = True
40
  logger.info("Deep Translator and translation_models imported successfully.")
 
43
  try:
44
  subprocess.check_call([sys.executable, "-m", "pip", "install", "deep-translator"])
45
  from deep_translator import GoogleTranslator
 
46
  from translation_models import translate, detect_language, LANGUAGE_CODES, AUTO_DETECT_INDICATOR
47
  TRANSLATION_AVAILABLE = True
48
  logger.info("Successfully installed and imported deep-translator and translation_models.")
49
  except Exception as e:
50
  logger.error(f"CRITICAL: Failed to install/import deep-translator or translation_models: {e}", exc_info=True)
51
+ # Display warning in the UI now that set_page_config has run
52
+ st.warning("Translation features are disabled: Could not load or install 'deep-translator'. See logs for details.")
53
  TRANSLATION_AVAILABLE = False
 
54
  translate = None
55
  detect_language = None
56
  LANGUAGE_CODES = {"English": "en"}
 
63
  DRAWABLE_CANVAS_AVAILABLE = True
64
  logger.info(f"Streamlit Drawable Canvas Version: {CANVAS_VERSION} available.")
65
  except ImportError:
66
+ st.error("CRITICAL ERROR: `streamlit-drawable-canvas` is not installed. ROI drawing is disabled. Run `pip install streamlit-drawable-canvas`.")
67
  logger.critical("streamlit-drawable-canvas not found. ROI functionality disabled.")
68
  DRAWABLE_CANVAS_AVAILABLE = False
69
 
 
74
  PIL_VERSION = getattr(PIL, '__version__', 'Unknown')
75
  PIL_AVAILABLE = True
76
  logger.info(f"Pillow (PIL) Version: {PIL_VERSION} available.")
 
77
  import utils
78
  utils.Image = Image
79
  except ImportError:
80
+ # This error is critical, stop the app
81
  logger.critical("Pillow (PIL) not found. Application cannot function correctly.")
82
+ st.error("CRITICAL ERROR: Pillow (PIL) is not installed. Image handling is disabled. Run `pip install Pillow`.")
83
  st.stop() # Stop execution if PIL is missing
84
 
85
  # Pydicom and related libraries
 
89
  PYDICOM_VERSION = getattr(pydicom, '__version__', 'Unknown')
90
  PYDICOM_AVAILABLE = True
91
  logger.info(f"Pydicom Version: {PYDICOM_VERSION} available.")
92
+ try: import pylibjpeg; logger.info("pylibjpeg found.")
93
+ except ImportError: logger.info("pylibjpeg not found.")
94
+ try: import gdcm; logger.info("python-gdcm found.")
95
+ except ImportError: logger.info("python-gdcm not found.")
 
 
 
96
  except ImportError:
97
  PYDICOM_AVAILABLE = False
98
  PYDICOM_VERSION = 'Not Installed'
99
  logger.warning("pydicom not found. DICOM file support will be disabled.")
100
+ st.sidebar.warning("`pydicom` library not found. DICOM file support is disabled.", icon="⚠️") # Inform user in UI
101
+ pydicom = None
102
 
103
  # Custom Utilities & Backend Modules
104
  try:
 
108
  except ImportError as e:
109
  logger.error(f"Failed to import dicom_utils: {e}. DICOM specific features disabled.", exc_info=True)
110
  DICOM_UTILS_AVAILABLE = False
111
+ if PYDICOM_AVAILABLE:
112
+ st.warning("DICOM processing utilities (`dicom_utils.py`) not found. DICOM handling may be limited.")
 
 
 
 
 
 
 
 
 
 
 
113
 
114
  try:
115
+ # This file needs to exist now, even if it's basic
116
  from report_utils import generate_pdf_report_bytes
117
  REPORT_UTILS_AVAILABLE = True
118
  logger.info("report_utils imported successfully.")
119
  except ImportError as e:
120
  logger.error(f"Failed to import report_utils: {e}. PDF reporting disabled.", exc_info=True)
121
  REPORT_UTILS_AVAILABLE = False
122
+ # Display warning in the UI
123
+ st.warning("Report generation utility (`report_utils.py`) not found or failed to import. PDF reporting disabled.")
124
+ # Define a placeholder function to avoid errors in actions.py if it's called
125
+ def generate_pdf_report_bytes(*args, **kwargs):
126
+ logger.warning("generate_pdf_report_bytes called, but report_utils is unavailable. Returning None.")
127
+ return None
128
+
129
+
130
+ try:
131
+ from llm_interactions import run_initial_analysis, run_multimodal_qa, run_disease_analysis, estimate_ai_confidence
132
+ LLM_INTERACTIONS_AVAILABLE = True
133
+ logger.info("llm_interactions imported successfully.")
134
+ except ImportError as e:
135
+ st.error(f"Core AI module (`llm_interactions.py`) failed to import: {e}. AI analysis functions are disabled.")
136
+ logger.critical(f"Failed to import llm_interactions: {e}", exc_info=True)
137
+ LLM_INTERACTIONS_AVAILABLE = False
138
+ # Define placeholders if needed, or let actions.py handle the disabled state
139
 
140
  try:
141
  from ui_components import display_dicom_metadata, dicom_wl_sliders
142
  UI_COMPONENTS_AVAILABLE = True
143
  logger.info("ui_components imported successfully.")
144
  except ImportError as e:
145
+ logger.warning(f"Failed to import ui_components: {e}. Custom UI elements might use fallbacks.", exc_info=True)
146
  UI_COMPONENTS_AVAILABLE = False
147
 
 
148
  # HF Fallback Models (Optional)
149
  try:
150
  from hf_models import query_hf_vqa_inference_api, HF_VQA_MODEL_ID
 
155
  HF_MODELS_AVAILABLE = False
156
  logger.warning("hf_models not found or failed to import. Fallback VQA disabled.")
157
 
158
+
159
+ # --- Update config with availability flags (optional) ---
160
  import config
161
+ # (Keep this section as is)
162
  config.DRAWABLE_CANVAS_AVAILABLE = DRAWABLE_CANVAS_AVAILABLE
163
+ # ... etc ...
164
+ config.REPORT_UTILS_AVAILABLE = REPORT_UTILS_AVAILABLE # Update based on import success
 
 
 
 
 
 
 
165
 
166
  # --- Step 2: Configure Streamlit Page ---
167
+ # Already done at the top!
 
 
 
 
 
168
 
169
  # Apply Custom CSS
170
  st.markdown(CUSTOM_CSS, unsafe_allow_html=True)
171
 
172
  # --- Step 3: Apply Monkey Patches (Conditional) ---
173
  import streamlit.elements.image as st_image
174
+ import utils
175
+ utils.apply_image_to_url_monkey_patch(st_image)
176
 
177
  # --- Step 4: Initialize Session State ---
178
  from state import initialize_session_state
 
181
 
182
  # --- Step 5: Display Logo ---
183
  if os.path.exists(LOGO_PATH):
184
+ logo_col, _ = st.columns([1, 3])
 
185
  with logo_col:
186
+ st.image(LOGO_PATH, width=300)
187
  else:
188
  logger.warning(f"Hero logo not found at: {LOGO_PATH}")
189
+ # st.warning("RadVision AI Logo missing.") # Optional UI warning
 
 
190
 
191
  # --- Step 6: Render Sidebar and Get Uploaded File ---
192
  from ui import render_sidebar
 
194
  IS_DICOM=st.session_state.get("is_dicom", False),
195
  UI_COMPONENTS_AVAILABLE=UI_COMPONENTS_AVAILABLE,
196
  DICOM_UTILS_AVAILABLE=DICOM_UTILS_AVAILABLE,
197
+ REPORT_UTILS_AVAILABLE=REPORT_UTILS_AVAILABLE # Pass the actual availability status
198
  )
199
 
 
200
  # --- Step 7: Handle File Upload Processing ---
201
  from file_handler import process_uploaded_file
 
202
  process_uploaded_file(uploaded_file, PYDICOM_AVAILABLE, DICOM_UTILS_AVAILABLE, PIL_AVAILABLE)
203
 
204
  # --- Step 8: Render Main Page Content ---
205
  st.markdown("---")
206
  st.title(f"⚕️ {APP_TITLE}: AI-Assisted Image Analysis")
207
 
 
208
  with st.expander("User Guide & Disclaimer", expanded=False):
209
  st.warning("⚠️ **Disclaimer**: This tool is for research/educational purposes only and is **NOT** a substitute for professional medical advice or diagnosis.")
210
  st.markdown("""
 
220
  6. **Review Results**: Check the tabs ('Initial Analysis', 'Q&A History', 'Condition Focus') for AI output.
221
  7. **(Optional) Translation**: Use the 'Translation' tab to translate AI-generated text.
222
  8. **(Optional) Confidence**: Use the 'Estimate AI Confidence' button (sidebar) after analysis.
223
+ 9. **(Optional) Report**: Click 'Generate PDF Report Data' (sidebar) and then 'Download PDF Report' to save a summary. **(Note: PDF generation may be disabled if `report_utils.py` is missing or faulty)**
224
+ """) # Added note about disabled reporting
225
 
226
  st.markdown("---")
227
 
228
+ col1, col2 = st.columns([2, 3])
 
229
 
230
  with col1:
231
  from ui import render_image_viewer
 
239
 
240
  with col2:
241
  from ui import render_results_tabs
 
242
  translate_func = translate if TRANSLATION_AVAILABLE else None
243
  render_results_tabs(
244
  TRANSLATION_SERVICE_AVAILABLE=TRANSLATION_AVAILABLE,
 
246
  )
247
 
248
  # --- Step 9: Handle Button Actions ---
 
249
  from actions import handle_actions
250
+ # Check REPORT_UTILS_AVAILABLE before passing to handle_actions,
251
+ # or handle_actions should already check the flag from session state/config
252
  handle_actions(LLM_INTERACTIONS_AVAILABLE, REPORT_UTILS_AVAILABLE)
253
 
 
254
  # --- Step 10: Render Footer ---
255
  from ui import render_footer
256
  render_footer(st.session_state.get("session_id"))