mirror of
https://github.com/linyqh/NarratoAI.git
synced 2026-07-22 14:08:19 +00:00
feat(subtitle): 新增 FireRedASR2 本地 ASR 后端支持
添加 FireRedASR2 本地 ASR 转写后端的完整支持: 1. 新增配置参数与数据模型字段 2. 更新示例配置文件,添加默认本地服务地址 3. 完善任务服务中的转写逻辑,支持 FireRedASR 后端 4. 更新 WebUI 界面,新增对应配置选项 5. 补充中英文多语言翻译 6. 新增本地 FireRedASR 服务的单元测试
This commit is contained in:
parent
e6e39d2dcd
commit
34d5532119
@ -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
|
||||
|
||||
@ -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 = "",
|
||||
|
||||
@ -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", "")
|
||||
|
||||
@ -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"])
|
||||
|
||||
|
||||
@ -110,10 +110,11 @@
|
||||
|
||||
[fun_asr]
|
||||
# Fun-ASR 字幕转录配置
|
||||
# backend = "local" 使用本地 FunASR-Pack API;backend = "bailian" 使用阿里百炼在线 fun-asr
|
||||
# backend = "local" 使用本地 FunASR-Pack API;backend = "firered" 使用本地 FireRedASR2-AED-Pack API;backend = "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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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", "")
|
||||
|
||||
@ -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}",
|
||||
|
||||
@ -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}",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user