Skip to content

Latest commit

 

History

History
192 lines (153 loc) · 4.29 KB

File metadata and controls

192 lines (153 loc) · 4.29 KB

WebSocket Detection API

Running with Django Channels

Development (with Daphne):

# Install dependencies
pip install -r requirements.txt

# Run Daphne server
daphne -b 0.0.0.0 -p 8000 config.asgi:application

Production (with Gunicorn + Daphne):

# Use Daphne for ASGI
daphne -b 0.0.0.0 -p 8000 config.asgi:application

# Or with Gunicorn + Uvicorn
pip install uvicorn
uvicorn config.asgi:application --host 0.0.0.0 --port 8000

WebSocket Endpoint

URL: ws://localhost:8001/ws/detect/?token=<jwt_token>

Client Implementation (JavaScript)

const token = "your_jwt_token_here";
const ws = new WebSocket(`ws://localhost:8001/ws/detect/?token=${token}`);

ws.onopen = () => {
  console.log("Connected to detection service");
};

ws.onmessage = (event) => {
  const response = JSON.parse(event.data);
  console.log("Prediction:", response);
  // response: {label: "Suspicious", confidence: 0.85}
  // or: {label: "Normal", confidence: 0.92}
  // or: {label: null, confidence: null} (collecting frames)
};

ws.onerror = (error) => {
  console.error("WebSocket error:", error);
};

ws.onclose = () => {
  console.log("Connection closed");
};

// Send frame for prediction
const sendFrame = (base64Image, cameraId, type = "multi") => {
  ws.send(JSON.stringify({
    image: base64Image,
    camera_id: cameraId,
    type: type  // "multi", "multi15", "multi3d", "14"
  }));
};

// Example usage - send multiple frames
const captureAndSend = async () => {
  // Assuming you have a base64 encoded image from canvas or file input
  const base64Image = "data:image/jpeg;base64,...";
  sendFrame(base64Image, 1, "multi");
};

Client Implementation (Python)

import asyncio
import websockets
import json
import base64
import cv2

async def websocket_client():
    token = "your_jwt_token_here"
    uri = f"ws://localhost:8001/ws/detect/?token={token}"
    
    async with websockets.connect(uri) as websocket:
        print(await websocket.recv())  # Connected message
        
        # Send frame
        # Read image and convert to base64
        frame = cv2.imread("sample.jpg")
        _, buffer = cv2.imencode('.jpg', frame)
        base64_image = "data:image/jpeg;base64," + base64.b64encode(buffer).decode()
        
        message = {
            "image": base64_image,
            "camera_id": 1,
            "type": "multi"
        }
        
        await websocket.send(json.dumps(message))
        
        # Receive prediction
        response = await websocket.recv()
        print(json.loads(response))
        
        # Keep connection alive and send more frames
        for _ in range(10):
            await websocket.send(json.dumps(message))
            response = await websocket.recv()
            print(json.loads(response))

asyncio.run(websocket_client())

Message Format

Client → Server (Send Frame)

{
  "image": "data:image/jpeg;base64,...",
  "camera_id": 1,
  "camera_name": "Front Door",
  "type": "multi"
}

Parameters:

  • image (required): Base64 encoded image with data:image/jpeg;base64, prefix
  • camera_id (optional): Camera ID from database
  • camera_name (optional): Camera name from database
  • type (optional): Prediction model type
    • "multi" (default): CNN-LSTM
    • "multi15": Alternative CNN-LSTM
    • "multi3d": 3D CNN
    • "14": Frame buffering variant

Server → Client (Response)

Collecting frames:

{
  "label": null,
  "confidence": null
}

Prediction ready:

{
  "label": "Suspicious",
  "confidence": 0.85
}

Error:

{
  "error": "Invalid image format"
}

Performance Benefits

Metric HTTP WebSocket
Connection setup ~100ms ~50ms (persistent)
Per frame ~150ms ~80-100ms
10 frames 1500ms 800ms + initial
Overhead Per-request One-time

Streaming 10+ frames per second:

  • HTTP: ~1500ms overhead per 10 frames
  • WebSocket: ~800ms total for streaming session
  • Savings: ~40% latency reduction

Architecture

Client WebSocket Connection
    ↓
authentication (JWT token)
    ↓
DetectionConsumer (async handler)
    ↓
predict_frame_multi (global model)
    ↓
Response (label + confidence only)
    ↓
Send back to client

No model reload per request - global model instance reused.