Shakir60 commited on
Commit
d9a6878
·
verified ·
1 Parent(s): dbfc49d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -224
app.py CHANGED
@@ -4,9 +4,13 @@ from PIL import Image
4
  import torch
5
  import time
6
  import gc
 
7
  from knowledge_base import KNOWLEDGE_BASE, DAMAGE_TYPES
8
  from rag_utils import RAGSystem
9
 
 
 
 
10
  # Constants
11
  MAX_FILE_SIZE = 5 * 1024 * 1024 # 5MB
12
  MAX_IMAGE_SIZE = 1024 # Maximum dimension for images
@@ -16,317 +20,146 @@ MODEL = None
16
  PROCESSOR = None
17
  RAG_SYSTEM = None
18
 
 
19
  def cleanup_memory():
20
  """Clean up memory and GPU cache"""
21
  gc.collect()
22
  if torch.cuda.is_available():
23
  torch.cuda.empty_cache()
24
 
25
- def init_session_state():
26
- """Initialize session state variables"""
27
- if 'history' not in st.session_state:
28
- st.session_state.history = []
29
- if 'dark_mode' not in st.session_state:
30
- st.session_state.dark_mode = False
31
-
32
  @st.cache_resource(show_spinner="Loading AI model...")
33
  def load_model():
34
  """Load and cache the model and processor"""
35
  try:
36
  model_name = "google/vit-base-patch16-224"
37
- # Initialize the processor first
38
  processor = ViTImageProcessor.from_pretrained(model_name)
39
-
40
- # Load model with specific device configuration
41
  device = "cuda" if torch.cuda.is_available() else "cpu"
 
42
  model = ViTForImageClassification.from_pretrained(
43
  model_name,
44
  num_labels=len(DAMAGE_TYPES),
45
  ignore_mismatched_sizes=True,
46
  ).to(device)
47
-
48
- # Ensure model is in evaluation mode
49
  model.eval()
50
-
51
  return model, processor
52
  except Exception as e:
53
- st.error(f"Error loading model: {str(e)}")
 
54
  return None, None
55
 
 
 
56
  def init_rag_system():
57
- """Initialize the RAG system with knowledge base"""
58
  global RAG_SYSTEM
59
- if RAG_SYSTEM is None:
60
  RAG_SYSTEM = RAGSystem()
61
  RAG_SYSTEM.initialize_knowledge_base(KNOWLEDGE_BASE)
 
 
 
 
62
 
 
63
  def validate_image(image):
64
- """Validate image size and format"""
65
  if image.size[0] * image.size[1] > 1024 * 1024:
66
- st.warning("Large image detected. The image will be resized for better performance.")
67
  if image.format not in ['JPEG', 'PNG']:
68
- st.warning("Image format not optimal. Consider using JPEG or PNG for better performance.")
69
 
 
70
  def preprocess_image(uploaded_file):
71
- """Preprocess and validate uploaded image"""
72
  try:
73
  image = Image.open(uploaded_file)
74
- # Resize if image is too large
75
  if max(image.size) > MAX_IMAGE_SIZE:
76
  ratio = MAX_IMAGE_SIZE / max(image.size)
77
  new_size = tuple([int(dim * ratio) for dim in image.size])
78
  image = image.resize(new_size, Image.Resampling.LANCZOS)
79
  return image
80
  except Exception as e:
81
- st.error(f"Error processing image: {str(e)}")
 
82
  return None
83
 
 
84
  def analyze_damage(image, model, processor):
85
- """Analyze structural damage in the image"""
86
  try:
87
  device = next(model.parameters()).device
88
  with torch.no_grad():
89
  image = image.convert('RGB')
90
  inputs = processor(images=image, return_tensors="pt")
91
- # Move inputs to the same device as model
92
  inputs = {k: v.to(device) for k, v in inputs.items()}
93
  outputs = model(**inputs)
94
  probs = torch.nn.functional.softmax(outputs.logits, dim=1)[0]
95
  cleanup_memory()
96
- return probs.cpu() # Move results back to CPU
97
- except RuntimeError as e:
98
- if "out of memory" in str(e):
99
- cleanup_memory()
100
- st.error("Out of memory. Please try with a smaller image.")
101
- else:
102
- st.error(f"Error analyzing image: {str(e)}")
103
  return None
104
 
105
- def get_custom_css():
106
- """Return custom CSS styles"""
107
- return """
108
- <style>
109
- .main {
110
- padding: 2rem;
111
- }
112
- .stProgress > div > div > div > div {
113
- background-image: linear-gradient(to right, var(--progress-color, #ff6b6b), var(--progress-color-end, #f06595));
114
- }
115
- .damage-card {
116
- padding: 1.5rem;
117
- border-radius: 0.5rem;
118
- background: var(--card-bg, #f8f9fa);
119
- margin-bottom: 1rem;
120
- border: 1px solid var(--border-color, #dee2e6);
121
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
122
- }
123
- .damage-header {
124
- font-size: 1.25rem;
125
- font-weight: bold;
126
- margin-bottom: 1rem;
127
- color: var(--text-color, #212529);
128
- }
129
- .dark-mode {
130
- background-color: #1a1a1a;
131
- color: #ffffff;
132
- }
133
- .dark-mode .damage-card {
134
- background: #2d2d2d;
135
- border-color: #404040;
136
- }
137
- </style>
138
- """
139
-
140
- def display_header():
141
- """Display application header"""
142
- st.markdown(
143
- """
144
- <div style='text-align: center; padding: 1rem;'>
145
- <h1>🏗️ Structural Damage Analyzer Pro</h1>
146
- <p style='font-size: 1.2rem;'>Advanced AI-powered structural damage assessment tool</p>
147
- </div>
148
- """,
149
- unsafe_allow_html=True
150
- )
151
-
152
  def display_enhanced_analysis(damage_type, confidence):
153
- """Display enhanced analysis from RAG system"""
154
  try:
155
  enhanced_info = RAG_SYSTEM.get_enhanced_analysis(damage_type, confidence)
156
-
157
  st.markdown("### 🔍 Enhanced Analysis")
158
 
159
  with st.expander("📚 Technical Details", expanded=True):
160
  for detail in enhanced_info["technical_details"]:
161
  st.markdown(detail)
162
-
163
  with st.expander("⚠️ Safety Considerations"):
164
  for safety in enhanced_info["safety_considerations"]:
165
  st.warning(safety)
166
-
167
  with st.expander("👷 Expert Recommendations"):
168
  for rec in enhanced_info["expert_recommendations"]:
169
  st.info(rec)
170
-
171
- custom_query = st.text_input(
172
- "Ask specific questions about this damage type:",
173
- placeholder="E.g., What are the long-term implications of this damage?",
174
- key=f"text_input_{damage_type}"
175
- )
176
- if custom_query:
177
- custom_results = RAG_SYSTEM.get_enhanced_analysis(
178
- damage_type,
179
- confidence,
180
- custom_query=custom_query
181
- )
182
- st.markdown("### 💡 Custom Query Results")
183
- for category, results in custom_results.items():
184
- if results:
185
- st.markdown(f"**{category.replace('_', ' ').title()}:**")
186
- for result in results:
187
- st.markdown(result)
188
  except Exception as e:
189
- st.error(f"Error generating enhanced analysis: {str(e)}")
190
-
191
- def display_analysis_results(predictions, analysis_time):
192
- """Display analysis results with damage details"""
193
- st.markdown("### 📊 Analysis Results")
194
- st.markdown(f"*Analysis completed in {analysis_time:.2f} seconds*")
195
-
196
- detected = False
197
- for idx, prob in enumerate(predictions):
198
- confidence = float(prob) * 100
199
- if confidence > 15:
200
- detected = True
201
- damage_type = DAMAGE_TYPES[idx]['name']
202
- cases = KNOWLEDGE_BASE[damage_type]
203
-
204
- with st.expander(f"{damage_type.replace('_', ' ').title()} - {confidence:.1f}%", expanded=True):
205
- st.markdown(
206
- f"""
207
- <style>
208
- .stProgress > div > div > div > div {{
209
- background-color: {DAMAGE_TYPES[idx]['color']} !important;
210
- }}
211
- </style>
212
- """,
213
- unsafe_allow_html=True
214
- )
215
- st.progress(confidence / 100)
216
-
217
- tabs = st.tabs(["📋 Details", "🔧 Repairs", "⚠️ Actions"])
218
-
219
- with tabs[0]:
220
- for case in cases:
221
- st.markdown(f"""
222
- - **Severity:** {case['severity']}
223
- - **Description:** {case['description']}
224
- - **Location:** {case['location']}
225
- - **Required Expertise:** {case['required_expertise']}
226
- """)
227
-
228
- with tabs[1]:
229
- for step in cases[0]['repair_method']:
230
- st.markdown(f"✓ {step}")
231
- st.info(f"**Estimated Cost:** {cases[0]['estimated_cost']}")
232
- st.info(f"**Timeframe:** {cases[0]['timeframe']}")
233
-
234
- with tabs[2]:
235
- st.warning("**Immediate Actions Required:**")
236
- st.markdown(cases[0]['immediate_action'])
237
- st.success("**Prevention Measures:**")
238
- st.markdown(cases[0]['prevention'])
239
-
240
- # Display enhanced analysis
241
- display_enhanced_analysis(damage_type, confidence)
242
-
243
- if not detected:
244
- st.info("No significant structural damage detected. Regular maintenance recommended.")
245
 
 
246
  def main():
247
- """Main application function"""
248
- init_session_state()
249
  st.set_page_config(
250
  page_title="Structural Damage Analyzer Pro",
251
  page_icon="🏗️",
252
- layout="wide",
253
- initial_sidebar_state="expanded"
254
  )
255
-
256
- st.markdown(get_custom_css(), unsafe_allow_html=True)
257
-
258
- # Sidebar
259
- with st.sidebar:
260
- st.markdown("### ⚙️ Settings")
261
- st.session_state.dark_mode = st.toggle("Dark Mode", st.session_state.dark_mode)
262
- st.markdown("### 📖 Analysis History")
263
- if st.session_state.history:
264
- for item in st.session_state.history[-5:]:
265
- st.markdown(f"- {item}")
266
-
267
- display_header()
268
 
269
  # Load model and initialize RAG system
270
  global MODEL, PROCESSOR
271
  if MODEL is None or PROCESSOR is None:
272
- with st.spinner("Loading AI model..."):
273
- MODEL, PROCESSOR = load_model()
274
- if MODEL is None:
275
- st.error("Failed to load model. Please refresh the page.")
276
- return
277
-
278
  init_rag_system()
279
 
280
- # File upload
281
  uploaded_file = st.file_uploader(
282
- "Drag and drop or click to upload an image",
283
- type=['jpg', 'jpeg', 'png'],
284
- help="Supported formats: JPG, JPEG, PNG"
285
  )
286
 
287
  if uploaded_file:
288
- try:
289
- if uploaded_file.size > MAX_FILE_SIZE:
290
- st.error("File size too large. Please upload an image smaller than 5MB.")
291
- return
292
-
293
- image = preprocess_image(uploaded_file)
294
- if image is None:
295
- return
296
-
297
- validate_image(image)
298
-
299
- col1, col2 = st.columns([1, 1])
300
-
301
- with col1:
302
- st.image(image, caption="Uploaded Structure", use_container_width=True)
303
-
304
- with col2:
305
- with st.spinner("🔍 Analyzing damage..."):
306
- start_time = time.time()
307
- predictions = analyze_damage(image, MODEL, PROCESSOR)
308
- analysis_time = time.time() - start_time
309
-
310
- if predictions is not None:
311
- display_analysis_results(predictions, analysis_time)
312
- st.session_state.history.append(f"Analyzed image: {uploaded_file.name}")
313
 
314
- except Exception as e:
315
- cleanup_memory()
316
- st.error(f"Error processing image: {str(e)}")
317
- st.info("Please try uploading a different image.")
318
 
319
- # Footer
320
- st.markdown("---")
321
- st.markdown(
322
- """
323
- <div style='text-align: center'>
324
- <p>🏗️ Structural Damage Analyzer Pro | Built with Streamlit & Transformers</p>
325
- <p style='font-size: 0.8rem;'>For professional use only. Always consult with a structural engineer.</p>
326
- </div>
327
- """,
328
- unsafe_allow_html=True
329
- )
330
 
331
  if __name__ == "__main__":
332
- main()
 
4
  import torch
5
  import time
6
  import gc
7
+ import logging
8
  from knowledge_base import KNOWLEDGE_BASE, DAMAGE_TYPES
9
  from rag_utils import RAGSystem
10
 
11
+ # Configure logging
12
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
13
+
14
  # Constants
15
  MAX_FILE_SIZE = 5 * 1024 * 1024 # 5MB
16
  MAX_IMAGE_SIZE = 1024 # Maximum dimension for images
 
20
  PROCESSOR = None
21
  RAG_SYSTEM = None
22
 
23
+ # Cleanup function for memory
24
  def cleanup_memory():
25
  """Clean up memory and GPU cache"""
26
  gc.collect()
27
  if torch.cuda.is_available():
28
  torch.cuda.empty_cache()
29
 
30
+ # Session state initialization
 
 
 
 
 
 
31
  @st.cache_resource(show_spinner="Loading AI model...")
32
  def load_model():
33
  """Load and cache the model and processor"""
34
  try:
35
  model_name = "google/vit-base-patch16-224"
 
36
  processor = ViTImageProcessor.from_pretrained(model_name)
 
 
37
  device = "cuda" if torch.cuda.is_available() else "cpu"
38
+
39
  model = ViTForImageClassification.from_pretrained(
40
  model_name,
41
  num_labels=len(DAMAGE_TYPES),
42
  ignore_mismatched_sizes=True,
43
  ).to(device)
44
+
 
45
  model.eval()
46
+ logging.info("Model loaded successfully.")
47
  return model, processor
48
  except Exception as e:
49
+ logging.error(f"Failed to load model: {str(e)}")
50
+ st.error("Error loading model. Please restart the app.")
51
  return None, None
52
 
53
+ # Initialize RAG system
54
+ @st.cache_resource
55
  def init_rag_system():
 
56
  global RAG_SYSTEM
57
+ try:
58
  RAG_SYSTEM = RAGSystem()
59
  RAG_SYSTEM.initialize_knowledge_base(KNOWLEDGE_BASE)
60
+ logging.info("RAG system initialized successfully.")
61
+ except Exception as e:
62
+ logging.error(f"Failed to initialize RAG system: {str(e)}")
63
+ st.error("Error initializing knowledge base.")
64
 
65
+ # Image validation
66
  def validate_image(image):
 
67
  if image.size[0] * image.size[1] > 1024 * 1024:
68
+ st.warning("Large image detected. Resizing for better performance.")
69
  if image.format not in ['JPEG', 'PNG']:
70
+ st.warning("Non-optimal image format. Use JPEG or PNG.")
71
 
72
+ # Image preprocessing
73
  def preprocess_image(uploaded_file):
 
74
  try:
75
  image = Image.open(uploaded_file)
 
76
  if max(image.size) > MAX_IMAGE_SIZE:
77
  ratio = MAX_IMAGE_SIZE / max(image.size)
78
  new_size = tuple([int(dim * ratio) for dim in image.size])
79
  image = image.resize(new_size, Image.Resampling.LANCZOS)
80
  return image
81
  except Exception as e:
82
+ logging.error(f"Error processing image: {str(e)}")
83
+ st.error("Image processing error.")
84
  return None
85
 
86
+ # Damage analysis
87
  def analyze_damage(image, model, processor):
 
88
  try:
89
  device = next(model.parameters()).device
90
  with torch.no_grad():
91
  image = image.convert('RGB')
92
  inputs = processor(images=image, return_tensors="pt")
 
93
  inputs = {k: v.to(device) for k, v in inputs.items()}
94
  outputs = model(**inputs)
95
  probs = torch.nn.functional.softmax(outputs.logits, dim=1)[0]
96
  cleanup_memory()
97
+ return probs.cpu()
98
+ except Exception as e:
99
+ logging.error(f"Error analyzing image: {str(e)}")
100
+ st.error("Image analysis failed.")
 
 
 
101
  return None
102
 
103
+ # Display enhanced analysis
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  def display_enhanced_analysis(damage_type, confidence):
 
105
  try:
106
  enhanced_info = RAG_SYSTEM.get_enhanced_analysis(damage_type, confidence)
 
107
  st.markdown("### 🔍 Enhanced Analysis")
108
 
109
  with st.expander("📚 Technical Details", expanded=True):
110
  for detail in enhanced_info["technical_details"]:
111
  st.markdown(detail)
112
+
113
  with st.expander("⚠️ Safety Considerations"):
114
  for safety in enhanced_info["safety_considerations"]:
115
  st.warning(safety)
116
+
117
  with st.expander("👷 Expert Recommendations"):
118
  for rec in enhanced_info["expert_recommendations"]:
119
  st.info(rec)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  except Exception as e:
121
+ logging.error(f"Failed to generate enhanced analysis: {str(e)}")
122
+ st.error("Error generating enhanced analysis.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
+ # Main function
125
  def main():
 
 
126
  st.set_page_config(
127
  page_title="Structural Damage Analyzer Pro",
128
  page_icon="🏗️",
129
+ layout="wide"
 
130
  )
131
+ st.title("🏗️ Structural Damage Analyzer Pro")
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
  # Load model and initialize RAG system
134
  global MODEL, PROCESSOR
135
  if MODEL is None or PROCESSOR is None:
136
+ MODEL, PROCESSOR = load_model()
 
 
 
 
 
137
  init_rag_system()
138
 
 
139
  uploaded_file = st.file_uploader(
140
+ "Upload an image for analysis (JPG, PNG)",
141
+ type=['jpg', 'jpeg', 'png']
 
142
  )
143
 
144
  if uploaded_file:
145
+ if uploaded_file.size > MAX_FILE_SIZE:
146
+ st.error("File too large. Limit: 5MB.")
147
+ return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
+ image = preprocess_image(uploaded_file)
150
+ validate_image(image)
 
 
151
 
152
+ st.image(image, caption="Uploaded Image", use_column_width=True)
153
+
154
+ with st.spinner("Analyzing damage..."):
155
+ start_time = time.time()
156
+ predictions = analyze_damage(image, MODEL, PROCESSOR)
157
+ analysis_time = time.time() - start_time
158
+
159
+ if predictions is not None:
160
+ st.markdown(f"*Analysis completed in {analysis_time:.2f} seconds*")
161
+ confidence = float(predictions[0]) * 100
162
+ display_enhanced_analysis(DAMAGE_TYPES[0]['name'], confidence)
163
 
164
  if __name__ == "__main__":
165
+ main()