Chrome MV3 Tab Capture + 飞书妙记 + 企业微信 aibot:一个端到端直播录音 AI 整理推送工作流

0 阅读1分钟

Chrome MV3 Tab Capture + 飞书妙记 + 企业微信 aibot:一个端到端直播录音 AI 整理推送工作流

一个开发者想用工具链把"录播 → AI 转写 → 推到团队群"全自动化时会遇到的真实问题:每个环节都有坑。本文按一条端到端流水线组织——从录制 webm,到 ASR 出文字稿,到最终 push 给企业微信——记 6 个核心踩坑全过程,附带两个 CLI 小细节。

TL;DR

  • :Chrome MV3 Tab Capture API(用 chrome.tabs.getMediaStreamId)+ offscreen document 跑 MediaRecorder
  • :ffmpeg → 飞书妙记 ASR(lark-cli 触发)
  • :lark-cli 拉智能纪要(摘要 + 章节时间轴 + 关键词)
  • :wecom-cli aibot send → 企业微信智能机器人 → 群/个人
  • :30 行 Python 脚本 douyin-flow.py 把四段合成一条命令
  • 耗时:单场 46 分钟直播,从录完到团队群收到结构化推送 ≈ 3 分钟

全链路

录 (Chrome 扩展)         转 (ffmpeg + 飞书妙记)         读 (lark-cli)         推 (wecom-cli)
───────────────   →      ──────────────       →       ──────────    →     ──────────
chrome.tabs                ffmpeg -ac 1 -ar            minutes +detail           aibot send
.getMediaStreamId()        8000 -b:a 16k               --summary                markdown
                  ↓        ↓                            --chapter                  ↓
webm                      ≤5MB mp3                     --keyword           企业微信群
                  ↓        ↓                                  ↓                (或个人 ID)
                  飞书云盘上传                       智能纪要
                  ↓                                       ↓
                  触发 ASR                       {summary, chapters[]}
                  ↓                                       ↓
                  飞书妙记智能纪要                  ─────  →  ─────
                  (1~3 分钟)

1. 录制

这一段把"空气里的声音"变成 webm 文件。

工具链

  • chrome.tabs.getMediaStreamId() —— MV3 推荐 Tab Capture 入口
  • Chrome MV3 manifest v3 —— 扩展必须用 MV3
  • chrome.offscreen —— 后台跑 MediaRecorder 的"不可见 tab"
  • MediaRecorder (Opus in WebM) —— 把 MediaStream 编码成 webm blob

关键代码

// service-worker.js — MV3 正确写法
const streamId = await chrome.tabs.getMediaStreamId(tabId);

const stream = await navigator.mediaDevices.getUserMedia({
  audio: {
    mandatory: { chromeMediaSource: 'tab', chromeMediaSourceId: streamId }
  }
});

const mediaRecorder = new MediaRecorder(stream, {
  mimeType: 'audio/webm;codecs=opus'
});
mediaRecorder.ondataavailable = (ev) => chunks.push(ev.data);
mediaRecorder.start(1000); // 每秒一片

这一段踩到的 3 个坑

坑 ① Chrome MV3 service worker 不持久

MV3 把 service worker 改成 event-driven,5 分钟 idle 必杀。把录制状态放 service worker 模块作用域,重启就丢。第二次点按钮判断"是否在录"永远 false,导致反复报 Cannot capture a tab with an active stream

修法offscreen document 当 source of truth。offscreen 是 Chrome 内部常驻 HTML 页面,比 SW 寿命长,重启也不丢。所有 state 全在 offscreen 内部,service worker 只做转发。

坑 ② tabCapture 老 API 路径

MV3 下 chrome.tabCapture 整个 deprecated。chrome.tabCapture.getMediaStreamId 还是能用,但官方推荐路径是 chrome.tabs.getMediaStreamId(tabId)

修法:用新的 chrome.tabs.getMediaStreamId,streamId 拿去 navigator.mediaDevices.getUserMedia({audio: {mandatory: {chromeMediaSource: 'tab', chromeMediaSourceId}}})

// 错 → deprecated
const streamId = await chrome.tabCapture.getMediaStreamId({ targetTabId: tabId });

// 对 → MV3 推荐
const streamId = await chrome.tabs.getMediaStreamId(tabId);
坑 ③ MediaRecorder 出错时 stream 残留

MediaRecorder 在直播流中断、目标 tab 静音、Chrome 内部失败时会进入 error 状态。但默认没有 onerror handler——stream 残留 → 下次录制报 "active stream"。

修法:补 mediaRecorder.onerror 自动 cleanup + 每次开始前 force-stop 兜底 + 设最大时长(1 小时)防止 Chrome bug 累积让内存爆炸。

外加一个隐藏陷阱:chrome.downloads.download() 在 service worker / popup 里能用,offscreen 里不行——offscreen 是真 HTML 页面,直接用标准 <a download>.click()

const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = filename;
document.body.appendChild(a);
a.click();

2. 转写

这一段把 webm 变成结构化文字稿。

工具链

  • ffmpeg —— webm → mp3
  • 飞书妙记 —— 字节跳动自家 ASR,中文顶级
  • lark-cli —— 飞书官方 Rust CLI(含 AI Agent Skills)

关键命令

# ① 转 mp3 — 8kHz mono 16kbps (46 分直播 ≈5MB)
ffmpeg -y -loglevel error -i in.webm -ac 1 -ar 8000 -b:a 16k out.mp3

# ② 上传飞书云盘 + 触发 ASR
lark-cli drive +upload --file out.mp3 --as user --format json
lark-cli minutes +upload --file-token <drive_file_token> --as user --format json

这一段的核心坑

坑 ④ 飞书 Drive 单文件 20MB 限制
errcode 1061043, "file size beyond limit"

直播 mp3 默认 64kbps → 46 分钟直播约 22MB 超过 20MB。降一档:

ffmpeg -i in.webm -ac 1 -ar 8000 -b:a 16k out.mp3

8kHz 采样对中文语音 ASR 足够(飞书内部模型 16kHz 但能 upsample),文件大小砍到 1/4。这条对所有 ASR 引擎都通用


3. 读取

这一段把 ASR 出的原始文字稿变成结构化纪要。

工具

  • lark-cli minutes +detail —— 拿转写后的智能纪要
  • AI 自动产出:摘要 + 章节 + 关键词 + 待办
  • 输出:JSON + 文件 dump 到 --output-dir

关键命令

lark-cli minutes +detail \
  --minute-tokens <minute_token> \
  --summary --chapter --keyword --transcript \
  --output-dir ./minutes --overwrite \
  --as user --format json

返回结构:

{
  "data": {
    "minutes": [{
      "note_id": "...",
      "artifacts": {
        "summary": "...",
        "chapters": [{"start_ms": 0, "title": "...", "summary_content": "..."}],
        "keywords": [...]
      }
    }]
  }
}

这一段的核心坑

坑 ⑤ API 字段嵌套变化
// 老版本
{data: {minute: {token: "..."}}}
// 当前版本
{data: {minute_token: "..."}}  ← 直接是字符串

跑脚本第一遍踩过——data['minute']['token'] 拿到 undefined。兼容写法:

mt = data.get('data', {}).get('minute_token') \
  or data.get('data', {}).get('minute', {}).get('token')

4. 推送

这一段把结构化纪要发到企业微信。

工具链

  • 企业微信智能机器人(aibot)—— 客户端能 @ 触发 + 服务端能 push
  • wecom-cli —— 企业微信官方 Rust CLI(含 12 个 AI Agent Skills)

关键命令

wecom-cli message aibot send \
  --chat-id "<企业微信 userid 或 chat_id>" \
  --msg-type markdown \
  --markdown '{"content":"## 📊 直播自动整理\n..."}'

这一段踩到的 2 个坑

坑 ⑥ 个人微信 API 不开放 + 内容超 4096 字节静默截断

个人微信

全行业死结。个人号 API 永久没开放。最终路径:企业微信智能机器人 → 推到企微群 → 群里的外部微信成员在个人微信端看到推送(腾讯官方「企业微信联系人」通道)。但不在群里 → 不装企微 → 收不到

4096 字节静默截断

智能纪要内容长会超过 4096 字节——超过的部分被静默截断,没有错误提示。

修法

content = f"## 直播自动整理\n\n摘要(前 1500 字):\n{summary[:1500]}\n\n" + \
          '\n'.join(f"- {ch['title']}" for ch in chapters[:5]) + \
          f"\n\n[查看完整妙记](https://feishu.cn/minutes/{note_id})"

拆条(摘要 + 章节两条),或整体截断到 ~4000 字节 + 末行加飞书妙记链接让用户去浏览完整版。

CLI 小坑合集(不是核心,但踩过)
  • lark-cli path 安全--file 必须相对路径,abs 路径一票否决
  • wecom-cli aibot send 不支持 --format:传 --format json 会报 "unexpected argument"
  • aibot 不能 push 非 session 外部 userid:Bot 必须先在群里互动过

串联:douyin-flow.py(30 行核心)

import json, subprocess, time, shutil
from pathlib import Path

# ① ffmpeg — 8kHz/16kbps mono
mp3 = f"{Path(webm).stem}-small.mp3"
subprocess.run(['ffmpeg','-y','-loglevel','error','-i',webm,
                '-ac','1','-ar','8000','-b:a','16k', mp3])

# ② lark-cli — 上传 + 触发 ASR
shutil.copy(mp3, '.')
ft = json.loads(subprocess.run(['lark-cli','drive','+upload','--file',mp3,
                                '--as','user','--format','json'], capture_output=True).stdout)['data']['file_token']
mt = json.loads(subprocess.run(['lark-cli','minutes','+upload','--file-token',ft,
                                '--as','user','--format','json'], capture_output=True).stdout)['data']['minute_token']

# ③ 等转写完(轮询 20s,~3 分钟;分钟内轮询一次 detail)
for _ in range(15):
    d = json.loads(subprocess.run(['lark-cli','minutes','+detail',
                                    '--minute-tokens', mt, '--summary','--chapter','--keyword',
                                    '--as','user','--output-dir','./minutes','--overwrite'],
                                   capture_output=True).stdout)
    if d.get('ok') and d['data']['minutes'][0]['artifacts'].get('summary'):
        arts = d['data']['minutes'][0]['artifacts']
        break
    time.sleep(20)

# ④ wecom-cli — 推送给企业微信
content = f"## 直播自动整理\n\n摘要:{arts['summary'][:1500]}\n\n" + \
          '\n'.join(f"- {ch['title']}" for ch in arts.get('chapters', []))
wecom = shutil.which('wecom-cli')
subprocess.run([wecom,'message','aibot','send','--chat-id','<userid>',
                '--msg-type','markdown','--markdown',
                json.dumps({'content':content}, ensure_ascii=False)])

跑一条命令:

python douyin-flow.py douyin-xxx.webm

~3 分钟后你企业微信里就有一条结构化推送。


适合谁 / 不适合谁

✅ 适合⚠️ 不适合❌ 不适合
每天/每周固定直播、会议、讲座1 小时内多场直播想绕过腾讯限制推个人微信
想自动整理成结构化笔记强实时推送需求单场直播 < 1 分钟
能接受企微 vs 个人微信的限制多语言直播(中文最佳)完全离线环境

总结

工具链最不显眼的价值不是「自动化」——是让一个原本只能一个人靠手工的活儿,可以同时给 10 个人用。你录了一场公开直播,把它分享给团队——这件事以前要你自己听、自己整理、自己转告同事。链路通之后,主播专心讲,团队专心听

完整工具链清单:

  • lark-cli —— 飞书官方 Rust CLI(含 12 个 AI Agent Skills)
  • wecom-cli —— 企业微信官方 Rust CLI(含 12 个 AI Agent Skills)
  • ffmpeg —— 视频处理老牌工具
  • Chrome MV3 Tab Capture + offscreen —— 浏览器原生录音
  • 企业微信智能机器人 aibot —— 2026 年合规推送的最优路径

每个坑都有一两个修复帖可参考,欢迎在评论里分享你的版本。

如果对你有用,欢迎点赞 + 收藏 + 在评论里分享你踩到的其他坑。