"""
Traffic Accident Reconstruction System
======================================
Main Streamlit Application
Huawei AI Innovation Challenge 2026
This system uses MindSpore AI to analyze traffic accidents
and generate probable scenarios with 2D simulation.
"""
import streamlit as st
import sys
from pathlib import Path
# Add project root to path
sys.path.insert(0, str(Path(__file__).parent))
from config import STREAMLIT_CONFIG, CASE_STUDY_LOCATION, COLORS
from ui.components import render_sidebar, render_header, render_footer
from ui.map_viewer import render_map_section
from ui.vehicle_input import render_vehicle_input
from ui.party_input import render_party_input, render_evidence_upload, render_party_summary
from ui.results_display import render_results
# ============================================================
# PAGE CONFIGURATION
# ============================================================
st.set_page_config(
page_title=STREAMLIT_CONFIG["page_title"],
page_icon=STREAMLIT_CONFIG["page_icon"],
layout=STREAMLIT_CONFIG["layout"],
initial_sidebar_state=STREAMLIT_CONFIG["initial_sidebar_state"]
)
# ============================================================
# CUSTOM CSS - CrashLens Modern Design
# ============================================================
st.markdown("""
""", unsafe_allow_html=True)
# ============================================================
# SESSION STATE INITIALIZATION
# ============================================================
def init_session_state():
"""Initialize all session state variables."""
# Application state
if 'current_step' not in st.session_state:
st.session_state.current_step = 1
# Accident information
if 'accident_info' not in st.session_state:
st.session_state.accident_info = {
'location': CASE_STUDY_LOCATION.copy(),
'datetime': None,
'road_type': 'roundabout',
'weather': 'clear',
'road_condition': 'dry',
'visibility': 1.0,
'lighting': 'daylight',
'notes': ''
}
# Vehicle 1 data (for analysis)
if 'vehicle_1' not in st.session_state:
st.session_state.vehicle_1 = {
'type': 'sedan',
'speed': 50,
'direction': 'north',
'action': 'entering_roundabout',
'braking': False,
'signaling': False,
'lights_on': True,
'horn_used': False,
'path': [],
'description': ''
}
# Vehicle 2 data (for analysis)
if 'vehicle_2' not in st.session_state:
st.session_state.vehicle_2 = {
'type': 'sedan',
'speed': 50,
'direction': 'east',
'action': 'going_straight',
'braking': False,
'signaling': False,
'lights_on': True,
'horn_used': False,
'path': [],
'description': ''
}
# Party 1 data (driver details)
if 'party_1' not in st.session_state:
st.session_state.party_1 = {
'full_name': '',
'id_iqama': '',
'phone': '',
'role': 'Driver',
'vehicle_make_model': '',
'plate_number': '',
'insurance': '',
'damage_notes': '',
'statement': ''
}
# Party 2 data (driver details)
if 'party_2' not in st.session_state:
st.session_state.party_2 = {
'full_name': '',
'id_iqama': '',
'phone': '',
'role': 'Driver',
'vehicle_make_model': '',
'plate_number': '',
'insurance': '',
'damage_notes': '',
'statement': ''
}
# Evidence photos
if 'evidence_photos' not in st.session_state:
st.session_state.evidence_photos = []
# Analysis results
if 'analysis_results' not in st.session_state:
st.session_state.analysis_results = None
# Generated scenarios
if 'scenarios' not in st.session_state:
st.session_state.scenarios = []
# Map data
if 'map_data' not in st.session_state:
st.session_state.map_data = None
# Analysis ready flag
if 'analysis_ready' not in st.session_state:
st.session_state.analysis_ready = False
# ============================================================
# MAIN APPLICATION
# ============================================================
def main():
"""Main application entry point."""
# Initialize session state
init_session_state()
# Render modern header - clean without logo
col1, col2, col3 = st.columns([1, 6, 1])
with col1:
st.markdown("## 🚗")
with col2:
st.markdown("""
CrashLens AI
Traffic Accident Scenario Analysis • MindSpore-ready • PDF report
""", unsafe_allow_html=True)
with col3:
st.write("")
st.markdown("
", unsafe_allow_html=True)
# Render sidebar
render_sidebar()
# Modern step indicator with pills - Using columns to avoid HTML rendering issues
steps = ["📍 Location", "🚙 Vehicle 1", "🚗 Vehicle 2", "👥 Parties", "📄 Evidence", "🔍 Analysis", "📊 Results"]
cols = st.columns(len(steps))
for i, (col, step_name) in enumerate(zip(cols, steps), 1):
with col:
if i < st.session_state.current_step:
# Completed step - Green
st.markdown(f"""
✓ {step_name.split()[-1]}
""", unsafe_allow_html=True)
elif i == st.session_state.current_step:
# Active step - Blue gradient
st.markdown(f"""
{step_name}
""", unsafe_allow_html=True)
else:
# Future step - Dark gray
st.markdown(f"""
{step_name.split()[-1]}
""", unsafe_allow_html=True)
st.markdown("", unsafe_allow_html=True)
# Main content based on current step
if st.session_state.current_step == 1:
render_step_1_location()
elif st.session_state.current_step == 2:
render_step_2_vehicle1()
elif st.session_state.current_step == 3:
render_step_3_vehicle2()
elif st.session_state.current_step == 4:
render_step_4_parties()
elif st.session_state.current_step == 5:
render_step_5_evidence()
elif st.session_state.current_step == 6:
render_step_6_analysis()
elif st.session_state.current_step == 7:
render_step_7_results()
# Render footer
render_footer()
# ============================================================
# STEP 1: LOCATION SELECTION
# ============================================================
def render_step_1_location():
"""Render the location selection step."""
st.header("📍 Step 1: Accident Location")
st.markdown("""
Accident Details
Enter the location and conditions where the accident occurred.
""", unsafe_allow_html=True)
col1, col2 = st.columns([2, 1])
with col1:
# Map display
render_map_section()
with col2:
st.subheader("Location Details")
# Location name
location_name = st.text_input(
"Location Name",
value=st.session_state.accident_info['location']['name']
)
# Coordinates
lat = st.number_input(
"Latitude",
value=st.session_state.accident_info['location']['latitude'],
format="%.6f",
step=0.0001
)
lon = st.number_input(
"Longitude",
value=st.session_state.accident_info['location']['longitude'],
format="%.6f",
step=0.0001
)
# Road type - expanded options
road_types = [
'roundabout', 'crossroad', 't_junction', 'highway_merge',
'parking', 'highway', 'urban_road', 'other'
]
road_type_labels = {
'roundabout': 'Roundabout (دوار)',
'crossroad': 'Crossroad (تقاطع)',
't_junction': 'T-Junction',
'highway_merge': 'Highway Merge',
'parking': 'Parking / Low Speed',
'highway': 'Highway',
'urban_road': 'Urban Road',
'other': 'Other'
}
road_type = st.selectbox(
"Road Type",
options=road_types,
format_func=lambda x: road_type_labels.get(x, x.title()),
index=road_types.index(st.session_state.accident_info.get('road_type', 'roundabout'))
)
# Date and time
accident_date = st.date_input("Accident Date")
accident_time = st.time_input("Accident Time")
# Weather conditions
weather = st.selectbox(
"Weather Conditions",
options=['clear', 'cloudy', 'rainy', 'foggy', 'sandstorm'],
format_func=lambda x: x.title()
)
# Road condition
road_condition = st.selectbox(
"Road Condition",
options=['dry', 'wet', 'sandy', 'oily'],
format_func=lambda x: x.title()
)
# Notes
notes = st.text_area(
"Notes (optional)",
value=st.session_state.accident_info.get('notes', ''),
placeholder="Any extra context about the accident...",
height=80
)
# Update session state
st.session_state.accident_info.update({
'location': {
'name': location_name,
'latitude': lat,
'longitude': lon,
'radius_meters': 200
},
'road_type': road_type,
'datetime': f"{accident_date} {accident_time}",
'weather': weather,
'road_condition': road_condition,
'notes': notes
})
# Navigation buttons
col1, col2, col3 = st.columns([1, 2, 1])
with col3:
if st.button("Next: Vehicle 1 →", type="primary"):
st.session_state.current_step = 2
st.rerun()
# ============================================================
# STEP 2: VEHICLE 1 INPUT
# ============================================================
def render_step_2_vehicle1():
"""Render Vehicle 1 input step."""
st.header("🚙 Step 2: First Vehicle Information")
st.markdown("""
Vehicle 1 (Red)
Enter the details of the first vehicle involved in the accident.
""", unsafe_allow_html=True)
col1, col2 = st.columns([2, 1])
with col1:
# Map with path drawing
render_map_section(vehicle_id=1)
with col2:
render_vehicle_input(1)
# Navigation buttons
col1, col2, col3 = st.columns([1, 2, 1])
with col1:
if st.button("← Back"):
st.session_state.current_step = 1
st.rerun()
with col3:
if st.button("Next: Vehicle 2 →", type="primary"):
st.session_state.current_step = 3
st.rerun()
# ============================================================
# STEP 3: VEHICLE 2 INPUT
# ============================================================
def render_step_3_vehicle2():
"""Render Vehicle 2 input step."""
st.header("🚗 Step 3: Second Vehicle Information")
st.markdown("""
Vehicle 2 (Blue)
Enter the details of the second vehicle involved in the accident.
""", unsafe_allow_html=True)
col1, col2 = st.columns([2, 1])
with col1:
# Map with path drawing (showing both vehicles)
render_map_section(vehicle_id=2)
with col2:
render_vehicle_input(2)
# Navigation buttons
col1, col2, col3 = st.columns([1, 2, 1])
with col1:
if st.button("← Back"):
st.session_state.current_step = 2
st.rerun()
with col3:
if st.button("Analyze Accident →", type="primary"):
st.session_state.current_step = 4
st.rerun()
# ============================================================
# STEP 4: PARTIES INFORMATION
# ============================================================
def render_step_4_parties():
"""Render the parties (driver details) input step."""
st.header("👥 Step 4: Parties Information")
st.markdown("""
Driver & Vehicle Details
Enter information about the parties involved in the accident. This information will be included in the official report.
""", unsafe_allow_html=True)
# Two columns for both parties
col1, col2 = st.columns(2)
with col1:
render_party_input(1)
with col2:
render_party_input(2)
# Navigation buttons
st.markdown("---")
col1, col2, col3 = st.columns([1, 2, 1])
with col1:
if st.button("← Back to Vehicle 2"):
st.session_state.current_step = 3
st.rerun()
with col3:
if st.button("Next: Evidence →", type="primary"):
st.session_state.current_step = 5
st.rerun()
# ============================================================
# STEP 5: EVIDENCE UPLOAD
# ============================================================
def render_step_5_evidence():
"""Render the evidence upload step."""
st.header("📷 Step 5: Evidence (Optional)")
st.markdown("""
Upload Evidence Photos
Upload photos of the accident scene, vehicle damage, or any other relevant evidence. This is optional but recommended.
""", unsafe_allow_html=True)
# Evidence upload
render_evidence_upload()
# Quick summary of data entered so far
st.markdown("---")
st.subheader("📋 Data Summary")
col1, col2, col3 = st.columns(3)
with col1:
st.markdown("**📍 Location**")
st.write(f"{st.session_state.accident_info['location'].get('name', 'Not set')}")
st.write(f"Type: {st.session_state.accident_info.get('road_type', 'N/A').replace('_', ' ').title()}")
with col2:
st.markdown("**🚙 Vehicle 1**")
# Defensive check - ensure vehicle_1 is a dict
v1 = st.session_state.vehicle_1
if isinstance(v1, dict):
st.write(f"{v1.get('type', 'sedan').title()} @ {v1.get('speed', 50)} km/h")
else:
st.write("Vehicle 1 data")
party1_name = st.session_state.party_1.get('full_name', '') if isinstance(st.session_state.party_1, dict) else ''
if party1_name:
st.write(f"Driver: {party1_name}")
with col3:
st.markdown("**🚗 Vehicle 2**")
# Defensive check - ensure vehicle_2 is a dict
v2 = st.session_state.vehicle_2
if isinstance(v2, dict):
st.write(f"{v2.get('type', 'sedan').title()} @ {v2.get('speed', 50)} km/h")
else:
st.write("Vehicle 2 data")
party2_name = st.session_state.party_2.get('full_name', '') if isinstance(st.session_state.party_2, dict) else ''
if party2_name:
st.write(f"Driver: {party2_name}")
# Navigation buttons
st.markdown("---")
col1, col2, col3 = st.columns([1, 2, 1])
with col1:
if st.button("← Back to Parties"):
st.session_state.current_step = 4
st.rerun()
with col3:
if st.button("Run Analysis →", type="primary"):
st.session_state.current_step = 6
st.rerun()
# ============================================================
# STEP 6: AI ANALYSIS
# ============================================================
def render_step_6_analysis():
"""Render the AI analysis step."""
st.header("🤖 Step 4: AI Analysis")
st.markdown("""
MindSpore AI Analysis
Review the accident data below and click "Run AI Analysis" to generate possible scenarios.
""", unsafe_allow_html=True)
# Data validation
validation_passed = True
validation_messages = []
# Check paths
if not st.session_state.vehicle_1.get('path'):
validation_messages.append("⚠️ Vehicle 1 path not defined - will use direction-based estimation")
if not st.session_state.vehicle_2.get('path'):
validation_messages.append("⚠️ Vehicle 2 path not defined - will use direction-based estimation")
# Summary of inputs in cards
st.subheader("📋 Input Data Summary")
col1, col2, col3 = st.columns(3)
with col1:
st.markdown("""
📍 Location
""", unsafe_allow_html=True)
st.write(f"**{st.session_state.accident_info['location'].get('name', 'Unknown')}**")
st.write(f"🛣️ Type: `{st.session_state.accident_info['road_type']}`")
st.write(f"🌤️ Weather: `{st.session_state.accident_info['weather']}`")
st.write(f"🛤️ Road: `{st.session_state.accident_info['road_condition']}`")
st.write(f"📅 {st.session_state.accident_info.get('datetime', 'Not specified')}")
with col2:
st.markdown("""
🚙 Vehicle 1 (Red)
""", unsafe_allow_html=True)
v1 = st.session_state.vehicle_1 if isinstance(st.session_state.vehicle_1, dict) else {'type': 'sedan', 'speed': 50, 'direction': 'north', 'action': 'going_straight', 'path': []}
st.write(f"**Type:** {v1.get('type', 'sedan').title()}")
st.write(f"**Speed:** {v1.get('speed', 50)} km/h")
st.write(f"**Direction:** {v1.get('direction', 'north').title()}")
st.write(f"**Action:** {v1.get('action', 'going_straight').replace('_', ' ').title()}")
path_status = "✅ Defined" if v1.get('path') else "⚠️ Not set"
st.write(f"**Path:** {path_status}")
with col3:
st.markdown("""
🚗 Vehicle 2 (Blue)
""", unsafe_allow_html=True)
v2 = st.session_state.vehicle_2 if isinstance(st.session_state.vehicle_2, dict) else {'type': 'sedan', 'speed': 50, 'direction': 'east', 'action': 'going_straight', 'path': []}
st.write(f"**Type:** {v2.get('type', 'sedan').title()}")
st.write(f"**Speed:** {v2.get('speed', 50)} km/h")
st.write(f"**Direction:** {v2.get('direction', 'east').title()}")
st.write(f"**Action:** {v2.get('action', 'going_straight').replace('_', ' ').title()}")
path_status = "✅ Defined" if v2.get('path') else "⚠️ Not set"
st.write(f"**Path:** {path_status}")
# Show validation messages
if validation_messages:
st.markdown("---")
for msg in validation_messages:
st.warning(msg)
st.markdown("---")
# Analysis section
st.subheader("🚀 Run Analysis")
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
if st.button("🧠 Run MindSpore AI Analysis", type="primary", use_container_width=True):
# Progress bar
progress_bar = st.progress(0)
status_text = st.empty()
try:
# Step 1: Validate data
status_text.text("Step 1/4: Validating input data...")
progress_bar.progress(10)
import time
time.sleep(0.5)
# Step 2: Extract features
status_text.text("Step 2/4: Extracting features...")
progress_bar.progress(30)
time.sleep(0.5)
# Step 3: Run AI model
status_text.text("Step 3/4: Running MindSpore AI model...")
progress_bar.progress(50)
# Import and run analysis
from analysis.scenario_analyzer import analyze_accident
results = analyze_accident(
accident_info=st.session_state.accident_info,
vehicle_1=st.session_state.vehicle_1,
vehicle_2=st.session_state.vehicle_2
)
progress_bar.progress(80)
time.sleep(0.3)
# Step 4: Generate scenarios
status_text.text("Step 4/4: Generating scenarios...")
progress_bar.progress(100)
# Store results
st.session_state.analysis_results = results
st.session_state.scenarios = results.get('scenarios', [])
st.session_state.analysis_ready = True
status_text.empty()
progress_bar.empty()
# Success message
st.success(f"""
✅ **Analysis Complete!**
- Generated **{len(st.session_state.scenarios)}** possible scenarios
- Most likely: **{results.get('most_likely_scenario', {}).get('type', 'Unknown').replace('_', ' ').title()}**
- Confidence: **{results.get('overall_collision_probability', 0)*100:.1f}%**
""")
except Exception as e:
st.error(f"❌ Analysis failed: {str(e)}")
progress_bar.empty()
status_text.empty()
# Show results preview if available
if st.session_state.analysis_results:
st.markdown("---")
st.subheader("📊 Quick Results Preview")
results = st.session_state.analysis_results
scenarios = st.session_state.scenarios
# Quick metrics
metric_cols = st.columns(4)
with metric_cols[0]:
st.metric(
"Scenarios Generated",
len(scenarios)
)
with metric_cols[1]:
most_likely = results.get('most_likely_scenario', {})
st.metric(
"Most Likely",
f"#{most_likely.get('id', 1)}"
)
with metric_cols[2]:
prob = results.get('overall_collision_probability', 0) * 100
st.metric(
"Collision Certainty",
f"{prob:.1f}%"
)
with metric_cols[3]:
fault = results.get('preliminary_fault_assessment', {})
st.metric(
"Primary Factor",
fault.get('primary_factor', 'Unknown').replace('_', ' ').title()[:15]
)
# Top scenarios
st.write("**Top Scenarios:**")
for i, scenario in enumerate(scenarios[:3], 1):
prob_pct = scenario['probability'] * 100
st.write(f"{i}. **{scenario['accident_type'].replace('_', ' ').title()}** - {prob_pct:.1f}%")
# Navigation
st.markdown("---")
col1, col2, col3 = st.columns([1, 2, 1])
with col1:
if st.button("← Back to Evidence"):
st.session_state.current_step = 5
st.rerun()
with col3:
if st.session_state.analysis_results:
if st.button("View Full Results →", type="primary"):
st.session_state.current_step = 7
st.rerun()
# ============================================================
# STEP 7: RESULTS
# ============================================================
def render_step_7_results():
"""Render the results step."""
st.header("📊 Step 7: Analysis Results")
if not st.session_state.analysis_results:
st.warning("No analysis results available. Please run the analysis first.")
if st.button("← Go to Analysis"):
st.session_state.current_step = 6
st.rerun()
return
# Render full results
render_results()
# Navigation
col1, col2, col3 = st.columns([1, 2, 1])
with col1:
if st.button("← Back to Analysis"):
st.session_state.current_step = 6
st.rerun()
with col3:
if st.button("🔄 Start New Analysis"):
# Reset session state
for key in list(st.session_state.keys()):
del st.session_state[key]
st.rerun()
# ============================================================
# RUN APPLICATION
# ============================================================
if __name__ == "__main__":
main()