fix(dubbing): retain actionable native failure diagnostics
This commit is contained in:
@@ -16,6 +16,10 @@ the frozen-backend fallback mirror it for their toolchains.
|
||||
|
||||
- Handle missing Electron signing credentials and retry packaging fixes without moving release tags (#2157)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Show scrubbed native error tails and exit codes for failed dubbing extraction (#2167)
|
||||
|
||||
## [0.5.3] — 2026-09-17
|
||||
|
||||
**Highlights**
|
||||
|
||||
@@ -64,6 +64,17 @@ from core.logging_utils import log_safe
|
||||
|
||||
logger = logging.getLogger("omnivoice.dub_pipeline")
|
||||
|
||||
|
||||
def _media_process_error(tool: str, returncode: int, stderr: bytes) -> str:
|
||||
"""Keep the actionable end of native diagnostics without leaking paths."""
|
||||
from core.scrub import scrub_text
|
||||
detail = scrub_text(stderr.decode(errors="replace")).strip()
|
||||
tail = detail[-2000:]
|
||||
if len(detail) > 2000:
|
||||
tail = "…" + tail
|
||||
return f"{tool} exited with code {returncode}" + (f": {tail}" if tail else ". No diagnostic output.")
|
||||
|
||||
|
||||
# ── Module-level state ──────────────────────────────────────────────────────
|
||||
# These used to live in dub_core.py. The router now re-exports them for
|
||||
# backward compat during the transition.
|
||||
@@ -1326,7 +1337,7 @@ async def ingest_pipeline(
|
||||
"-ar", "16000", "-ac", "1", audio_path, "-y",
|
||||
])
|
||||
if p.returncode != 0:
|
||||
msg = (stderr.decode(errors="replace") or f"ffmpeg returned exit code {p.returncode}").strip()[:500]
|
||||
msg = _media_process_error("FFmpeg", p.returncode, stderr)
|
||||
raise Exception(msg)
|
||||
# Second, FULL-QUALITY extraction for source separation. audio.wav
|
||||
# is deliberately 16 kHz mono — that's what ASR wants — but Demucs
|
||||
@@ -1476,7 +1487,7 @@ async def ingest_pipeline(
|
||||
elif evt[0] == "done":
|
||||
rc, stderr_full = evt[1], evt[2]
|
||||
if rc != 0:
|
||||
raise Exception(stderr_full.decode(errors="replace")[:500])
|
||||
raise Exception(_media_process_error("Demucs", rc, stderr_full))
|
||||
# Stems land under the INPUT's basename ("audio_hq" when the
|
||||
# full-quality extraction succeeded, "audio" on its fallback).
|
||||
demucs_out = os.path.join(
|
||||
|
||||
@@ -1148,3 +1148,7 @@ remove the app binary itself are in
|
||||
[docs/install/uninstall.md](uninstall.md).
|
||||
|
||||
**Linked issue:** [#1089](https://github.com/debpalash/VoiceStudio/issues/1089)
|
||||
|
||||
### Dubbing extraction fails
|
||||
|
||||
Extraction errors show the FFmpeg exit code and the end of its diagnostics, with private paths scrubbed. Use the final error line to distinguish missing audio streams, unsupported inputs, permissions, or disk errors. A version banner alone does not identify the cause; include the final diagnostic and source format when reporting a failure.
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import json
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
from services import dub_pipeline
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_extract_error_preserves_failure_after_long_banner(tmp_path, monkeypatch):
|
||||
stderr = ("ffmpeg version configuration " * 100 + "\n/home/private/media/secret.mp4: No audio stream found").encode()
|
||||
async def run_proc(args):
|
||||
return SimpleNamespace(returncode=1), b"", stderr
|
||||
monkeypatch.setattr(dub_pipeline, "find_ffmpeg", lambda: "ffmpeg")
|
||||
monkeypatch.setattr(dub_pipeline, "run_proc_factory", lambda job: run_proc)
|
||||
events = [event async for event in dub_pipeline.ingest_pipeline(
|
||||
"diagnostic", str(tmp_path), {"kind": "upload", "path": str(tmp_path / "input.mp4")},
|
||||
)]
|
||||
output = "\n".join(events)
|
||||
assert "No audio stream found" in output
|
||||
assert "code 1" in output
|
||||
assert "/home/private/" not in output
|
||||
|
||||
|
||||
def test_empty_native_diagnostic_retains_exit_code():
|
||||
assert "code 7" in dub_pipeline._media_process_error("FFmpeg", 7, b"")
|
||||
Reference in New Issue
Block a user