Skip to main content

CLI 工具:下载并增强 YouTube 播客字幕,支持 Azure OpenAI 转写与总结

Project description

podcast_transformer

podcast_transformer 是一个命令行工具,用于从 YouTube 视频中抽取字幕,并可选地调用 Azure OpenAI gpt-4o-transcribe-diarize 服务进行说话人分离。输出为包含时间戳、文本与说话人信息的 JSON。

功能特性

  • 基于 youtube-transcript-api 获取时间戳精确到秒的字幕段。
  • 使用 yt_dlp + ffmpeg 下载并转换音频,并提交至 Azure OpenAI 语音转写接口。
  • 支持 B 站等多站点视频音频提取,按照 URL 主机自动设置 Referer 与缓存目录结构。
  • 内置 Android 客户端回退逻辑,即使未配置 cookie 也能规避常见的 403 Forbidden 下载失败。
  • 自动检测超长(超过 Azure 1,500 秒限制)或超大音频并切分成多个片段,逐段提交 Azure,并通过流式返回实时刷新进度条。
  • 通过 gpt-4o-transcribe-diarize 返回的说话人分段信息,将不同说话人合并入字幕。
  • 兼容 Azure OpenAI diarized_json 响应中 response.output[*].content 等多层嵌套结构,自动提取 segments/chunks 字段,即使 YouTube 无字幕也能利用 Azure 转写结果产出文本。
  • 支持通过 --azure-streaming/--no-azure-streaming 控制 Azure 转写是否流式执行;启用时会实时刷新进度条,必要时可设置 PODCAST_TRANSFORMER_DEBUG_PAYLOAD=1 输出原始 chunk 便于排查。
  • 摘要 Markdown 会自动复制一份到 PODCAST_TRANSFORMER_OUTBOX_DIR(默认 ~/Library/Mobile Documents/iCloud~md~obsidian/Documents/Obsidian Vault/010 outbox),便于在 Obsidian 等笔记库中直接浏览。
  • 当 Azure 暂未返回说话人分段时,会退回空说话人列表并继续使用已有字幕,避免 CLI 直接失败。
  • 若视频已提供带时间轴的字幕,默认直接复用字幕并跳过 Azure 说话人分离,避免冗余的音频下载与 ASR 调用;如需强制执行可添加 --force-azure-diarization
  • 可选调用 Azure GPT-5 Pro(默认部署 gpt-5-pro),通过 Responses API 翻译与总结 ASR 片段,可使用 --summary-prompt-file 定制提示词。
  • 支持通过 --summary-prompt-file 指定外部 Prompt 配置文件,无需改动代码即可调整摘要策略。
  • 摘要结果以标准 Markdown 格式输出,包含封面、目录与时间轴表格,并自动写入缓存目录的 summary.md 文件。
  • 自动加载工作目录或 PODCAST_TRANSFORMER_DOTENV 指向的 .env 文件,简化凭据管理。
  • 提供 --clean-cache--check-cache 选项,方便排查与清理缓存。
  • 命令行输出 JSON,可通过 --pretty 选项进行格式化。

安装依赖

如已发布至 PyPI,可直接执行:

pip install podcast-transformer

若从源码安装,可在 podcast_transformer 目录下运行:

pip install .

或使用传统方式:

pip install youtube-transcript-api yt-dlp openai
# 若网络环境需要代理,请额外安装 httpx[socks] 以支持 SOCKS 代理
pip install "httpx[socks]"

或者执行项目提供的 setup_and_run.sh 脚本,它会自动创建虚拟环境并安装必要依赖。

同时需要本地安装 ffmpeg,macOS 可通过 brew install ffmpeg,其他平台请参考官方安装说明。

Azure 配置

  1. 在 Azure 门户中创建 Azure OpenAI 资源,并为 gpt-4o-transcribe-diarize 模型部署一个实例。
  2. 复制终结点、密钥以及 API 版本(未配置时默认 2024-06-01),并在命令行环境设置:
export AZURE_OPENAI_API_KEY="<your-key>"
export AZURE_OPENAI_ENDPOINT="<https://your-resource.openai.azure.com>"
# 可选:指定 API 版本与部署名称
export AZURE_OPENAI_API_VERSION="2025-03-01-preview"
export AZURE_OPENAI_TRANSCRIBE_DEPLOYMENT="gpt-4o-transcribe-diarize"
# chunking_strategy 默认使用 "auto";如需自定义可设置字符串或 JSON:
# export AZURE_OPENAI_CHUNKING_STRATEGY="server_vad"
# export AZURE_OPENAI_CHUNKING_STRATEGY='{"type": "server_vad", "threshold": 0.6}'
# 可选:配置 GPT-5 翻译/总结调用所用的 API 版本与部署名称
export AZURE_OPENAI_SUMMARY_API_VERSION="2025-01-01-preview"
export AZURE_OPENAI_SUMMARY_DEPLOYMENT="gpt-5-pro"
# 可选:覆盖 Responses API 基础地址(默认 <AZURE_OPENAI_ENDPOINT>/openai/v1)
# export AZURE_OPENAI_RESPONSES_BASE_URL="https://region-001.openai.azure.com/openai/v1"

可通过 --max-speakers 对说话人数量做最佳努力限制;超出时会将较小说话人映射到主要说话人之一。

提示:若执行 ./setup_and_run.sh 并包含 --azure-diarization 选项,脚本会在运行前检查 AZURE_OPENAI_API_KEYAZURE_OPENAI_ENDPOINT 是否已设置。

环境变量管理

仓库提供 .env.example。复制后补齐密钥,即可让 CLI 自动加载:

cp .env.example .env

也可设置 PODCAST_TRANSFORMER_DOTENV=/path/to/.env 指向自定义位置,run 函数会在执行时自动读取文件并填充缺失的环境变量(不会覆盖已存在的设置)。

使用方法

# 首次或重复运行均可,脚本会自动复用 .venv
./setup_and_run.sh \
  --url "https://www.youtube.com/watch?v=<video-id>" \
  --language en \
  --fallback-language zh-Hans \
  --clean-cache \
  --azure-diarization \
  --azure-streaming \
  --azure-summary \
  --summary-prompt-file /absolute/path/to/prompt.txt \
  --pretty

如果只需要字幕(无需说话人分离),省略 --azure-diarization 选项即可。若目标视频无所需语言字幕,可通过 --fallback-language 多次指定备用语言。当所有字幕均不可用时,启用 --azure-diarization 会自动调用 Azure OpenAI 完整转写与说话人分离。

默认情况下,即使添加了 --azure-diarization,只要成功获取带时间线的字幕段,CLI 就会直接输出字幕并跳过 Azure 调用;若需要强制执行 Azure 说话人分离,可附加 --force-azure-diarization,或提供 --known-speaker/--known-speaker-name/--max-speakers 参数以触发完整流程。

若希望辅助识别特定说话人,可附加 --known-speaker 名称=音频路径 选项(可多次指定),工具会自动将参照音频转为数据 URL 并传递给 Azure OpenAI。若仅有姓名提示,可使用 --known-speaker-name 姓名 多次指定(例如 --known-speaker-name Alice --known-speaker-name Bob),脚本会将所有姓名通过 known_speaker_names 参数直接发送给 Azure 接口,以提升说话人标签的准确率。

yt_dlp 遭遇无 cookie 时的 403 Forbidden,CLI 会自动改用 Android 客户端参数重新发起下载,并切换到移动端 User-Agent,以提升公开视频的成功率。

提示:非 YouTube URL 暂不具备内建字幕获取能力,若需转写请启用 --azure-diarization 以调用 Azure OpenAI。

当生成的 WAV 超过约 25 分钟(1,500 秒)或 100MB 时,CLI 会在缓存目录下自动生成不超过约 23 分钟的 audio_partXXX.wav 片段并依序调用 Azure,从而绕过 audio duration ... is longer than 1500 seconds 等超限报错;若缓存中仍存在旧的超长片段,工具会自动清理并重新切分。若 Azure 返回空的说话人/转写结果,CLI 会回退为空列表并继续后续流程,可结合原始字幕输出完成后续摘要或导出。

当缓存文件异常或想强制重新下载音频时,可追加 --clean-cache 选项,脚本会在调用任何外部服务前删除当前 URL 的缓存目录。

若仅需检查缓存内容,可使用:

./setup_and_run.sh --url "https://www.youtube.com/watch?v=<video-id>" --check-cache

命令会输出缓存路径、存在的文件列表以及 audio.wav 是否存在。

音频文件与转换后的 WAV 会缓存于 ~/.cache/podcast_transformer/<video_id>/(或通过设置 PODCAST_TRANSFORMER_CACHE_DIR 自定义位置);对于非 YouTube 站点,会在缓存目录中包含域名与 URL 哈希前缀,重复执行时同样复用缓存,避免再次下载。

注意:部分视频仅提供其他语言字幕,脚本会尝试自动翻译为 --language 指定的语言;如仍无法获取,请使用 --fallback-language 指明可用的字幕语言代码(可在报错信息中查看)。

GPT-5 翻译与总结

启用 --azure-summary 选项即可在原始字幕/转写结果基础上,调用 Azure GPT-5(默认部署名 gpt-5)生成翻译与总结,system prompt 详见 SUMMARY_PROMPT。命令示例:

./setup_and_run.sh \
  --url "https://www.youtube.com/watch?v=<video-id>" \
  --language en \
  --azure-streaming \
  --azure-summary \
  --summary-prompt-file ./prompts/summary_prompt.txt

输出 JSON 将新增 summary 字段,内容遵循以下约定:

  • 始终保留原始时间线;若原文非中文,先翻译成中文。
  • 长内容会包含 AbstractKeypoints 与按主题分段的正文,每段不超过约 300 字。
  • 多人对话按说话人分段,保持第一人称述说;专业名词可带原文注释。
  • 同时会在对应视频缓存目录(例如 ~/.cache/podcast_transformer/youtube/<video_id>/summary.md)写入一份结构化 Markdown 文件,含封面标题、目录与时间轴表格;CLI 输出会额外返回 summary_path 方便调用方读取该文件。

若需调整文案风格,可通过 AZURE_OPENAI_SUMMARY_DEPLOYMENT 更换部署,或在调用 CLI 时提供 --summary-prompt-file 指向自定义 prompt 文件;保持为空时则回退到内置的 SUMMARY_PROMPT

调试提示:若需检查 Azure 分段返回的原始数据,可在命令前设置 PODCAST_TRANSFORMER_DEBUG_PAYLOAD=1,缓存目录会生成 debug_payload_*.json 供分析。

示例脚本

快速体验可运行:

./run_example.sh "https://www.youtube.com/watch?v=<video-id>"

脚本会自动加载同目录下的 .env 并调用 setup_and_run.sh

Docker 部署

仓库提供 Dockerfile,可通过以下命令构建镜像:

docker build -t podcast-transformer ./podcast_transformer

运行时挂载缓存目录与 .env

docker run --rm \
  --env-file ./podcast_transformer/.env \
  -v "$HOME/.cache/podcast_transformer:/app/.cache/podcast_transformer" \
  podcast-transformer \
  --url "https://www.youtube.com/watch?v=<video-id>" \
  --language en \
  --pretty

测试

项目根目录(即 podcast_transformer 目录)执行:

PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 pytest test/test_cli.py

若在其父目录运行,可将路径改为 pytest podcast_transformer/test/test_cli.py

限制

  • 需要网络访问 YouTube 以及 Azure OpenAI 服务。
  • Azure OpenAI 识别质量受音频质量、部署规格与配额影响;可根据实际情况调整 --max-speakers
  • 当前实现依赖 ffmpeg 进行音频转码,若本地缺失需提前安装。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

podcast_transformer-0.1.2.tar.gz (45.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

podcast_transformer-0.1.2-py3-none-any.whl (29.9 kB view details)

Uploaded Python 3

File details

Details for the file podcast_transformer-0.1.2.tar.gz.

File metadata

  • Download URL: podcast_transformer-0.1.2.tar.gz
  • Upload date:
  • Size: 45.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for podcast_transformer-0.1.2.tar.gz
Algorithm Hash digest
SHA256 cb291c2e726c6f8cad0455659d7828eb17a2cfa67127b8c8c7f1b2bf9cc13222
MD5 85e9193f5fbd3dc9ffa70f6df87f5802
BLAKE2b-256 86d356e479644c5f0be82003e69d62be9aea34ec28a95ba29ccc5f5fd090757d

See more details on using hashes here.

File details

Details for the file podcast_transformer-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for podcast_transformer-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 12dabc332341bfea5192722c0764ff8e5eac7cf527f3fb7351e579b533d00056
MD5 9a1d4aae58b3fad7c11777875816defa
BLAKE2b-256 f8faad831946ffa8b0c404e445d2eef49664c6fffba12dc1ba18bff0173b6904

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page