feat: enhance face-lock service with improved upload handling and response structure
python / test (push) Failing after 8s

- Updated README.md to reflect new features and API changes.
- Introduced versioning in app initialization.
- Enhanced configuration management in app/config.py with new validation functions.
- Refactored main.py to improve request handling and response generation.
- Added new models in app/models.py for structured API responses.
- Implemented a dedicated UI rendering function in app/ui.py.
- Improved Docker configuration for better security and health checks.
- Updated tests to cover new validation rules and response formats.
- Added CLAUDE.md for project guidelines and working rules.
This commit is contained in:
Space-Banane
2026-06-20 11:23:12 +02:00
parent f1072cb7b0
commit 3cf4a9a40a
17 changed files with 759 additions and 222 deletions
+18 -2
View File
@@ -2,7 +2,7 @@ from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
from typing import Any
from typing import TypedDict
import cv2
import numpy as np
@@ -31,6 +31,20 @@ HOG = cv2.HOGDescriptor()
HOG.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
class ProcessedImage(TypedDict):
filename: str
detector: str
method: str
buffer_ratio: float
detected_bbox: dict[str, int]
square_bbox: dict[str, int]
source_size: dict[str, int]
crop_data_url: str
annotated_data_url: str
mime_type: str
crop_bytes: bytes
def decode_image(image_bytes: bytes) -> np.ndarray:
data = np.frombuffer(image_bytes, dtype=np.uint8)
image = cv2.imdecode(data, cv2.IMREAD_COLOR)
@@ -68,6 +82,8 @@ def fallback_bbox(image: np.ndarray) -> BBox:
def detect_face(image: np.ndarray) -> BBox | None:
if FACE_CASCADE.empty():
return None
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
faces = FACE_CASCADE.detectMultiScale(gray, scaleFactor=1.08, minNeighbors=5, minSize=(24, 24))
@@ -173,7 +189,7 @@ def _data_url(image_bytes: bytes, mime_type: str) -> str:
return f"data:{mime_type};base64,{base64.b64encode(image_bytes).decode('ascii')}"
def process_image(image_bytes: bytes, filename: str, buffer_ratio: float = 0.15, detector: str = "subject") -> dict[str, Any]:
def process_image(image_bytes: bytes, filename: str, buffer_ratio: float = 0.15, detector: str = "subject") -> ProcessedImage:
image = decode_image(image_bytes)
bbox, method = select_primary_bbox(image, detector=detector)
square = square_bbox(bbox, image.shape, buffer_ratio=buffer_ratio)