feat(transcribe): Whisper transcription module with Groq→OpenAI fallback (#277)

Adds agent_reach/transcribe.py (download → compress → chunk → transcribe with provider fallback, fully mocked tests). Maintainer follow-up on the branch: wired an agent-reach transcribe CLI subcommand + skill docs so agents can actually invoke it, added the missing configure openai-key branch the error hint referenced, removed two dead static methods. 103 tests pass; wheel-gate clean.
This commit is contained in:
ming
2026-06-10 17:03:37 +10:00
committed by GitHub
parent 9045fee67e
commit 4ca570a39f
8 changed files with 607 additions and 4 deletions
+28 -3
View File
@@ -17,6 +17,7 @@ class YouTubeChannel(Channel):
def can_handle(self, url: str) -> bool:
from urllib.parse import urlparse
d = urlparse(url).netloc.lower()
return "youtube.com" in d or "youtu.be" in d
@@ -40,7 +41,31 @@ class YouTubeChannel(Channel):
has_js_config = "--js-runtimes" in read_utf8_text(ytdlp_config)
if not has_js_config:
return "warn", (
"yt-dlp 已安装但未配置 JS runtime。运行:\n"
f" {render_ytdlp_fix_command()}"
f"yt-dlp 已安装但未配置 JS runtime。运行:\n {render_ytdlp_fix_command()}"
)
return "ok", "可提取视频信息和字幕"
# Surface transcription readiness so `doctor` reports it.
msg = "可提取视频信息和字幕"
if config is not None:
providers = []
if config.is_configured("groq_whisper"):
providers.append("groq")
if config.is_configured("openai_whisper"):
providers.append("openai")
if providers:
if not shutil.which("ffmpeg"):
msg += "(音频转写需安装 ffmpeg"
else:
msg += f",可转写音频({''.join(providers)}"
return "ok", msg
def transcribe(self, url: str, *, provider: str = "auto", config=None) -> str:
"""Download a YouTube video's audio and return its transcript.
Delegates to :func:`agent_reach.transcribe.transcribe`. Imported lazily
so the channel module stays cheap to import for users who never
transcribe.
"""
from agent_reach.transcribe import transcribe as _transcribe
return _transcribe(url, provider=provider, config=config)