Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb6457f4f7 | ||
|
|
b06366fcd9 | ||
|
|
7f4cdff169 | ||
|
|
68acce34e3 | ||
|
|
a048b9351b |
@@ -28,6 +28,7 @@ the frozen-backend fallback mirror it for their toolchains.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Dubbing jobs can now reuse every source-language code produced by automatic ASR detection without a 400 error on the next upload (#1737)
|
||||
- Incomplete Sherpa-ONNX model snapshots now self-repair before recognizer startup instead of failing on a missing ONNX file (#1733)
|
||||
- OmniVoice subprocess startup now allows slow packaged Windows Python runtimes to signal readiness before termination (#1711)
|
||||
- SRT files selected during source analysis now wait for speaker cloning, then replace transcript text without losing voices (#1709)
|
||||
|
||||
@@ -518,9 +518,12 @@ _ingest_gen = dub_pipeline.ingest_pipeline
|
||||
#: container so a mislabelled video can't slip past the video-skipping branch.
|
||||
_AUDIO_EXTS = {".wav", ".mp3", ".m4a", ".aac", ".flac", ".ogg", ".opus", ".wma"}
|
||||
|
||||
# Source-language choices exposed by the first-party dub UI. Keeping this an
|
||||
# allow-list rejects language names and private-use BCP-47 tags before they are
|
||||
# persisted as ASR overrides. Values are normalized to lowercase below.
|
||||
# Source-language choices exposed by the first-party dub UI, plus every
|
||||
# language code Whisper can write back after auto-detection. A restored job
|
||||
# may reuse that detected value as the next upload's override, so rejecting our
|
||||
# own persisted codes strands otherwise valid dubbing sessions (#1737).
|
||||
# Keeping this an allow-list still rejects language names and private-use
|
||||
# BCP-47 tags. Values are normalized to lowercase below.
|
||||
_DUB_SOURCE_LANG_CODES = frozenset({
|
||||
"af", "sq", "am", "ar", "hy", "az", "eu", "be", "bn", "bs", "bg",
|
||||
"my", "ca", "cmn-hans", "cmn-hant", "hr", "cs", "da", "nl", "en",
|
||||
@@ -531,6 +534,8 @@ _DUB_SOURCE_LANG_CODES = frozenset({
|
||||
"ru", "sm", "gd", "sr", "sn", "sd", "si", "sk", "sl", "so", "es",
|
||||
"su", "sw", "sv", "tg", "ta", "te", "th", "tr", "uk", "ur", "uz",
|
||||
"vi", "cy", "xh", "yi", "yo", "zu",
|
||||
"as", "ba", "bo", "br", "fo", "lb", "ln", "mg", "nn", "oc", "sa",
|
||||
"tk", "tl", "tt", "yue", "zh",
|
||||
})
|
||||
|
||||
|
||||
@@ -544,6 +549,20 @@ def _source_lang_override(value: str | None) -> str | None:
|
||||
return code
|
||||
|
||||
|
||||
def _detected_source_lang(value: str | None) -> str:
|
||||
"""Normalize an ASR language without truncating valid three-letter codes."""
|
||||
code = (value or "en").split("_", 1)[0].strip().lower()
|
||||
if code in _DUB_SOURCE_LANG_CODES:
|
||||
return code
|
||||
short = code[:2]
|
||||
return short if short in _DUB_SOURCE_LANG_CODES else "en"
|
||||
|
||||
|
||||
def _resolved_source_lang(override: str | None, detected: str | None) -> str:
|
||||
"""Prefer an explicit source while preserving a valid ASR language code."""
|
||||
return override or _detected_source_lang(detected)
|
||||
|
||||
|
||||
@router.post("/dub/upload")
|
||||
async def dub_upload(
|
||||
video: UploadFile = File(...),
|
||||
@@ -1809,9 +1828,9 @@ async def dub_transcribe_stream(
|
||||
except Exception as e:
|
||||
logger.warning("speaker_clone extraction skipped: %s", e)
|
||||
|
||||
job["source_lang"] = job.get("source_lang_override") or (
|
||||
(detected_lang or "en").split("_")[0][:2] or "en"
|
||||
).lower()
|
||||
job["source_lang"] = _resolved_source_lang(
|
||||
job.get("source_lang_override"), detected_lang
|
||||
)
|
||||
job["full_transcript"] = " ".join(s.get("text", "") for s in final_segs)
|
||||
_save_job(job_id, job)
|
||||
|
||||
@@ -2008,9 +2027,9 @@ async def dub_transcribe(job_id: str, num_speakers: Optional[int] = None):
|
||||
except Exception as e:
|
||||
logger.warning("Failed to unload ASR backend: %s", e)
|
||||
|
||||
job["source_lang"] = job.get("source_lang_override") or (
|
||||
(detected_lang or "en").split("_")[0][:2] or "en"
|
||||
).lower()
|
||||
job["source_lang"] = _resolved_source_lang(
|
||||
job.get("source_lang_override"), detected_lang
|
||||
)
|
||||
|
||||
scene_cuts = job.get("scene_cuts") or []
|
||||
segments = segment_transcript(result, duration=job.get("duration", 0.0), scene_cuts=scene_cuts)
|
||||
|
||||
@@ -339,3 +339,22 @@ class TestAudioOnlyDubbing:
|
||||
|
||||
assert response.status_code == 202
|
||||
assert queued[0][5]["source_lang"] == "fr"
|
||||
|
||||
def test_asr_detected_source_languages_can_be_reused_as_overrides(self, app_client):
|
||||
_client, dc, _dx, _tmp = app_client
|
||||
detected_codes = {
|
||||
"as", "ba", "bo", "br", "fo", "lb", "ln", "mg", "nn", "oc",
|
||||
"sa", "tk", "tl", "tt", "yue", "zh",
|
||||
}
|
||||
|
||||
for code in detected_codes:
|
||||
assert dc._source_lang_override(code) == code
|
||||
|
||||
def test_asr_detected_cantonese_code_is_not_truncated(self, app_client):
|
||||
_client, dc, _dx, _tmp = app_client
|
||||
|
||||
assert dc._detected_source_lang("yue") == "yue"
|
||||
assert dc._detected_source_lang("es_ES") == "es"
|
||||
assert dc._detected_source_lang("unknown-language") == "en"
|
||||
assert dc._resolved_source_lang(None, "yue") == "yue"
|
||||
assert dc._resolved_source_lang("fr", "yue") == "fr"
|
||||
|
||||
Reference in New Issue
Block a user