attendance-api / api /websocket.py
vrfefavr's picture
Update api/websocket.py
1724c8d verified
import json
import base64
import cv2
import numpy as np
import asyncio
from fastapi import WebSocket, WebSocketDisconnect
from services.vision import process_frame_synchronous
from services.attendance import mark_attendance
from core.state import active_connections
async def websocket_endpoint(websocket: WebSocket):
"""
Hard-Locked WebSocket Connection with Visual Debugging.
Returns crops and bounding boxes alongside the Truth Report.
"""
await websocket.accept()
active_connections.append(websocket)
try:
while True:
data = await websocket.receive_text()
payload = json.loads(data)
if payload.get("type") == "heartbeat":
await websocket.send_json({"type": "heartbeat_ack"})
continue
if payload.get("type") == "frame":
encoded_data = payload["image"].split(',')[1]
nparr = np.frombuffer(base64.b64decode(encoded_data), np.uint8)
frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
report, stats = await asyncio.to_thread(process_frame_synchronous, frame)
results_summary = []
# Prepare visual data for frontend
client_faces = []
for face in report:
name = face["name"]
score = face["score"]
status = face["status"]
# Store data for drawing boxes and showing crops
client_faces.append({
"name": name,
"score": score,
"status": status,
"box": face["box"],
"crop": face["crop_b64"]
})
if status == "match":
# Business Logic: Mark Attendance
status_db, time_str = mark_attendance(name)
results_summary.append(f"✅ {name} ({score}%)")
# Push to session attendance list
await websocket.send_json({
"type": "attendance",
"name": name,
"time": time_str or "Just Now",
"status": "success"
})
else:
results_summary.append(f"❌ {name} ({score}%)")
# Detailed Terminal Output
debug_msg = f"Faces: {stats['detected']} | "
debug_msg += " | ".join(results_summary) if results_summary else "No faces found."
# Send frame processing result back to browser
await websocket.send_json({
"type": "ready",
"debug": debug_msg,
"faces": client_faces # ALL visual debug data included here
})
except WebSocketDisconnect:
if websocket in active_connections:
active_connections.remove(websocket)