fix(vision): limite di tipo e dimensione sui tre endpoint di upload
/execute, /preview e /reference-images leggevano l'immagine senza limite di tipo o dimensione, e /reference-images scriveva su disco con estensione .png fissa qualunque fosse il tipo reale. Riusa la convenzione già esistente in files.py (ALLOWED_IMAGE_TYPES, validate_file_size) invece di inventarne una seconda: tipo controllato dall'header prima di leggere, dimensione controllata sul corpo letto, un PDF non è qualcosa che un grafo di visione può misurare. save_reference_image ora scrive con l'estensione del tipo reale dell'upload. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014BBnuACZSCJqXrMYC3LUMU
This commit is contained in:
@@ -9,6 +9,8 @@ from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from src.backend.api.middleware.api_key import require_maker, require_measurement_tec
|
||||
from src.backend.api.routers.files import ALLOWED_IMAGE_TYPES, validate_file_size
|
||||
from src.backend.config import settings
|
||||
from src.backend.database import get_db
|
||||
from src.backend.models.api.vision import VisionExecuteResponse, VisionMeasurementResult
|
||||
from src.backend.models.orm.task import RecipeTask
|
||||
@@ -17,6 +19,15 @@ from src.backend.services import vision_service
|
||||
|
||||
router = APIRouter(prefix="/api/vision", tags=["vision"])
|
||||
|
||||
# A vision graph measures pixels, not a PDF: stricter than files.py's
|
||||
# ALLOWED_TYPES, which also accepts documents for technical drawings.
|
||||
_IMAGE_EXTENSIONS = {
|
||||
"image/jpeg": "jpg",
|
||||
"image/png": "png",
|
||||
"image/gif": "gif",
|
||||
"image/webp": "webp",
|
||||
}
|
||||
|
||||
|
||||
async def _task_or_404(db: AsyncSession, task_id: int) -> RecipeTask:
|
||||
"""Shared by the endpoints of this router."""
|
||||
@@ -30,6 +41,28 @@ async def _task_or_404(db: AsyncSession, task_id: int) -> RecipeTask:
|
||||
return task
|
||||
|
||||
|
||||
async def _read_image(image: UploadFile) -> bytes:
|
||||
"""Type checked from the header before reading, size checked once the body
|
||||
is in hand - the same two-step convention `files.py::upload_file` already
|
||||
uses, reused rather than reinvented here.
|
||||
"""
|
||||
if image.content_type not in ALLOWED_IMAGE_TYPES:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"File type {image.content_type} not allowed. Must be an image.",
|
||||
)
|
||||
content = await image.read()
|
||||
if not validate_file_size(len(content)):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=(
|
||||
f"File size {len(content)} bytes exceeds maximum "
|
||||
f"{settings.max_upload_size_mb}MB"
|
||||
),
|
||||
)
|
||||
return content
|
||||
|
||||
|
||||
@router.post("/execute", response_model=VisionExecuteResponse)
|
||||
async def execute(
|
||||
task_id: int = Form(...),
|
||||
@@ -45,7 +78,7 @@ async def execute(
|
||||
result, saved = await vision_service.execute_task(
|
||||
db,
|
||||
task,
|
||||
await image.read(),
|
||||
await _read_image(image),
|
||||
current_user.id,
|
||||
version_id=task.version_id,
|
||||
lot_number=lot_number,
|
||||
@@ -80,8 +113,10 @@ async def add_reference_image(
|
||||
current_user: User = Depends(require_maker),
|
||||
) -> dict:
|
||||
task = await _task_or_404(db, task_id)
|
||||
content = await _read_image(image)
|
||||
reference = await vision_service.save_reference_image(
|
||||
db, task.id, await image.read(), note=note,
|
||||
db, task.id, content, note=note,
|
||||
extension=_IMAGE_EXTENSIONS[image.content_type],
|
||||
)
|
||||
await db.commit()
|
||||
return {"id": reference.id, "path": reference.path, "note": reference.note}
|
||||
@@ -95,4 +130,4 @@ async def preview(
|
||||
current_user: User = Depends(require_maker),
|
||||
) -> dict:
|
||||
task = await _task_or_404(db, task_id)
|
||||
return await vision_service.preview(db, task, await image.read())
|
||||
return await vision_service.preview(db, task, await _read_image(image))
|
||||
|
||||
Reference in New Issue
Block a user