diff --git a/app/services/ai_vision.py b/app/services/ai_vision.py index 625a3c2..16069b8 100644 --- a/app/services/ai_vision.py +++ b/app/services/ai_vision.py @@ -40,15 +40,40 @@ def _get_client() -> genai.Client: async def _read_image(file_path: str) -> tuple[bytes, str]: + """Lit l'image via le StorageBackend et la redimensionne pour l'AI (max 1024px).""" path = Path(file_path) suffix = path.suffix.lower() + backend = get_storage_backend() + data = await backend.get_bytes(file_path) + + # Redimensionner pour éviter les timeouts AI sur les grandes images + try: + from PIL import Image as PILImage + import io as pil_io + original_size = len(data) + img = PILImage.open(pil_io.BytesIO(data)) + max_dim = 1024 + if img.width > max_dim or img.height > max_dim: + img.thumbnail((max_dim, max_dim), PILImage.Resampling.LANCZOS) + buf = pil_io.BytesIO() + if img.mode in ("RGBA", "P"): + img = img.convert("RGB") + img.save(buf, format="JPEG", quality=85) + data = buf.getvalue() + logger.info("ai.image_resized", extra={ + "file": path.name, + "original_bytes": original_size, + "resized_bytes": len(data), + }) + return data, "image/jpeg" + except Exception: + pass # Si Pillow échoue, on utilise l'image originale + mime_map = { ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".png": "image/png", ".gif": "image/gif", ".webp": "image/webp", } media_type = mime_map.get(suffix, "image/jpeg") - backend = get_storage_backend() - data = await backend.get_bytes(file_path) return data, media_type