Fix meeting summaries: long transcripts overflowed the LLM context

Reproduced on the 68-min meeting: the timestamped transcript filled
the whole 32k window (prompt_eval 32451), gemma4 hit the length limit
and returned an EMPTY answer (done_reason=length) — which the server
wrote as an empty summary.md and marked "done". Fixes:

- num_ctx 32768 -> 65536 and transcript cap 90k -> 100k chars (env
  OLLAMA_NUM_CTX / TRANSCRIPT_MAX_CHARS); ~33k tokens now fit with
  plenty of room for the answer
- _ollama_chat treats an empty response as an ERROR (with done_reason
  and prompt_eval in the message) instead of producing a done-with-empty
  summary
- truncated transcripts get a note appended to the summary
- startup recovery: a container restart resets stale "pending" statuses
  so the UI can never stick on "wird erstellt" from dead threads
- phone: the summary/agenda poll survives transient fetch errors
  (previously one network hiccup stopped the poll forever)
This commit is contained in:
2026-09-08 20:53:33 +02:00
parent 76611af7e0
commit 293ec8bdec
2 changed files with 51 additions and 13 deletions
@@ -205,17 +205,20 @@ private fun LibraryDetail(
}
}
// poll while the server is generating (summary + agenda run via Ollama)
LaunchedEffect(meta?.summary, meta?.agendaStatus) {
val m = meta ?: return@LaunchedEffect
// poll while the server is generating (summary + agenda run via Ollama);
// transient fetch errors must not stop the poll — the UI would stick on
// "wird erstellt" forever
LaunchedEffect(item) {
val m0 = (item as? LibraryItem.Server)?.meta ?: return@LaunchedEffect
var m = m0
val url = storageUrl.trim().trimEnd('/')
if (m.summary == "pending" || m.agendaStatus == "pending") {
while (m.summary == "pending" || m.agendaStatus == "pending") {
delay(5_000)
try {
meta = withContext(Dispatchers.IO) {
StorageClient.fetchMeta(url, m.id)
}
m = withContext(Dispatchers.IO) { StorageClient.fetchMeta(url, m.id) }
meta = m
} catch (_: Exception) {
// network hiccup — retry on the next loop iteration
}
}
}