Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

本项目所有重要变更记录于此。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),遵循 [语义化版本](https://semver.org/lang/zh-CN/)。

## [Unreleased]

### Fixed

- **快手 ASR 接口下线后用户看到无信息量的「未知错误」**:快手官方已永久关闭 `ai.kuaishou.com/api/effects/subtitle_generate`(返回 `code=501, msg=效果subtitle_generate禁用`),旧实现默默地把这条 501 错误冒泡出去,前端只能展示「快手 API 返回错误: 未知错误」之类的笼统提示,用户无从得知是该接口本身已下线。`KuaishouTranscriber._submit` 现在直接在入口处抛 `RuntimeError` 并提示用户切换到 bcut 或 Faster Whisper,避免无谓的上传带宽消耗。

## [2.4.4] - 2026-06-23

### Security
Expand Down
39 changes: 6 additions & 33 deletions backend/app/transcriber/kuaishou.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,12 @@ def _load_file(self, file_path: str) -> bytes:

def _submit(self, file_path: str) -> dict:
"""提交识别请求"""
try:
file_binary = self._load_file(file_path)

payload = {
"typeId": "1"
}

# 使用文件名作为上传文件名
file_name = os.path.basename(file_path)
files = [('file', (file_name, file_binary, 'audio/mpeg'))]

logger.info(f"开始向快手API提交请求,文件: {file_name}")
response = requests.post(self.API_URL, data=payload, files=files, timeout=300)
response.raise_for_status() # 检查HTTP错误

result = response.json()
print('result',result)
# 检查快手API返回是否包含错误
if "data" not in result or result.get("code", 0) != 0:
error_msg = f"快手API返回错误: {result.get('message', '未知错误')}"
logger.error(error_msg)
raise Exception(error_msg)

return result

except requests.exceptions.RequestException as e:
error_msg = f"快手ASR请求网络错误: {str(e)}"
logger.error(error_msg)
raise
except Exception as e:
error_msg = f"快手ASR请求处理错误: {str(e)}"
logger.error(error_msg)
raise
# 快手 ASR API 已于 2025 年永久关停 (code=501, msg="效果subtitle_generate禁用"),
# 请使用 bcut(B站必剪)或 fast-whisper(本地)替代。
raise RuntimeError(
"快手 ASR 转写接口已永久关停(快手官方已禁用 subtitle_generate API)。"
"请在「设置 → 音频转写配置」中将转写引擎切换为「必剪(bcut)」或「Faster Whisper(本地)」。"
)

@timeit
def transcript(self, file_path: str) -> TranscriptResult:
Expand Down
49 changes: 49 additions & 0 deletions backend/tests/test_kuaishou_disabled.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""
Coverage for the Kuaishou ASR disabled-state guard.

Background: 快手 (Kuaishou) 关闭了对外开放的 subtitle_generate 语音识别接口,
任何调用都会立刻返回 ``{"code": 501, "msg": "效果subtitle_generate禁用"}``。
旧实现默默地把这条错误抛出去,前端没有针对性的提示,用户只能从
"未知错误" 里猜原因。

本次改动在 KuaishouTranscriber._submit 开头直接抛带操作指引的
``RuntimeError``,而不是花时间把文件 POST 上去再被 501 拒掉。
"""
import pytest

from app.transcriber import kuaishou as kuaishou_module
from app.transcriber.kuaishou import KuaishouTranscriber


def test_kuaishou_submit_raises_clear_error(tmp_path):
"""_submit should raise immediately with a message that names the replacement engines."""
f = tmp_path / "audio.mp3"
f.write_bytes(b"fake")

t = KuaishouTranscriber()
with pytest.raises(RuntimeError) as exc:
t._submit(str(f))
msg = str(exc.value)
# 用户需要能根据这条提示自助切换到 bcut / faster-whisper
assert "快手" in msg or "Kuaishou" in msg
assert "已" in msg or "关闭" in msg or "禁用" in msg
assert "bcut" in msg or "必剪" in msg
assert "whisper" in msg.lower() or "Faster Whisper" in msg


def test_kuaishou_submit_does_not_make_network_call(monkeypatch, tmp_path):
"""短路上线后,不应再发起网络请求 (避免无谓的上传带宽消耗)."""
called = {"n": 0}

def fake_post(*args, **kwargs):
called["n"] += 1
raise AssertionError("submit() should not reach requests.post after the shutdown guard")

monkeypatch.setattr(kuaishou_module.requests, "post", fake_post)
f = tmp_path / "audio.mp3"
f.write_bytes(b"fake")

t = KuaishouTranscriber()
with pytest.raises(RuntimeError):
t._submit(str(f))
assert called["n"] == 0