detector / app.py
Emannn2004's picture
Update app.py
22e283a verified
Raw History Blame Contribute Delete
5.7 kB
# ==============================
# Imports
# ==============================
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
import numpy as np
import cv2
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import (
InputLayer, TimeDistributed, GlobalAveragePooling2D,
LSTM, Dense, Dropout
)
from tensorflow.keras.applications import MobileNetV2
import os
# ==============================
# Parameters
# ==============================
IMG_H, IMG_W, CHANNELS = 224, 224, 3
NUM_FRAMES = 30
MODEL_PATH = "video_mobilenetv2_final_backup.keras"
model = None # Lazy loading
# ==============================
# Model Loader
# ==============================
def load_model():
global model
if model is not None:
return model
print("🔄 Loading model...")
base_cnn = MobileNetV2(
include_top=False,
weights='imagenet',
input_shape=(IMG_H, IMG_W, CHANNELS)
)
for layer in base_cnn.layers[:-20]:
layer.trainable = False
model = Sequential([
InputLayer(shape=(NUM_FRAMES, IMG_H, IMG_W, CHANNELS)),
TimeDistributed(base_cnn),
TimeDistributed(GlobalAveragePooling2D()),
LSTM(128),
Dropout(0.5),
Dense(128, activation='relu'),
Dropout(0.5),
Dense(1, activation='sigmoid')
])
model.load_weights(MODEL_PATH)
print("✅ Model loaded successfully!")
return model
# ==============================
# Frame Extraction
# ==============================
def extract_video_frames(video_path, n_frames=NUM_FRAMES):
cap = cv2.VideoCapture(video_path)
total = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
if total <= 0:
blank = np.zeros((IMG_H, IMG_W, 3), dtype=np.float32)
return np.stack([blank]*n_frames)
idxs = np.linspace(0, total - 1, n_frames).astype(int)
frames = []
for i in idxs:
cap.set(cv2.CAP_PROP_POS_FRAMES, i)
ok, frame = cap.read()
if not ok:
frames.append(np.zeros((IMG_H, IMG_W, 3), dtype=np.float32))
continue
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = cv2.resize(frame, (IMG_W, IMG_H))
frame = frame.astype(np.float32) / 255.0
frames.append(frame)
cap.release()
return np.array(frames, dtype=np.float32)
# ==============================
# Predict
# ==============================
def predict_video(path):
model = load_model()
frames = extract_video_frames(path)
frames = np.expand_dims(frames, 0)
score = model.predict(frames, verbose=0)[0][0]
label = "Violence" if score >= 0.5 else "NonViolence"
conf = score*100 if score >= 0.5 else (1 - score)*100
return label, conf
# ==============================
# FastAPI App
# ==============================
app = FastAPI(
title="Video Violence Detector",
description="API for detecting violence in videos using deep learning",
version="1.0.0"
)
# ==============================
# Startup Event - Preload Model
# ==============================
@app.on_event("startup")
async def startup_event():
"""Preload model on startup to avoid cold start delays"""
print("🚀 Starting up application...")
try:
load_model()
print("✅ Model preloaded successfully!")
except Exception as e:
print(f"⚠️ Warning: Could not preload model: {e}")
# ==============================
# Health Check Endpoint
# ==============================
@app.get("/health")
def health_check():
"""Health check endpoint for monitoring"""
return {
"status": "healthy",
"model_loaded": model is not None
}
# ==============================
# Root Endpoint
# ==============================
@app.get("/")
def home():
"""Root endpoint with API information"""
return {
"message": "Video Violence Detector API",
"endpoints": {
"POST /predict": "Upload a video file for violence detection",
"GET /health": "Check API health status"
},
"usage": "Send a POST request to /predict with a video file"
}
# ==============================
# Prediction Endpoint
# ==============================
@app.post("/predict")
async def upload(file: UploadFile = File(...)):
"""
Upload a video file and get violence prediction
Returns:
JSON with prediction (Violence/NonViolence) and confidence score
"""
# Validate file type
if not file.content_type.startswith('video/'):
return JSONResponse(
status_code=400,
content={"error": "File must be a video"}
)
temp = f"temp_{file.filename}"
try:
# Save uploaded file
with open(temp, "wb") as f:
f.write(await file.read())
# Make prediction
label, conf = predict_video(temp)
# Clean up temp file
if os.path.exists(temp):
os.remove(temp)
return {
"prediction": label,
"confidence": f"{conf:.2f}%",
"filename": file.filename
}
except Exception as e:
# Clean up on error
if os.path.exists(temp):
os.remove(temp)
return JSONResponse(
status_code=500,
content={
"error": "Prediction failed",
"details": str(e)
}
)
# ==============================
# Run locally (not used in HF)
# ==============================
if __name__ == "__main__":
import uvicorn
uvicorn.run("app:app", host="0.0.0.0", port=7860, reload=True)