import streamlit as st import pandas as pd import requests import plotly.express as px from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from xgboost import XGBClassifier from sklearn.preprocessing import LabelEncoder from sklearn.metrics import accuracy_score, f1_score import sqlite3 import base64 import logging import os import numpy as np # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Database connection DB_PATH = "crime_records.db" def get_db_connection(): if not os.path.exists(DB_PATH): logger.error(f"Database file {DB_PATH} does not exist") raise Exception(f"Database file {DB_PATH} not found. Run init_db.py to create it.") conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row return conn # Data analysis function def load_crime_data(search_query=""): try: conn = get_db_connection() query = "SELECT LOWER(crime_type) AS crime_type, LOWER(description) AS description, LOWER(location) AS location, date, LOWER(officer_in_charge) AS officer_in_charge, LOWER(status) AS status FROM Crimes" if search_query: query += " WHERE LOWER(crime_type) LIKE ? OR LOWER(location) LIKE ?" df = pd.read_sql(query, conn, params=(f"%{search_query.lower()}%", f"%{search_query.lower()}%")) else: df = pd.read_sql(query, conn) conn.close() if df.empty: logger.warning("No data found in Crimes table") st.warning("No crime data available. Please add crimes via 'Add Crime'.") return df except Exception as e: logger.error(f"Error loading crime data: {e}") st.error(f"Error loading crime data: {e}. Ensure the database and Crimes table are initialized.") return pd.DataFrame() # ML model training and prediction def train_ml_models(): df = load_crime_data() if df.empty or len(df) < 5: logger.warning("Insufficient data for ML training") st.error("Insufficient data for ML training. Please add at least 5 crime records.") return None, None, None, None, None, 0, 0, 0, 0 df = df.dropna() if len(df['status'].unique()) < 2: logger.warning("Only one status value found; ML models require multiple classes") st.error("ML models require at least two different status values (e.g., 'open' and 'closed').") return None, None, None, None, None, 0, 0, 0, 0 le_crime = LabelEncoder() le_location = LabelEncoder() le_status = LabelEncoder() df['crime_type_encoded'] = le_crime.fit_transform(df['crime_type']) df['location_encoded'] = le_location.fit_transform(df['location']) df['status_encoded'] = le_status.fit_transform(df['status']) features = ['crime_type_encoded', 'location_encoded'] X = df[features] y = df['status_encoded'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # Random Forest rf_model = RandomForestClassifier(n_estimators=100, random_state=42) rf_model.fit(X_train, y_train) rf_pred = rf_model.predict(X_test) rf_accuracy = accuracy_score(y_test, rf_pred) rf_f1 = f1_score(y_test, rf_pred, average='weighted') # XGBoost xgb_model = XGBClassifier(use_label_encoder=False, eval_metric='mlogloss', random_state=42) xgb_model.fit(X_train, y_train) xgb_pred = xgb_model.predict(X_test) xgb_accuracy = accuracy_score(y_test, xgb_pred) xgb_f1 = f1_score(y_test, xgb_pred, average='weighted') return rf_model, xgb_model, le_crime, le_location, le_status, rf_accuracy, rf_f1, xgb_accuracy, xgb_f1 # Function to set modern styling with background image and white text def set_background_and_text(image_file): try: with open(image_file, "rb") as image: encoded_image = base64.b64encode(image.read()).decode() css = f""" """ st.markdown(css, unsafe_allow_html=True) logger.info(f"Modern styling and background image set for {image_file}") except FileNotFoundError: logger.error(f"Background image {image_file} not found") st.warning(f"Background image for {image_file} not found.") css = """ """ st.markdown(css, unsafe_allow_html=True) # Initialize session state for user authentication if 'user' not in st.session_state: st.session_state.user = None st.session_state.role = None if 'page' not in st.session_state: st.session_state.page = "Login" # Role-based menu options ROLE_MENUS = { "admin": ["Dashboard", "Add Crime", "View Crimes", "Add FIR", "View FIRs", "Data Analysis", "ML Predictions", "Sign Up", "Login", "Logout"], "police": ["Dashboard", "View Crimes", "Add FIR", "View FIRs", "ML Predictions", "Login", "Logout"], None: ["Login", "Sign Up"] } # Sidebar navigation st.sidebar.header("User Authentication") auth_choice = st.sidebar.selectbox("Action", ["Login", "Sign Up", "Logout"] if st.session_state.user else ["Login", "Sign Up"], key="auth_choice") # Signup if auth_choice == "Sign Up": st.header("Sign Up") username = st.text_input("Username", help="Enter a unique username") password = st.text_input("Password", type="password", help="Enter a secure password") role = st.selectbox("Role", ["admin", "police"], help="Select user role: admin or police") if st.button(" Register", key="signup", help="Create a new user account"): if username and password: try: response = requests.post("http://localhost:8000/api/users", json={"username": username, "password": password, "role": role}) response.raise_for_status() st.success("User registered successfully! Please log in.") st.session_state.page = "Login" except requests.RequestException as e: st.error(f"Error: {e}") else: st.error("Please fill in all fields.") # Login elif auth_choice == "Login": st.header("Login") username = st.text_input("Username", help="Enter your username") password = st.text_input("Password", type="password", help="Enter your password") if st.button(" Login", key="login", help="Log in to the system"): if username and password: try: response = requests.post("http://localhost:8000/api/login", json={"username": username, "password": password}) response.raise_for_status() data = response.json() st.session_state.user = data["username"] st.session_state.role = data["role"] st.success(f"Logged in as {data['username']} ({data['role']})") st.session_state.page = "Dashboard" except requests.RequestException as e: st.error(f"Error: {e}") else: st.error("Please fill in all fields.") # Logout elif auth_choice == "Logout": st.session_state.user = None st.session_state.role = None st.session_state.page = "Login" st.success("Logged out successfully!") st.rerun() # Set background image and modern styling background_images = { "Dashboard": "static\mainmenu.jpg", "Add Crime": "static\AddCrimes.jpg", "View Crimes": "static\ViewCrimes.jpg", "Add FIR": "static\AddFirs.jpg", "View FIRs": "static\ViewFirs.jpg", "Data Analysis": "static\mainmenu.jpg", "ML Predictions": "static\AddCrimes.jpg", "Sign Up": "static\ViewCrimes.jpg", "Login": "static\ViewFirs.jpg" } # Apply background and styling if st.session_state.page in background_images: set_background_and_text(background_images[st.session_state.page]) else: set_background_and_text(None) # Main menu navigation (only shown if logged in) if st.session_state.user: st.sidebar.header("Navigation") menu = ROLE_MENUS[st.session_state.role] choice = st.sidebar.selectbox("Menu", menu, key="main_menu") else: choice = st.session_state.page # Main app logic if choice == "Dashboard" and st.session_state.user: st.header("Dashboard") st.write(f"Welcome, {st.session_state.user} ({st.session_state.role.title()})! Navigate using the sidebar.") elif choice == "Add Crime" and st.session_state.user and st.session_state.role == "admin": st.header("Add Crime") crime_type = st.text_input("Crime Type", help="e.g., Cyber Crimes, Theft, Assault") description = st.text_area("Description", help="Brief description of the crime") location = st.text_input("Location", help="e.g., New York, Chicago") date = st.date_input("Date") officer = st.text_input("Officer In Charge", help="Name of the assigned officer") if st.button(" Submit Crime", key="add_crime", help="Save the crime record"): if crime_type and description and location and officer: crime_data = { "crime_type": crime_type.lower(), "description": description.lower(), "location": location.lower(), "date": str(date), "officer_in_charge": officer.lower() } try: response = requests.post("http://localhost:8000/api/crimes", json=crime_data) response.raise_for_status() st.success("Crime added successfully!") except requests.RequestException as e: st.error(f"Error: {e}") else: st.error("Please fill in all fields.") elif choice == "View Crimes" and st.session_state.user: st.header("View Crimes") with st.container(): st.markdown('