#!/usr/bin/env python3 """ zeroFire - Fire Detection Classification App AI-powered fire detection using ConvNeXt transfer learning """ import streamlit as st import torch import torch.nn.functional as F from PIL import Image import numpy as np import plotly.graph_objects as go import plotly.express as px from plotly.subplots import make_subplots import pandas as pd import sys import os import time from io import BytesIO import base64 # Add utils to path sys.path.append('utils') from model_utils import load_model, FireDetectionClassifier from data_utils import get_inference_transform, prepare_image_for_inference, check_data_directory # Page Configuration st.set_page_config( page_title="πŸ”₯ zeroFire - Fire Detection System", page_icon="πŸ”₯", layout="wide", initial_sidebar_state="expanded" ) # Custom CSS for Beautiful UI st.markdown(""" """, unsafe_allow_html=True) @st.cache_resource def load_fire_model(): """Load the trained fire detection model""" model_path = 'models/fire_detection_classifier.pth' if not os.path.exists(model_path): return None, "Model not found. Please train the model first." try: model, model_info = load_model(model_path, device='cpu') return model, model_info except Exception as e: return None, f"Error loading model: {str(e)}" def get_prediction(image, model, transform): """Get prediction from the model""" try: # Prepare image input_tensor = prepare_image_for_inference(image, transform) # Get prediction with torch.no_grad(): model.eval() outputs = model(input_tensor) probabilities = F.softmax(outputs, dim=1) confidence, predicted = torch.max(probabilities, 1) # Convert to numpy predicted_class = predicted.item() confidence_score = confidence.item() all_probs = probabilities.squeeze().cpu().numpy() return predicted_class, confidence_score, all_probs except Exception as e: st.error(f"Error during prediction: {str(e)}") return None, None, None def create_confidence_chart(probabilities, class_names): """Create confidence chart using Plotly""" fig = go.Figure(data=[ go.Bar( x=class_names, y=probabilities, marker_color=['#dc3545', '#28a745'], text=[f'{p:.1%}' for p in probabilities], textposition='auto', ) ]) fig.update_layout( title="Fire Detection Confidence", xaxis_title="Prediction", yaxis_title="Confidence", yaxis=dict(range=[0, 1]), showlegend=False, height=400, template="plotly_white" ) return fig def create_safety_metrics_chart(predicted_class, confidence): """Create safety metrics visualization""" if predicted_class == 0: # Fire danger_level = confidence * 100 safety_level = (1 - confidence) * 100 primary_color = '#dc3545' status = "FIRE DETECTED" else: # No Fire danger_level = (1 - confidence) * 100 safety_level = confidence * 100 primary_color = '#28a745' status = "NO FIRE" fig = go.Figure(go.Indicator( mode = "gauge+number+delta", value = danger_level, domain = {'x': [0, 1], 'y': [0, 1]}, title = {'text': "Fire Risk Level"}, delta = {'reference': 50}, gauge = {'axis': {'range': [None, 100]}, 'bar': {'color': primary_color}, 'steps' : [ {'range': [0, 25], 'color': "lightgray"}, {'range': [25, 50], 'color': "yellow"}, {'range': [50, 75], 'color': "orange"}, {'range': [75, 100], 'color': "red"}], 'threshold' : {'line': {'color': "red", 'width': 4}, 'thickness': 0.75, 'value': 90}})) fig.update_layout(height=400) return fig def analyze_fire_risk(predicted_class, confidence): """Analyze fire risk and provide recommendations""" if predicted_class == 0: # Fire detected risk_level = confidence * 100 if risk_level >= 90: return { 'level': 'CRITICAL', 'color': '#dc3545', 'icon': '🚨', 'message': 'IMMEDIATE ACTION REQUIRED', 'recommendations': [ 'Activate fire suppression system immediately', 'Evacuate the area', 'Call emergency services UAE 997', 'Shut down affected equipment if safe to do so', 'Monitor surrounding areas for spread' ] } elif risk_level >= 75: return { 'level': 'HIGH', 'color': '#fd7e14', 'icon': '⚠️', 'message': 'HIGH FIRE RISK DETECTED', 'recommendations': [ 'Investigate the area immediately', 'Prepare fire suppression systems', 'Alert security personnel', 'Consider equipment shutdown', 'Increase monitoring frequency' ] } else: return { 'level': 'MODERATE', 'color': '#ffc107', 'icon': 'πŸ”Ά', 'message': 'POSSIBLE FIRE DETECTED', 'recommendations': [ 'Verify with additional sensors', 'Send personnel to investigate', 'Check equipment temperatures', 'Review recent maintenance logs', 'Maintain heightened awareness' ] } else: # No fire safety_level = confidence * 100 if safety_level >= 95: return { 'level': 'SAFE', 'color': '#28a745', 'icon': 'βœ…', 'message': 'NORMAL OPERATION', 'recommendations': [ 'Continue normal operations', 'Maintain regular monitoring', 'Keep fire suppression systems ready', 'Perform scheduled maintenance', 'Review safety protocols periodically' ] } else: return { 'level': 'CAUTION', 'color': '#17a2b8', 'icon': '⚠️', 'message': 'MONITOR CLOSELY', 'recommendations': [ 'Increase monitoring frequency', 'Check for unusual conditions', 'Verify sensor functionality', 'Review environmental factors', 'Maintain readiness for action' ] } # display_fire_safety_checklist function removed - content moved to right column def main(): """Main application function""" # Header st.markdown("""

πŸ”₯ zeroFire

AI-Powered Fire Detection System for Data Centers

""", unsafe_allow_html=True) # Sidebar with st.sidebar: st.markdown("### πŸ”₯ Fire Detection System") st.markdown("---") # Model status model, model_info = load_fire_model() if model is None: st.error("❌ Model not available") st.info("Train the model first using: `python train_fire_detection.py`") return else: st.success("βœ… Model loaded successfully") if isinstance(model_info, dict): accuracy = model_info.get('best_acc', 'Unknown') if accuracy != 'Unknown': # Format accuracy to 2 decimal places accuracy_formatted = f"{float(accuracy):.2f}%" st.info(f"πŸ“Š Model: ConvNeXt Large") st.info(f"🎯 Accuracy: {accuracy_formatted}") st.info(f"πŸ”„ Transfer Learning: Foodβ†’Fire") st.info(f"⚑ Precision: High-recall optimized") else: st.info("πŸ“Š Model Accuracy: Unknown") st.markdown("---") # Settings st.markdown("### βš™οΈ Settings") confidence_threshold = st.slider( "Confidence Threshold", min_value=0.0, max_value=1.0, value=0.5, step=0.05, help="Minimum confidence required for fire detection" ) show_details = st.checkbox("Show detailed analysis", value=True) st.markdown("---") st.markdown("### πŸ“Š Data Center Status") check_data_directory('data') # Main content col1, col2 = st.columns([2, 1]) with col1: # Upload section st.markdown("""

πŸ“Έ Fire Detection Input

Upload an image or take a photo to detect fire or smoke
in your data center

""", unsafe_allow_html=True) # Mobile-friendly file uploader st.markdown("**πŸ“± Take Photo or Upload Image**") # Clear mobile instructions st.markdown("""

πŸ“± Mobile Users:

Tap "Browse files" below β†’ Select "Camera" to take a photo
Or select "Photos" to choose from gallery

""", unsafe_allow_html=True) # Troubleshooting info with st.expander("πŸ”§ Camera not working? Click here for help"): st.markdown(""" **If you don't see the Camera option:** 1. **βœ… Check your browser:** - Use Chrome, Safari, or Firefox (latest versions) - Edge or other browsers may not support camera 2. **πŸ” Ensure secure connection:** - Camera requires HTTPS (βœ… Hugging Face uses HTTPS) - Local development requires HTTPS for camera access 3. **πŸ“± Mobile device requirements:** - iOS: Safari 11+ or Chrome 64+ - Android: Chrome 53+ or Firefox 68+ - Some older devices may not support camera 4. **πŸ› οΈ Try these steps:** - Refresh the page and try again - Clear browser cache and cookies - Try a different browser - Check if camera works on other websites 5. **πŸ”„ Alternative options:** - Take photo with your camera app first - Then select "Photos" to upload the saved image - Or use the desktop version for file upload """) st.info("πŸ’‘ **Note**: Camera access depends on your browser and device. If it doesn't work, you can still upload photos from your gallery!") # Standard Streamlit file uploader uploaded_file = st.file_uploader( "Browse files", type=['jpg', 'jpeg', 'png'], help="πŸ“± Mobile: Tap to see Camera and Photos options | πŸ’» Desktop: Click to browse files" ) # Process the uploaded image image = None image_source = "uploaded" if uploaded_file is not None: image = Image.open(uploaded_file) image_source = "uploaded" # Process the image (whether uploaded or from camera) if image is not None: # Display the image with appropriate caption st.image(image, caption="πŸ“Έ Your Image", use_column_width=True) # Get prediction transform = get_inference_transform() predicted_class, confidence_score, all_probs = get_prediction(image, model, transform) if predicted_class is not None: class_names = ['Fire', 'No Fire'] predicted_label = class_names[predicted_class] # Fire detection result moved to right column # Technical details (keep only this in left column) with st.expander("πŸ”¬ Technical Details"): st.markdown(f""" **Prediction Details:** - Predicted Class: {predicted_label} - Confidence Score: {confidence_score:.4f} - Fire Probability: {all_probs[0]:.4f} - No-Fire Probability: {all_probs[1]:.4f} - Threshold: {confidence_threshold:.2f} """) with col2: # Display fire detection result first if 'predicted_class' in locals(): # Display fire detection result box if predicted_class == 0: # Fire st.markdown(f"""

🚨 FIRE DETECTED - Confidence: {confidence_score:.1%}

IMMEDIATE ACTION REQUIRED

""", unsafe_allow_html=True) else: # No Fire st.markdown(f"""

βœ… NO FIRE DETECTED - Confidence: {confidence_score:.1%}

Normal Operation

""", unsafe_allow_html=True) # Quick metrics st.markdown("### πŸ“Š Quick Metrics") if 'predicted_class' in locals(): # Create three columns for metrics in a row metric_col1, metric_col2, metric_col3 = st.columns(3) with metric_col1: # Fire risk gauge risk_percentage = all_probs[0] * 100 st.metric( label="Fire Risk", value=f"{risk_percentage:.1f}%" ) with metric_col2: # Safety score safety_score = all_probs[1] * 100 st.metric( label="Safety Score", value=f"{safety_score:.1f}%" ) with metric_col3: # Model status instead of redundant confidence status = "FIRE ALERT" if predicted_class == 0 else "NORMAL" st.metric( label="Status", value=status ) # Charts removed to eliminate confusion and redundancy # Detailed analysis moved from left column if show_details: st.markdown("### πŸ“‹ Detailed Analysis") analysis = analyze_fire_risk(predicted_class, confidence_score) # Use red styling only for fire detection card_class = "info-card-fire" if predicted_class == 0 else "info-card" st.markdown(f"""

{analysis['icon']} Risk Level: {analysis['level']}

{analysis['message']}

""", unsafe_allow_html=True) st.markdown("#### 🎯 Recommended Actions:") for rec in analysis['recommendations']: st.markdown(f"- {rec}") # Fire Safety Checklist moved here st.markdown("---") st.markdown("""

πŸ”₯ Fire Safety Checklist

Essential fire safety measures for data centers:

""", unsafe_allow_html=True) safety_items = [ "πŸ”₯ **Fire Detection Systems** - Smoke, heat, and flame detectors", "πŸ’¨ **Suppression Systems** - Clean agent, water mist, or CO2", "🌑️ **Temperature Monitoring** - Continuous thermal monitoring", "⚑ **Electrical Safety** - Arc fault and ground fault protection", "πŸšͺ **Emergency Exits** - Clear and well-marked escape routes", "πŸ“‹ **Emergency Procedures** - Staff training and evacuation plans", "πŸ”§ **Equipment Maintenance** - Regular inspection and testing", "πŸ“ž **Emergency Contacts** - Quick access to fire department", "🎯 **Response Plans** - Pre-defined actions for different scenarios", "πŸ“Š **Documentation** - Incident logging and safety records" ] for item in safety_items: st.markdown(f"- {item}") # Additional info moved to bottom # Footer st.markdown("---") # Emergency Contacts only (Fire Safety Checklist moved to right column) st.markdown("""

🚨 Emergency Contacts

Fire Dept: UAE 997 Security: [Your Number] Facilities: [Your Number] IT Ops: [Your Number]
""", unsafe_allow_html=True) st.markdown("---") st.markdown("""

πŸ”₯ zeroFire - AI-Powered Fire Detection System

Protecting your data center with advanced machine learning

""", unsafe_allow_html=True) if __name__ == "__main__": main()