feat(subtitle): 新增 FireRedASR2 本地 ASR 后端支持

添加 FireRedASR2 本地 ASR 转写后端的完整支持:
1. 新增配置参数与数据模型字段
2. 更新示例配置文件,添加默认本地服务地址
3. 完善任务服务中的转写逻辑,支持 FireRedASR 后端
4. 更新 WebUI 界面,新增对应配置选项
5. 补充中英文多语言翻译
6. 新增本地 FireRedASR 服务的单元测试
This commit is contained in:
viccy 2026-06-07 17:58:02 +08:00
parent e6e39d2dcd
commit 34d5532119
9 changed files with 331 additions and 28 deletions

View File

@ -201,6 +201,7 @@ class VideoClipParams(BaseModel):
subtitle_auto_transcribe_enabled: bool = False
subtitle_auto_transcribe_backend: str = "local"
subtitle_auto_transcribe_api_url: str = ""
subtitle_auto_transcribe_firered_api_url: str = ""
subtitle_auto_transcribe_api_key: str = ""
subtitle_auto_transcribe_hotword: str = ""
subtitle_auto_transcribe_enable_spk: bool = False

View File

@ -24,6 +24,7 @@ TRANSCRIPTION_URL = f"{DASHSCOPE_BASE_URL}/api/v1/services/audio/asr/transcripti
TASK_URL_TEMPLATE = f"{DASHSCOPE_BASE_URL}/api/v1/tasks/{{task_id}}"
MODEL_NAME = "fun-asr"
LOCAL_FUN_ASR_API_URL = "http://127.0.0.1:7860"
LOCAL_FIRERED_ASR_API_URL = "http://127.0.0.1:7867"
TERMINAL_FAILED_STATUSES = {"FAILED", "CANCELED", "UNKNOWN"}
PUNCTUATION_BREAKS = set(",。!?;,.!?;")
@ -131,7 +132,11 @@ def _absolute_local_download_url(api_url: str, download_url: str) -> str:
return urljoin(f"{_local_base_url(api_url)}/", download_url)
def _raise_for_local_http(response: requests.Response, action: str) -> None:
def _raise_for_local_http(
response: requests.Response,
action: str,
service_name: str = "本地 FunASR-Pack 服务",
) -> None:
status_code = getattr(response, "status_code", 200)
if status_code and status_code >= 400:
detail = ""
@ -142,16 +147,20 @@ def _raise_for_local_http(response: requests.Response, action: str) -> None:
except Exception:
detail = ""
suffix = f": {detail}" if detail else ""
raise FunAsrError(f"{action}失败{suffix},请确认本地 FunASR-Pack 服务可用")
raise FunAsrError(f"{action}失败{suffix},请确认{service_name}可用")
try:
response.raise_for_status()
except Exception as exc:
raise FunAsrError(f"{action}失败,请确认本地 FunASR-Pack 服务可用") from exc
raise FunAsrError(f"{action}失败,请确认{service_name}可用") from exc
def _local_json(response: requests.Response, action: str) -> dict[str, Any]:
_raise_for_local_http(response, action)
def _local_json(
response: requests.Response,
action: str,
service_name: str = "本地 FunASR-Pack 服务",
) -> dict[str, Any]:
_raise_for_local_http(response, action, service_name=service_name)
try:
data = response.json()
except Exception as exc:
@ -520,6 +529,19 @@ def request_local_fun_asr_health(api_url: str = LOCAL_FUN_ASR_API_URL, session=r
return _local_json(response, "检查本地 FunASR-Pack 服务")
def request_local_firered_asr_health(
api_url: str = LOCAL_FIRERED_ASR_API_URL,
session=requests,
) -> dict[str, Any]:
"""Fetch FireRedASR2-AED-Pack health metadata from the local service."""
response = _session_get(session, f"{_local_base_url(api_url)}/health", timeout=10)
return _local_json(
response,
"检查本地 FireRedASR2-AED-Pack 服务",
service_name="本地 FireRedASR2-AED-Pack 服务",
)
def request_local_fun_asr(
local_file: str,
api_url: str = LOCAL_FUN_ASR_API_URL,
@ -548,21 +570,61 @@ def request_local_fun_asr(
return _local_json(response, "调用本地 FunASR-Pack ASR API")
def request_local_firered_asr(
local_file: str,
api_url: str = LOCAL_FIRERED_ASR_API_URL,
enable_vad: Optional[bool] = True,
enable_lid: Optional[bool] = True,
enable_punc: Optional[bool] = True,
return_timestamp: Optional[bool] = True,
timeout: float = 600.0,
session=requests,
) -> dict[str, Any]:
"""Call the local FireRedASR2-AED-Pack `/asr` API and return its JSON result."""
_require_local_file(local_file)
data: dict[str, str] = {}
options = {
"enable_vad": enable_vad,
"enable_lid": enable_lid,
"enable_punc": enable_punc,
"return_timestamp": return_timestamp,
}
for key, value in options.items():
if value is not None:
data[key] = "true" if value else "false"
with open(local_file, "rb") as file_obj:
files = {"file": (_safe_upload_name(local_file), file_obj)}
response = _session_post(
session,
_local_asr_url(api_url),
data=data,
files=files,
timeout=timeout,
)
return _local_json(
response,
"调用本地 FireRedASR2-AED-Pack ASR API",
service_name="本地 FireRedASR2-AED-Pack 服务",
)
def download_local_srt(
download_url: str,
api_url: str = LOCAL_FUN_ASR_API_URL,
subtitle_file: str = "",
session=requests,
service_name: str = "本地 FunASR-Pack 服务",
) -> str:
"""Download an SRT exposed by FunASR-Pack and save it as a NarratoAI subtitle."""
absolute_url = _absolute_local_download_url(api_url, download_url)
if not absolute_url:
raise FunAsrError("本地 FunASR-Pack 结果缺少 SRT 下载地址")
response = _session_get(session, absolute_url, timeout=60)
_raise_for_local_http(response, "下载本地 FunASR-Pack SRT")
_raise_for_local_http(response, "下载本地 SRT", service_name=service_name)
srt_content = _response_text(response)
if not srt_content.strip():
raise FunAsrError("本地 FunASR-Pack 返回了空 SRT")
raise FunAsrError(f"{service_name}返回了空 SRT")
return write_srt_file(srt_content, subtitle_file)
@ -665,6 +727,45 @@ def local_fun_asr_result_to_srt(
return "\n".join(lines).rstrip() + "\n"
def firered_asr_result_to_srt(result_json: dict[str, Any]) -> str:
"""Convert a FireRedASR2-AED-Pack JSON response into SRT when no SRT URL is returned."""
blocks: list[dict[str, Any]] = []
sentences = result_json.get("sentences")
if isinstance(sentences, list):
for sentence in sentences:
if not isinstance(sentence, dict):
continue
text = str(sentence.get("text") or "").strip()
if not text:
continue
start = sentence.get("start_ms", sentence.get("begin_time", sentence.get("start_time", 0)))
end = sentence.get("end_ms", sentence.get("end_time"))
start_ms = _timestamp_ms(start, "firered.sentence.start_ms")
end_ms = _timestamp_ms(end, "firered.sentence.end_ms") if end is not None else start_ms + 500
blocks.append({"start": start_ms, "end": end_ms, "text": text})
if not blocks:
return local_fun_asr_result_to_srt(result_json)
lines = []
for index, block in enumerate(blocks, start=1):
lines.append(_srt_block(index, block["start"], block["end"], block["text"]))
return "\n".join(lines).rstrip() + "\n"
def _get_local_srt_download_url(result_json: dict[str, Any]) -> str:
downloads = result_json.get("downloads") or {}
if isinstance(downloads, dict):
download_url = downloads.get("srt")
if download_url:
return str(download_url)
for key in ("srt_url", "srt_download_url", "download_url"):
download_url = result_json.get(key)
if download_url:
return str(download_url)
return ""
def create_with_local_fun_asr(
local_file: str,
subtitle_file: str = "",
@ -689,8 +790,7 @@ def create_with_local_fun_asr(
if isinstance(srt_file, str) and srt_file and os.path.isfile(srt_file):
output_file = copy_srt_file(srt_file, subtitle_file)
else:
downloads = result_json.get("downloads") or {}
download_url = downloads.get("srt") if isinstance(downloads, dict) else ""
download_url = _get_local_srt_download_url(result_json)
if download_url:
output_file = download_local_srt(
download_url,
@ -710,6 +810,56 @@ def create_with_local_fun_asr(
raise FunAsrError("本地 FunASR-Pack 字幕转写失败,请检查服务地址、文件或模型状态") from exc
def create_with_local_firered_asr(
local_file: str,
subtitle_file: str = "",
api_url: str = LOCAL_FIRERED_ASR_API_URL,
enable_vad: Optional[bool] = True,
enable_lid: Optional[bool] = True,
enable_punc: Optional[bool] = True,
return_timestamp: Optional[bool] = True,
timeout: float = 600.0,
session=requests,
) -> Optional[str]:
"""Create an SRT file through a locally running FireRedASR2-AED-Pack API."""
service_name = "本地 FireRedASR2-AED-Pack 服务"
try:
result_json = request_local_firered_asr(
local_file=local_file,
api_url=api_url,
enable_vad=enable_vad,
enable_lid=enable_lid,
enable_punc=enable_punc,
return_timestamp=return_timestamp,
timeout=timeout,
session=session,
)
srt_file = result_json.get("srt_file")
if isinstance(srt_file, str) and srt_file and os.path.isfile(srt_file):
output_file = copy_srt_file(srt_file, subtitle_file)
else:
download_url = _get_local_srt_download_url(result_json)
if download_url:
output_file = download_local_srt(
download_url,
api_url=api_url,
subtitle_file=subtitle_file,
session=session,
service_name=service_name,
)
else:
srt_content = firered_asr_result_to_srt(result_json)
output_file = write_srt_file(srt_content, subtitle_file)
logger.info(f"本地 FireRedASR2-AED-Pack 字幕文件已生成: {output_file}")
return output_file
except FunAsrError:
raise
except Exception as exc:
raise FunAsrError("本地ASR字幕转写失败请检查 FireRedASR2-AED-Pack 服务地址、文件或模型状态") from exc
def create_with_fun_asr(
local_file: str,
subtitle_file: str = "",

View File

@ -24,7 +24,7 @@ def _is_auto_transcription_enabled(params: VideoClipParams) -> bool:
def _get_auto_transcription_backend(params: VideoClipParams) -> str:
backend = str(getattr(params, "subtitle_auto_transcribe_backend", "") or "").strip().lower()
if backend not in {"local", "bailian"}:
if backend not in {"local", "firered", "bailian"}:
backend = "local"
return backend
@ -80,6 +80,19 @@ def _transcribe_final_video(task_id: str, video_path: str, params: VideoClipPara
hotword=str(getattr(params, "subtitle_auto_transcribe_hotword", "") or "").strip(),
enable_spk=bool(getattr(params, "subtitle_auto_transcribe_enable_spk", False)),
)
elif backend == "firered":
api_url = str(
getattr(params, "subtitle_auto_transcribe_firered_api_url", "")
or config.fun_asr.get("firered_api_url", fun_asr_subtitle.LOCAL_FIRERED_ASR_API_URL)
).strip()
if not api_url:
raise ValueError("请先输入本地ASR API 地址")
generated_path = fun_asr_subtitle.create_with_local_firered_asr(
local_file=video_path,
subtitle_file=subtitle_file,
api_url=api_url,
)
else:
api_key = str(
getattr(params, "subtitle_auto_transcribe_api_key", "")

View File

@ -481,6 +481,91 @@ class LocalFunAsrServiceTests(unittest.TestCase):
self.assertIn("世界。", srt)
class LocalFireRedAsrServiceTests(unittest.TestCase):
def test_request_local_firered_asr_posts_file_and_options(self):
class LocalSession:
def __init__(self):
self.calls = []
def post(self, url, **kwargs):
self.calls.append(("POST", url, kwargs))
return FakeResponse({"text": "你好", "srt_url": "/outputs/out.srt"})
with tempfile.TemporaryDirectory() as tmp_dir:
local_file = Path(tmp_dir) / "audio.wav"
local_file.write_bytes(b"audio")
session = LocalSession()
result = fasr.request_local_firered_asr(
str(local_file),
api_url="127.0.0.1:7867",
enable_vad=True,
enable_lid=False,
enable_punc=True,
return_timestamp=True,
timeout=456,
session=session,
)
self.assertEqual("你好", result["text"])
self.assertEqual("POST", session.calls[0][0])
self.assertEqual("http://127.0.0.1:7867/asr", session.calls[0][1])
self.assertEqual(
{
"enable_vad": "true",
"enable_lid": "false",
"enable_punc": "true",
"return_timestamp": "true",
},
session.calls[0][2]["data"],
)
self.assertEqual(456, session.calls[0][2]["timeout"])
self.assertIn("file", session.calls[0][2]["files"])
def test_create_with_local_firered_asr_downloads_srt_url(self):
class LocalSession:
def __init__(self):
self.calls = []
def post(self, url, **kwargs):
self.calls.append(("POST", url, kwargs))
return FakeResponse({"text": "你好", "srt_url": "/outputs/result.srt"})
def get(self, url, **kwargs):
self.calls.append(("GET", url, kwargs))
return FakeResponse(text="1\n00:00:00,000 --> 00:00:01,000\n你好\n")
with tempfile.TemporaryDirectory() as tmp_dir:
local_file = Path(tmp_dir) / "audio.wav"
local_file.write_bytes(b"audio")
subtitle_file = Path(tmp_dir) / "out.srt"
session = LocalSession()
result_path = fasr.create_with_local_firered_asr(
str(local_file),
subtitle_file=str(subtitle_file),
api_url="http://127.0.0.1:7867",
session=session,
)
self.assertEqual(str(subtitle_file), result_path)
self.assertEqual("http://127.0.0.1:7867/outputs/result.srt", session.calls[1][1])
self.assertIn("你好", subtitle_file.read_text(encoding="utf-8"))
def test_firered_asr_result_to_srt_uses_sentence_timestamps(self):
result = {
"sentences": [
{"text": "你好。", "start_ms": 40, "end_ms": 900},
{"text": "欢迎观看。", "start_ms": 900, "end_ms": 2100},
]
}
srt = fasr.firered_asr_result_to_srt(result)
self.assertIn("1\n00:00:00,040 --> 00:00:00,900\n你好。", srt)
self.assertIn("2\n00:00:00,900 --> 00:00:02,100\n欢迎观看。", srt)
class FunAsrConfigTests(unittest.TestCase):
def test_save_config_persists_fun_asr_section(self):
original_config_file = cfg.config_file
@ -503,6 +588,7 @@ class FunAsrConfigTests(unittest.TestCase):
config_data = tomllib.loads(Path("config.example.toml").read_text(encoding="utf-8"))
self.assertEqual("local", config_data["fun_asr"]["backend"])
self.assertEqual("http://127.0.0.1:7860", config_data["fun_asr"]["api_url"])
self.assertEqual("http://127.0.0.1:7867", config_data["fun_asr"]["firered_api_url"])
self.assertEqual("fun-asr", config_data["fun_asr"]["model"])
self.assertIn("api_key", config_data["fun_asr"])

View File

@ -110,10 +110,11 @@
[fun_asr]
# Fun-ASR 字幕转录配置
# backend = "local" 使用本地 FunASR-Pack APIbackend = "bailian" 使用阿里百炼在线 fun-asr
# backend = "local" 使用本地 FunASR-Pack APIbackend = "firered" 使用本地 FireRedASR2-AED-Pack APIbackend = "bailian" 使用阿里百炼在线 fun-asr
auto_transcribe_enabled = false
backend = "local"
api_url = "http://127.0.0.1:7860"
firered_api_url = "http://127.0.0.1:7867"
hotword = ""
enable_spk = false
# 使用阿里百炼在线 fun-asr 时,访问 https://bailian.console.aliyun.com/?tab=model#/api-key 获取 API Key

View File

@ -996,11 +996,12 @@ def render_fun_asr_transcription(tr):
backend_options = {
tr("Local FunASR-Pack API"): "local",
tr("Local FireRedASR API"): "firered",
tr("Ali Bailian Online Fun-ASR"): "bailian",
tr("上传字幕文件"): "upload",
}
saved_backend = str(config.fun_asr.get("backend", "")).strip().lower()
if saved_backend not in {"local", "bailian", "upload"}:
if saved_backend not in {"local", "firered", "bailian", "upload"}:
saved_backend = (
"bailian"
if config.fun_asr.get("api_key") and not config.fun_asr.get("api_url")
@ -1012,6 +1013,7 @@ def render_fun_asr_transcription(tr):
backend = saved_backend
api_key = ""
api_url = config.fun_asr.get("api_url", fun_asr_subtitle.LOCAL_FUN_ASR_API_URL)
firered_api_url = config.fun_asr.get("firered_api_url", fun_asr_subtitle.LOCAL_FIRERED_ASR_API_URL)
hotword = config.fun_asr.get("hotword", "")
enable_spk = bool(config.fun_asr.get("enable_spk", False))
media_paths = _selected_video_paths()
@ -1020,11 +1022,10 @@ def render_fun_asr_transcription(tr):
with subtitle_cols[0]:
with st.expander(tr("Ali Bailian Fun-ASR Subtitle Transcription"), expanded=False):
backend_label = st.radio(
backend_label = st.selectbox(
tr("Subtitle Processing Method"),
options=backend_labels,
index=backend_values.index(saved_backend),
horizontal=True,
key="fun_asr_backend",
)
backend = backend_options[backend_label]
@ -1051,6 +1052,14 @@ def render_fun_asr_transcription(tr):
help=tr("Enable speaker diarization Help"),
key="fun_asr_enable_spk",
)
elif backend == "firered":
st.caption(tr("Local FireRed-ASR upload caption"))
firered_api_url = st.text_input(
tr("Local FireRedASR API URL"),
value=firered_api_url,
help=tr("Local FireRedASR API URL Help"),
key="fun_asr_firered_api_url",
)
else:
st.caption(tr("Fun-ASR upload caption"))
st.markdown(
@ -1166,6 +1175,10 @@ def render_fun_asr_transcription(tr):
clear_fun_asr_subtitle_state()
st.error(tr("Please enter local FunASR-Pack API URL"))
return
if backend == "firered" and not str(firered_api_url).strip():
clear_fun_asr_subtitle_state()
st.error(tr("Please enter local FireRedASR API URL"))
return
missing_paths = [path for path in media_paths if not os.path.exists(path)]
if not media_paths or missing_paths:
clear_fun_asr_subtitle_state()
@ -1184,22 +1197,25 @@ def render_fun_asr_transcription(tr):
config.fun_asr["backend"] = backend
config.fun_asr["api_url"] = str(api_url).strip()
config.fun_asr["firered_api_url"] = str(firered_api_url).strip()
config.fun_asr["api_key"] = api_key.strip()
config.fun_asr["hotword"] = str(hotword).strip()
config.fun_asr["enable_spk"] = bool(enable_spk)
config.fun_asr["model"] = "fun-asr"
config.save_config()
spinner_text = (
tr("Transcribing with local FunASR-Pack...")
if backend == "local"
else tr("Transcribing with Fun-ASR...")
)
if backend == "local":
spinner_text = tr("Transcribing with local FunASR-Pack...")
elif backend == "firered":
spinner_text = tr("Transcribing with local FireRedASR...")
else:
spinner_text = tr("Transcribing with Fun-ASR...")
with st.spinner(spinner_text):
progress_bar = st.progress(0) if len(media_paths) > 1 else None
generated_paths = []
for index, media_path in enumerate(media_paths, start=1):
subtitle_name = f"{os.path.splitext(os.path.basename(media_path))[0]}_fun_asr.srt"
subtitle_suffix = "firered_asr" if backend == "firered" else "fun_asr"
subtitle_name = f"{os.path.splitext(os.path.basename(media_path))[0]}_{subtitle_suffix}.srt"
subtitle_path = _unique_file_path(utils.subtitle_dir(), subtitle_name)
if backend == "local":
@ -1210,6 +1226,12 @@ def render_fun_asr_transcription(tr):
hotword=str(hotword).strip(),
enable_spk=bool(enable_spk),
)
elif backend == "firered":
generated_path = fun_asr_subtitle.create_with_local_firered_asr(
local_file=media_path,
subtitle_file=subtitle_path,
api_url=str(firered_api_url).strip(),
)
else:
generated_path = fun_asr_subtitle.create_with_fun_asr(
local_file=media_path,

View File

@ -457,7 +457,7 @@ def render_subtitle_mask_settings(tr):
def _get_saved_auto_transcribe_backend():
saved_backend = str(config.fun_asr.get("backend", "")).strip().lower()
if saved_backend not in {"local", "bailian"}:
if saved_backend not in {"local", "firered", "bailian"}:
saved_backend = (
"bailian"
if config.fun_asr.get("api_key") and not config.fun_asr.get("api_url")
@ -481,6 +481,7 @@ def render_auto_transcription_settings(tr):
backend = _get_saved_auto_transcribe_backend()
api_url = config.fun_asr.get("api_url", fun_asr_subtitle.LOCAL_FUN_ASR_API_URL)
firered_api_url = config.fun_asr.get("firered_api_url", fun_asr_subtitle.LOCAL_FIRERED_ASR_API_URL)
hotword = config.fun_asr.get("hotword", "")
enable_spk = bool(config.fun_asr.get("enable_spk", False))
api_key = config.fun_asr.get("api_key", "")
@ -488,6 +489,7 @@ def render_auto_transcription_settings(tr):
if not auto_transcribe_enabled:
st.session_state['subtitle_auto_transcribe_backend'] = backend
st.session_state['subtitle_auto_transcribe_api_url'] = api_url
st.session_state['subtitle_auto_transcribe_firered_api_url'] = firered_api_url
st.session_state['subtitle_auto_transcribe_hotword'] = hotword
st.session_state['subtitle_auto_transcribe_enable_spk'] = enable_spk
st.session_state['subtitle_auto_transcribe_api_key'] = api_key
@ -495,17 +497,17 @@ def render_auto_transcription_settings(tr):
backend_options = {
tr("Local FunASR-Pack API"): "local",
tr("Local FireRedASR API"): "firered",
tr("Ali Bailian Online Fun-ASR"): "bailian",
}
backend_values = list(backend_options.values())
backend_labels = list(backend_options.keys())
backend_label = st.radio(
backend_label = st.selectbox(
tr("Subtitle Processing Method"),
options=backend_labels,
index=backend_values.index(backend),
horizontal=True,
key="subtitle_auto_transcribe_backend_radio",
key="subtitle_auto_transcribe_backend_select",
)
backend = backend_options[backend_label]
@ -529,6 +531,14 @@ def render_auto_transcription_settings(tr):
help=tr("Enable speaker diarization Help"),
key="subtitle_auto_transcribe_enable_spk_checkbox",
)
elif backend == "firered":
st.caption(tr("Auto Transcription FireRed Caption"))
firered_api_url = st.text_input(
tr("Local FireRedASR API URL"),
value=firered_api_url,
help=tr("Local FireRedASR API URL Help"),
key="subtitle_auto_transcribe_firered_api_url_input",
)
else:
st.caption(tr("Auto Transcription Online Caption"))
st.markdown(
@ -546,6 +556,7 @@ def render_auto_transcription_settings(tr):
config.fun_asr["backend"] = backend
config.fun_asr["api_url"] = str(api_url).strip()
config.fun_asr["firered_api_url"] = str(firered_api_url).strip()
config.fun_asr["api_key"] = str(api_key).strip()
config.fun_asr["hotword"] = str(hotword).strip()
config.fun_asr["enable_spk"] = bool(enable_spk)
@ -553,6 +564,7 @@ def render_auto_transcription_settings(tr):
st.session_state['subtitle_auto_transcribe_backend'] = backend
st.session_state['subtitle_auto_transcribe_api_url'] = str(api_url).strip()
st.session_state['subtitle_auto_transcribe_firered_api_url'] = str(firered_api_url).strip()
st.session_state['subtitle_auto_transcribe_api_key'] = str(api_key).strip()
st.session_state['subtitle_auto_transcribe_hotword'] = str(hotword).strip()
st.session_state['subtitle_auto_transcribe_enable_spk'] = bool(enable_spk)
@ -692,6 +704,10 @@ def get_subtitle_params():
'subtitle_auto_transcribe_api_url',
config.fun_asr.get("api_url", "")
),
'subtitle_auto_transcribe_firered_api_url': st.session_state.get(
'subtitle_auto_transcribe_firered_api_url',
config.fun_asr.get("firered_api_url", "")
),
'subtitle_auto_transcribe_api_key': st.session_state.get(
'subtitle_auto_transcribe_api_key',
config.fun_asr.get("api_key", "")

View File

@ -414,14 +414,19 @@
"Ali Bailian Fun-ASR Subtitle Transcription": "Subtitle Processing",
"Subtitle Processing Method": "Subtitle Processing Method",
"Fun-ASR Backend": "Fun-ASR Backend",
"Local FunASR-Pack API": "Local",
"Ali Bailian Online Fun-ASR": "Online",
"Local FunASR-Pack API": "FunASR (Local)",
"Local FireRedASR API": "FireRedASR2 (Local)",
"Ali Bailian Online Fun-ASR": "FunASR (Online)",
"Local Fun-ASR upload caption": "The current video above will be converted to SRT subtitles through the locally running FunASR-Pack API.",
"Local FireRed-ASR upload caption": "The current video above will be converted to SRT subtitles through the locally running FireRedASR2-AED-Pack API.",
"Fun-ASR upload caption": "The current video above will be uploaded to temporary Ali Bailian storage and converted to SRT subtitles with fun-asr.",
"Auto Transcription Local Caption": "After the final video is merged, it will be converted to SRT subtitles through the locally running FunASR-Pack API.",
"Auto Transcription FireRed Caption": "After the final video is merged, it will be converted to SRT subtitles through the locally running FireRedASR2-AED-Pack API.",
"Auto Transcription Online Caption": "After the final video is merged, it will be uploaded to temporary Ali Bailian storage and converted to SRT subtitles with fun-asr.",
"Local FunASR-Pack API URL": "Local FunASR-Pack API URL",
"Local FunASR-Pack API URL Help": "For example, http://127.0.0.1:7860. A full /asr endpoint URL is also supported.",
"Local FireRedASR API URL": "Local ASR API URL",
"Local FireRedASR API URL Help": "For example, http://127.0.0.1:7867. A full /asr endpoint URL is also supported.",
"Fun-ASR Hotword": "Hotword",
"Fun-ASR Hotword Help": "Optional hotwords passed to the local FunASR-Pack API.",
"Enable speaker diarization": "Enable speaker diarization",
@ -439,8 +444,10 @@
"Calibrate subtitles": "Calibrate Subtitles",
"Please enter Ali Bailian API Key": "Please enter the Ali Bailian API Key first",
"Please enter local FunASR-Pack API URL": "Please enter the local FunASR-Pack API URL first",
"Please enter local FireRedASR API URL": "Please enter the local ASR API URL first",
"Please upload media to transcribe": "Please upload the audio or video file to transcribe first",
"Transcribing with local FunASR-Pack...": "Transcribing subtitles with local FunASR-Pack, please wait...",
"Transcribing with local FireRedASR...": "Transcribing subtitles with local ASR, please wait...",
"Transcribing with Fun-ASR...": "Transcribing subtitles with Ali Bailian Fun-ASR, please wait...",
"Fun-ASR failed without subtitle file": "Fun-ASR transcription failed: no subtitle file was generated",
"Subtitle transcription succeeded": "Subtitle transcription succeeded: {file}",

View File

@ -365,14 +365,19 @@
"Ali Bailian Fun-ASR Subtitle Transcription": "字幕处理",
"Subtitle Processing Method": "字幕处理方式",
"Fun-ASR Backend": "Fun-ASR 后端",
"Local FunASR-Pack API": "本地转写",
"Ali Bailian Online Fun-ASR": "在线转写",
"Local FunASR-Pack API": "FunASR(本地部署)",
"Local FireRedASR API": "FireRedASR2(本地部署)",
"Ali Bailian Online Fun-ASR": "FunASR(在线服务)",
"Local Fun-ASR upload caption": "将使用上方当前视频,通过本机运行的 FunASR-Pack API 生成 SRT 字幕。",
"Local FireRed-ASR upload caption": "将使用上方当前视频,通过本机运行的 FireRedASR2-AED-Pack API 生成 SRT 字幕。",
"Fun-ASR upload caption": "将使用上方当前视频,自动上传到阿里百炼临时存储并通过 fun-asr 生成 SRT 字幕。",
"Auto Transcription Local Caption": "将在最终视频合并完成后,通过本机运行的 FunASR-Pack API 生成 SRT 字幕。",
"Auto Transcription FireRed Caption": "将在最终视频合并完成后,通过本机运行的 FireRedASR2-AED-Pack API 生成 SRT 字幕。",
"Auto Transcription Online Caption": "将在最终视频合并完成后,自动上传到阿里百炼临时存储并通过 fun-asr 生成 SRT 字幕。",
"Local FunASR-Pack API URL": "本地 FunASR-Pack API 地址",
"Local FunASR-Pack API URL Help": "例如 http://127.0.0.1:7860也可以直接填到 /asr 的完整地址。",
"Local FireRedASR API URL": "本地ASR API 地址",
"Local FireRedASR API URL Help": "例如 http://127.0.0.1:7867也可以直接填到 /asr 的完整地址。",
"Fun-ASR Hotword": "热词",
"Fun-ASR Hotword Help": "可选,传给本地 FunASR-Pack 的热词参数。",
"Enable speaker diarization": "启用说话人分段",
@ -390,8 +395,10 @@
"Calibrate subtitles": "校准字幕",
"Please enter Ali Bailian API Key": "请先输入阿里百炼 API Key",
"Please enter local FunASR-Pack API URL": "请先输入本地 FunASR-Pack API 地址",
"Please enter local FireRedASR API URL": "请先输入本地ASR API 地址",
"Please upload media to transcribe": "请先上传需要转录的音频或视频文件",
"Transcribing with local FunASR-Pack...": "正在使用本地 FunASR-Pack 转写字幕,请稍候...",
"Transcribing with local FireRedASR...": "正在使用本地ASR转写字幕请稍候...",
"Transcribing with Fun-ASR...": "正在使用阿里百炼 Fun-ASR 转写字幕,请稍候...",
"Fun-ASR failed without subtitle file": "Fun-ASR 转写失败:未生成字幕文件",
"Subtitle transcription succeeded": "字幕转写成功: {file}",