fix(ai): risposta AI malformata -> 502, non 400 (#36 punto 7)

json.JSONDecodeError e' un ValueError: KeyError/JSONDecodeError sulla
risposta del modello finivano nell'except ValueError del router (pensato
per i nostri errori di configurazione, es. API key mancante) e uscivano
come 400 invece di 502. Nuova AIResponseError dedicata in ai_service.py
per contenuto malformato o JSON non valido; recipes.py la traduce in 502,
toccato solo per questo except.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-21 22:43:42 +02:00
parent 65f6a4b18b
commit 403c923188
4 changed files with 127 additions and 2 deletions
+22 -2
View File
@@ -11,6 +11,17 @@ from src.backend.config import settings
logger = logging.getLogger(__name__)
class AIResponseError(Exception):
"""The AI model's response could not be used: missing fields or invalid JSON.
Distinct from ValueError (raised for our own misconfiguration, e.g. a
missing API key) so the router can tell "we are broken" (400) apart from
"the upstream AI service is broken" (502) instead of both landing on the
same except clause.
"""
SYSTEM_PROMPT = """Sei un assistente specializzato nell'analisi di schede tecniche industriali.
Analizza il testo estratto da una scheda tecnica e identifica i blocchi operativi distinti.
Per ogni blocco, estrai:
@@ -65,7 +76,10 @@ async def parse_technical_sheet(pdf_bytes: bytes) -> list[dict]:
resp.raise_for_status()
data = resp.json()
content = data["choices"][0]["message"]["content"].strip()
try:
content = data["choices"][0]["message"]["content"].strip()
except (KeyError, IndexError, TypeError, AttributeError) as e:
raise AIResponseError(f"Risposta del modello AI malformata: {e}") from e
# Strip markdown fences if present
if content.startswith("```"):
@@ -74,4 +88,10 @@ async def parse_technical_sheet(pdf_bytes: bytes) -> list[dict]:
content = content[:-3]
content = content.strip()
return json.loads(content)
try:
return json.loads(content)
except json.JSONDecodeError as e:
# json.JSONDecodeError is itself a ValueError: without this, the
# router's `except ValueError` (meant for our own config errors)
# would misreport a broken upstream response as our fault (400).
raise AIResponseError(f"Risposta del modello AI non e' JSON valido: {e}") from e