1. 从一段视频到一份文字稿:Trae 音视频工具要解决的真实问题
你手里有一段 40 分钟的会议录屏,或者一节网课视频,现在需要把它变成可编辑、可搜索的文字稿。传统做法是打开某个在线转换网站,上传、等待、下载,遇到大文件还要付费;要么就是本地装一堆工具,ffmpeg 抽音频、再找个识别接口,中间鉴权、格式、路径全是坑。AI编程的价值就在这里:用 Trae 这类 AI IDE,把「视频抽音频 + 语音识别出文本」这条链路一次性写成一个小工具,以后每次处理视频只要点一下。
这篇要做的音视频工具,核心能力就两件事:第一,从任意 mp4/mov/mkv 里把音轨提取成识别接口能吃的格式;第二,把音频送进语音识别模型,拿回带时间戳或纯文本的结果。适合谁?适合经常要整理会议记录、课程笔记、播客文稿的开发者,也适合想练手 AI编程、又不想从零啃音视频编解码的初学者。整个流程我实测下来,一小时内跑通完全没问题,前提是把鉴权通道统一好——这也是后面要重点讲的 TaoToken 统一 Key 的作用。
先说清楚技术选型,避免你走弯路。音频提取用 ffmpeg,这是音视频处理的事实标准,命令行一条就能抽轨,稳定且跨平台。识别环节走 HTTP 接口,用统一的 API 通道做鉴权,这样模型换了、供应商换了,你的代码不用大改。Trae 负责把这两段逻辑串起来,生成项目骨架、写调用代码、补错误处理。你不需要精通 Electron 或前端框架,只要能把配置填对、把命令跑通。
我试过用最朴素的方式:一个 Node.js 脚本 + 两个函数,一个调 ffmpeg,一个发识别请求。Trae 的 Builder 模式能根据你的自然语言描述直接生成这套结构,你负责审代码、改参数、验证结果。下面按「先跑通、再优化」的顺序展开,每一步都给可复制的命令和配置,你跟着做就能看到文字稿输出。
2. TaoToken 统一 Key 与 API 通道:音视频工具鉴权的前置准备
做音视频工具,最烦的不是抽音频,而是识别接口的鉴权管理。你可能会遇到:这个模型用一家平台的 Key,换个模型又要换另一家的 Key,代码里散落一堆 base_url 和 token,改起来容易漏。TaoToken 的思路是把这些统一到一个 API 通道上,你只维护一个 Key、一个 Base URL,模型通过 Model ID 切换。对音视频工具这种「识别模型可能随时换」的场景,特别省事。
先明确三个要素,后面配置里反复用到:
| 要素 | 值 | 说明 |
|---|---|---|
| Base URL | https://taotoken.net/api | 所有请求走这个入口,不要加多余路径 |
| API Key | 在控制台创建 | 形如sk-...,只显示一次,及时保存 |
| Model ID | 按识别模型填 | 例如语音识别类模型的具体标识 |
获取 Key 的入口在控制台的 API Keys 页面,创建后复制到环境变量里,别硬编码进代码。模型对话能力可以在模型对话页先试一下通道是否通,确认没问题再写进项目。如果你后面要做长期的编码或 Agent 类任务,Coding Plan 页有更系统的方案,但本篇的音视频工具用按量调用就够了。
这里要强调一个容易踩的坑:Base URL 到底带不带/v1。不同工具对路径的处理不一样,有的 SDK 会自动补/v1,有的不会。稳妥做法是先用 curl 直接打一次,确认返回正常,再决定代码里怎么填。下面这段就是最小验证命令,把$TAOTOKEN_API_KEY换成你自己的 Key:
curl https://taotoken.net/api/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "你的识别模型ID", "messages": [{"role": "user", "content": "ping"}] }'返回里能看到choices字段,说明通道和 Key 都没问题。如果返回 401,先查 Key 有没有复制全、有没有多余空格;如果返回路径错误,检查是不是多写了/v1。这一步过了,再进 Trae 写项目,能省掉大量「到底是代码错还是鉴权错」的排查时间。
把 Key 放进环境变量,Linux/macOS 用export TAOTOKEN_API_KEY=sk-xxx,Windows PowerShell 用$env:TAOTOKEN_API_KEY="sk-xxx"。项目里读环境变量,不要写死在源码。这样你换 Key、换模型都不用动代码,也避免把密钥提交到仓库。前置准备就这些,接下来进 Trae 建项目。
3. 在 Trae 里搭出可复制的音视频工具项目配置
打开 Trae,新建一个空目录作为项目根,比如av-transcriber。用 Builder 模式描述需求:「创建一个 Node.js 项目,用 ffmpeg 从视频提取音频为 wav,再调用 OpenAI 兼容接口做语音识别,输出文本文件」。Trae 会生成package.json、入口脚本和基本目录结构。你要做的是把配置改对,尤其是鉴权部分。
先看package.json,依赖只需要很少几个。ffmpeg 建议用系统安装的二进制,通过child_process调用,比装 npm 包更可控:
{ "name": "av-transcriber", "version": "1.0.0", "type": "module", "scripts": { "start": "node src/index.js" }, "dependencies": { "dotenv": "^16.4.5" } }项目里放一个.env文件管理配置,注意这个文件要加进.gitignore:
TAOTOKEN_API_KEY=sk-你的Key TAOTOKEN_BASE_URL=https://taotoken.net/api ASR_MODEL=你的识别模型ID然后是核心的音频提取函数。ffmpeg 抽音频的关键参数是-vn(不要视频流)、-ac 1(单声道,识别够用且体积小)、-ar 16000(16kHz 采样率,多数识别模型的标准输入)。输出 wav 格式兼容性最好:
import { execFile } from 'node:child_process'; import { promisify } from 'node:util'; const execFileAsync = promisify(execFile); export async function extractAudio(videoPath, audioPath) { const args = [ '-y', '-i', videoPath, '-vn', '-ac', '1', '-ar', '16000', '-f', 'wav', audioPath, ]; const { stderr } = await execFileAsync('ffmpeg', args); return { audioPath, log: stderr }; }识别调用部分,用统一的 Base URL 和 Key,请求体按 OpenAI 兼容格式组织。注意音频文件如果较大,很多接口对单次请求有大小限制,超过就先切片,这个后面排障会讲:
import fs from 'node:fs'; export async function transcribe(audioPath) { const apiKey = process.env.TAOTOKEN_API_KEY; const baseUrl = process.env.TAOTOKEN_BASE_URL; const model = process.env.ASR_MODEL; const audioBuffer = fs.readFileSync(audioPath); const form = new FormData(); form.append('file', new Blob([audioBuffer]), 'audio.wav'); form.append('model', model); const res = await fetch(`${baseUrl}/audio/transcriptions`, { method: 'POST', headers: { Authorization: `Bearer ${apiKey}` }, body: form, }); if (!res.ok) { const errText = await res.text(); throw new Error(`识别失败 ${res.status}: ${errText}`); } const data = await res.json(); return data.text; }入口脚本把两步串起来,读命令行参数,输出到同名.txt:
import 'dotenv/config'; import path from 'node:path'; import fs from 'node:fs'; import { extractAudio } from './audio.js'; import { transcribe } from './asr.js'; const videoPath = process.argv[2]; if (!videoPath) { console.error('用法: node src/index.js <视频路径>'); process.exit(1); } const audioPath = path.join('/tmp', `${Date.now()}.wav`); await extractAudio(videoPath, audioPath); const text = await transcribe(audioPath); const outPath = videoPath.replace(/\.[^.]+$/, '') + '.txt'; fs.writeFileSync(outPath, text, 'utf8'); console.log(`完成,文本已写入 ${outPath}`);这套配置的好处是:鉴权只有一处,模型 ID 在.env里改,ffmpeg 参数集中在一个函数。Trae 生成初版后,你重点检查 Base URL 有没有被自动补成/v1、FormData 的字段名是不是file和model,这两处最容易出错。配置对了,下一步就是跑通验证。
4. 端到端验证:从视频到文本的完整请求与成功结果
配置写完,拿一段真实视频跑一遍。准备一个 1 到 2 分钟的小视频,太长的话第一次验证等待久、出错也不好定位。假设文件叫demo.mp4,执行:
node src/index.js ./demo.mp4正常的话,你会先看到 ffmpeg 的输出日志(被我们捕获在log里,没打印出来),然后脚本等待识别接口返回,最后终端打印完成,文本已写入 ./demo.txt。打开demo.txt,应该能看到视频里说的话被转成了文字。如果视频是中文,识别结果里可能有少量标点缺失或同音字,这是模型特性,不影响整体可用。
想更直观地确认音频提取这一步对不对,可以单独跑一次 ffmpeg,把中间产物留下来听一下:
ffmpeg -y -i ./demo.mp4 -vn -ac 1 -ar 16000 -f wav ./demo.wav用播放器打开demo.wav,能听到清晰人声就说明抽轨没问题。这一步能帮你把「音频问题」和「识别问题」分开:如果 wav 正常但识别报错,那就是接口或鉴权的事;如果 wav 本身没声音,那是 ffmpeg 参数或源视频音轨的问题。
识别接口返回的典型成功结构长这样,你可以对照自己的返回确认字段:
{ "text": "大家好,今天我们讲一下音视频工具的实现思路。", "duration": 12.4 }拿到text就说明端到端通了。如果返回里没有text而是别的字段名,说明模型接口格式和预期不一致,需要按实际返回调整取值。验证阶段建议先用短音频,确认链路通,再换长视频。长视频会遇到请求体过大、超时等问题,这些放到下一节排障里说。
成功跑通后,你可以把输出改成带时间戳的格式,方便定位原文位置;也可以批量处理一个目录下的视频。这些扩展都不难,核心链路已经稳定。记住验证顺序:先 curl 验通道,再 ffmpeg 验抽轨,最后脚本验串联。任何一步失败,问题范围都能立刻缩小。
5. 常见报错排查:401、local proxy failed、reading choices 与 OAuth
音视频工具跑不通,九成问题集中在这几类报错上。逐个说清楚现象、原因和解法。
401 Unauthorized。现象是识别请求返回 401,或 curl 验证时就失败。原因通常是 Key 不对、没带Bearer前缀、或者环境变量没加载。检查.env是否被dotenv正确读取,console.log(process.env.TAOTOKEN_API_KEY?.slice(0,6))看前几位对不对。注意 Key 前后不要有空格和换行,复制时容易带上。如果 Key 确认没问题还是 401,检查请求头是不是写成了Authorization: sk-xxx,正确格式是Bearer sk-xxx。
local proxy failed。这个报错一般出现在你的运行环境配置了本地网络代理,而请求没走通。现象是连接被拒绝或超时。处理方式是检查系统或终端的代理环境变量(HTTP_PROXY、HTTPS_PROXY),如果不需要就清掉;如果确实需要网络配置,确保它指向可用的地址。这类问题和你代码无关,是运行环境层面的,先排除环境再怀疑代码。
reading 'choices'。典型报错是Cannot read properties of undefined (reading 'choices')。这说明返回体里没有choices字段,代码却直接取了。原因可能是:接口返回的是错误对象(比如{"error": {...}}),或者你用的识别接口返回结构本来就不是 chat 格式。解法是先打印完整返回体再取值:
const data = await res.json(); console.log(JSON.stringify(data, null, 2));看清楚实际结构再改取值逻辑。语音识别接口通常返回text,不是choices,别把对话接口和识别接口的返回格式搞混。
OAuth 相关报错。如果你用的是需要 OAuth 授权的工具链(比如某些 CLI 或 IDE 插件),可能会遇到 token 过期、授权失败。这类问题的通用解法是重新走一遍授权流程,确认授权范围包含你要调用的能力。如果你在 Trae 里配置了外部工具,检查它的认证方式是不是和你的 Key 体系一致,不一致就统一到 API Key 方式,减少变量。
还有一个高频问题:音频太大导致请求失败或超时。多数识别接口对单次上传有大小限制,长视频抽出的 wav 可能几十上百 MB。解法是用 ffmpeg 按时间切片,比如每 5 分钟一段,分别识别再拼接:
ffmpeg -y -i ./demo.mp4 -vn -ac 1 -ar 16000 -f segment -segment_time 300 ./chunk_%03d.wav切片后循环调用识别函数,把结果按顺序拼起来。注意切片边界可能切断句子,拼接时按段落处理即可,不影响可用性。
排查的核心思路是分层:通道层(curl 能不能通)、抽轨层(wav 有没有声音)、代码层(返回结构对不对)。每层单独验证,不要混在一起猜。把这几类报错处理完,你的音视频工具基本就稳了。
6. 把统一 Key 用起来:音视频工具的后续扩展与接入入口
链路跑通后,这个音视频工具还能往几个方向扩。一是批量处理,遍历目录下所有视频,输出对应的 txt,适合整理一整个课程包。二是加一个简单的界面,用 Trae 生成一个本地网页,拖拽视频进去就出文字,体验会好很多。三是把识别结果做后处理,比如自动分段、提取关键词、生成摘要,这些都可以复用同一个 API 通道,模型 ID 换一下就行。
统一 Key 的价值在扩展时会越来越明显:你新增一个摘要功能,不用再去申请新平台的账号、配新的鉴权,直接在现有通道上加一次调用。模型对话页可以先试不同模型的效果,确认合适再写进代码。接入文档里有各接口的详细参数,遇到字段不确定时对照查。如果你要把这套能力做成长期跑的编码或 Agent 任务,Coding Plan 页有更省心的方案。
需要提醒的是,音视频工具处理的是你自己的素材,注意版权和隐私,别把敏感录音随便传到不可控的地方。本地抽音频、按需调用识别,是相对可控的做法。工具本身只是提效,怎么用还是看场景。
回到最开始那个问题:视频转文字这件事,用 AI编程 加统一 API 通道,一小时内确实能做出一个自己用的小工具。核心不是写多少代码,而是把 ffmpeg 抽轨、识别接口调用、鉴权配置这三件事串对。你按上面的步骤走一遍,遇到报错对照第五节排查,基本都能解决。跑通之后,把.env里的模型 ID 换成你更满意的识别模型,效果还能再调。工具做出来是给自己省时间的,够用就好,别过度设计。