Spaces:
Sleeping
Sleeping
| from fastapi import APIRouter, HTTPException, Query, Body | |
| from pydantic import BaseModel, Field, validator | |
| from typing import List, Optional | |
| from .utils import save_cameras, load_cameras, get_user_file, user_exists | |
| from .config import UPLOAD_DIR,GCS_UPLOAD_DIR | |
| import os | |
| import shutil | |
| print(" CAMERA API LOADED ") | |
| router = APIRouter(prefix="/camera", tags=["Camera"]) | |
| # ================= MODELS ================= | |
| class CameraData(BaseModel): | |
| user_id: str = Field(..., min_length=1) | |
| camera_name: str = Field(..., min_length=1) | |
| camera_loc: Optional[List[float]] = None | |
| def validate_loc(cls, loc): | |
| if loc is None: | |
| return loc | |
| if len(loc) != 2: | |
| raise ValueError("camera_loc must be [lat, lon]") | |
| lat, lon = loc | |
| if not (-90 <= lat <= 90): | |
| raise ValueError("Latitude must be between -90 and 90") | |
| if not (-180 <= lon <= 180): | |
| raise ValueError("Longitude must be between -180 and 180") | |
| return loc | |
| class EditCameraData(BaseModel): | |
| user_id: str | |
| old_camera_name: str | |
| new_camera_name: str | |
| new_camera_loc: List[float] | |
| def validate_loc(cls, loc): | |
| if len(loc) != 2: | |
| raise ValueError("new_camera_loc must be [lat, lon]") | |
| lat, lon = loc | |
| if not (-90 <= lat <= 90): | |
| raise ValueError("Latitude must be between -90 and 90") | |
| if not (-180 <= lon <= 180): | |
| raise ValueError("Longitude must be between -180 and 180") | |
| return loc | |
| # ================= ROUTES ================= | |
| def home(): | |
| return { | |
| "message": "Camera API is Running", | |
| "endpoints": [ | |
| "/camera/add_camera", | |
| "/camera/edit_camera", | |
| "/camera/delete_camera", | |
| "/camera/get_cameras?user_id=<id>" | |
| ] | |
| } | |
| # ---------- GET CAMERAS ---------- | |
| def get_cameras(user_id: str = Query(...)): | |
| if not user_exists(user_id): | |
| raise HTTPException(status_code=404, detail="User not found") | |
| cameras = load_cameras(user_id) | |
| return {"success": True, "user_id": user_id, "cameras": cameras, "count": len(cameras)} | |
| # ---------- ADD CAMERA ---------- | |
| def add_camera(data: CameraData): | |
| cameras = load_cameras(data.user_id) | |
| if len(cameras) >= 2: | |
| raise HTTPException(status_code=400, detail="Only 2 cameras allowed") | |
| for cam in cameras: | |
| if cam["camera_name"].lower() == data.camera_name.lower(): | |
| raise HTTPException(status_code=400, detail="Camera already exists") | |
| cameras.append({"camera_name": data.camera_name, "camera_loc": data.camera_loc}) | |
| save_cameras(data.user_id, cameras) | |
| return {"success": True, "camera": data.camera_name} | |
| def edit_camera(data: EditCameraData): | |
| if not user_exists(data.user_id): | |
| raise HTTPException(status_code=404, detail="User not found") | |
| cameras = load_cameras(data.user_id) | |
| # Check if new camera name already exists (case-insensitive) | |
| if any(cam["camera_name"].lower() == data.new_camera_name.lower() for cam in cameras): | |
| raise HTTPException(status_code=400, detail=f"Camera name '{data.new_camera_name}' already exists") | |
| camera_found = False | |
| for cam in cameras: | |
| if cam["camera_name"].lower() == data.old_camera_name.lower(): | |
| old_name = cam["camera_name"] | |
| cam["camera_name"] = data.new_camera_name | |
| cam["camera_loc"] = data.new_camera_loc | |
| camera_found = True | |
| # Rename camera folder | |
| old_folder = os.path.join(UPLOAD_DIR, data.user_id, old_name) | |
| new_folder = os.path.join(UPLOAD_DIR, data.user_id, data.new_camera_name) | |
| if os.path.exists(old_folder) and os.path.isdir(old_folder): | |
| try: | |
| os.rename(old_folder, new_folder) | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Failed to rename camera folder: {str(e)}") | |
| # Rename detection JSON | |
| for f in os.listdir(new_folder): | |
| if f.endswith("_detections.json") and f.lower().startswith(old_name.lower()): | |
| old_json = os.path.join(new_folder, f) | |
| new_json_name = f.replace(old_name, data.new_camera_name) | |
| new_json = os.path.join(new_folder, new_json_name) | |
| try: | |
| os.rename(old_json, new_json) | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Failed to rename detection JSON: {str(e)}") | |
| break # Only one detection JSON per camera | |
| save_cameras(data.user_id, cameras) | |
| return {"success": True, "updated": cam} | |
| if not camera_found: | |
| raise HTTPException(status_code=404, detail="Camera not found") | |
| def delete_camera(user_id: str = Query(...), camera_name: str = Query(...)): | |
| if not user_exists(user_id): | |
| raise HTTPException(status_code=404, detail="User not found") | |
| cameras = load_cameras(user_id) | |
| new_list = [c for c in cameras if c["camera_name"].lower() != camera_name.lower()] | |
| if len(new_list) == len(cameras): | |
| raise HTTPException(status_code=404, detail="Camera not found") | |
| save_cameras(user_id, new_list) | |
| camera_folder = os.path.join(UPLOAD_DIR, user_id, camera_name) | |
| if os.path.exists(camera_folder) and os.path.isdir(camera_folder): | |
| try: | |
| shutil.rmtree(camera_folder) | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Failed to delete camera folder: {str(e)}") | |
| return {"success": True, "deleted": camera_name} | |