Bild-Weiche v2: frischer Client + Retry fuer den Vision-Unteraufruf

Befund :9010 (Journal): httpx.ReadTimeout nach Sekunden trotz timeout=240 -
der gepoolte Keep-Alive-Client reicht Sockets wieder aus, die llama-swap
beim Modell-Swap gekappt hat. Der Beschreibungs-Unteraufruf nutzt jetzt
einen eigenen Kurzzeit-Client und versucht es einmal erneut.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-15 15:30:36 +02:00
parent 202e97333a
commit d2398b3624
+15 -8
View File
@@ -1,6 +1,8 @@
import logging import logging
import os import os
import httpx
from fastapi import APIRouter, Request from fastapi import APIRouter, Request
from fastapi.responses import JSONResponse, StreamingResponse from fastapi.responses import JSONResponse, StreamingResponse
@@ -61,18 +63,23 @@ async def _bilder_fuer_coder_beschreiben(body: dict, client, vision_alias: str)
"messages": [{"role": "user", "messages": [{"role": "user",
"content": [part, {"type": "text", "text": _BILD_BESCHREIB_PROMPT}]}], "content": [part, {"type": "text", "text": _BILD_BESCHREIB_PROMPT}]}],
} }
try: # Eigener Kurzzeit-Client statt des gepoolten (Befund 15.07.: ReadTimeout nach
# Grosszuegiger Timeout: VL-30B ist on-demand (Kaltladen ~30 s) + Beschreibung ~25 s. # Sekunden trotz timeout=240 — llama-swap kappt beim Modell-Swap gern alte
r = await client.post(f"{LLAMA_SWAP_URL}/v1/chat/completions", json=frage, timeout=240.0) # Keep-Alive-Sockets, der Pool reicht sie trotzdem wieder aus) + 1 Retry.
text = "" text = ""
for versuch in (1, 2):
try:
async with httpx.AsyncClient(timeout=240.0) as c:
r = await c.post(f"{LLAMA_SWAP_URL}/v1/chat/completions", json=frage)
if r.status_code == 200: if r.status_code == 200:
text = ((r.json().get("choices") or [{}])[0].get("message") or {}).get("content") or "" text = ((r.json().get("choices") or [{}])[0].get("message") or {}).get("content") or ""
if not text.strip(): if text.strip():
log.warning("Bild-Weiche v2: Beschreibung leer/fehlgeschlagen (HTTP %s) — Fallback Umleitung. Body: %.200s", break
r.status_code, r.text) log.warning("Bild-Weiche v2 (Versuch %s): Beschreibung leer/HTTP %s%.200s",
return False versuch, r.status_code, r.text)
except Exception: except Exception:
log.warning("Bild-Weiche v2: Vision-Aufruf scheiterte — Fallback Umleitung", exc_info=True) log.warning("Bild-Weiche v2 (Versuch %s): Vision-Aufruf scheiterte", versuch, exc_info=True)
if not text.strip():
return False return False
msg["content"][idx] = {"type": "text", "text": ( msg["content"][idx] = {"type": "text", "text": (
f"[Bild {nr}: dem Request lag ein Bild bei — {vision_alias} beschreibt es so:\n" f"[Bild {nr}: dem Request lag ein Bild bei — {vision_alias} beschreibt es so:\n"