From 3bc7fa16e213a0d84d7b6299ae38bdf14bae2395 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:31:34 +0200 Subject: [PATCH] feat(photo-upload): Limits hochschrauben fuer Tablet-Fotos Tablet- und iPad-Pro-Kameras liefern JPEGs/HEICs bis 15 MB. Mit den alten 8-/10-MB-Limits scheiterte das Upload beim SvelteKit-Body-Parser mit "Multipart erwartet" (undurchsichtiger Fehler, weil SvelteKit den Body frueher abweist als unser Endpoint-Check). - Endpoint MAX_BYTES: 8 -> 20 MB - BODY_SIZE_LIMIT: 10 -> 25 MB (mit Multipart-Overhead) Co-Authored-By: Claude Opus 4.7 (1M context) --- docker-compose.prod.yml | 7 ++++--- src/routes/api/recipes/extract-from-photo/+server.ts | 6 +++++- tests/integration/extract-from-photo.test.ts | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 39996f8..57cf054 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -17,9 +17,10 @@ services: - GEMINI_API_KEY=${GEMINI_API_KEY:-} - GEMINI_MODEL=${GEMINI_MODEL:-gemini-2.5-flash} - GEMINI_TIMEOUT_MS=${GEMINI_TIMEOUT_MS:-20000} - # adapter-node-Default ist 512 KB; Rezept-Fotos koennen bis 8 MB sein. - # Multipart-Overhead einrechnen -> 10 MB gibt etwas Puffer. - - BODY_SIZE_LIMIT=10000000 + # adapter-node-Default ist 512 KB. Tablet- und iPad-Pro-Kameras liefern + # JPEGs/HEICs bis 15 MB. Endpoint-Limit ist 20 MB; hier 25 MB fuer den + # Multipart-Overhead. + - BODY_SIZE_LIMIT=25000000 depends_on: - searxng restart: unless-stopped diff --git a/src/routes/api/recipes/extract-from-photo/+server.ts b/src/routes/api/recipes/extract-from-photo/+server.ts index cc8da10..927b1ac 100644 --- a/src/routes/api/recipes/extract-from-photo/+server.ts +++ b/src/routes/api/recipes/extract-from-photo/+server.ts @@ -6,7 +6,11 @@ import { pickRandomPhrase } from '$lib/server/ai/description-phrases'; import { createRateLimiter } from '$lib/server/ai/rate-limit'; import type { Ingredient, Step } from '$lib/types'; -const MAX_BYTES = 8 * 1024 * 1024; +// 20 MB deckt auch Tablet- und iPad-Pro-Fotos ab (oft 10-15 MB JPEG/HEIC). +// Muss zusammen mit BODY_SIZE_LIMIT (docker-compose.prod.yml) hochgezogen werden -- +// SvelteKit rejected groessere Bodies frueher und wirft dann undurchsichtige +// "Multipart erwartet"-Fehler. +const MAX_BYTES = 20 * 1024 * 1024; const ALLOWED_MIME = new Set([ 'image/jpeg', 'image/png', diff --git a/tests/integration/extract-from-photo.test.ts b/tests/integration/extract-from-photo.test.ts index 68c0388..ed9a137 100644 --- a/tests/integration/extract-from-photo.test.ts +++ b/tests/integration/extract-from-photo.test.ts @@ -70,8 +70,8 @@ describe('POST /api/recipes/extract-from-photo', () => { expect(body.recipe.id).toBeNull(); }); - it('413 when file exceeds 8 MB', async () => { - const big = Buffer.alloc(9 * 1024 * 1024); + it('413 when file exceeds 20 MB', async () => { + const big = Buffer.alloc(21 * 1024 * 1024); const fd = new FormData(); fd.append('photo', new Blob([new Uint8Array(big)], { type: 'image/jpeg' })); // eslint-disable-next-line @typescript-eslint/no-explicit-any