fix(ollama): Streaming statt Single-Request — beendet ReadTimeout bei langen Antworten
Vorher: stream=False → der gesamte Generierungs-Lauf musste innerhalb des Read-Timeout (default 600 s) abgeschlossen sein. Bei langen Transkripten oder größeren Modellen reicht das nicht und der Mac-Worker wirft httpx.ReadTimeout. Jetzt: stream=True + httpx.Timeout(read=...) pro Chunk. Solange Ollama kontinuierlich Tokens liefert, läuft kein Timeout. Zusätzlich keep_alive 30m, damit das Modell zwischen Calls im RAM bleibt (kein erneuter Load-Overhead). Logs jetzt mit Chunk-Anzahl + Gesamtlänge — leichter zu debuggen.
This commit is contained in:
parent
220b7ccbc3
commit
3d39d3e829
@ -40,19 +40,51 @@ def _truncate(text: str, max_chars: int = 60000) -> str:
|
||||
|
||||
|
||||
async def _chat(prompt: str) -> str:
|
||||
"""Ruft Ollama im Streaming-Modus auf.
|
||||
|
||||
Streaming hat zwei wichtige Vorteile:
|
||||
1. Read-Timeout gilt pro Chunk statt für die gesamte Antwort —
|
||||
lange Generierungen laufen nicht mehr in den Gesamt-Timeout.
|
||||
2. Wir können in den Logs sehen, dass das Modell tatsächlich arbeitet
|
||||
(Anzahl Chunks).
|
||||
|
||||
`keep_alive`: das Modell bleibt 30 min im RAM zwischen Calls,
|
||||
damit nachfolgende Anfragen nicht erneut die Ladezeit zahlen.
|
||||
"""
|
||||
url = f"{settings.ollama_url.rstrip('/')}/api/generate"
|
||||
payload = {
|
||||
"model": settings.ollama_model,
|
||||
"prompt": prompt,
|
||||
"stream": False,
|
||||
"stream": True,
|
||||
"keep_alive": "30m",
|
||||
"options": {"temperature": 0.2},
|
||||
}
|
||||
log.info("Ollama generate model=%s prompt_len=%d", settings.ollama_model, len(prompt))
|
||||
async with httpx.AsyncClient(timeout=settings.ollama_timeout) as c:
|
||||
r = await c.post(url, json=payload)
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
return data.get("response", "")
|
||||
log.info("Ollama generate model=%s prompt_len=%d (streaming)", settings.ollama_model, len(prompt))
|
||||
timeout = httpx.Timeout(
|
||||
connect=15.0,
|
||||
read=settings.ollama_timeout, # pro Chunk — großzügig wegen initial Modell-Load
|
||||
write=30.0,
|
||||
pool=10.0,
|
||||
)
|
||||
chunks: list[str] = []
|
||||
chunk_count = 0
|
||||
async with httpx.AsyncClient(timeout=timeout) as c:
|
||||
async with c.stream("POST", url, json=payload) as r:
|
||||
r.raise_for_status()
|
||||
async for line in r.aiter_lines():
|
||||
if not line.strip():
|
||||
continue
|
||||
try:
|
||||
obj = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
log.warning("Ollama: ungültige JSON-Zeile übersprungen: %r", line[:100])
|
||||
continue
|
||||
chunks.append(obj.get("response", ""))
|
||||
chunk_count += 1
|
||||
if obj.get("done"):
|
||||
break
|
||||
log.info("Ollama: %d Chunks empfangen, Gesamtlänge %d Zeichen", chunk_count, sum(map(len, chunks)))
|
||||
return "".join(chunks)
|
||||
|
||||
|
||||
async def summarize(transcript: str, title: str = "", profile_name: str | None = None) -> dict[str, Any]:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user