diff options
| author | historia <historiavg@proton.me> | 2026-09-01 03:17:01 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-09-01 03:17:01 -0400 |
| commit | 058b19e7a65b40b1024a4fdeb2233062ff273cfd (patch) | |
| tree | fe3643872cd6b317a88eec950ae6ecc4d81d843d /app/ui/runview.py | |
| parent | 10e72d4960e865acf5346ab8cf518ed5844fe45c (diff) | |
| download | tts-audiobook-generator-058b19e7a65b40b1024a4fdeb2233062ff273cfd.tar.gz | |
fix: better errors for generate all models
Diffstat (limited to 'app/ui/runview.py')
| -rw-r--r-- | app/ui/runview.py | 64 |
1 files changed, 57 insertions, 7 deletions
diff --git a/app/ui/runview.py b/app/ui/runview.py index 759fcfb..21ac08c 100644 --- a/app/ui/runview.py +++ b/app/ui/runview.py @@ -161,6 +161,7 @@ class RunView(ScreenView): self.chunk_total = 0 self.book_results: List[tuple] = [] # (name, ok, files, error, model) self.error_message = "" + self._book_error = "" # current book's failure reason (results row) self.started_server = False # cancelled/cancelling/finished_at: base self.boot_started: Optional[float] = None self.convert_started: Optional[float] = None @@ -215,6 +216,11 @@ class RunView(ScreenView): self.chapter = None self.chunk_done = 0 self.chunk_total = 0 + # A new book starts with a clean slate: a failure message from + # the previous book (an earlier model of an "All" run) must not + # linger under this one's progress. + self.error_message = "" + self._book_error = "" self.convert_started = self.convert_started or self._now() if self.server == "ready": self.server = "processing" @@ -231,15 +237,30 @@ class RunView(ScreenView): if self.server in ("ready", "processing"): self.server = "processing" elif kind == "chunk_failed": - self.error_message = (f"chunk {event.get('chunk')}/" - f"{event.get('total')} failed") + # The converter emits book_done(ok=False) for a chunk failure + # with no error of its own, so remember the reason here for + # that results row. The live message names the model (an "All" + # run stamps its events) and the server's error detail. + detail = event.get("error") or "" + self._book_error = detail or (f"chunk {event.get('chunk')}/" + f"{event.get('total')} failed") + message = self._book_error + if detail: + message = (f"chunk {event.get('chunk')}/" + f"{event.get('total')} failed — {detail}") + if event.get("model"): + message = f"{event['model']}: {message}" + self.error_message = message if self.server in ("ready", "processing"): self.server = "ready" elif kind == "book_done": self.book_results.append((event.get("name") or "?", bool(event.get("ok")), list(event.get("files") or []), - "", event.get("model"))) + "" if event.get("ok") + else (event.get("error") + or self._book_error), + event.get("model"))) elif kind == "book_failed": self.book_results.append((event.get("name") or "?", False, list(event.get("files") or []), @@ -256,7 +277,8 @@ class RunView(ScreenView): elif total and ok >= total and not self.error_message: self._finish("done") else: - self.error_message = self.error_message or \ + self.error_message = self._failure_summary(total) or \ + self.error_message or \ f"{total - ok} of {total} book(s) failed" self._finish("error") elif kind == "error": @@ -510,6 +532,26 @@ class RunView(ScreenView): f"{self.config.log_path}") return "\n".join(lines) + def _failure_summary(self, total: int) -> str: + """The run-level failure line for the terminal "done" screen. + + Names every book that produced no audiobook (the generating model + on an "All" run, the book file otherwise) instead of leaving a + stale per-chunk message as the run's headline. Capped so the two + detail lines stay readable; the [FAIL] result rows below carry the + full list with each failure's reason. Empty when the results say + every book succeeded (the count comes from the events, not the + rows — see the caller's fallback). + """ + failed = [(model or name) for name, ok, _files, _error, model + in self.book_results if not ok] + if not failed: + return "" + shown = ", ".join(failed[:5]) + if len(failed) > 5: + shown += f", … +{len(failed) - 5} more" + return f"{len(failed)} of {total} book(s) failed: {shown}" + _server_stopped_confirmed = False # ------------------------------------------------------------------ @@ -665,16 +707,24 @@ class RunView(ScreenView): _text(scr, theme, y, value_x, _fit(result, value_w), theme.get(kind, theme["body"])) y += 1 - for name, ok, _files, _error, model in self.book_results[:5]: + # Failed rows first (stable sort keeps each group in completion + # order): with an "All" run's dozens of results the failures must + # not require scrolling to find. A failed row carries its reason + # (the server's error, remembered from the chunk_failed event). + rows = sorted(self.book_results, + key=lambda result: 1 if result[1] else 0) + for name, ok, _files, error, model in rows[:5]: mark = "[OK] " if ok else "[FAIL]" label = f"{name} — {model}" if model else name + if not ok and error: + label = f"{label}: {error}" _text(scr, theme, y, value_x, _fit(f"{mark} {label}", value_w), theme["ok"] if ok else theme["err"]) y += 1 - if len(self.book_results) > 5: + if len(rows) > 5: _text(scr, theme, y, value_x, - _fit(f"... and {len(self.book_results) - 5} more", + _fit(f"... and {len(rows) - 5} more", value_w), theme["dim"]) y += 1 if self.phase == "error": |
