Extends the existing parametrized test on top of #2143 to cover every
new normalization branch the function introduces (Chinese Traditional,
Mandarin, zho, in→id, iw→he, fil→tl), and adds a parametrized
ValueError check for empty and whitespace-only input.
This addresses the CodeRabbit quick-win nit on #2143 so its coverage
matches the production branches. All 47 dub_translate tests pass.
An imported or pasted subtitle whose line is just a number — a year, a
score, a street number, a "3 / 2 / 1" countdown — was silently deleted,
and when that line was the cue's only text the whole cue disappeared.
Cue bodies are sliced from a timing line up to the next one, which
swallows the next cue's index. The parser clawed that back by popping
every trailing digit-only line, a rule that cannot tell an index from
numeric dialogue. Three shapes fell out of it:
- the last cue of a file has no next index to pop, so a closing "1999"
was taken for one and the cue was dropped as empty;
- an index-less export has no indices at all, yet still lost its
closing numeric line — and lost it without counting a skip, so the
import reported itself lossless while dropping a line;
- the `while` loop popped digit lines until it hit a non-digit, eating
a multi-line countdown cue whole.
Give back exactly the one line that was swallowed: a single line, only
when a next cue exists to own it, and only in a file that indexes its
cues at all — decided once from the preamble before the first timing
line, since a body of "42" is indistinguishable from an index on its
own. Index detection is ASCII-only, because `str.isdigit()` is also
true for Arabic-Indic and Devanagari numerals, which in a 646-language
dubbing app are dialogue rather than SubRip indices.
Affects both subtitle entry points: POST /dub/import-srt/{job_id} and
POST /dub/parse-subtitle-text.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
On a Tesla T4 the backend exited during the first /generate with no
traceback and no HTTP response, leaving the client with
RemoteDisconnected and every later call with ConnectionRefused. Three
separate defects combined, which is why none of the reporter's
workarounds helped.
1. torch.compile(mode="reduce-overhead") captures CUDA graphs. T4
(sm_75) passed the existing arch gate, so capture was attempted and
aborted the process from inside the native CUDA library — below the
interpreter, where neither the #278 eager-fallback wrapper nor any
except clause can see it. The compile mode is now resolved per GPU:
Ampere (sm_80) and newer keep the cudagraph mode, older cards drop to
the non-cudagraph "default" mode and keep their compiled Inductor
kernels. Fails open on any probe error, so no GPU that works today
loses the optimization. OMNIVOICE_FORCE_CUDAGRAPH=1 restores it.
2. should_torch_compile() never read TORCH_COMPILE_DISABLE. main.py sets
it on win32, build_engine_env injected it into subprocesses, and
docs/install/windows.md tells users to export it — but the in-process
gate ignored it, so the reporter exported the documented variable and
still got "torch.compile applied". The gate now honours
TORCH_COMPILE_DISABLE / TORCHDYNAMO_DISABLE / TORCHINDUCTOR_DISABLE on
every platform, and an env opt-out on the parent propagates to engine
subprocesses. The settings DB path is logged alongside the toggle:
the reporter had three omnivoice.db files and edited one the backend
never opened.
3. Settings -> Performance -> "Disable torch.compile" was rendered
disabled outside Windows in both the Tauri and Electron UIs, so the
one control that would have stopped this was unreachable for the
affected Linux user. The toggle is now live on every platform, and
build_engine_env honours it everywhere rather than only on win32.
Also arms faulthandler before torch is imported, so a fatal native
signal writes the faulting thread's Python stack to backend_err.log
instead of the process vanishing silently. This does not prevent a
crash; it makes one diagnosable. OMNIVOICE_DISABLE_FAULTHANDLER=1 skips
it.
Tests fail before / pass after, verified by stashing the source and
running the new tests against unfixed code. The crash test kills a real
child interpreter with a real SIGSEGV and requires a named Python frame
in the output. test_torch_compile_path_gate's fixture now clears the
compile-disable env vars: main.py setdefaults them on win32, so on a
Windows runner they leaked into os.environ and decided those tests.
Not verified on real hardware — no Turing GPU available. The sm_80 floor
is inferred from the crash report and from docs/hardware-notes-tesla-t4.md,
which already flagged cudagraphs on T4 as attempted by default and never
evaluated.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Argos Translate ships pairs as zh, not Chinese. Passing the UI
label or a tag like cmn-Hans made get_translation_from_codes
return None and every subtitle stayed in the source language.
Fixes#2140
- _ping_while retrieves failures that occur after the consumer disconnects,
preventing "exception was never retrieved" at GC; the early-exit test
covers this case
- stream_cut_backend_alive_local now builds the Settings → Logs → Backend
path from each locale's actual UI labels (`settings.title`,
`settings.logs`, `common.backend`)
- Fix incorrect section names in 15 locales, including ru, de, and zh-TW
Addresses CodeRabbit review on #2138
`_ping_while` runs awaited work as its own task, so a client disconnect
previously cancelled only the ping loop. Reference-text refinement could
continue running while `run_transcribe_guarded` skipped its abandon path
and the stream finalizer unloaded the ASR model underneath it.
Cancel unfinished work on early exit, matching the cancellation behavior
of the bare `await` it replaced. Do not await it in `finally`, which can
also run under `GeneratorExit`.
- **dub_core**: `_ping_while` cancels an unfinished future in `finally`,
covering all seven call sites
- **test**: verify that `_ping_while` cancels work on `aclose()` while
leaving completed work untouched (fail-before / pass-after)
- **CHANGELOG**: add a Highlights entry for the user-visible fix; keep
Fixed entries under `### Fixed` per `CLAUDE.md`
Addresses Greptile P1/P2 on #2138