Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import requests | |
| from datetime import datetime, timedelta | |
| import pandas as pd | |
| import plotly.express as px | |
| import plotly.graph_objects as go | |
| from plotly.subplots import make_subplots | |
| import numpy as np | |
| import os | |
| import folium | |
| from streamlit_folium import st_folium | |
| import json | |
| import time | |
| from geopy.geocoders import Nominatim | |
| from geopy.distance import geodesic | |
| import warnings | |
| warnings.filterwarnings('ignore') | |
| # Enhanced Emergency AI System - NEW FEATURES | |
| class EmergencyAI: | |
| def __init__(self): | |
| self.disaster_log = [] | |
| self.rescue_teams = [] | |
| self.languages = { | |
| 'en': 'English', 'es': 'Spanish', 'fr': 'French', 'de': 'German', | |
| 'it': 'Italian', 'pt': 'Portuguese', 'ar': 'Arabic', 'ur': 'Urdu', | |
| 'hi': 'Hindi', 'zh': 'Chinese', 'ja': 'Japanese', 'ko': 'Korean', | |
| 'ru': 'Russian', 'tr': 'Turkish' | |
| } | |
| def get_first_aid_instructions(self, emergency_type, severity="moderate"): | |
| """Provide instant first aid instructions based on emergency type""" | |
| instructions = { | |
| 'earthquake': { | |
| 'immediate': { | |
| 'high': [ | |
| "🚨 IMMEDIATE ACTIONS:", | |
| "1. DROP to hands and knees immediately", | |
| "2. COVER your head and neck under a desk/table", | |
| "3. HOLD ON to your shelter and protect yourself", | |
| "4. Stay where you are until shaking stops", | |
| "5. Do NOT run outside during shaking" | |
| ], | |
| 'moderate': [ | |
| "⚠️ SAFETY ACTIONS:", | |
| "1. Move away from windows and heavy objects", | |
| "2. Take cover under sturdy furniture", | |
| "3. Protect your head and neck", | |
| "4. Wait for shaking to stop completely" | |
| ], | |
| 'low': [ | |
| "ℹ️ PRECAUTIONARY ACTIONS:", | |
| "1. Stay calm and aware of your surroundings", | |
| "2. Identify safe spaces in your location", | |
| "3. Check for any structural damage", | |
| "4. Be prepared for possible aftershocks" | |
| ] | |
| }, | |
| 'after': [ | |
| "🏥 POST-EARTHQUAKE CARE:", | |
| "1. Check for injuries - provide first aid if trained", | |
| "2. Check for gas leaks, electrical damage, structural damage", | |
| "3. Use flashlight, not candles or matches", | |
| "4. Stay out of damaged buildings", | |
| "5. Listen to emergency broadcasts", | |
| "6. Be prepared for aftershocks", | |
| "7. Help others if you can do so safely" | |
| ] | |
| }, | |
| 'flood': { | |
| 'immediate': { | |
| 'high': [ | |
| "🌊 FLOOD EMERGENCY:", | |
| "1. Get to higher ground IMMEDIATELY", | |
| "2. Avoid walking in moving water (6+ inches can knock you down)", | |
| "3. Don't drive through flooded roads", | |
| "4. If trapped in building, go to highest floor", | |
| "5. Signal for help from roof/upper floor" | |
| ], | |
| 'moderate': [ | |
| "⚠️ FLOOD PRECAUTIONS:", | |
| "1. Move to higher ground if possible", | |
| "2. Avoid flood waters", | |
| "3. Monitor emergency broadcasts", | |
| "4. Prepare emergency supplies" | |
| ], | |
| 'low': [ | |
| "ℹ️ FLOOD AWARENESS:", | |
| "1. Monitor water levels", | |
| "2. Prepare evacuation plan", | |
| "3. Move valuables to higher ground", | |
| "4. Stay informed of conditions" | |
| ] | |
| } | |
| }, | |
| 'injury': { | |
| 'bleeding': [ | |
| "🩸 BLEEDING CONTROL:", | |
| "1. Apply direct pressure with clean cloth", | |
| "2. Elevate injured area above heart if possible", | |
| "3. Don't remove objects embedded in wounds", | |
| "4. Apply pressure to pressure points if bleeding severe", | |
| "5. Seek medical help immediately for severe bleeding" | |
| ], | |
| 'fracture': [ | |
| "🦴 FRACTURE CARE:", | |
| "1. Don't move the person unless in immediate danger", | |
| "2. Immobilize the injured area", | |
| "3. Apply ice wrapped in cloth (not directly on skin)", | |
| "4. Check circulation below injury site", | |
| "5. Get emergency medical help" | |
| ], | |
| 'unconscious': [ | |
| "😵 UNCONSCIOUS PERSON:", | |
| "1. Check for responsiveness (tap shoulders, shout)", | |
| "2. Check for breathing and pulse", | |
| "3. If breathing: place in recovery position", | |
| "4. If not breathing: start CPR if trained", | |
| "5. Call emergency services immediately" | |
| ] | |
| } | |
| } | |
| return instructions.get(emergency_type, {}).get('immediate', {}).get(severity, | |
| instructions.get(emergency_type, {}).get('immediate', {}).get('moderate', | |
| ["No specific instructions available for this emergency type."])) | |
| def coordinate_rescue_teams(self, emergency_location, emergency_type, severity): | |
| """Coordinate rescue teams and resources""" | |
| coordination_plan = { | |
| 'priority_level': self._get_priority_level(severity), | |
| 'required_teams': self._get_required_teams(emergency_type, severity), | |
| 'resource_allocation': self._get_resource_allocation(emergency_type), | |
| 'evacuation_zones': self._calculate_evacuation_zones(emergency_location, severity), | |
| 'communication_protocol': self._get_communication_protocol(severity) | |
| } | |
| return coordination_plan | |
| def _get_priority_level(self, severity): | |
| priority_map = {'low': 'P3 - Standard', 'moderate': 'P2 - Urgent', 'high': 'P1 - Critical', 'extreme': 'P0 - Immediate'} | |
| return priority_map.get(severity, 'P2 - Urgent') | |
| def _get_required_teams(self, emergency_type, severity): | |
| base_teams = ['Emergency Medical Services', 'Fire Department', 'Police'] | |
| if emergency_type == 'earthquake': | |
| base_teams.extend(['Search and Rescue', 'Structural Engineers', 'Utility Teams']) | |
| if severity in ['high', 'extreme']: | |
| base_teams.extend(['Heavy Rescue', 'Disaster Relief', 'Military Support']) | |
| elif emergency_type == 'flood': | |
| base_teams.extend(['Water Rescue', 'Coast Guard', 'Emergency Shelters']) | |
| return base_teams | |
| def _get_resource_allocation(self, emergency_type): | |
| resources = { | |
| 'earthquake': ['Medical Supplies', 'Heavy Machinery', 'Communication Equipment', 'Emergency Shelters', 'Food & Water'], | |
| 'flood': ['Boats/Rafts', 'Water Pumps', 'Sandbags', 'Medical Supplies', 'Emergency Shelters'], | |
| 'general': ['First Aid Supplies', 'Communication Equipment', 'Transportation', 'Emergency Power'] | |
| } | |
| return resources.get(emergency_type, resources['general']) | |
| def _calculate_evacuation_zones(self, location, severity): | |
| radius_map = {'low': 1, 'moderate': 3, 'high': 10, 'extreme': 25} | |
| radius = radius_map.get(severity, 3) | |
| return { | |
| 'immediate_evacuation': f"{radius/2} km radius", | |
| 'precautionary_evacuation': f"{radius} km radius", | |
| 'shelter_locations': "Community centers, schools, hospitals outside danger zone", | |
| 'evacuation_routes': "Main roads leading away from epicenter/danger zone" | |
| } | |
| def _get_communication_protocol(self, severity): | |
| if severity in ['high', 'extreme']: | |
| return { | |
| 'frequency': 'Every 15 minutes', | |
| 'channels': ['Emergency Radio', 'Cell Broadcast', 'Social Media', 'TV/Radio'], | |
| 'languages': 'Multi-language broadcasts required', | |
| 'backup_systems': 'Satellite communication activated' | |
| } | |
| else: | |
| return { | |
| 'frequency': 'Every hour', | |
| 'channels': ['Emergency Radio', 'Official websites'], | |
| 'languages': 'Local language primary', | |
| 'backup_systems': 'Standard communication systems' | |
| } | |
| def translate_emergency_message(self, message, target_language='en'): | |
| """Translate emergency messages - in real implementation would use translation API""" | |
| # This is a simplified version - in production, you'd integrate with Google Translate API or similar | |
| translations = { | |
| 'earthquake_alert': { | |
| 'en': 'EARTHQUAKE ALERT: Take cover immediately!', | |
| 'es': 'ALERTA DE TERREMOTO: ¡Busque refugio inmediatamente!', | |
| 'fr': 'ALERTE AU TREMBLEMENT DE TERRE: Mettez-vous à l\'abri immédiatement!', | |
| 'de': 'ERDBEBENALARM: Sofort Schutz suchen!', | |
| 'ur': 'زلزلے کا الرٹ: فوری طور پر محفوظ جگہ تلاش کریں!', | |
| 'ar': 'تنبيه زلزال: ابحث عن مأوى فوراً!', | |
| 'zh': '地震警报:立即寻找掩护!', | |
| 'ja': '地震警報:直ちに避難してください!' | |
| }, | |
| 'evacuation_order': { | |
| 'en': 'EVACUATION ORDER: Leave the area immediately via designated routes.', | |
| 'es': 'ORDEN DE EVACUACIÓN: Abandone el área inmediatamente por las rutas designadas.', | |
| 'fr': 'ORDRE D\'ÉVACUATION: Quittez la zone immédiatement par les routes désignées.', | |
| 'de': 'EVAKUIERUNGSBEFEHL: Verlassen Sie das Gebiet sofort über die vorgesehenen Routen.', | |
| 'ur': 'انخلاء کا حکم: مقررہ راستوں سے فوری طور پر علاقہ چھوڑیں۔', | |
| 'ar': 'أمر إخلاء: اتركوا المنطقة فوراً عبر الطرق المحددة.', | |
| 'zh': '疏散令:立即通过指定路线离开该地区。', | |
| 'ja': '避難命令:指定されたルートで直ちにその地域から避難してください。' | |
| } | |
| } | |
| # In production, this would make an API call to a translation service | |
| return translations.get(message.lower().replace(' ', '_'), {}).get(target_language, | |
| f"Translation not available for {target_language}") | |
| def learn_from_disaster(self, disaster_data): | |
| """Learn from each disaster to improve future responses""" | |
| learning_points = { | |
| 'response_time': disaster_data.get('response_time', 0), | |
| 'effectiveness': disaster_data.get('effectiveness_rating', 0), | |
| 'casualties': disaster_data.get('casualties', 0), | |
| 'lessons_learned': disaster_data.get('lessons', []), | |
| 'improvements_needed': [] | |
| } | |
| # Analyze patterns and suggest improvements | |
| if learning_points['response_time'] > 600: # 10 minutes | |
| learning_points['improvements_needed'].append("Improve emergency alert systems") | |
| if learning_points['effectiveness'] < 7: # out of 10 | |
| learning_points['improvements_needed'].append("Enhanced training for emergency teams") | |
| self.disaster_log.append({ | |
| 'timestamp': datetime.now(), | |
| 'data': disaster_data, | |
| 'learning_points': learning_points | |
| }) | |
| return learning_points | |
| # Initialize Emergency AI | |
| emergency_ai = EmergencyAI() | |
| # Secure API key handling | |
| def get_groq_api_key(): | |
| """Securely get GROQ API key from environment variables or Streamlit secrets""" | |
| try: | |
| return st.secrets["GROQ_API_KEY"] | |
| except: | |
| api_key = os.getenv("GROQ_API_KEY") | |
| if not api_key: | |
| st.error("🔐 GROQ API key not found. Please configure it in Streamlit secrets or environment variables.") | |
| st.info(""" | |
| **To configure the API key:** | |
| 1. **For Hugging Face Spaces**: Add `GROQ_API_KEY` in your Space settings under 'Repository secrets' | |
| 2. **For local development**: Set environment variable `GROQ_API_KEY=your_key_here` | |
| 3. **For Streamlit Cloud**: Add to secrets.toml file | |
| """) | |
| return None | |
| return api_key | |
| # Color schemes for different magnitude levels | |
| MAGNITUDE_COLORS = { | |
| 'Low': '#00ff00', # Green | |
| 'Moderate': '#ffff00', # Yellow | |
| 'High': '#ff8000', # Orange | |
| 'Severe': '#ff0000', # Red | |
| 'Extreme': '#800000' # Dark Red | |
| } | |
| # Risk assessment thresholds | |
| RISK_THRESHOLDS = { | |
| 'low': {'count': 5, 'max_magnitude': 3.0}, | |
| 'moderate': {'count': 10, 'max_magnitude': 4.5}, | |
| 'high': {'count': 20, 'max_magnitude': 5.5}, | |
| 'severe': {'count': 30, 'max_magnitude': 6.5}, | |
| 'extreme': {'count': 50, 'max_magnitude': 7.0} | |
| } | |
| # Emergency protocols | |
| EMERGENCY_PROTOCOLS = { | |
| 'low': "Monitor situation. No immediate action required.", | |
| 'moderate': "Stay alert. Review emergency plans.", | |
| 'high': "Prepare emergency kit. Stay informed.", | |
| 'severe': "Follow evacuation orders if issued. Seek shelter.", | |
| 'extreme': "IMMEDIATE EVACUATION. Follow emergency services." | |
| } | |
| def get_groq_summary(prompt, context=""): | |
| """Enhanced Groq LLM function with secure API key handling""" | |
| api_key = get_groq_api_key() | |
| if not api_key: | |
| return "AI Analysis unavailable - API key not configured" | |
| try: | |
| from groq import Groq | |
| client = Groq(api_key=api_key) | |
| full_prompt = f"{context}\n\n{prompt}" if context else prompt | |
| response = client.chat.completions.create( | |
| model="llama-3.3-70b-versatile", | |
| messages=[ | |
| {"role": "system", "content": "You are an expert emergency response AI, seismologist, and disaster management specialist. Provide detailed, accurate, and actionable information with focus on safety and emergency preparedness."}, | |
| {"role": "user", "content": full_prompt} | |
| ], | |
| max_tokens=2048, | |
| temperature=0.7, | |
| top_p=0.9, | |
| presence_penalty=0.1, | |
| frequency_penalty=0.1 | |
| ) | |
| return response.choices[0].message.content | |
| except ImportError: | |
| return "AI Analysis unavailable - Groq library not installed" | |
| except Exception as e: | |
| return f"AI Analysis Error: {str(e)}" | |
| def fetch_earthquakes(min_magnitude=2.5, hours=24, region_bbox=None, detailed=True): | |
| """Fetch earthquake data with enhanced error handling and data processing""" | |
| try: | |
| endtime = datetime.utcnow() | |
| starttime = endtime - timedelta(hours=hours) | |
| url = "https://earthquake.usgs.gov/fdsnws/event/1/query" | |
| params = { | |
| "format": "geojson", | |
| "starttime": starttime.strftime('%Y-%m-%dT%H:%M:%S'), | |
| "endtime": endtime.strftime('%Y-%m-%dT%H:%M:%S'), | |
| "minmagnitude": min_magnitude, | |
| "orderby": "time", | |
| "limit": 500 if detailed else 200 | |
| } | |
| if region_bbox: | |
| params.update({ | |
| "minlatitude": region_bbox[1], | |
| "maxlatitude": region_bbox[3], | |
| "minlongitude": region_bbox[0], | |
| "maxlongitude": region_bbox[2], | |
| }) | |
| response = requests.get(url, params=params, timeout=30) | |
| response.raise_for_status() | |
| data = response.json() | |
| features = data.get('features', []) | |
| earthquakes = [] | |
| for f in features: | |
| prop = f['properties'] | |
| geom = f['geometry'] | |
| earthquake = { | |
| 'time': datetime.utcfromtimestamp(prop['time']/1000), | |
| 'place': prop['place'], | |
| 'magnitude': prop['mag'], | |
| 'longitude': geom['coordinates'][0], | |
| 'latitude': geom['coordinates'][1], | |
| 'depth': geom['coordinates'][2], | |
| 'url': prop['url'], | |
| 'type': prop.get('type', 'earthquake'), | |
| 'status': prop.get('status', 'automatic'), | |
| 'tsunami': prop.get('tsunami', 0), | |
| 'felt': prop.get('felt', 0), | |
| 'cdi': prop.get('cdi', 0), | |
| 'mmi': prop.get('mmi', 0), | |
| 'alert': prop.get('alert', ''), | |
| 'sig': prop.get('sig', 0) | |
| } | |
| earthquake['risk_level'] = calculate_risk_level(earthquake['magnitude']) | |
| earthquake['time_ago'] = calculate_time_ago(earthquake['time']) | |
| earthquakes.append(earthquake) | |
| df = pd.DataFrame(earthquakes) | |
| if not df.empty: | |
| df['magnitude_category'] = df['magnitude'].apply(categorize_magnitude) | |
| df['depth_category'] = df['depth'].apply(categorize_depth) | |
| df['hour_of_day'] = df['time'].dt.hour | |
| df['day_of_week'] = df['time'].dt.day_name() | |
| return df | |
| except requests.exceptions.RequestException as e: | |
| st.error(f"Network error: {e}") | |
| return pd.DataFrame() | |
| except Exception as e: | |
| st.error(f"Data processing error: {e}") | |
| return pd.DataFrame() | |
| def calculate_risk_level(magnitude): | |
| """Calculate risk level based on magnitude""" | |
| if magnitude >= 7.0: | |
| return 'extreme' | |
| elif magnitude >= 6.0: | |
| return 'severe' | |
| elif magnitude >= 5.0: | |
| return 'high' | |
| elif magnitude >= 4.0: | |
| return 'moderate' | |
| else: | |
| return 'low' | |
| def categorize_magnitude(magnitude): | |
| """Categorize magnitude for analysis""" | |
| if magnitude >= 7.0: | |
| return 'Major (≥7.0)' | |
| elif magnitude >= 6.0: | |
| return 'Strong (6.0-6.9)' | |
| elif magnitude >= 5.0: | |
| return 'Moderate (5.0-5.9)' | |
| elif magnitude >= 4.0: | |
| return 'Light (4.0-4.9)' | |
| else: | |
| return 'Minor (<4.0)' | |
| def categorize_depth(depth): | |
| """Categorize depth for analysis""" | |
| if depth < 70: | |
| return 'Shallow (<70km)' | |
| elif depth < 300: | |
| return 'Intermediate (70-300km)' | |
| else: | |
| return 'Deep (>300km)' | |
| def calculate_time_ago(time): | |
| """Calculate time ago in human readable format""" | |
| now = datetime.utcnow() | |
| diff = now - time | |
| if diff.days > 0: | |
| return f"{diff.days} day(s) ago" | |
| elif diff.seconds >= 3600: | |
| hours = diff.seconds // 3600 | |
| return f"{hours} hour(s) ago" | |
| elif diff.seconds >= 60: | |
| minutes = diff.seconds // 60 | |
| return f"{minutes} minute(s) ago" | |
| else: | |
| return "Just now" | |
| def analyze_seismic_patterns(df): | |
| """Analyze seismic patterns and trends""" | |
| if df.empty: | |
| return {} | |
| analysis = {} | |
| try: | |
| if len(df) > 0: | |
| analysis['hourly_distribution'] = df['hour_of_day'].value_counts().sort_index() | |
| analysis['daily_distribution'] = df['day_of_week'].value_counts() | |
| if 'magnitude' in df.columns and len(df) > 0: | |
| analysis['magnitude_stats'] = { | |
| 'mean': df['magnitude'].mean(), | |
| 'median': df['magnitude'].median(), | |
| 'std': df['magnitude'].std(), | |
| 'max': df['magnitude'].max(), | |
| 'min': df['magnitude'].min() | |
| } | |
| if 'depth' in df.columns and len(df) > 0: | |
| analysis['depth_stats'] = { | |
| 'mean': df['depth'].mean(), | |
| 'median': df['depth'].median(), | |
| 'std': df['depth'].std() | |
| } | |
| if 'risk_level' in df.columns and len(df) > 0: | |
| analysis['risk_distribution'] = df['risk_level'].value_counts() | |
| if len(df) > 1 and 'latitude' in df.columns and 'longitude' in df.columns: | |
| analysis['geographic_center'] = { | |
| 'lat': df['latitude'].mean(), | |
| 'lon': df['longitude'].mean() | |
| } | |
| except Exception as e: | |
| st.warning(f"Error in pattern analysis: {str(e)}") | |
| return {} | |
| return analysis | |
| def calculate_overall_risk(df): | |
| """Calculate overall risk assessment""" | |
| if df.empty: | |
| return 'low', "No recent seismic activity" | |
| count = len(df) | |
| max_magnitude = df['magnitude'].max() | |
| risk_score = 0 | |
| if count >= RISK_THRESHOLDS['extreme']['count']: | |
| risk_score += 40 | |
| elif count >= RISK_THRESHOLDS['severe']['count']: | |
| risk_score += 30 | |
| elif count >= RISK_THRESHOLDS['high']['count']: | |
| risk_score += 20 | |
| elif count >= RISK_THRESHOLDS['moderate']['count']: | |
| risk_score += 10 | |
| if max_magnitude >= RISK_THRESHOLDS['extreme']['max_magnitude']: | |
| risk_score += 40 | |
| elif max_magnitude >= RISK_THRESHOLDS['severe']['max_magnitude']: | |
| risk_score += 30 | |
| elif max_magnitude >= RISK_THRESHOLDS['high']['max_magnitude']: | |
| risk_score += 20 | |
| elif max_magnitude >= RISK_THRESHOLDS['moderate']['max_magnitude']: | |
| risk_score += 10 | |
| if risk_score >= 60: | |
| risk_level = 'extreme' | |
| elif risk_score >= 40: | |
| risk_level = 'severe' | |
| elif risk_score >= 25: | |
| risk_level = 'high' | |
| elif risk_score >= 10: | |
| risk_level = 'moderate' | |
| else: | |
| risk_level = 'low' | |
| return risk_level, f"Risk Score: {risk_score}/80" | |
| def create_advanced_map(df, region_bbox=None): | |
| """Create an advanced interactive map""" | |
| if df.empty: | |
| return None | |
| center_lat = df['latitude'].mean() | |
| center_lon = df['longitude'].mean() | |
| m = folium.Map( | |
| location=[center_lat, center_lon], | |
| zoom_start=6, | |
| tiles='OpenStreetMap' | |
| ) | |
| for idx, row in df.iterrows(): | |
| if row['magnitude'] >= 6.0: | |
| color = 'red' | |
| radius = 15 | |
| elif row['magnitude'] >= 5.0: | |
| color = 'orange' | |
| radius = 12 | |
| elif row['magnitude'] >= 4.0: | |
| color = 'yellow' | |
| radius = 10 | |
| else: | |
| color = 'green' | |
| radius = 8 | |
| popup_content = f""" | |
| <b>Magnitude {row['magnitude']}</b><br> | |
| Location: {row['place']}<br> | |
| Time: {row['time'].strftime('%Y-%m-%d %H:%M:%S')}<br> | |
| Depth: {row['depth']:.1f} km<br> | |
| Risk Level: {row['risk_level'].upper()}<br> | |
| <a href="{row['url']}" target="_blank">USGS Details</a> | |
| """ | |
| folium.CircleMarker( | |
| location=[row['latitude'], row['longitude']], | |
| radius=radius, | |
| popup=popup_content, | |
| color=color, | |
| fill=True, | |
| fillOpacity=0.7 | |
| ).add_to(m) | |
| if region_bbox: | |
| folium.Rectangle( | |
| bounds=[[region_bbox[1], region_bbox[0]], [region_bbox[3], region_bbox[2]]], | |
| color='blue', | |
| weight=2, | |
| fillOpacity=0.1 | |
| ).add_to(m) | |
| return m | |
| def create_comprehensive_charts(df, analysis): | |
| """Create comprehensive visualization charts""" | |
| if df.empty: | |
| return [] | |
| charts = [] | |
| # Magnitude over time with trend - with error handling | |
| fig1 = go.Figure() | |
| fig1.add_trace(go.Scatter( | |
| x=df['time'], y=df['magnitude'], | |
| mode='markers', | |
| marker=dict( | |
| size=df['magnitude'] * 2, | |
| color=df['magnitude'], | |
| colorscale='Reds', | |
| showscale=True | |
| ), | |
| name='Earthquakes' | |
| )) | |
| # Only add trend line if we have enough data points (at least 2) | |
| if len(df) >= 2: | |
| try: | |
| z = np.polyfit(range(len(df)), df['magnitude'], 1) | |
| p = np.poly1d(z) | |
| fig1.add_trace(go.Scatter( | |
| x=df['time'], y=p(range(len(df))), | |
| mode='lines', | |
| name='Trend', | |
| line=dict(color='blue', dash='dash') | |
| )) | |
| except (np.linalg.LinAlgError, ValueError) as e: | |
| st.warning(f"Trend analysis unavailable: {str(e)}") | |
| fig1.update_layout( | |
| title='Earthquake Magnitude Over Time with Trend', | |
| xaxis_title='Time', | |
| yaxis_title='Magnitude', | |
| height=400 | |
| ) | |
| charts.append(fig1) | |
| # Magnitude distribution histogram - only if we have data | |
| if len(df) > 0: | |
| fig2 = px.histogram( | |
| df, x='magnitude', nbins=min(20, len(df)), | |
| title='Magnitude Distribution', | |
| labels={'magnitude': 'Magnitude', 'count': 'Frequency'} | |
| ) | |
| fig2.update_layout(height=400) | |
| charts.append(fig2) | |
| # Depth vs Magnitude scatter - only if we have data | |
| if len(df) > 0: | |
| fig3 = px.scatter( | |
| df, x='depth', y='magnitude', color='magnitude', | |
| title='Depth vs Magnitude Relationship', | |
| labels={'depth': 'Depth (km)', 'magnitude': 'Magnitude'} | |
| ) | |
| fig3.update_layout(height=400) | |
| charts.append(fig3) | |
| # Hourly distribution - only if we have the data | |
| if 'hourly_distribution' in analysis and len(analysis['hourly_distribution']) > 0: | |
| fig4 = px.bar( | |
| x=analysis['hourly_distribution'].index, | |
| y=analysis['hourly_distribution'].values, | |
| title='Earthquake Activity by Hour of Day', | |
| labels={'x': 'Hour', 'y': 'Count'} | |
| ) | |
| fig4.update_layout(height=400) | |
| charts.append(fig4) | |
| # Risk level distribution - only if we have the data | |
| if 'risk_distribution' in analysis and len(analysis['risk_distribution']) > 0: | |
| fig5 = px.pie( | |
| values=analysis['risk_distribution'].values, | |
| names=analysis['risk_distribution'].index, | |
| title='Risk Level Distribution' | |
| ) | |
| fig5.update_layout(height=400) | |
| charts.append(fig5) | |
| return charts | |
| def main(): | |
| st.set_page_config( | |
| page_title="🌍 QuakeGuard AI - Emergency Response System", | |
| page_icon="🌍", | |
| layout="wide", | |
| initial_sidebar_state="expanded" | |
| ) | |
| st.markdown(""" | |
| <style> | |
| .main-header { | |
| font-size: 3rem; | |
| font-weight: bold; | |
| text-align: center; | |
| color: #1f77b4; | |
| margin-bottom: 2rem; | |
| } | |
| .risk-extreme { color: #800000; font-weight: bold; font-size: 1.2rem; } | |
| .risk-severe { color: #ff0000; font-weight: bold; font-size: 1.1rem; } | |
| .risk-high { color: #ff8000; font-weight: bold; } | |
| .risk-moderate { color: #ffaa00; font-weight: bold; } | |
| .risk-low { color: #44aa44; font-weight: bold; } | |
| .metric-card { | |
| background-color: #f0f2f6; | |
| padding: 1rem; | |
| border-radius: 0.5rem; | |
| border-left: 4px solid #1f77b4; | |
| color: #222 !important; | |
| } | |
| .emergency-card { | |
| background-color: #ffe6e6; | |
| padding: 1rem; | |
| border-radius: 0.5rem; | |
| border-left: 4px solid #ff0000; | |
| color: #222 !important; | |
| } | |
| .first-aid-card { | |
| background-color: #e6f3ff; | |
| padding: 1rem; | |
| border-radius: 0.5rem; | |
| border-left: 4px solid #0066cc; | |
| color: #222 !important; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| st.markdown('<h1 class="main-header">🌍 Emergency AI Response System</h1>', unsafe_allow_html=True) | |
| st.markdown("### Real-time disaster monitoring with AI-powered emergency response, first aid, rescue coordination & multilingual support") | |
| # Check if API key is configured | |
| if not get_groq_api_key(): | |
| st.stop() | |
| # Enhanced sidebar with new emergency features | |
| st.sidebar.header("⚙️ Configuration") | |
| # Emergency AI Settings | |
| st.sidebar.subheader("🚨 Emergency AI Settings") | |
| emergency_language = st.sidebar.selectbox( | |
| "🌐 Emergency Language", | |
| options=list(emergency_ai.languages.keys()), | |
| format_func=lambda x: emergency_ai.languages[x], | |
| index=0 | |
| ) | |
| show_first_aid = st.sidebar.checkbox("🏥 First Aid Instructions", value=True) | |
| show_rescue_coordination = st.sidebar.checkbox("🚁 Rescue Coordination", value=True) | |
| show_multilingual = st.sidebar.checkbox("🗣️ Multilingual Support", value=True) | |
| show_disaster_learning = st.sidebar.checkbox("🧠 Disaster Learning", value=True) | |
| region = st.sidebar.text_input( | |
| "🌍 Region (optional)", | |
| placeholder="e.g., California, Pakistan, Japan" | |
| ) | |
| col1, col2 = st.sidebar.columns(2) | |
| with col1: | |
| min_magnitude = st.slider("📏 Min Magnitude", 1.0, 7.0, 2.5, 0.1) | |
| with col2: | |
| hours = st.slider("⏰ Hours", 1, 168, 24) | |
| with st.sidebar.expander("🔧 Advanced Options"): | |
| show_detailed_analysis = st.checkbox("Detailed Analysis", value=True) | |
| show_ai_summary = st.checkbox("AI Summary", value=True) | |
| show_emergency_protocols = st.checkbox("Emergency Protocols", value=True) | |
| region_bboxes = { | |
| "California": [-125, 32, -114, 42], | |
| "Pakistan": [60, 23, 77, 37], | |
| "Japan": [129, 31, 146, 45], | |
| "Chile": [-75, -56, -66, -17], | |
| "Turkey": [25, 36, 45, 43], | |
| "Indonesia": [95, -11, 141, 6], | |
| "India": [68, 6, 97, 37], | |
| "Mexico": [-118, 14, -86, 33], | |
| "USA": [-125, 24, -66, 49], | |
| "World": [-180, -90, 180, 90] | |
| } | |
| region_bbox = region_bboxes.get(region.strip().title()) if region else None | |
| if st.button("🔄 Refresh Data", type="primary"): | |
| st.rerun() | |
| with st.spinner("🌐 Fetching earthquake data..."): | |
| df = fetch_earthquakes(min_magnitude, hours, region_bbox, show_detailed_analysis) | |
| if df.empty: | |
| st.warning("⚠️ No recent earthquakes found matching your criteria.") | |
| st.info("💡 Try reducing the minimum magnitude or increasing the time range.") | |
| # Show emergency features even when no data | |
| if show_first_aid: | |
| st.markdown(""" | |
| <div class="first-aid-card"> | |
| <h3>🏥 Emergency First Aid - Ready Mode</h3> | |
| <p>First aid instructions available for:</p> | |
| <ul> | |
| <li>🌍 Earthquake injuries</li> | |
| <li>🌊 Flood emergencies</li> | |
| <li>🩸 Bleeding control</li> | |
| <li>🦴 Fracture management</li> | |
| <li>😵 Unconscious victims</li> | |
| </ul> | |
| <p><strong>Emergency activated instructions will appear when seismic activity is detected.</strong></p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Show a simple message when no data is available | |
| st.markdown(""" | |
| <div class="metric-card"> | |
| <h3>🚨 Current Risk Level: <span class="risk-low">LOW</span></h3> | |
| <p><strong>Risk Score:</strong> 0/80</p> | |
| <p><strong>Emergency Protocol:</strong> Monitor situation. No immediate action required.</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Show tabs with appropriate messages | |
| tab1, tab2, tab3, tab4, tab5, tab6 = st.tabs(["🗺️ Map", "📊 Analytics", "📋 Data", "🤖 AI Analysis", "🚨 Emergency", "🏥 Emergency AI"]) | |
| with tab1: | |
| st.subheader("🌍 Interactive Earthquake Map") | |
| st.info("No earthquake data available for map visualization") | |
| with tab2: | |
| st.subheader("📊 Advanced Analytics") | |
| st.info("No earthquake data available for analysis") | |
| with tab3: | |
| st.subheader("📋 Earthquake Data") | |
| st.info("No earthquake data available") | |
| with tab4: | |
| st.subheader("🤖 AI-Powered Analysis") | |
| if show_ai_summary: | |
| st.info("No earthquake data available for AI analysis") | |
| else: | |
| st.info("Enable AI Summary in Advanced Options to see AI analysis.") | |
| with tab5: | |
| st.subheader("🚨 Emergency Information") | |
| if show_emergency_protocols: | |
| st.markdown(""" | |
| ### 🚨 Emergency Response Protocols | |
| **Immediate Actions During Earthquake:** | |
| - Drop, Cover, and Hold On | |
| - Stay indoors if you're inside | |
| - Move to open area if you're outside | |
| - Stay away from windows, mirrors, and heavy objects | |
| **After Earthquake:** | |
| - Check for injuries and provide first aid | |
| - Check for gas leaks and electrical damage | |
| - Listen to emergency broadcasts | |
| - Be prepared for aftershocks | |
| **Emergency Contacts:** | |
| - Emergency Services: 911 (US) / 112 (EU) / 999 (UK) | |
| - USGS Earthquake Information: https://earthquake.usgs.gov | |
| - Local Emergency Management: Check your local government website | |
| """) | |
| st.markdown(""" | |
| ### 📊 Current Emergency Status | |
| - **Risk Level**: LOW | |
| - **Recommended Action**: Monitor situation. No immediate action required. | |
| - **Monitoring Required**: No | |
| """) | |
| else: | |
| st.info("Enable Emergency Protocols in Advanced Options to see emergency information.") | |
| with tab6: | |
| st.subheader("🏥 Emergency AI - Standby Mode") | |
| if show_first_aid: | |
| st.markdown("### 🩺 First Aid Training Mode") | |
| injury_type = st.selectbox("Select injury type for training:", | |
| ["bleeding", "fracture", "unconscious"]) | |
| instructions = emergency_ai.get_first_aid_instructions('injury') | |
| if injury_type in instructions: | |
| st.markdown(f""" | |
| <div class="first-aid-card"> | |
| <h4>{injury_type.title()} Management</h4> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| for instruction in instructions[injury_type]: | |
| st.write(instruction) | |
| if show_multilingual: | |
| st.markdown("### 🌐 Emergency Translation Test") | |
| test_message = st.selectbox("Test emergency message:", | |
| ["earthquake_alert", "evacuation_order"]) | |
| if st.button("🔄 Translate"): | |
| translation = emergency_ai.translate_emergency_message(test_message, emergency_language) | |
| st.success(f"**Translation ({emergency_ai.languages[emergency_language]}):** {translation}") | |
| if show_disaster_learning: | |
| st.markdown("### 🧠 Disaster Learning System") | |
| st.info("Learning system is active and ready to analyze future disasters.") | |
| if emergency_ai.disaster_log: | |
| st.write(f"**Previous disasters analyzed:** {len(emergency_ai.disaster_log)}") | |
| else: | |
| st.write("**Previous disasters analyzed:** 0") | |
| else: | |
| st.success(f"✅ Found {len(df)} earthquakes in the last {hours} hours") | |
| st.write(f"🕐 Last updated: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC") | |
| risk_level, risk_score = calculate_overall_risk(df) | |
| # Enhanced risk display with emergency AI features | |
| st.markdown(f""" | |
| <div class="{'emergency-card' if risk_level in ['high', 'severe', 'extreme'] else 'metric-card'}"> | |
| <h3>🚨 Current Risk Level: <span class="risk-{risk_level}">{risk_level.upper()}</span></h3> | |
| <p><strong>Risk Score:</strong> {risk_score}</p> | |
| <p><strong>Emergency Protocol:</strong> {EMERGENCY_PROTOCOLS[risk_level]}</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Emergency AI Alerts | |
| if risk_level in ['high', 'severe', 'extreme']: | |
| if show_first_aid: | |
| first_aid_instructions = emergency_ai.get_first_aid_instructions('earthquake', risk_level) | |
| st.markdown(f""" | |
| <div class="emergency-card"> | |
| <h3>🏥 EMERGENCY FIRST AID ACTIVATED</h3> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| for instruction in first_aid_instructions: | |
| st.error(instruction) | |
| if show_rescue_coordination: | |
| coord_plan = emergency_ai.coordinate_rescue_teams( | |
| df.iloc[0] if not df.empty else None, 'earthquake', risk_level | |
| ) | |
| st.markdown(f""" | |
| <div class="emergency-card"> | |
| <h3>🚁 RESCUE COORDINATION ACTIVATED</h3> | |
| <p><strong>Priority Level:</strong> {coord_plan['priority_level']}</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| if show_multilingual: | |
| alert_msg = emergency_ai.translate_emergency_message('earthquake_alert', emergency_language) | |
| st.markdown(f""" | |
| <div class="emergency-card"> | |
| <h3>🌐 MULTILINGUAL ALERT</h3> | |
| <p><strong>{emergency_ai.languages[emergency_language]}:</strong> {alert_msg}</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| col1, col2, col3, col4 = st.columns(4) | |
| with col1: | |
| st.metric("Total Earthquakes", len(df)) | |
| with col2: | |
| st.metric("Max Magnitude", f"{df['magnitude'].max():.1f}") | |
| with col3: | |
| st.metric("Avg Magnitude", f"{df['magnitude'].mean():.2f}") | |
| with col4: | |
| st.metric("Avg Depth", f"{df['depth'].mean():.1f} km") | |
| tab1, tab2, tab3, tab4, tab5, tab6 = st.tabs(["🗺️ Map", "📊 Analytics", "📋 Data", "🤖 AI Analysis", "🚨 Emergency", "🏥 Emergency AI"]) | |
| with tab1: | |
| st.subheader("🌍 Interactive Earthquake Map") | |
| if not df.empty: | |
| try: | |
| map_obj = create_advanced_map(df, region_bbox) | |
| if map_obj: | |
| st_folium(map_obj, width=800, height=500) | |
| else: | |
| st.info("Unable to create map visualization") | |
| except Exception as e: | |
| st.error(f"Error creating map: {str(e)}") | |
| st.info("Try adjusting your search criteria") | |
| else: | |
| st.info("No earthquake data available for map visualization") | |
| with tab2: | |
| st.subheader("📊 Advanced Analytics") | |
| if not df.empty: | |
| try: | |
| analysis = analyze_seismic_patterns(df) | |
| charts = create_comprehensive_charts(df, analysis) | |
| for i, chart in enumerate(charts): | |
| st.plotly_chart(chart, use_container_width=True) | |
| if analysis: | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.subheader("📈 Magnitude Statistics") | |
| if 'magnitude_stats' in analysis: | |
| stats_df = pd.DataFrame([analysis['magnitude_stats']]).T | |
| stats_df.columns = ['Value'] | |
| st.dataframe(stats_df) | |
| else: | |
| st.info("Insufficient data for magnitude statistics") | |
| with col2: | |
| st.subheader("📊 Risk Distribution") | |
| if 'risk_distribution' in analysis and len(analysis['risk_distribution']) > 0: | |
| risk_df = pd.DataFrame(analysis['risk_distribution']) | |
| risk_df.columns = ['Count'] | |
| st.dataframe(risk_df) | |
| else: | |
| st.info("No risk distribution data available") | |
| except Exception as e: | |
| st.error(f"Error in analytics: {str(e)}") | |
| st.info("Try adjusting your search criteria or check your internet connection") | |
| else: | |
| st.info("No earthquake data available for analysis") | |
| with tab3: | |
| st.subheader("📋 Earthquake Data") | |
| if not df.empty: | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| magnitude_filter = st.multiselect( | |
| "Filter by Magnitude Category", | |
| options=df['magnitude_category'].unique(), | |
| default=df['magnitude_category'].unique() | |
| ) | |
| with col2: | |
| risk_filter = st.multiselect( | |
| "Filter by Risk Level", | |
| options=df['risk_level'].unique(), | |
| default=df['risk_level'].unique() | |
| ) | |
| filtered_df = df[ | |
| (df['magnitude_category'].isin(magnitude_filter)) & | |
| (df['risk_level'].isin(risk_filter)) | |
| ] | |
| st.dataframe( | |
| filtered_df[['time', 'place', 'magnitude', 'depth', 'risk_level', 'time_ago', 'url']], | |
| use_container_width=True | |
| ) | |
| csv = filtered_df.to_csv(index=False) | |
| st.download_button( | |
| label="📥 Download CSV", | |
| data=csv, | |
| file_name=f"earthquakes_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv", | |
| mime="text/csv" | |
| ) | |
| with tab4: | |
| st.subheader("🤖 AI-Powered Analysis") | |
| if show_ai_summary and not df.empty: | |
| with st.spinner("🤖 Generating AI analysis..."): | |
| analysis = analyze_seismic_patterns(df) | |
| risk_level, risk_score = calculate_overall_risk(df) | |
| prompt = f""" | |
| As an expert emergency response AI and seismologist, provide a comprehensive analysis of the following earthquake data: | |
| SUMMARY STATISTICS: | |
| - Total earthquakes: {len(df)} | |
| - Time period: {hours} hours | |
| - Magnitude range: {df['magnitude'].min():.1f} - {df['magnitude'].max():.1f} | |
| - Average magnitude: {df['magnitude'].mean():.2f} | |
| - Risk level: {risk_level.upper()} | |
| - Risk score: {risk_score} | |
| RECENT MAJOR EARTHQUAKES: | |
| {df.nlargest(5, 'magnitude')[['time', 'place', 'magnitude', 'depth']].to_string(index=False)} | |
| Please provide: | |
| 1. **Emergency Risk Assessment**: Detailed evaluation of immediate dangers | |
| 2. **First Aid Priorities**: What medical emergencies to expect and prepare for | |
| 3. **Rescue Coordination Needs**: What emergency services and resources are needed | |
| 4. **Pattern Analysis**: Identification of concerning seismic patterns | |
| 5. **Public Safety Recommendations**: Specific actions for affected populations | |
| 6. **Emergency Preparedness**: Immediate and long-term preparedness steps | |
| 7. **Monitoring Recommendations**: What to watch for in coming hours/days | |
| 8. **Resource Allocation**: Priority areas for emergency resources | |
| Focus on actionable emergency response information and public safety. | |
| """ | |
| summary = get_groq_summary(prompt) | |
| st.markdown(summary) | |
| else: | |
| st.info("Enable AI Summary in Advanced Options to see AI analysis.") | |
| with tab5: | |
| st.subheader("🚨 Emergency Information") | |
| if show_emergency_protocols: | |
| st.markdown(""" | |
| ### 🚨 Emergency Response Protocols | |
| **Immediate Actions During Earthquake:** | |
| - Drop, Cover, and Hold On | |
| - Stay indoors if you're inside | |
| - Move to open area if you're outside | |
| - Stay away from windows, mirrors, and heavy objects | |
| **After Earthquake:** | |
| - Check for injuries and provide first aid | |
| - Check for gas leaks and electrical damage | |
| - Listen to emergency broadcasts | |
| - Be prepared for aftershocks | |
| **Emergency Contacts:** | |
| - Emergency Services: 911 (US) / 112 (EU) / 999 (UK) | |
| - USGS Earthquake Information: https://earthquake.usgs.gov | |
| - Local Emergency Management: Check your local government website | |
| """) | |
| st.markdown(f""" | |
| ### 📊 Current Emergency Status | |
| - **Risk Level**: {risk_level.upper()} | |
| - **Recommended Action**: {EMERGENCY_PROTOCOLS[risk_level]} | |
| - **Monitoring Required**: {'Yes' if risk_level in ['high', 'severe', 'extreme'] else 'No'} | |
| """) | |
| else: | |
| st.info("Enable Emergency Protocols in Advanced Options to see emergency information.") | |
| with tab6: | |
| st.subheader("🏥 Emergency AI Dashboard") | |
| if show_first_aid: | |
| st.markdown("### 🩺 Active First Aid System") | |
| if risk_level in ['high', 'severe', 'extreme']: | |
| first_aid_instructions = emergency_ai.get_first_aid_instructions('earthquake', risk_level) | |
| st.markdown(""" | |
| <div class="emergency-card"> | |
| <h4>🚨 EARTHQUAKE FIRST AID - ACTIVE EMERGENCY</h4> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| for instruction in first_aid_instructions: | |
| st.error(instruction) | |
| # Post-earthquake care | |
| after_instructions = emergency_ai.get_first_aid_instructions('earthquake')['after'] | |
| st.markdown("#### 🏥 After Shaking Stops:") | |
| for instruction in after_instructions: | |
| st.warning(instruction) | |
| else: | |
| st.success("✅ First Aid System Ready - No immediate emergency detected") | |
| st.info("First aid instructions will be automatically activated if seismic risk increases.") | |
| if show_rescue_coordination: | |
| st.markdown("### 🚁 Rescue Coordination System") | |
| if not df.empty: | |
| # Use the first earthquake location as reference | |
| location = df.iloc[0] if not df.empty else {'latitude': 0, 'longitude': 0} | |
| coord_plan = emergency_ai.coordinate_rescue_teams(location, 'earthquake', risk_level) | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown(f""" | |
| **Priority Level:** {coord_plan['priority_level']} | |
| **Required Teams:** | |
| """) | |
| for team in coord_plan['required_teams']: | |
| st.write(f"• {team}") | |
| with col2: | |
| st.markdown("**Resource Allocation:**") | |
| for resource in coord_plan['resource_allocation']: | |
| st.write(f"• {resource}") | |
| st.markdown("**Evacuation Zones:**") | |
| for zone, distance in coord_plan['evacuation_zones'].items(): | |
| if zone != 'evacuation_routes': | |
| st.write(f"• **{zone.replace('_', ' ').title()}:** {distance}") | |
| else: | |
| st.write(f"• **{zone.replace('_', ' ').title()}:** {distance}") | |
| if show_multilingual: | |
| st.markdown("### 🌐 Multilingual Emergency Alerts") | |
| if risk_level in ['high', 'severe', 'extreme']: | |
| # Show earthquake alert in selected language | |
| alert_translation = emergency_ai.translate_emergency_message('earthquake_alert', emergency_language) | |
| st.markdown(f""" | |
| <div class="emergency-card"> | |
| <h4>🚨 ACTIVE ALERT - {emergency_ai.languages[emergency_language].upper()}</h4> | |
| <p style="font-size: 1.2rem; font-weight: bold;">{alert_translation}</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| if risk_level == 'extreme': | |
| evacuation_translation = emergency_ai.translate_emergency_message('evacuation_order', emergency_language) | |
| st.markdown(f""" | |
| <div class="emergency-card"> | |
| <h4>🚨 EVACUATION ORDER - {emergency_ai.languages[emergency_language].upper()}</h4> | |
| <p style="font-size: 1.2rem; font-weight: bold;">{evacuation_translation}</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Language support info | |
| st.markdown("**Available Languages:**") | |
| cols = st.columns(3) | |
| for i, (code, name) in enumerate(emergency_ai.languages.items()): | |
| with cols[i % 3]: | |
| if code == emergency_language: | |
| st.success(f"🔹 {name} (Active)") | |
| else: | |
| st.write(f"• {name}") | |
| if show_disaster_learning: | |
| st.markdown("### 🧠 Disaster Learning System") | |
| if risk_level in ['moderate', 'high', 'severe', 'extreme']: | |
| # Simulate learning from current disaster | |
| current_disaster = { | |
| 'location': region if region else 'Global', | |
| 'magnitude_max': df['magnitude'].max(), | |
| 'earthquake_count': len(df), | |
| 'risk_level': risk_level, | |
| 'response_time': 300, # Simulated 5 minute response time | |
| 'effectiveness_rating': 8.5, # Simulated effectiveness | |
| 'casualties': 0, # Simulated (would be real data) | |
| 'lessons': [ | |
| f"High seismic activity detected in {region if region else 'monitored region'}", | |
| f"Maximum magnitude {df['magnitude'].max():.1f} requires {risk_level} response", | |
| "Early warning system functioning correctly", | |
| "Multi-language alerts deployed successfully" | |
| ] | |
| } | |
| learning_points = emergency_ai.learn_from_disaster(current_disaster) | |
| st.success("🧠 Learning from current seismic event...") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown("**Current Event Analysis:**") | |
| st.write(f"• Response Time: {learning_points['response_time']} seconds") | |
| st.write(f"• Effectiveness: {learning_points['effectiveness']}/10") | |
| st.write(f"• Casualties: {learning_points['casualties']}") | |
| with col2: | |
| st.markdown("**Lessons Learned:**") | |
| for lesson in learning_points['lessons_learned']: | |
| st.write(f"• {lesson}") | |
| if learning_points['improvements_needed']: | |
| st.markdown("**🔧 Recommended Improvements:**") | |
| for improvement in learning_points['improvements_needed']: | |
| st.warning(f"• {improvement}") | |
| # Historical learning data | |
| if emergency_ai.disaster_log: | |
| st.markdown(f"**📚 Historical Analysis:** {len(emergency_ai.disaster_log)} disasters analyzed") | |
| # Show trend of learning | |
| if len(emergency_ai.disaster_log) >= 2: | |
| recent_effectiveness = [log['learning_points']['effectiveness'] for log in emergency_ai.disaster_log[-5:]] | |
| if recent_effectiveness: | |
| avg_effectiveness = sum(recent_effectiveness) / len(recent_effectiveness) | |
| st.metric("Average Response Effectiveness", f"{avg_effectiveness:.1f}/10") | |
| else: | |
| st.info("No historical disaster data available yet.") | |