SecondEar — 给 Agent 一双能听懂长视频的耳朵。
把一个 B 站公开视频链接交给 Agent,SecondEar 会先读取视频信息,再按需取得原生字幕或只下载音频并在本地转写。Agent 拿到带时间戳的字幕后,就能总结长视频、围绕某个时间点讨论,或直接交付字幕文件。
第一版只支持 B 站公开视频。它不使用 Cookie,也不绕过登录、大会员、充电、地区、DRM 或风控限制。
在手机上的 Codex 或其他 Agent 中直接发送:
https://www.bilibili.com/video/BVxxxxxxxxx
Agent 先执行只读检查,不下载媒体:
second-ear inspect --json 'https://www.bilibili.com/video/BVxxxxxxxxx'确认视频后,Agent 会问你想总结、讨论还是拿字幕。比如回复“总结前 10 分钟”,它会执行:
second-ear transcribe 'https://www.bilibili.com/video/BVxxxxxxxxx' \
--range 00:00-10:00 --json命令返回 transcript.txt、transcript.srt 和本次运行记录的路径;同目录还会生成结构化的 transcript.json。再次处理同一分 P、范围、后端与模型时会复用已完成的字幕缓存。
B 站链接 → inspect 元数据 → 尝试原生字幕 → 仅下载所需音频 → 本地 ASR → 字幕缓存 → Agent 总结/讨论
- 优先使用视频公开提供的原生字幕;没有可用字幕时才进入本地 ASR。
- 只需要字幕时不下载视频画面;范围转写只请求所选时间段的音频。
- 默认在成功后删除临时音频,只保留字幕文件和诊断日志;传入
--keep-audio才保留音频。 - 不把音频或字幕发送给外部 ASR 服务。首次准备模型需要联网下载模型,读取 B 站内容也需要联网。
当前只提供 GitHub 源码安装,暂不发布 PyPI。需要:
- Python
>=3.11,<3.13 ffmpeg与ffprobe>=6.1- macOS Apple Silicon,或 Linux x86_64
uv(推荐安装方式)
跨平台支持的安装方式是检出源码并使用仓库 lockfile。这样 Linux x86_64 会保留 CPU-only PyTorch 索引和已锁定的依赖解析:
git clone https://github.com/yearth/SecondEar.git
cd SecondEar
uv sync --frozen --dev先检查环境。doctor 只读,不会安装依赖或下载模型;首次运行时看到 model_cache: missing 属于正常现象。
uv run second-ear doctor --json再完成一次冷启动:下载固定的本地模型快照,并用仓库自带的普通话短音频做真实 smoke test。
uv run second-ear prepare --json后续在仓库目录内用 uv run second-ear ...。Agent 不在该目录时,可以固定调用:
uv run --project /absolute/path/to/SecondEar second-ear inspect --json URL其中 /absolute/path/to/SecondEar 替换为实际检出路径。第一版不以直接 Git URL 的
uv tool install 作为跨平台安装方式,因为它不会采用本仓库的
[tool.uv.sources] 和 lockfile,Linux 上可能解析到非 CPU-only 的 PyTorch 包。
模型下载只发生在首次准备或本地模型缓存被清理后。之后 prepare 会复用模型,但仍会运行 smoke test;日常转写直接读取本地模型缓存,不会再经历首次下载等待。JSON 结果包含 model_cache_hit、model_prepare_seconds、smoke_test_seconds、total_seconds 和 record,同一份脱敏记录会原子写入 ${SECONDEAR_HOME:-.secondear}/prepare.json,便于之后核对首次准备耗时。
- macOS / Apple Silicon:已在本机实测。 使用
mlx-community/whisper-small-mlx-4bit,通过 MLX 在 Apple 芯片上本地运行。 - Linux / x86_64 CPU:代码支持,尚未在真实 Linux 机器验收。 使用 FunASR
iic/SenseVoiceSmall,并配套本地 VAD 与标点模型。现阶段不要把它理解为已验证的 Linux 承诺。 - 其他平台:不支持。
doctor会报告unsupported。
后端和模型由平台确定。第一版不提供运行时换模型,也不自动升级 yt-dlp。
GitHub Actions 在 Ubuntu、Python 3.11/3.12 上执行固定 lockfile 的 lint 和离线测试;默认 CI 明确排除 live 标记,不访问 B 站,也不下载 ASR 模型。当前仓库配置可本地复现为:
uv sync --frozen --dev
uv run ruff check .
uv run pytest -m "not live" -v真实 B 站集成测试是显式 opt-in 的本地验收,默认会被 pytest 跳过。准备好当前平台的模型后运行:
uv run second-ear prepare --json
SECONDEAR_LIVE_TEST=1 uv run pytest tests/test_live_bilibili.py -v测试默认使用一个公开 B 站视频的 00:30-01:30;可通过 BILIBILI_TEST_PUBLIC_URL 覆盖链接。不要在自动 CI 中开启它。macOS Apple Silicon 已执行真实 doctor、prepare、B 站范围测试和 10 分钟转写验收;Linux x86_64 仍是代码支持、尚未在真实 Linux 实机验收。
检查链接及多 P 信息:
second-ear inspect --json URL转写完整的已选视频或分 P:
second-ear transcribe URL --full --json转写一个时间范围(支持秒、MM:SS 或 HH:MM:SS):
second-ear transcribe URL --range 06:30-12:30 --json附加选项:
--keep-audio:成功后保留本次下载的音频。--force:忽略已完成的字幕缓存并重新处理。--json:输出适合 Agent 消费的结构化结果。
仓库根目录的 SKILL.md 定义了 Agent 应遵循的流程,核心边界是:
- 只有链接时,先
second-ear inspect --json URL,再询问是总结、讨论还是拿字幕;inspect 阶段不下载、不转写。 - 用户已说清总结、讨论、字幕或时间范围时,不重复询问意图;但 URL 没有
?p=N且本轮尚未确认元数据时,在首次转写前仍只读 inspect 一次,以识别多 P。 - 多 P 视频未通过
?p=N选中分 P 时,列出分 P 并且只询问选择哪一 P,保留用户已经说清的意图;单 P、已有?p=N或本轮已确认元数据时直接继续,不反复 inspect。 - 总结默认处理完整的已选视频或分 P;围绕时间点讨论时默认取前后各 3 分钟;字幕可取完整内容或指定范围。
- 仅在失败或用户追问耗时时读取运行日志,不主动发送冗余过程汇报。
默认数据目录是执行命令时当前目录下的 .secondear/;设置 SECONDEAR_HOME 可以改到其他位置。
${SECONDEAR_HOME:-.secondear}/
├── prepare.json # 模型缓存命中、准备、smoke 与总耗时
├── bilibili/<bvid>/p<n>/<range>/<backend-model>/
│ ├── transcript.txt
│ ├── transcript.srt
│ ├── transcript.json
│ └── complete.json
├── runs/run-*/
│ ├── run.json
│ ├── run.log
│ ├── commands.log
│ └── workspace/ # --keep-audio、原生字幕或失败产物可能留在这里
└── run.log # 独立 inspect 等命令的默认命令日志
transcribe --json 返回的 run 字段指向对应 run.json。转写失败或需要解释耗时时,先按这个返回路径读取 run.json,不要硬编码 .secondear,这样才能兼容自定义 SECONDEAR_HOME;同目录的 run.log 是阶段、耗时、缓存命中和稳定错误类别的摘要。只有需要定位命令级根因时,再读取同目录的 commands.log。
首次模型准备与转写是两个独立流程:prepare.json 记录模型缓存命中、模型准备、smoke test 与准备总耗时;转写的 run.json 记录音频下载、本地 ASR、清理与转写总耗时。Agent 回答首次准备为何耗时时,应读取 prepare --json 返回的 record,而不是在转写日志中寻找冷启动阶段。
commands.log 和独立 inspect 使用的 ${SECONDEAR_HOME:-.secondear}/run.log 会记录已脱敏的命令、stdout 与 stderr。脱敏会处理已知凭证和 URL 查询串,但日志仍可能包含视频标题、元数据、字幕文本或转写工具输出;不要把日志当作绝对不含视频内容的文件,也不要未经检查就对外分享。
SecondEar 当前的安全边界是受信任的单用户、同 UID、本地 CLI。运行目录会采用受限权限并防护常见的路径替换,但恶意同 UID 进程与不受信任的进程内插件不属于当前威胁模型。不要在不受信任的共享运行环境里处理私有媒体。
- 仅支持 B 站标准视频链接,公开能力也只承诺 B 站公开视频。
- 遇到多 P 且链接没有
?p=N时,inspect会列出分 P 并要求选择;把?p=2之类的参数加到链接后再处理。 - 登录、大会员、充电、地区、DRM 或风控限制不会被绕过;SecondEar 不接收、提取或注入 Cookie。
MODEL_NOT_PREPARED:运行second-ear prepare --json。DEPENDENCY_MISSING或doctor非 ready:确认 Python、ffmpeg/ffprobe 和平台依赖满足上面的版本要求。transcribe其他失败:先读取 JSON 返回的run路径,再按需查看同目录run.log和commands.log;独立inspect失败则查看${SECONDEAR_HOME:-.secondear}/run.log。必要时用--force排除旧缓存,但不要自动升级yt-dlp。
其他视频网站支持不在第一版承诺范围。阿里云 ASR 只记录为未来可选方案,当前没有实现,也不会在本地流程中被调用。
项目代码使用 MIT License。
smoke test 使用的 assets/smoke/mandarin.wav 来自 Google FLEURS,按 CC BY 4.0 单独再分发,不受 MIT License 覆盖;来源、署名、许可链接和 SHA-256 见 assets/smoke/NOTICE.md。