
Byted Mediakit Voiceover Editing
- 25 installs
- 411 repo stars
- Updated August 4, 2026
- bytedance/agentkit-samples
byted-mediakit-voiceover-editing is a Claude skill that runs a Volcengine AI MediaKit workflow to automatically edit talking-head videos by removing pauses and verbal slips.
About
This skill runs a one-stop Volcengine AI MediaKit workflow for automatically editing talking-head (voiceover) videos. A creator uses it to remove pauses and verbal slips, process audio, and export a cut talking-head video through steps from media setup to a review UI and iterative refinement. Scripts generate candidate cuts via ASR while the agent makes final keep/delete decisions, and it runs in apig, cloud, or fully local mode with automatic downgrade.
- One-stop Volcengine AI MediaKit workflow for automatic talking-head (voiceover) video editing
- Removes pauses and verbal slips via ASR-driven candidate cuts, with a review UI and iterative refinement
- Runs in apig, cloud or fully local (Qwen3-ASR/Demucs/ffmpeg) mode with automatic downgrade
Byted Mediakit Voiceover Editing by the numbers
- 25 all-time installs (skills.sh)
- Ranked #990 of 1,335 Generative Media skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
byted-mediakit-voiceover-editing capabilities & compatibility
Cloud and apig modes need Volcengine AK/SK, a VOD space and ASR keys (billed by Volcengine); local mode runs fully offline with Qwen3-ASR/Demucs/ffmpeg.
- Capabilities
- talking head editing · pause removal · transcription · video editing
- Use cases
- video generation · transcription
- Pricing
- Bring your own API key
What byted-mediakit-voiceover-editing says it does
Volcano Engine AI MediaKit talking-head video editing Skill: a one-stop workflow from environment setup through media management, audio processing, talking-head cuts, video export, review UI, and iter
**优先级**:`apig > cloud > local`。自动检测按此顺序依次检查环境变量,缺参时打印 `.env` 路径与缺失变量列表并自动降级。
**核心原则:脚本提供候选(含 deleted_parts + cleaned_text),Agent 做最终决策。**
npx skills add https://github.com/bytedance/agentkit-samples --skill byted-mediakit-voiceover-editingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 25 |
|---|---|
| repo stars | ★ 411 |
| Last updated | August 4, 2026 |
| Repository | bytedance/agentkit-samples ↗ |
What it does
Automatically cut talking-head videos by removing pauses and verbal slips via Volcengine AI MediaKit.
Who is it for?
Automatically cutting talking-head videos, removing pauses and verbal slips, and exporting the edited result.
Skip if: Videos that are not talking-head footage, since the workflow is built around ASR-driven speech editing.
When should I use this skill?
The user mentions talking-head editing, cutting a talking video, removing pauses, removing verbal slips, or exporting a talking video.
What you get
Produces an automatically cut talking-head video with pauses and slips removed, reviewable in a UI before export.
- automatically edited talking-head video
- review UI with candidate cuts
- exported final video
By the numbers
- three execution modes: apig, cloud, local
- recommended host timeout of 60 minutes
Files
一、模式与凭据
1.1 三种执行模式
| 模式 | 说明 | 所需环境变量 | ASR 方式 |
|---|---|---|---|
| apig | SkillHub 网关代理,Bearer Token 认证 | ARK_SKILL_API_BASE + ARK_SKILL_API_KEY(容器注入)+ VOLC_SPACE_NAME + ASR_API_KEY + ASR_BASE_URL | 豆包语音大模型 |
| cloud | 直连火山引擎 OpenAPI,HMAC 签算 | VOLC_ACCESS_KEY_ID + VOLC_ACCESS_KEY_SECRET + VOLC_SPACE_NAME + ASR_API_KEY + ASR_BASE_URL | 豆包语音大模型 |
| local | 完全本地执行,无需云端服务 | 无(可选 EXECUTION_MODE=local) | Qwen3-ASR 本地推理 |
优先级:apig > cloud > local。自动检测按此顺序依次检查环境变量,缺参时打印 .env 路径与缺失变量列表并自动降级。
1.2 凭据配置
- `.env` 文件位置:
<SKILL_DIR>/.env - 脚本先读进程环境变量,再用
.env补全未设置的项(不覆盖容器注入) ARK_SKILL_*通常由部署容器注入,不必手写到.env- 缺参不阻塞:不使用终端
input()交互,缺参时打印提示信息并自动降级到可用模式 - Agent 推荐用户通过编辑 `.env` 文件或Agent 文件写入工具来配置变量,避免终端粘贴问题
- 安全:控制台创建仅含所需权限的密钥;测试请用独立点播空间;
.env勿提交仓库
1.3 模式意图识别(Agent 必读)
当用户在对话中表达模式切换意图时,Agent 应识别并执行:
| 用户表达 | 识别为 | 操作 |
|---|---|---|
| "用本地模式" / "不走云端" / "离线处理" | EXECUTION_MODE=local | 写入 .env 或传 --mode local |
| "用云端" / "用火山引擎" / "走 AK/SK" | EXECUTION_MODE=cloud | 写入 .env 或传 --mode cloud |
| "走网关" / "用 apig" / "用 SkillHub" | EXECUTION_MODE=apig | 写入 .env 或传 --mode apig |
隔离要求:各任务的模式选择相互独立。一个任务中切换到 local 不应影响另一个任务的模式。Agent 应在每次任务开始时重新检测或遵循用户当次指定。
---
二、执行约束(STRICT — NO EXCEPTIONS)
1. 仅使用以下脚本,禁止创建新脚本 2. 按顺序执行所有步骤,跳步即任务失败 3. 执行任何脚本前必须先 cd <SKILL_DIR>/scripts 4. 每个 CHECKPOINT 必须验证产物后再继续 5. 任何步骤失败必须立即停止并报告,不得继续 6. Step 4/5/6 输出禁止简化版、占位符、示例或省略内容 7. 最终输出必须保持原样,不能做任何修改 8. 审核页是否自动打开由 TALKING_VIDEO_AUTO_EDIT_REVIEW_AUTO_OPEN 决定(强制):Agent 不得额外执行 open/start/xdg-open 等命令 9. 超时设置:音视频处理时长较长,宿主超时时间应设置为 60 分钟
职责分工
| 组件 | 职责 | 不做 |
|---|---|---|
| 脚本(规则引擎) | ASR 优化、候选生成(标记位置+规则置信度+删除建议) | 不做最终删除/保留决策 |
| 宿主 Agent(你) | 语义断句、口癖识别确认、候选复核、最终删除/保留决策 | 不修改脚本 |
核心原则:脚本提供候选(含 deleted_parts + cleaned_text),Agent 做最终决策。
---
三、路径规则
3.1 SKILL_DIR 与 Output-dir
- SKILL_DIR:
byted-mediakit-voiceover-editing目录路径 - PROJECT_ROOT:由
scripts/project_paths.py推导:
1. 环境变量 VOICEOVER_EDITING_PROJECT_ROOT 若设置则用之 2. 否则为 <SKILL_DIR> 的 parents[2](沿父链上移 3 级,不依赖中间目录命名)
- Output-dir:
<PROJECT_ROOT>/output/<素材名>/;若目录已存在则自动递增为<素材名>_01、<素材名>_02... - 脚本启动时会打印路径推导日志,便于调试确认
3.2 素材名推导
| 来源 | 推导规则 | 示例 |
|---|---|---|
| URL | 取最后一段去扩展名 | https://x.com/video.mp4 → video |
| 本地文件 | 取文件名去扩展名 | /path/Test_Video_720p.mp4 → Test_Video_720p |
| DirectUrl | 取 FileName 去扩展名 | test.mp4 → test |
| Vid | 取 Vid 值 | v0xxx → v0xxx |
3.3 从上下文推导 output-dir
- 推导优先级(按顺序尝试):
1. 对话历史/命令参数中已显式传入 --output-dir output/<子目录> → 直接沿用 2. 无法从对话历史获得 → 询问用户指定
- Agent 不得扫描仓库来推断
output-dir
3.4 重复处理
写入任何输出文件/目录前,若目标已存在,必须提示用户:
- 目录已存在:「是否删除原目录?[删除/保留并新建(01)]」
- 文件已存在:「是否删除/覆盖/保留?」
- 超时 20 秒默认「保留并新建(01)」
---
四、脚本清单
执行前必须 cd <SKILL_DIR>/scripts| 脚本 | 用途 |
|---|---|
./scripts/setup.sh | 环境检查与依赖安装 |
./scripts/step2_confirm_config.py | Step 2: 语气词/卡顿词确认完成后生成 checkpoint(阻止跳步) |
./scripts/pipeline_url_to_asr.py | Step 3: URL → ASR 流水线(支持 --mode local/cloud/apig) |
./scripts/merge_asr_words.py | Step 4 产出缺 words 时,从 raw 合并 |
./scripts/prepare_export_data.py | Step 6a: 数据预处理(--width --height --write-step6) |
./scripts/serve_review_page.py | Step 6b: 审核页静态服务 + 数据保存 + 导出代理 |
./scripts/export_server.py | 导出服务(独立进程,接收审核页 POST) |
./scripts/vod_direct_export.py | Step 6c: VOD 导出任务提交与查询 |
---
五、必经步骤
执行顺序:按顺序执行所有步骤,不得跳步即任务失败
各 Step 完整检查单见 references/执行步骤/ 下分步文档。| Step | 说明 | 文档 |
|---|---|---|
| Step 1 | 环境检查与依赖安装 | 1. 环境检查.md |
| Step 2 | 语气词/卡顿词确认与规则更新 | 2. 语气词提示与用户行为更新.md |
| Step 3 | URL → ASR 流水线与候选生成 | 3. URL到ASR流水线与候选生成.md |
| Step 4 | ASR 语义纠错(Agent 执行) | 4. ASR语义纠错.md |
| Step 5 | 口播剪辑(Agent 执行) | 5. 口播剪辑.md |
| Step 5.5 | 审核逻辑确认 | 5.5 审核逻辑确认.md |
| Step 6a | 数据预处理 | 6a. 数据预处理.md |
| Step 6b | 审核与导出 | 6b. 审核与导出.md |
| Step 6c | VOD 导出任务提交与查询 | 6c. VOD导出任务提交与查询.md |
---
六、产物对照表
| 产物文件 | 生成步骤 | 说明 |
|---|---|---|
step1_preuploaded.json | Step 3 | 素材上传/注册结果(含 _execution_mode) |
step3_voice_separation_result.json | Step 3 | 人声分离结果 |
step5_asr_raw_*.json | Step 3 | ASR 原始转写 |
step5_asr_optimized.json | Step 4 | 语义纠错后 ASR |
step6_speech_cut.json | Step 5 | 口播剪辑决策 |
review_import_data.json | Step 6a | 审核页数据(含 _execution_mode、track、sentences) |
export_request.json | Step 6a / 审核保存 | 导出请求(审核页"保存"后会同步更新此文件) |
export_submit_*.json | Step 6b/6c | 最终提交的导出数据 |
---
七、审核页与数据联动
7.1 模式感知
审核页通过 review_import_data.json 中的 _execution_mode 字段自动识别当前模式,并在界面上:
- 显示模式徽标(APIG 蓝/云端绿/本地橙)
- 调整导出按钮文案(本地模式显示"本地导出视频")
- 调整导出成功信息(本地模式显示输出文件路径,云端显示 OutputVid + PlayURL)
7.2 本地模式审核页
本地模式完全支持审核页。Source 字段使用 http://127.0.0.1:<port>/local-media/<绝对路径> 格式,由 serve_review_page.py 的 /local-media/ 路由代理访问本地文件。
7.3 数据联动(审核修改 ↔ 直接导出同步)
审核页提供两个操作按钮:
| 按钮 | 功能 | 数据流 |
|---|---|---|
| 💾 保存审核 | 将修改持久化到磁盘 | POST /api/save-review → 更新 review_import_data.json + 重新生成 export_request.json |
| 导出 | 直接触发视频导出 | POST /export → apply_review_to_export → export_submit_*.json → ffmpeg/VOD |
关键:用户在审核页做了修改后,点击"💾 保存审核"即可将修改同步到磁盘。此后即使关闭审核页,Agent 通过 vod_direct_export.py --output-dir <输出目录> submit --wait 直接导出时也会读取更新后的 export_request.json,确保数据一致。
⚠️ 关键约束:调用vod_direct_export.py时,--output-dir必须写在submit/query子命令之前。一行式调用格式:
>
```
cd SKILL_DIR/scripts && source .venv/bin/activate && python vod_direct_export.py --output-dir <绝对路径> submit --wait
```
7.4 审核页服务端点
| 端点 | 方法 | 说明 |
|---|---|---|
/ | GET | 审核页 HTML |
/api/review-data | GET | 返回 review_import_data.json |
/api/mode | GET | 返回当前执行模式 |
/api/save-review | POST | 保存审核修改(回写 review_import_data + 重生成 export_request) |
/export | POST | 触发导出(local: ffmpeg;cloud/apig: vod_direct_export) |
/local-media/<path> | GET | 本地模式媒体文件代理 |
---
八、常见问题
| 现象 | 处理 |
|---|---|
| 本地文件走了 DirectUrl 模式 | 本地文件必须作为第一个位置参数传入;--directurl 仅用于 VOD 空间内已有 FileName |
| step5 写入失败 | 必须写入 output/<文件名>/step5_asr_optimized.json,禁止写 output 根目录 |
| concat 规则要删但音频还在播 | actionTime 必须从 step5 words 查出仅保留部分的 ms |
| 重复文件未提示 | 写入前必须检查目标是否存在,按 3.4 规则处理 |
| step6 修正未生效 | 确保 step6 顶层为 optimized_segments 或 sentences;运行 --write-step6 写回 |
| segment 起止时间不准 | Step 6a 会依 step5 words 校正 |
| delete 未在 deleted_parts | 每个 action: delete 段必须在 deleted_parts 中有对应项 |
| 审核页修改关闭后丢失 | 关闭前点击"💾 保存审核"持久化到磁盘 |
| 审核页本地资源 404 | 确认 Source 字段为 /local-media/ URL 格式;检查 serve_review_page.py 是否正常运行 |
| 缺参提示后阻塞 | 不再使用 input(),缺参时自动降级并打印 .env 路径提示 |
---
九、字幕可见性(Alpha)
- 字段:
textElement.Extra[transform].Alpha(0~1) - 含义:
0隐藏(不渲染到画布),1展示 - 删除态:Alpha 设为 0;恢复:Alpha 设为 1
{
"_schema": "EDL v1 - 编辑决策列表,时间单位均为 ms。开头/片段间无说话段必须在 output 显式标记 mute。",
"_actions": {
"mute": "无说话:保留时长,做静音处理(音量置 0)",
"delete": "整段删除,不参与输出(仅用于明确需剪掉的冗余内容,非无说话段)",
"concat": "句内剪辑:取多个 trim 片段拼接,中间删除(如去掉重复词、语气词)",
"keep": "原样保留"
},
"optimized_segments": [
{
"text": "大家好,今天跟大家聊一下我最近做的一个口播剪辑的工具。",
"source_text": "大家好,今天跟大家聊一下我最近做的一个一个口播剪辑的工具。",
"start_time": 630,
"end_time": 7470,
"reason": "句内重复:一个一个(A+A 模式),删前留后,保留最后一个「一个」",
"action": "concat",
"actionTime": [
{ "start_time": 630, "end_time": 5310 },
{ "start_time": 5950, "end_time": 7470 }
]
},
{
"text": "",
"source_text": "",
"start_time": 7470,
"end_time": 25960,
"reason": "片段间静音 18490ms(约 18.5s),无说话,保留时长做静音处理",
"action": "mute",
"actionTime": [{ "start_time": 7470, "end_time": 25960 }]
},
{
"text": "那个,做这个工具的原因其实很简单,就是我们平时录口播视频的时候,总会有各种各样的口癖,对吧?",
"source_text": "那个,做这个工具的原因其实很简单,就是我们平时录口播视频的时候,总会有各种各样的口癖,对吧?",
"start_time": 25960,
"end_time": 35520,
"reason": "保留",
"action": "keep",
"actionTime": [{ "start_time": 25960, "end_time": 35520 }]
}
]
}
{
"sentences": [
{
"text": "大家好,我是李明。",
"source_text": "大家好,我是李明。",
"reason": "保留",
"action": "keep",
"start_time": 290, // 必需字段
"end_time": 1770, // 必需字段
"actionTime": [
{
"start_time": 290,
"end_time": 1770
}
]
}
]
}
{
// 画布大小
"Canvas": {
"Width": 1280,
"Height": 2160 // 画布高度为单个视频高度的 3 倍 (720 * 3)
},
"Track": [
[
{
"Type": "video",
"Source": "vid://your_main_video_vid",
"TargetTime": [0, " 视频原始时长"], // 单位 ms
"Extra": [{ "Type": "a_volume", "Volume": 0 }]
}
],
[
{
"Type": "audio",
"Source": "vid://your_voice_vid",
"TargetTime": [0, 10000], // 音频在播放的那个时间节点出现 , 背景音需要按照原始duration 进行处理
"Extra": [{ "Type": "trim", "StartTime": 0, "EndTime": 10000 }] // 需要处理的原视频时间
}
],
[
{
"Type": "audio",
"Source": "vid://your_bgm_vid",
"TargetTime": [0, 10000], // 人声需要根据岂止 时间处理
"Extra": [{ "Type": "a_volume", "Volume": 0.3 }]
}
],
[
{
"Type": "text",
"TargetTime": [0, 3000],
"Text": "第一句字幕",
"FontType": "SY_Black",
"FontSize": 54,
"FontColor": "#FFFFFFFF",
"AlignType": 1,
"Extra": [
{
"Type": "transform",
"Width": 1800,
"Height": 200,
"PosX": 60,
"PosY": 440
}
]
},
{
"Type": "text",
"TargetTime": [3000, 7000],
"Text": "第二句字幕",
"FontType": "SY_Black",
"FontSize": 54,
"FontColor": "#FFFFFFFF",
"AlignType": 1,
"Extra": [
{
"Type": "transform",
"Width": 1800,
"Height": 200,
"PosX": 60,
"PosY": 440
}
]
},
{
"Type": "text",
"TargetTime": [7000, 10000],
"Text": "第三句字幕",
"FontType": "SY_Black",
"FontSize": 54,
"FontColor": "#FFFFFFFF",
"AlignType": 1,
"Extra": [
{
"Type": "transform",
"Width": 1800,
"Height": 200,
"PosX": 60,
"PosY": 440
}
]
}
]
]
}
export const MOCK_DESCRIBE_PROJECT = [
{
// "ProjectName": 'Mock AIDP项目',
LatestEditParam: {
Canvas: {
Width: 1920,
Height: 1080,
BackgroundColor: '#000000FF',
},
Track: [],
},
},
]
// searchEditMaterial 期望返回 { Total, Detail }
// Detail 每项: Name, EditMid, Source (vid://xxx | mid://xxx), Type (video|audio|image)
// 之后编辑器会对每条再调 getVideoInfo(video/audio) 或 mGetMaterial(image) 补详情
export const MOCK_SEARCH_EDIT_MATERIAL = {
Total: 9,
Detail: [
{
EditMid: 'm02bd00d3tlh09vtk12qe2o8b30',
ProjectId: 'p024600d3nl788u77eiocql5k50',
Name: '下载.mp3',
Type: 'audio',
Status: 'Failed',
Source: 'vid://v02bffg10064d30igdqljht5q0mvetjg',
Content: {},
CreatedAt: '2025-10-24T18:44:18+08:00',
UpdatedAt: '2025-10-24T18:44:18+08:00',
Extra: '',
},
{
EditMid: 'm02af00d40cthgk5gt3ts3hbba0',
ProjectId: 'p024600d3nl788u77eiocql5k50',
Name: '',
Type: 'video',
Status: 'Completed',
Source: 'vid://v0dbffg10064d406uhqljht6tre6u5b0',
Content: {
Sprite: {
Format: 'jpeg',
StoreUrls: [
'https://console-image-cn.volcvod.com/aideo-dev/c0a5c4f215d5456bbde831a3d3ec7bb6~noop.image?sign=1769676640-r0-u0-a002495a0bc733a594a8ee5a00dc61d0',
],
ImgXLen: 5,
ImgYLen: 5,
CellWidth: 136,
CellHeight: 240,
Interval: 1,
CaptureNum: 10,
},
},
CreatedAt: '2025-10-28T22:10:14+08:00',
UpdatedAt: '2025-10-28T22:10:20+08:00',
Extra: '',
},
{
EditMid: 'm029500d41j94iqsb7ai48hi3f0',
ProjectId: 'p024600d3nl788u77eiocql5k50',
Name: 'split_55.mp4',
Type: 'video',
Status: 'Completed',
Source: 'vid://v02bffg10064d3vjq9aljht6ujf4ij5g',
Content: {
Sprite: {
Format: 'jpeg',
StoreUrls: [
'https://console-image-cn.volcvod.com/aideo-dev/07488a6a761f4cdd9c4face89cad7dc6~noop.image?sign=1770023668-r0-u0-4f193db285d042335f2116329d225c4f',
],
ImgXLen: 5,
ImgYLen: 5,
CellWidth: 136,
CellHeight: 240,
Interval: 1,
CaptureNum: 2,
},
},
CreatedAt: '2025-10-30T17:49:06+08:00',
UpdatedAt: '2025-10-30T17:49:06+08:00',
Extra: '',
},
{
EditMid: 'm026b00d41j94hg3f82h8c9a3a0',
ProjectId: 'p024600d3nl788u77eiocql5k50',
Name: 'split_54.mp4',
Type: 'video',
Status: 'Completed',
Source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
Content: {
Sprite: {
Format: 'jpeg',
StoreUrls: [
'https://console-image-cn.volcvod.com/aideo-dev/07488a6a761f4cdd9c4face89cad7dc6~noop.image?sign=1769676640-r0-u0-1060bb4d9da950c3c417ff1f95e3ffc0',
],
ImgXLen: 5,
ImgYLen: 5,
CellWidth: 136,
CellHeight: 240,
Interval: 1,
CaptureNum: 3,
},
},
CreatedAt: '2025-10-30T17:49:06+08:00',
UpdatedAt: '2025-10-30T17:49:06+08:00',
Extra: '',
},
{
EditMid: 'm025100d41j94he7q01h1h0utj0',
ProjectId: 'p024600d3nl788u77eiocql5k50',
Name: 'split_34.mp4',
Type: 'video',
Status: 'Completed',
Source: 'vid://v02bffg10064d3vjq82ljhtejm9u1uog',
Content: {
Sprite: {
Format: 'jpeg',
StoreUrls: [
'https://console-image-cn.volcvod.com/aideo-dev/7c3d3a6c4f534648b56aa691d14fd10c~noop.image?sign=1769676640-r0-u0-118ee6b0012b65a7a9fcfa21ebd7b478',
],
ImgXLen: 5,
ImgYLen: 5,
CellWidth: 136,
CellHeight: 240,
Interval: 1,
CaptureNum: 4,
},
},
CreatedAt: '2025-10-30T17:49:06+08:00',
UpdatedAt: '2025-10-30T17:49:06+08:00',
Extra: '',
},
{
EditMid: 'm02af00d41j94gk5gt3ts3hbbbg',
ProjectId: 'p024600d3nl788u77eiocql5k50',
Name: 'split_48.mp4',
Type: 'video',
Status: 'Completed',
Source: 'vid://v02bffg10064d3vjq8qljht4tvopr0bg',
Content: {
Sprite: {
Format: 'jpeg',
StoreUrls: [
'https://console-image-cn.volcvod.com/aideo-dev/869fc58d581c43f0833ff510cf065994~noop.image?sign=1769676640-r0-u0-789f395b3ffb0efaf777bf0d17bdb79c',
],
ImgXLen: 5,
ImgYLen: 5,
CellWidth: 136,
CellHeight: 240,
Interval: 1,
CaptureNum: 1,
},
},
CreatedAt: '2025-10-30T17:49:06+08:00',
UpdatedAt: '2025-10-30T17:49:06+08:00',
Extra: '',
},
{
EditMid: 'm025100d41j94he7q01h1h0utjg',
ProjectId: 'p024600d3nl788u77eiocql5k50',
Name: 'split_50.mp4',
Type: 'video',
Status: 'Completed',
Source: 'vid://v02bffg10064d3vjq92ljhtbribb9sq0',
Content: {
Sprite: {
Format: 'jpeg',
StoreUrls: [
'https://console-image-cn.volcvod.com/aideo-dev/5b8632e10a8e4ac1a11f592f57e39380~noop.image?sign=1769676640-r0-u0-5c51ecbb95e5d30174b74f8294139c20',
],
ImgXLen: 5,
ImgYLen: 5,
CellWidth: 136,
CellHeight: 240,
Interval: 1,
CaptureNum: 2,
},
},
CreatedAt: '2025-10-30T17:49:06+08:00',
UpdatedAt: '2025-10-30T17:49:06+08:00',
Extra: '',
},
{
EditMid: 'm02e200d41j94ime1pcg60li660',
ProjectId: 'p024600d3nl788u77eiocql5k50',
Name: 'split_51.mp4',
Type: 'video',
Status: 'Completed',
Source: 'vid://v02bffg10064d3vjq92ljhtbffh24lsg',
Content: {
Sprite: {
Format: 'jpeg',
StoreUrls: [
'https://console-image-cn.volcvod.com/aideo-dev/e7c11288c56e49e5b917a5e6ea46a369~noop.image?sign=1769676640-r0-u0-55b5bf27c805ff82ef9f83b57fdb4400',
],
ImgXLen: 5,
ImgYLen: 5,
CellWidth: 136,
CellHeight: 240,
Interval: 1,
CaptureNum: 2,
},
},
CreatedAt: '2025-10-30T17:49:06+08:00',
UpdatedAt: '2025-10-30T17:49:06+08:00',
Extra: '',
},
{
EditMid: 'm028e00d41j94j4m8fsvh10ccig',
ProjectId: 'p024600d3nl788u77eiocql5k50',
Name: 'split_46.mp4',
Type: 'video',
Status: 'Completed',
Source: 'vid://v02bffg10064d3vjq8qljhta4p6vrss0',
Content: {
Sprite: {
Format: 'jpeg',
StoreUrls: [
'https://console-image-cn.volcvod.com/aideo-dev/30f8eb1ecb7947acb61bc00f7c2b6682~noop.image?sign=1769676640-r0-u0-68640c2fc375adf07c90070bb6e6ee1b',
],
ImgXLen: 5,
ImgYLen: 5,
CellWidth: 136,
CellHeight: 240,
Interval: 1,
CaptureNum: 5,
},
},
CreatedAt: '2025-10-30T17:49:06+08:00',
UpdatedAt: '2025-10-30T17:49:06+08:00',
Extra: '',
},
],
}
// getVideoInfo 按 Vid 匹配的 mock 返回值(Vid = 素材 Source 去掉 "vid://" 后的值)
export const MOCK_GET_VIDEO_INFO_BY_VID = {
v02bffg10064d30igdqljht5q0mvetjg: {
Title: '下载.mp3',
Vid: 'v02bffg10064d30igdqljht5q0mvetjg',
Filename: '下载.mp3',
PublishStatus: 'Published',
Duration: 21.644,
Codec: 'mp3',
Height: 0,
Width: 0,
Format: 'MP3',
Size: 347368,
Bitrate: 128394,
Tags: [],
Description: '',
PosterUrl:
'https://console-image-cn.volcvod.com/~noop.jpeg?sign=1769680056-r0-u0-48697b269df27915f3922c0d2ca783c7',
PlayInfo: {
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/%E4%B8%8B%E8%BD%BD.mp3?auth_key=1772272056-9e077c0cdde1498f855940887098a64b-0-c9d6b59a69db7400ff59e4f368b98f08',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/%E4%B8%8B%E8%BD%BD.mp3?auth_key=1772272056-b2ef3efb3b2449b982eaa86dc680c43a-0-9da133b3a315733d9d6dabb0d7bf3a3b',
Status: 1,
},
PosterInfo: {
MainPosterUri: '',
BackupPosterUris: [],
MainPosterInfo: {
PosterUri: '',
PosterUrl:
'https://console-image-cn.volcvod.com/~noop.jpeg?sign=1769680056-r0-u0-48697b269df27915f3922c0d2ca783c7',
},
BackupPosterInfo: [],
},
CreatedTime: '2025-9-10 15:26:48',
UpdatedTime: '2025-9-10 15:26:49',
CategoryTags: [],
Classification: null,
TosStorageClass: 'STANDARD',
DynamicRange: 'SDR',
OuterPosterUrl: '',
FileType: 'audio',
StoreUri: 'aideo-dev/下载.mp3',
Md5: 'c373c73379c20d28800ea60db32df6da',
VodUploadSource: 'upload',
BlockStatus: '',
HlsMediaSize: 0,
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/%E4%B8%8B%E8%BD%BD.mp3?auth_key=1772272056-9e077c0cdde1498f855940887098a64b-0-c9d6b59a69db7400ff59e4f368b98f08',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/%E4%B8%8B%E8%BD%BD.mp3?auth_key=1772272056-b2ef3efb3b2449b982eaa86dc680c43a-0-9da133b3a315733d9d6dabb0d7bf3a3b',
Status: 1,
PlayUrl:
'https://vod-fe-test-aideo.byte-test.com/%E4%B8%8B%E8%BD%BD.mp3?auth_key=1772272056-9e077c0cdde1498f855940887098a64b-0-c9d6b59a69db7400ff59e4f368b98f08',
},
// 可在此继续按 Vid 追加更多条目
v02bffg10064d3vjq8qljhta4p6vrss0: {
Title: 'split_46.mp4',
Vid: 'v02bffg10064d3vjq8qljhta4p6vrss0',
Filename: 'split_46.mp4',
PublishStatus: 'Published',
Duration: 5,
Codec: 'h264',
Height: 1920,
Width: 1080,
Format: 'MP4',
Size: 1862730,
Bitrate: 2980368,
Tags: [],
Description: '',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/oUOfenDMjgvlg8RpX31DQe2GzIqpjUEQzRymff~noop.jpeg?sign=1769680345-r0-u0-7ea4f1881aec3d987ebbe583d8c8ed71',
PlayInfo: {
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_46.mp4?auth_key=1772272345-e3667e6549b3423bacf4e85d3d8b7c29-0-3f84896fa481feeac0f8a98c164e9a76',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_46.mp4?auth_key=1772272345-43c8a7fbe8fd49c199d3d06ed8d8430a-0-a674c426e509a2c34bf7488f8387c076',
Status: 1,
},
PosterInfo: {
MainPosterUri: 'aideo-dev/oUOfenDMjgvlg8RpX31DQe2GzIqpjUEQzRymff',
BackupPosterUris: [],
MainPosterInfo: {
PosterUri: 'aideo-dev/oUOfenDMjgvlg8RpX31DQe2GzIqpjUEQzRymff',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/oUOfenDMjgvlg8RpX31DQe2GzIqpjUEQzRymff~noop.jpeg?sign=1769680345-r0-u0-7ea4f1881aec3d987ebbe583d8c8ed71',
},
BackupPosterInfo: [],
},
CreatedTime: '2025-10-27 17:36:39',
UpdatedTime: '2025-10-27 17:36:40',
CategoryTags: [],
Classification: null,
TosStorageClass: 'STANDARD',
DynamicRange: 'SDR',
OuterPosterUrl:
'https://vod-fe-test-aideo-img.byte-test.com/aideo-dev/oUOfenDMjgvlg8RpX31DQe2GzIqpjUEQzRymff~tplv-vod-noop.image',
FileType: 'video',
StoreUri: 'aideo-dev/split_46.mp4',
Md5: 'ec0e5ad5fd380318cc04b0c1d464b18e',
VodUploadSource: 'upload',
BlockStatus: '',
HlsMediaSize: 0,
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_46.mp4?auth_key=1772272345-e3667e6549b3423bacf4e85d3d8b7c29-0-3f84896fa481feeac0f8a98c164e9a76',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_46.mp4?auth_key=1772272345-43c8a7fbe8fd49c199d3d06ed8d8430a-0-a674c426e509a2c34bf7488f8387c076',
Status: 1,
PlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_46.mp4?auth_key=1772272345-e3667e6549b3423bacf4e85d3d8b7c29-0-3f84896fa481feeac0f8a98c164e9a76',
},
v0dbffg10064d406uhqljht6tre6u5b0: {
Title: '',
Vid: 'v0dbffg10064d406uhqljht6tre6u5b0',
Filename: 'cd65aeb811b146ffb7b0d3b8b2890776.mp4',
PublishStatus: 'Published',
Duration: 10,
Codec: 'h264',
Height: 1280,
Width: 720,
Format: 'MP4',
Size: 78363,
Bitrate: 62690,
Tags: [],
Description: '',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/o80A9peuAg3Zfb18BlQPKb9VHGmMb6IxAeaCsG~noop.jpeg?sign=1769680345-r0-u0-4521e640a3a508ba10fbf5ec59c8d130',
PlayInfo: {
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/cd65aeb811b146ffb7b0d3b8b2890776.mp4?auth_key=1772272345-143d19b5150c46ada0f898c37597a8c2-0-e4a704f39af30254f62561bb00829967',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/cd65aeb811b146ffb7b0d3b8b2890776.mp4?auth_key=1772272345-b5fcb962fcb046489d7757c34b5d1c69-0-ce803923aaa60886603008dce12acfc5',
Status: 1,
},
PosterInfo: {
MainPosterUri: 'aideo-dev/o80A9peuAg3Zfb18BlQPKb9VHGmMb6IxAeaCsG',
BackupPosterUris: [],
MainPosterInfo: {
PosterUri: 'aideo-dev/o80A9peuAg3Zfb18BlQPKb9VHGmMb6IxAeaCsG',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/o80A9peuAg3Zfb18BlQPKb9VHGmMb6IxAeaCsG~noop.jpeg?sign=1769680345-r0-u0-4521e640a3a508ba10fbf5ec59c8d130',
},
BackupPosterInfo: [],
},
CreatedTime: '2025-10-28 15:22:48',
UpdatedTime: '2025-10-28 15:22:50',
CategoryTags: [],
Classification: null,
TosStorageClass: 'STANDARD',
DynamicRange: 'SDR',
OuterPosterUrl:
'https://vod-fe-test-aideo-img.byte-test.com/aideo-dev/o80A9peuAg3Zfb18BlQPKb9VHGmMb6IxAeaCsG~tplv-vod-noop.image',
FileType: 'video',
StoreUri: 'aideo-dev/cd65aeb811b146ffb7b0d3b8b2890776.mp4',
Md5: '350318965a713f046d4ee3ffaf9ddc2f',
VodUploadSource: 'media_edit',
BlockStatus: '',
HlsMediaSize: 0,
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/cd65aeb811b146ffb7b0d3b8b2890776.mp4?auth_key=1772272345-143d19b5150c46ada0f898c37597a8c2-0-e4a704f39af30254f62561bb00829967',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/cd65aeb811b146ffb7b0d3b8b2890776.mp4?auth_key=1772272345-b5fcb962fcb046489d7757c34b5d1c69-0-ce803923aaa60886603008dce12acfc5',
Status: 1,
PlayUrl:
'https://vod-fe-test-aideo.byte-test.com/cd65aeb811b146ffb7b0d3b8b2890776.mp4?auth_key=1772272345-143d19b5150c46ada0f898c37597a8c2-0-e4a704f39af30254f62561bb00829967',
},
v02bffg10064d3vjq92ljhtbffh24lsg: {
Title: 'split_55.mp4',
Vid: 'v02bffg10064d3vjq9aljht6ujf4ij5g',
Filename: 'split_55.mp4',
PublishStatus: 'Published',
Duration: 2.28,
Codec: 'h264',
Height: 1920,
Width: 1080,
Format: 'MP4',
Size: 1146706,
Bitrate: 4023529,
Tags: [],
Description: '',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/o8Ir2ejPffnqppYJfpGvQhKzGY30hfjKEAyXSZ~noop.jpeg?sign=1769680346-r0-u0-c15b908198163f97c1976a4a4a1d9f57',
PlayInfo: {
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_55.mp4?auth_key=1772272346-90cac36df3a74bd691c242f175e4368f-0-2bcfc5c3c4e30fe83267ef2b7838b7e4',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_55.mp4?auth_key=1772272346-d46b522ab9af455cb4784120b4539e63-0-b14aa531eeed7b82d51b5de48eae6be6',
Status: 1,
},
PosterInfo: {
MainPosterUri: 'aideo-dev/o8Ir2ejPffnqppYJfpGvQhKzGY30hfjKEAyXSZ',
BackupPosterUris: [],
MainPosterInfo: {
PosterUri: 'aideo-dev/o8Ir2ejPffnqppYJfpGvQhKzGY30hfjKEAyXSZ',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/o8Ir2ejPffnqppYJfpGvQhKzGY30hfjKEAyXSZ~noop.jpeg?sign=1769680346-r0-u0-c15b908198163f97c1976a4a4a1d9f57',
},
BackupPosterInfo: [],
},
CreatedTime: '2025-10-27 17:36:39',
UpdatedTime: '2025-10-27 17:36:40',
CategoryTags: [],
Classification: null,
TosStorageClass: 'STANDARD',
DynamicRange: 'SDR',
OuterPosterUrl:
'https://vod-fe-test-aideo-img.byte-test.com/aideo-dev/o8Ir2ejPffnqppYJfpGvQhKzGY30hfjKEAyXSZ~tplv-vod-noop.image',
FileType: 'video',
StoreUri: 'aideo-dev/split_55.mp4',
Md5: 'ff63829f39ab4806b25c1f7f5c5ee44a',
VodUploadSource: 'upload',
BlockStatus: '',
HlsMediaSize: 0,
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_55.mp4?auth_key=1772272346-90cac36df3a74bd691c242f175e4368f-0-2bcfc5c3c4e30fe83267ef2b7838b7e4',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_55.mp4?auth_key=1772272346-d46b522ab9af455cb4784120b4539e63-0-b14aa531eeed7b82d51b5de48eae6be6',
Status: 1,
PlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_55.mp4?auth_key=1772272346-90cac36df3a74bd691c242f175e4368f-0-2bcfc5c3c4e30fe83267ef2b7838b7e4',
},
v02bffg10064d3vjq82ljhtejm9u1uog: {
Title: 'split_34.mp4',
Vid: 'v02bffg10064d3vjq82ljhtejm9u1uog',
Filename: 'split_34.mp4',
PublishStatus: 'Published',
Duration: 4.16,
Codec: 'h264',
Height: 1920,
Width: 1080,
Format: 'MP4',
Size: 1941364,
Bitrate: 3733392,
Tags: [],
Description: '',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/oQPBzQvgf6RLi4ZPkmZ1E6ff7CSxdZ0IfIVXB9~noop.jpeg?sign=1769680468-r0-u0-36976857e53ad4cb07491c6daf5eed3b',
PlayInfo: {
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_34.mp4?auth_key=1772272468-3979f8e0de514b1cb865c88283ec4f0b-0-fd6991eb6cec50e47f90765478d8e52b',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_34.mp4?auth_key=1772272468-000f04184eaa497986e330d169e383f4-0-baa402352f6bdb71c30f9560e123cd3f',
Status: 1,
},
PosterInfo: {
MainPosterUri: 'aideo-dev/oQPBzQvgf6RLi4ZPkmZ1E6ff7CSxdZ0IfIVXB9',
BackupPosterUris: [],
MainPosterInfo: {
PosterUri: 'aideo-dev/oQPBzQvgf6RLi4ZPkmZ1E6ff7CSxdZ0IfIVXB9',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/oQPBzQvgf6RLi4ZPkmZ1E6ff7CSxdZ0IfIVXB9~noop.jpeg?sign=1769680468-r0-u0-36976857e53ad4cb07491c6daf5eed3b',
},
BackupPosterInfo: [],
},
CreatedTime: '2025-10-27 17:36:37',
UpdatedTime: '2025-10-27 17:36:38',
CategoryTags: [],
Classification: null,
TosStorageClass: 'STANDARD',
DynamicRange: 'SDR',
OuterPosterUrl:
'https://vod-fe-test-aideo-img.byte-test.com/aideo-dev/oQPBzQvgf6RLi4ZPkmZ1E6ff7CSxdZ0IfIVXB9~tplv-vod-noop.image',
FileType: 'video',
StoreUri: 'aideo-dev/split_34.mp4',
Md5: '60eafceab73d06a6325aee49bf8786c5',
VodUploadSource: 'upload',
BlockStatus: '',
HlsMediaSize: 0,
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_34.mp4?auth_key=1772272468-3979f8e0de514b1cb865c88283ec4f0b-0-fd6991eb6cec50e47f90765478d8e52b',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_34.mp4?auth_key=1772272468-000f04184eaa497986e330d169e383f4-0-baa402352f6bdb71c30f9560e123cd3f',
Status: 1,
PlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_34.mp4?auth_key=1772272468-3979f8e0de514b1cb865c88283ec4f0b-0-fd6991eb6cec50e47f90765478d8e52b',
},
v02bffg10064d3vjq92ljhtbribb9sq0: {
Title: 'split_50.mp4',
Vid: 'v02bffg10064d3vjq92ljhtbribb9sq0',
Filename: 'split_50.mp4',
PublishStatus: 'Published',
Duration: 1.88,
Codec: 'h264',
Height: 1920,
Width: 1080,
Format: 'MP4',
Size: 342910,
Bitrate: 1459191,
Tags: [],
Description: '',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/ocCC20RgflzxMErPZkISzVZ26fL7fCfvUQTc7Q~noop.jpeg?sign=1769680468-r0-u0-59379a5ce3341cf7f631554f76635028',
PlayInfo: {
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_50.mp4?auth_key=1772272468-7bd7243682014223aade44f3bca75f50-0-d960729404fbff5d8e6559b380effe9d',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_50.mp4?auth_key=1772272468-9a152c38a2f14a2e90fec25c5c52f9c7-0-0722973efc9b87c6b053b00c19a33f04',
Status: 1,
},
PosterInfo: {
MainPosterUri: 'aideo-dev/ocCC20RgflzxMErPZkISzVZ26fL7fCfvUQTc7Q',
BackupPosterUris: [],
MainPosterInfo: {
PosterUri: 'aideo-dev/ocCC20RgflzxMErPZkISzVZ26fL7fCfvUQTc7Q',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/ocCC20RgflzxMErPZkISzVZ26fL7fCfvUQTc7Q~noop.jpeg?sign=1769680468-r0-u0-59379a5ce3341cf7f631554f76635028',
},
BackupPosterInfo: [],
},
CreatedTime: '2025-10-27 17:36:37',
UpdatedTime: '2025-10-27 17:36:38',
CategoryTags: [],
Classification: null,
TosStorageClass: 'STANDARD',
DynamicRange: 'SDR',
OuterPosterUrl:
'https://vod-fe-test-aideo-img.byte-test.com/aideo-dev/ocCC20RgflzxMErPZkISzVZ26fL7fCfvUQTc7Q~tplv-vod-noop.image',
FileType: 'video',
StoreUri: 'aideo-dev/split_50.mp4',
Md5: '4ae2cfe920f9b0eb7c999e03404326cd',
VodUploadSource: 'upload',
BlockStatus: '',
HlsMediaSize: 0,
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_50.mp4?auth_key=1772272468-7bd7243682014223aade44f3bca75f50-0-d960729404fbff5d8e6559b380effe9d',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_50.mp4?auth_key=1772272468-9a152c38a2f14a2e90fec25c5c52f9c7-0-0722973efc9b87c6b053b00c19a33f04',
Status: 1,
PlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_50.mp4?auth_key=1772272468-7bd7243682014223aade44f3bca75f50-0-d960729404fbff5d8e6559b380effe9d',
},
v02bffg10064d3vjq92ljhtbffh24lsg: {
Title: 'split_51.mp4',
Vid: 'v02bffg10064d3vjq92ljhtbffh24lsg',
Filename: 'split_51.mp4',
PublishStatus: 'Published',
Duration: 1.8,
Codec: 'h264',
Height: 1920,
Width: 1080,
Format: 'MP4',
Size: 738919,
Bitrate: 3284084,
Tags: [],
Description: '',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/oUAjjfHbzEInfII3ZepERSpXzfQk8vkhxyq12e~noop.jpeg?sign=1769680524-r0-u0-94ef3ca5b9c06c89b12713ebefb63344',
PlayInfo: {
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_51.mp4?auth_key=1772272524-b06b686dcce74b2891bb06ae2edeb7ce-0-672058b16448c451383fd384b5b3d8c0',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_51.mp4?auth_key=1772272524-e817fd90cf3d48bfbc14eb9a8858c832-0-62f3dd435837f0fd222386fa1d58c8f2',
Status: 1,
},
PosterInfo: {
MainPosterUri: 'aideo-dev/oUAjjfHbzEInfII3ZepERSpXzfQk8vkhxyq12e',
BackupPosterUris: [],
MainPosterInfo: {
PosterUri: 'aideo-dev/oUAjjfHbzEInfII3ZepERSpXzfQk8vkhxyq12e',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/oUAjjfHbzEInfII3ZepERSpXzfQk8vkhxyq12e~noop.jpeg?sign=1769680524-r0-u0-94ef3ca5b9c06c89b12713ebefb63344',
},
BackupPosterInfo: [],
},
CreatedTime: '2025-10-27 17:36:39',
UpdatedTime: '2025-10-27 17:36:40',
CategoryTags: [],
Classification: null,
TosStorageClass: 'STANDARD',
DynamicRange: 'SDR',
OuterPosterUrl:
'https://vod-fe-test-aideo-img.byte-test.com/aideo-dev/oUAjjfHbzEInfII3ZepERSpXzfQk8vkhxyq12e~tplv-vod-noop.image',
FileType: 'video',
StoreUri: 'aideo-dev/split_51.mp4',
Md5: '8d66ebf6ff44d7fe9331e1c8ce5386d7',
VodUploadSource: 'upload',
BlockStatus: '',
HlsMediaSize: 0,
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_51.mp4?auth_key=1772272524-b06b686dcce74b2891bb06ae2edeb7ce-0-672058b16448c451383fd384b5b3d8c0',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_51.mp4?auth_key=1772272524-e817fd90cf3d48bfbc14eb9a8858c832-0-62f3dd435837f0fd222386fa1d58c8f2',
Status: 1,
PlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_51.mp4?auth_key=1772272524-b06b686dcce74b2891bb06ae2edeb7ce-0-672058b16448c451383fd384b5b3d8c0',
},
v02bffg10064d3vjq9aljht0oe413p20: {
Title: 'split_54.mp4',
Vid: 'v02bffg10064d3vjq9aljht0oe413p20',
Filename: 'split_54.mp4',
PublishStatus: 'Published',
Duration: 2.88,
Codec: 'h264',
Height: 1920,
Width: 1080,
Format: 'MP4',
Size: 711940,
Bitrate: 1977611,
Tags: [],
Description: '',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1769680580-r0-u0-e3f4226242978624c400b11c739d2ff5',
PlayInfo: {
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1772272580-75fb679fe71b479fa7f7481719dd0762-0-94faac1a6a10f00a69bf53c0c5815c27',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1772272580-8ce87a5c9da849808fe27181fdedd916-0-0b1de01412de5a34cced5b43974259ec',
Status: 1,
},
PosterInfo: {
MainPosterUri: 'aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk',
BackupPosterUris: [],
MainPosterInfo: {
PosterUri: 'aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1769680580-r0-u0-e3f4226242978624c400b11c739d2ff5',
},
BackupPosterInfo: [],
},
CreatedTime: '2025-10-27 17:36:39',
UpdatedTime: '2025-10-27 17:36:40',
CategoryTags: [],
Classification: null,
TosStorageClass: 'STANDARD',
DynamicRange: 'SDR',
OuterPosterUrl:
'https://vod-fe-test-aideo-img.byte-test.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~tplv-vod-noop.image',
FileType: 'video',
StoreUri: 'aideo-dev/split_54.mp4',
Md5: '6caa32ddf9decca3382cde69e12b55b2',
VodUploadSource: 'upload',
BlockStatus: '',
HlsMediaSize: 0,
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1772272580-75fb679fe71b479fa7f7481719dd0762-0-94faac1a6a10f00a69bf53c0c5815c27',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1772272580-8ce87a5c9da849808fe27181fdedd916-0-0b1de01412de5a34cced5b43974259ec',
Status: 1,
PlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1772272580-75fb679fe71b479fa7f7481719dd0762-0-94faac1a6a10f00a69bf53c0c5815c27',
},
v02bffg10064d3vjq9aljht6ujf4ij5g: {
Title: 'split_55.mp4',
Vid: 'v02bffg10064d3vjq9aljht6ujf4ij5g',
Filename: 'split_55.mp4',
PublishStatus: 'Published',
Duration: 2.28,
Codec: 'h264',
Height: 1920,
Width: 1080,
Format: 'MP4',
Size: 1146706,
Bitrate: 4023529,
Tags: [],
Description: '',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/o8Ir2ejPffnqppYJfpGvQhKzGY30hfjKEAyXSZ~noop.jpeg?sign=1769680580-r0-u0-d8c1502261739fd9730253e903aa2636',
PlayInfo: {
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_55.mp4?auth_key=1772272580-f2724df6d3ac400c91b07e6ab5870b71-0-1ec6c65c08e93163d43cd200e62d38a4',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_55.mp4?auth_key=1772272580-e5785e051f3d4bd49e3b81cde920f8d5-0-070df00d7394722ea0a28677037304c0',
Status: 1,
},
PosterInfo: {
MainPosterUri: 'aideo-dev/o8Ir2ejPffnqppYJfpGvQhKzGY30hfjKEAyXSZ',
BackupPosterUris: [],
MainPosterInfo: {
PosterUri: 'aideo-dev/o8Ir2ejPffnqppYJfpGvQhKzGY30hfjKEAyXSZ',
PosterUrl:
'https://console-image-cn.volcvod.com/aideo-dev/o8Ir2ejPffnqppYJfpGvQhKzGY30hfjKEAyXSZ~noop.jpeg?sign=1769680580-r0-u0-d8c1502261739fd9730253e903aa2636',
},
BackupPosterInfo: [],
},
CreatedTime: '2025-10-27 17:36:39',
UpdatedTime: '2025-10-27 17:36:40',
CategoryTags: [],
Classification: null,
TosStorageClass: 'STANDARD',
DynamicRange: 'SDR',
OuterPosterUrl:
'https://vod-fe-test-aideo-img.byte-test.com/aideo-dev/o8Ir2ejPffnqppYJfpGvQhKzGY30hfjKEAyXSZ~tplv-vod-noop.image',
FileType: 'video',
StoreUri: 'aideo-dev/split_55.mp4',
Md5: 'ff63829f39ab4806b25c1f7f5c5ee44a',
VodUploadSource: 'upload',
BlockStatus: '',
HlsMediaSize: 0,
MainPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_55.mp4?auth_key=1772272580-f2724df6d3ac400c91b07e6ab5870b71-0-1ec6c65c08e93163d43cd200e62d38a4',
BackupPlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_55.mp4?auth_key=1772272580-e5785e051f3d4bd49e3b81cde920f8d5-0-070df00d7394722ea0a28677037304c0',
Status: 1,
PlayUrl:
'https://vod-fe-test-aideo.byte-test.com/split_55.mp4?auth_key=1772272580-f2724df6d3ac400c91b07e6ab5870b71-0-1ec6c65c08e93163d43cd200e62d38a4',
},
}
// 未匹配到 Vid 时的默认返回值
const MOCK_GET_VIDEO_INFO_DEFAULT = {
Duration: 10,
PlayUrl: 'https://example.com/mock-video.mp4',
PosterUrl: 'https://example.com/mock-poster.jpg',
Width: 1920,
Height: 1080,
}
/**
* 根据 params.Vid 从 map 中取 mock 视频信息,无匹配则返回默认
* @param {{ Vid?: string; Space?: string }} params
* @returns {object}
*/
export function getMockVideoInfoByParams(params) {
const vid = params?.Vid
const matched = vid && MOCK_GET_VIDEO_INFO_BY_VID[vid]
return matched ? { ...matched } : { ...MOCK_GET_VIDEO_INFO_DEFAULT }
}
// mGetMaterial 在 image 时被调,期望返回 MaterialSet.MaterialInfos[0].MaterialBasicInfo
export const MOCK_M_GET_MATERIAL = {
MaterialSet: {
MaterialInfos: [
{
MaterialBasicInfo: {
Width: 1920,
Height: 1080,
PlayUrl: 'https://example.com/mock-image.jpg',
PosterUrl: 'https://example.com/mock-image.jpg',
},
},
],
},
}
/**
* MOCK_TRACK:仅作 Track 结构参考(Type、Source、TargetTime、Extra、UserData 等字段形状)。
* 其中的 url、auth_key 等为 MOCK 示例,不得直接用于预览。
* 预览页必须从 output/review_import_data.json 导入,track 内的 URL 需为流水线产出的真实可播放链接。
*/
export const MOCK_TRACK = [
[
{
ID: 'ucirqys1sp8',
Type: 'video',
Source: 'vid://v02bffg10064d3vjq9aljht6ujf4ij5g',
UserData: {
id: 'element19c4becc82b10000000001',
name: 'split_55.mp4',
source: 'vid://v02bffg10064d3vjq9aljht6ujf4ij5g',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_55.mp4?auth_key=1774870443-fcc8c01ff36b46f8b44547ebd0058cac-0-e23f1a65b3e3eaf49a39f0c299128f4f',
width: 1080,
height: 1920,
aspectRatio: 1080 / 1920,
originalDuration: 2.28,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/o8Ir2ejPffnqppYJfpGvQhKzGY30hfjKEAyXSZ~noop.jpeg?sign=1772278443-r0-u0-67dd3d85283b997c13ac9757d3f6aa00',
},
TargetTime: [0, 2280],
UserData: {
id: 'element19c1e87b2bf10000000008',
source: 'loki://1179433',
url: 'https://lf26-effectcdn-tos.byteeffecttos.com/obj/ies.fe.effect/4f6ef1bb3bd730dc6dd80ad5f5f5bb10',
fontFamily: '站酷仓耳渔阳体',
fontTypeUrl:
'https://lf5-hl-hw-effectcdn-tos.byteeffecttos.com/obj/ies.fe.effect/098d75dd0be7cc0f303b12e3cd2b918e',
fontTypeRef: '1187223',
type: 'text',
textType: '',
trackStyle: {
backgroundColor: 'green',
color: 'red',
fontSize: 14,
borderRadius: '4px',
},
},
},
],
[
{
ID: '8epztxp6y64',
Type: 'video',
Source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
UserData: {
id: 'element19ca40717641000000000f',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1774870443-f0fbe33b74af479e907768b22749391f-0-e211911e48e0e7d56f47525853d5fa1b',
width: 1080,
height: 1920,
aspectRatio: 1080 / 1920,
originalDuration: 2.88,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1772278443-r0-u0-0f12d033a0cf7a661ccc5d820bd5a3c6',
},
TargetTime: [1050, 3930],
Extra: [
{
ID: '8epztxp6y64_transform',
Type: 'transform',
PosX: 656,
PosY: 0,
ScaleX: 1,
ScaleY: 1,
Width: 608,
Height: 1080,
Rotation: 0,
FlipX: false,
FlipY: false,
Alpha: 1,
UserData: {
id: 'element19ca40717641000000000f',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1774870443-f0fbe33b74af479e907768b22749391f-0-e211911e48e0e7d56f47525853d5fa1b',
width: 1080,
height: 1920,
originalDuration: 2.88,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1772278443-r0-u0-0f12d033a0cf7a661ccc5d820bd5a3c6',
},
},
{
ID: '8epztxp6y64_eq',
Type: 'equalizer',
TargetTime: [0, 2880],
Brightness: 0,
Contrast: 0,
Saturation: 0,
Sharpen: 0,
Highlight: 0,
Temperature: 0,
Tone: 0,
UserData: {
id: 'element19ca40717641000000000f',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1774870443-f0fbe33b74af479e907768b22749391f-0-e211911e48e0e7d56f47525853d5fa1b',
width: 1080,
height: 1920,
originalDuration: 2.88,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1772278443-r0-u0-0f12d033a0cf7a661ccc5d820bd5a3c6',
},
},
{
ID: '8epztxp6y64_volume',
Type: 'a_volume',
Volume: 1,
UserData: {
id: 'element19ca40717641000000000f',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1774870443-f0fbe33b74af479e907768b22749391f-0-e211911e48e0e7d56f47525853d5fa1b',
width: 1080,
height: 1920,
originalDuration: 2.88,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1772278443-r0-u0-0f12d033a0cf7a661ccc5d820bd5a3c6',
},
},
{
ID: '8epztxp6y64_trim',
Type: 'trim',
StartTime: 0,
EndTime: 2880,
UserData: {
id: 'element19ca40717641000000000f',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1774870443-f0fbe33b74af479e907768b22749391f-0-e211911e48e0e7d56f47525853d5fa1b',
width: 1080,
height: 1920,
originalDuration: 2.88,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1772278443-r0-u0-0f12d033a0cf7a661ccc5d820bd5a3c6',
},
},
{
ID: '8epztxp6y64_speed',
Type: 'speed',
Speed: 1,
UserData: {
id: 'element19ca40717641000000000f',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1774870443-f0fbe33b74af479e907768b22749391f-0-e211911e48e0e7d56f47525853d5fa1b',
width: 1080,
height: 1920,
originalDuration: 2.88,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1772278443-r0-u0-0f12d033a0cf7a661ccc5d820bd5a3c6',
},
},
],
},
],
[
{
ID: '2qkr0vwsu98',
Type: 'video',
Source: 'vid://v02bffg10064d3vjq82ljhtejm9u1uog',
UserData: {
id: 'element19ca4085cb110000000016',
name: 'split_34.mp4',
source: 'vid://v02bffg10064d3vjq82ljhtejm9u1uog',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_34.mp4?auth_key=1774870443-3653567a0ef34b29b6f9c24bab42caad-0-1d242e5ff0863ed5e8bb7a5375858337',
width: 1080,
height: 1920,
originalDuration: 4.16,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/oQPBzQvgf6RLi4ZPkmZ1E6ff7CSxdZ0IfIVXB9~noop.jpeg?sign=1772278443-r0-u0-4966375c109791c89acff05c8e83a6ba',
},
TargetTime: [2640, 6800],
Extra: [
{
ID: '2qkr0vwsu98_transform',
Type: 'transform',
PosX: 656,
PosY: 0,
ScaleX: 1,
ScaleY: 1,
Width: 608,
Height: 1080,
Rotation: 0,
FlipX: false,
FlipY: false,
Alpha: 1,
UserData: {
id: 'element19ca4085cb110000000016',
name: 'split_34.mp4',
source: 'vid://v02bffg10064d3vjq82ljhtejm9u1uog',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_34.mp4?auth_key=1774870443-3653567a0ef34b29b6f9c24bab42caad-0-1d242e5ff0863ed5e8bb7a5375858337',
width: 1080,
height: 1920,
originalDuration: 4.16,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/oQPBzQvgf6RLi4ZPkmZ1E6ff7CSxdZ0IfIVXB9~noop.jpeg?sign=1772278443-r0-u0-4966375c109791c89acff05c8e83a6ba',
},
},
{
ID: '2qkr0vwsu98_eq',
Type: 'equalizer',
TargetTime: [0, 4160],
Brightness: 0,
Contrast: 0,
Saturation: 0,
Sharpen: 0,
Highlight: 0,
Temperature: 0,
Tone: 0,
UserData: {
id: 'element19ca4085cb110000000016',
name: 'split_34.mp4',
source: 'vid://v02bffg10064d3vjq82ljhtejm9u1uog',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_34.mp4?auth_key=1774870443-3653567a0ef34b29b6f9c24bab42caad-0-1d242e5ff0863ed5e8bb7a5375858337',
width: 1080,
height: 1920,
originalDuration: 4.16,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/oQPBzQvgf6RLi4ZPkmZ1E6ff7CSxdZ0IfIVXB9~noop.jpeg?sign=1772278443-r0-u0-4966375c109791c89acff05c8e83a6ba',
},
},
{
ID: '2qkr0vwsu98_volume',
Type: 'a_volume',
Volume: 1,
UserData: {
id: 'element19ca4085cb110000000016',
name: 'split_34.mp4',
source: 'vid://v02bffg10064d3vjq82ljhtejm9u1uog',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_34.mp4?auth_key=1774870443-3653567a0ef34b29b6f9c24bab42caad-0-1d242e5ff0863ed5e8bb7a5375858337',
width: 1080,
height: 1920,
originalDuration: 4.16,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/oQPBzQvgf6RLi4ZPkmZ1E6ff7CSxdZ0IfIVXB9~noop.jpeg?sign=1772278443-r0-u0-4966375c109791c89acff05c8e83a6ba',
},
},
{
ID: '2qkr0vwsu98_trim',
Type: 'trim',
StartTime: 0,
EndTime: 4160,
UserData: {
id: 'element19ca4085cb110000000016',
name: 'split_34.mp4',
source: 'vid://v02bffg10064d3vjq82ljhtejm9u1uog',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_34.mp4?auth_key=1774870443-3653567a0ef34b29b6f9c24bab42caad-0-1d242e5ff0863ed5e8bb7a5375858337',
width: 1080,
height: 1920,
originalDuration: 4.16,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/oQPBzQvgf6RLi4ZPkmZ1E6ff7CSxdZ0IfIVXB9~noop.jpeg?sign=1772278443-r0-u0-4966375c109791c89acff05c8e83a6ba',
},
},
{
ID: '2qkr0vwsu98_speed',
Type: 'speed',
Speed: 1,
UserData: {
id: 'element19ca4085cb110000000016',
name: 'split_34.mp4',
source: 'vid://v02bffg10064d3vjq82ljhtejm9u1uog',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_34.mp4?auth_key=1774870443-3653567a0ef34b29b6f9c24bab42caad-0-1d242e5ff0863ed5e8bb7a5375858337',
width: 1080,
height: 1920,
originalDuration: 4.16,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/oQPBzQvgf6RLi4ZPkmZ1E6ff7CSxdZ0IfIVXB9~noop.jpeg?sign=1772278443-r0-u0-4966375c109791c89acff05c8e83a6ba',
},
},
],
},
],
]
export const MOCK_TRACK2 = [
[
{
ID: 'h38fporyk3l',
Type: 'video',
Source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
UserData: {
id: 'element19c08a8b7f81000000000f',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
width: 1080,
height: 1920,
originalDuration: 2.88,
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1772272580-75fb679fe71b479fa7f7481719dd0762-0-94faac1a6a10f00a69bf53c0c5815c27',
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1769680580-r0-u0-e3f4226242978624c400b11c739d2ff5',
},
TargetTime: [0, 2880],
},
],
[
{
ID: 'va07tfjs8tr',
Type: 'video',
Source: 'vid://v02bffg10064d3vjq9aljht6ujf4ij5g',
UserData: {
id: 'element19c093370e41000000000f',
name: 'split_55.mp4',
source: 'vid://v02bffg10064d3vjq9aljht6ujf4ij5g',
type: 'video',
url: 'https://vod-fe-test-aideo.byte-test.com/split_55.mp4?auth_key=1772272580-f2724df6d3ac400c91b07e6ab5870b71-0-1ec6c65c08e93163d43cd200e62d38a4',
width: 1080,
height: 1920,
originalDuration: 2.28,
poster:
'https://console-image-cn.volcvod.com/aideo-dev/o8Ir2ejPffnqppYJfpGvQhKzGY30hfjKEAyXSZ~noop.jpeg?sign=1769680580-r0-u0-d8c1502261739fd9730253e903aa2636',
},
TargetTime: [900, 3180],
},
],
]
/** 模拟删除轨道:仅保留第 1 条轨道(用于 demo 按钮「删除轨道」在仅剩 1 条时恢复用) */
export const MOCK_TRACK_DEL = [MOCK_TRACK[0]]
/** 新增一条轨道时用的单个视频片段模板(后端格式),用于 demo「增加轨道」在现有轨道上追加一条 */
export const MOCK_NEW_TRACK_ELEMENT = {
ID: 'mock_add_track_element_1',
Type: 'video',
Source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
UserData: {
id: 'mock_add_element_1',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
width: 1080,
height: 1920,
originalDuration: 2.88,
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1772272580-75fb679fe71b479fa7f7481719dd0762-0-94faac1a6a10f00a69bf53c0c5815c27',
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1769680580-r0-u0-e3f4226242978624c400b11c739d2ff5',
},
TargetTime: [4000, 6880],
}
export const remark_TRACK_ELEMENT = [
// 一条轨道(Track),数组内为该轨道上的元素列表
[
{
// 元素唯一 ID,业务侧用于关联 getVideoFrame 等
ID: 'kbcgoc952m',
TrackId: 'track1',
// 元素类型:video | audio | image | text | effect | sticker
Type: 'video',
// 素材来源标识,视频/音频为 vid://xxx,图片为 mid://xxx
Source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
// 业务侧透传数据,含展示用 name、播放 url、封面 poster、原始宽高与时长等
UserData: {
id: 'element19c08a8b7f81000000000f',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
width: 1080,
height: 1920,
originalDuration: 2.88,
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1772279732-bf753f15aba547e99f8e4ecae8b5217d-0-1b9560eb6b509e1b2371f6fca04227e5',
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1769687732-r0-u0-79503ff3dc915c02d8dc9d0ef05944a6',
},
// 该元素在时间轴上的起止时间 [开始ms, 结束ms]
TargetTime: [0, 1704],
// 该元素上的滤镜/特效列表(transform、调色、音量、裁剪、倍速等)
Extra: [
{
ID: 'kbcgoc952m_transform',
Type: 'transform',
PosX: 656, // 画布内 X
PosY: 3, // 画布内 X
ScaleX: 1,
ScaleY: 1,
Width: 608,
Height: 1080,
Rotation: 14, // 旋转角度(度)
FlipX: false,
FlipY: false,
Alpha: 1, // 不透明度 0–1
UserData: {
id: 'element19c08a8b7f81000000000f',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
width: 1080,
height: 1920,
originalDuration: 2.88,
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1772279732-bf753f15aba547e99f8e4ecae8b5217d-0-1b9560eb6b509e1b2371f6fca04227e5',
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1769687732-r0-u0-79503ff3dc915c02d8dc9d0ef05944a6',
},
},
{
ID: 'kbcgoc952m_volume',
Type: 'a_volume',
Volume: 0.51, // 音量 0–1
UserData: {
id: 'element19c08a8b7f81000000000f',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
width: 1080,
height: 1920,
originalDuration: 2.88,
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1772279732-bf753f15aba547e99f8e4ecae8b5217d-0-1b9560eb6b509e1b2371f6fca04227e5',
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1769687732-r0-u0-79503ff3dc915c02d8dc9d0ef05944a6',
},
},
{
ID: 'kbcgoc952m_trim',
Type: 'trim',
StartTime: 0, // 裁剪起始时间 ms(相对原片)
EndTime: 2880, // 裁剪结束时间 ms(相对原片)
UserData: {
id: 'element19c08a8b7f81000000000f',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
width: 1080,
height: 1920,
originalDuration: 2.88,
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1772279732-bf753f15aba547e99f8e4ecae8b5217d-0-1b9560eb6b509e1b2371f6fca04227e5',
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1769687732-r0-u0-79503ff3dc915c02d8dc9d0ef05944a6',
},
},
{
ID: 'kbcgoc952m_speed',
Type: 'speed',
Speed: 1.69, // 播放倍速,如 1.69 表示 1.69 倍速
UserData: {
id: 'element19c08a8b7f81000000000f',
name: 'split_54.mp4',
source: 'vid://v02bffg10064d3vjq9aljht0oe413p20',
type: 'video',
width: 1080,
height: 1920,
originalDuration: 2.88,
url: 'https://vod-fe-test-aideo.byte-test.com/split_54.mp4?auth_key=1772279732-bf753f15aba547e99f8e4ecae8b5217d-0-1b9560eb6b509e1b2371f6fca04227e5',
poster:
'https://console-image-cn.volcvod.com/aideo-dev/ogfhfJtgz0XHffHyA2ujQKCPnIeRpGj8YEEqIk~noop.jpeg?sign=1769687732-r0-u0-79503ff3dc915c02d8dc9d0ef05944a6',
},
},
],
},
],
]
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
功能描述
byted-mediakit-voiceover-editing:口播视频一站式剪辑技能。从视频/音频素材到 VOD 导出的完整流水线。
Agent 快速识别
| 项目 | 说明 |
|---|---|
| 触发词 | 口播剪辑、剪口播、剪视频、去掉停顿、处理音频、导出口播、自动剪辑、去除口误、视频剪辑 |
| 输入 | 视频/音频 URL、本地文件、VOD Vid、DirectUrl(空间内文件名) |
| 核心能力 | ASR 转写 → 语义纠错 → 口癖/重复/静音剪辑(EDL) → 审核页修改 → VOD 导出 |
| 输出 | 剪辑后的视频(VOD OutputVid + PlayURL) |
| 前置 | 完成 SKILL.md 阅读;按顺序执行 Step 1~6c,不得跳步 |
规则
1. 请完成阅读 SKILL.MD 2. 禁止重新生成脚本 3. 需要根据环境变量 TALKING_VIDEO_AUTO_EDIT_REVIEW_AUTO_OPEN 是否打开审核页面:审核页启动时是否自动打开浏览器(默认不打开;0 表示不打开,1 打开) 4. 各个任务间相互隔离 5. 需要使用绝对路径运行。 6. 不得跳过 Step2:Step3(pipeline_url_to_asr.py)运行前必须先在同一 --output-dir 下生成 step2_config_confirmed.json(使用 scripts/step2_confirm_config.py),否则脚本会阻断继续执行。
产物目录(output)放在哪
默认产物根为 `<工程根>/output/`;--output-dir 只能指向该目录下(如 output/<素材名>)。工程根由 scripts/project_paths.py 解析,不硬编码路径名或绝对路径:
1. 若设置 `VOICEOVER_EDITING_PROJECT_ROOT`(可选),则以其为工程根(任意布局均适用)。 2. 否则:从 技能根目录(SKILL_DIR) 沿父目录 固定上移 3 级(parents[2],与中间文件夹叫什么无关);路径过浅时再退一级。
举例:技能在 <SKILL_DIR>(SKILL_DIR 为最末一级)→ 上移三级得到 <PROJECT_ROOT> → 默认产物为 `<PROJECT_ROOT>/output`。
环境变量配置
注册表元数据:SKILL.md frontmatter 中 env[].required/secret 与本表一致。运行时与 setup.sh 均优先使用进程环境变量,再用 .env 补全未设置的项;ARK_SKILL_* 通常由容器注入,不必写入 .env。VOD 接入:apig(两变量在环境中均非空)与 cloud(VOLC_ACCESS_KEY_*)二选一;VOLC_SPACE_NAME 与 ASR 仍必填(环境或 .env)。安全:最小权限与独立测试空间;.env 勿提交仓库。
依赖锁定:Python 依赖在 scripts/requirements.txt 中以 == 固定主版本;setup.sh 使用 python -m venv 创建 scripts/.venv 并执行 pip install -r requirements.txt。间接依赖由安装时 PyPI 元数据解析;若需全量字节级复现,可在受控环境自行导出 pip freeze 清单使用。
| 变量名 | 备注 | 默认值 | 是否必选 |
|---|---|---|---|
ARK_SKILL_API_BASE | SkillHub VOD 网关根 URL;与 KEY 同时非空则 apig。部署侧多由容器注入,一般不写 .env | - | 与 AK 二选一 * |
ARK_SKILL_API_KEY | SkillHub Bearer;与 BASE 同时非空则 apig。容器注入为主,可不写 .env | - | 与 BASE 二选一 * |
VOLC_ACCESS_KEY_ID | 火山引擎 Access Key ID(直连 cloud 时必填) | - | 与 ARK_SKILL 二选一 |
VOLC_ACCESS_KEY_SECRET | 火山引擎 Access Key Secret(直连 cloud 时必填) | - | 与 ARK_SKILL 二选一 |
VOLC_SPACE_NAME | 火山引擎点播空间名称 | - | 必选 |
VOLC_HOST | VOD API 主机(仅 cloud 模式有效) | vod.volcengineapi.com | 可选 |
VOLC_REGION | VOD 区域(仅 cloud 模式有效) | cn-north-1 | 可选 |
ASR_API_KEY | 豆包语音转写 API Key | - | 必选(ASR/剪辑时) |
ASR_BASE_URL | 豆包语音转写 API Base URL | https://openspeech.bytedance.com/api/v3/auc/bigmodel | 可选 |
VOD_EXPORT_SKIP_SUBTITLE | 导出时跳过字幕压制;默认跳过,0 表示启用字幕压制, 1 表示跳过 | 跳过字幕压制 | 可选 |
TALKING_VIDEO_AUTO_EDIT_REVIEW_AUTO_OPEN | 审核页启动时是否自动打开浏览器;默认不打开,1 表示打开,0标识不打开,打开审核页面需要在本地环境 | 不打开审核页面 | 可选 |
TALKING_VIDEO_AUTO_EDIT_VIDEO_CUT | 导出时是否进行视频剪辑;1 且(有字幕或音频静音)时移除 mute 段、主时间轴从 0 无缝拼接 | 1 进行视频剪辑 | 可选 |
VOICEOVER_EDITING_PROJECT_ROOT | 显式指定工程根(<根>/output 存放流水线产物);不设则按 SKILL_DIR 的 parents[2] 推断 | - | 可选 |
\ 二选一:进程环境中 `ARK_SKILL_API_BASE` + `ARK_SKILL_API_KEY`(皆非空)为 apig(`setup.sh` 与运行时均先读环境变量再读 `.env`*);否则须配置 VOLC_ACCESS_KEY_ID + VOLC_ACCESS_KEY_SECRET。
流程图
flowchart TD
subgraph 环境与配置
A1[Step 1: 环境检查 setup.sh]
A2[Step 2: 语气词/卡顿词配置确认]
end
subgraph 素材与ASR
B1["Step 3: pipeline_url_to_asr<br/>(URL | 本地 | Vid | DirectUrl)"]
B2[step1~step5 JSON]
end
subgraph Agent处理
C1[Step 4: ASR 语义纠错]
C2[step5_asr_optimized.json]
C3[Step 5: 口播剪辑]
C4[step6_speech_cut.json]
end
subgraph 导出流程
D1[Step 6a: prepare_export_data]
D2["export_request.json<br/>review_import_data.json"]
D3[Step 6b: 审核页 + 导出服务]
D4[用户审核修改]
D5[export_submit_*.json]
D6[Step 6c: vod_direct_export]
D7[VOD 导出任务完成]
end
A1 --> A2 --> B1 --> B2
B2 --> C1 --> C2 --> C3 --> C4
C4 --> D1 --> D2 --> D3 --> D4 --> D5 --> D6 --> D7<!-- input: 火山ASR转录结果 output: asr 纠错后的结果 pos: 核心,所有规则的基础 -->
角色
- 你是专注于各类语言 ASR 结果纠错的专家,能够 ASR 结果 ,通过分析前后语境、语气确定、句子的语义等对ASR 的内容进行纠错,返回正确结果
任务:
- 准确识别语音内容,认真参考提供的 ASR 转录文本,对 ASR 转录文本进行纠错。
- 仅做:① 标点恢复与断句(超长句按语义边界拆分,单 segment 建议 ≤10 字);② 同音/近音字纠错。
- 不做:删除重复词、口癖、顺句词或改写句式。
禁止行为:
- ❌ 删除内容,仅仅可以修改如
真环->甄嬛 - ❌ 删除或合并重复词(如「一个一个」「那个那个」)
- ❌ 删除或改写 嗯、啊、呃 等口癖/语气词
- ❌ 删除「就是」「其实」「比如说」「它」等顺句词
- ❌ 删除「的」或改写句式(如「口播剪辑的工具」→「口播剪辑工具」)
输出要求:
- text:矫正后的转录文本(仅标点 + 同音字纠错,其余尽量保持与 source_text 一致)
- source_text:原始 ASR 文本
- words(必含):逐字数组,与
step5_asr_raw_*.json的 utterances[].words 结构一致,每字{ "text": "字", "start_time": ms, "end_time": ms },同音纠错时仅替换该字text,时间戳不变 - 片段开始、结束时间要以word的为准
逐字约束(必须遵守):
- 每个 segment 必须包含
words数组,从源 utterances[].words 逐字继承,与 ASR raw 保存一致 - 不能多字:禁止插入原文不存在的字(如 重新说 → ~~又重新说的~~)
- 不能少字:禁止删除字(同音替换除外,如 的↔地、在↔再)
- 仅可做:① 同音/近音字替换(的↔地、在↔再);② 标点补充
words长度 = 该 segment 的字符数,时间戳取自源数据,不得改动
示例(正确 vs 错误):
| 原始 (source_text) | ✅ 正确 (text) | ❌ 错误 (text) |
|---|---|---|
| 我最近做的一个一个口播剪辑的工具。 | 我最近做的一个一个口播剪辑的工具。 | ~~我最近做的一个口播剪辑工具。~~(删了重复、改了句式) |
| 比如说,嗯啊呃这种,还有说错了重新说的。 | 比如说,嗯啊呃这种,还有说错了重新说的。 | ~~比如说,"嗯""啊""呃"这种语气词,还有说错了又重新说的。~~(改写了口癖、多了字「又」) |
EDL 编辑决策格式
口播剪辑的片段级编辑描述,供 Step 5 产出及导出使用。时间单位统一为 ms。
字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| text | string | ✓ | 处理后文本(concat 时为拼接结果);delete 时填 source_text,便于展示被删除内容 |
| source_text | string | ✓ | 原始 ASR 文本 |
| start_time | number | ✓ | 该片段在源音视频中的起始时间(ms);concat 删前留后时须为原句起始(含被删部分),不可写成保留部分起始 |
| end_time | number | ✓ | 该片段在源音视频中的结束时间(ms) |
| reason | string | ✓ | 处理原因,需明确 |
| action | string | ✓ | 处理动作:mute / delete / concat / keep |
| actionTime | array | ✓ | 处理时间范围,见下表 |
action 与 actionTime
| action | 含义 | actionTime 格式 |
|---|---|---|
| mute | 无说话:保留时长,做静音处理(音量置 0) | [{ start_time, end_time }] 需静音的范围 |
| delete | 整段删除,不参与输出(仅用于冗余内容,非无说话段) | [{ start_time, end_time }] 需删除的范围 |
| concat | 句内剪辑:取多个 trim 拼接,中间删除 | [{ start_time, end_time }, ...] 需保留的片段列表,按顺序拼接 |
| keep | 原样保留 | [{ start_time, end_time }] 原片段范围 |
时间一致性
- concat 与 deleted_parts:actionTime 的保留区间不得与 deleted_parts 中要删除的区间重叠
- mute 段:显式 mute 的时间范围不得与相邻 keep 段重叠
reason 规范
| 场景 | 格式示例 |
|---|---|
| 开头/片段间静音 | 片段 0-230ms 无说话,音频做静音处理 |
| 片段间静音 | 片段间静音 18490ms(约 18.5s),无说话,保留时长做静音处理 |
| 句内重复 | 句内重复:一个一个(A+A 模式),删前留后,保留最后一个「一个」 |
| 语气词 | 语气词:嗯/啊/呃,按删除边界拼接 |
| 卡顿词 | 卡顿词:那个那个,删前留后 |
| 保留 | 保留 |
句内 concat 示例
原文「我最近做的一个一个口播剪辑的工具」,去掉第一个「一个」:
{
"text": "大家好,今天跟大家聊一下我最近做的一个口播剪辑的工具。",
"source_text": "大家好,今天跟大家聊一下我最近做的一个一个口播剪辑的工具。",
"start_time": 230,
"end_time": 7470,
"reason": "句内重复:一个一个,删前留后",
"action": "concat",
"actionTime": [
{ "start_time": 230, "end_time": 5310 },
{ "start_time": 5950, "end_time": 7470 }
]
}actionTime 为保留并拼接的源时间范围,中间 5310-5950ms 被删除。
删前留后(顺句词/语气词)示例
原文「其实啊,做视频内容最大的痛苦是什么?」,去掉「其实啊」:
{
"text": "做视频内容最大的痛苦是什么?",
"source_text": "其实啊,做视频内容最大的痛苦是什么?",
"start_time": 18980,
"end_time": 22220,
"reason": "顺句词:其实啊,直接移除",
"action": "concat",
"actionTime": [{ "start_time": 19900, "end_time": 22220 }]
}start_time: 18980须覆盖整句,含删前 18980–19900actionTime仅保留部分 19900–22220deleted_parts对应项:start_time: 18980, end_time: 19900(延伸至首个保留字前)
导出格式规范(formats.md)
---
平台预设
抖音(douyin)
- 分辨率:1080 × 1920(竖屏 9:16)
- 帧率:30fps
- 视频码率:4 Mbps
- 音频码率:128 kbps
- 编码:H.264 / AAC
- CRF:23
- 字幕字体大小:18pt,白色+黑色描边
视频号(shipinhao)
- 分辨率:1080 × 1920(竖屏 9:16)
- 帧率:30fps
- 视频码率:3 Mbps
- 音频码率:128 kbps
- 编码:H.264 / AAC
- CRF:24
B站横屏(bilibili)
- 分辨率:1920 × 1080(横屏 16:9)
- 帧率:30fps
- 视频码率:5 Mbps
- 音频码率:192 kbps
- 编码:H.264 / AAC
- CRF:20
B站竖屏(bilibili_v)
- 分辨率:1080 × 1920(竖屏 9:16)
- 帧率:30fps
- 视频码率:4 Mbps
- 音频码率:192 kbps
- 编码:H.264 / AAC
- CRF:20
自定义(custom)
- 保持原始分辨率,CRF 22,码率 4M/128k
- 可通过
--preset custom后手动指定 FFmpeg 参数
---
字幕规范
- 格式:SRT
- 字体:系统默认(Noto Sans CJK 优先)
- 字号:18pt
- 颜色:白字黑描边
- 位置:底部居中(Alignment=2)
- 样式参数:
FontSize=18,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,Outline=2,Alignment=2
---
可编辑平台配置(用于字幕位置调整)
说明:
>
- 这是唯一可机器读写的配置块,支持用户调整“字幕位置/样式”并记录变更。
- 请仅修改 JSON 内容(保持合法 JSON),不要改动代码块外层标记。
- Alignment 取值参考 ASS 对齐:1/2/3=底左/底中/底右,7/8/9=顶左/顶中/顶右。- MarginV 为字幕离底部/顶部的像素边距(随对齐方向生效)。{
"presets": {
"bilibili": {
"audio_bitrate": "192k",
"crf": 20,
"fps": 30,
"resolution": "1920x1080",
"subtitle_style": {
"Alignment": 2,
"FontSize": 22,
"MarginV": 50,
"Outline": 2,
"OutlineColour": "&H00000000",
"PrimaryColour": "&H00FFFFFF"
},
"video_bitrate": "5M"
},
"bilibili_v": {
"audio_bitrate": "192k",
"crf": 20,
"fps": 30,
"resolution": "1080x1920",
"subtitle_style": {
"Alignment": 2,
"FontSize": 18,
"MarginV": 40,
"Outline": 2,
"OutlineColour": "&H00000000",
"PrimaryColour": "&H00FFFFFF"
},
"video_bitrate": "4M"
},
"custom": {
"audio_bitrate": "128k",
"crf": 22,
"fps": 30,
"resolution": "keep",
"subtitle_style": {
"Alignment": 2,
"FontSize": 18,
"MarginV": 40,
"Outline": 2,
"OutlineColour": "&H00000000",
"PrimaryColour": "&H00FFFFFF"
},
"video_bitrate": "4M"
},
"douyin": {
"audio_bitrate": "128k",
"crf": 23,
"fps": 30,
"resolution": "1080x1920",
"subtitle_style": {
"Alignment": 2,
"FontSize": 18,
"MarginV": 41,
"Outline": 2,
"OutlineColour": "&H00000000",
"PrimaryColour": "&H00FFFFFF"
},
"video_bitrate": "4M"
},
"shipinhao": {
"audio_bitrate": "128k",
"crf": 24,
"fps": 30,
"resolution": "1080x1920",
"subtitle_style": {
"Alignment": 2,
"FontSize": 18,
"MarginV": 40,
"Outline": 2,
"OutlineColour": "&H00000000",
"PrimaryColour": "&H00FFFFFF"
},
"video_bitrate": "3M"
}
}
}#
文件命名规范
output_{preset}_{YYYYMMdd_HHmmss}.mp4示例:output_douyin_20240101_120000.mp4
Step1: 环境检查与依赖安装
目标:检查环境是否符合要求,若不符合则提示用户配置环境变量
>
SKILL_DIR:指 byted-mediakit-voiceover-editing 目录路径>
前置要求:必须在 ./scripts 目录下执行本步骤命令检查单
- [ ] 确认
<SKILL_DIR>是否存在 - [ ] 存在切换到
byted-mediakit-voiceover-editing - [ ] 不存在退出并提示用户
- [ ] 存在继续下面流程
- [ ] Run:
./scripts/setup.sh - [ ] 若不存在
<SKILL_DIR>/.env,脚本会从templates/env.md复制生成.env骨架;不会自动写入云厂商密钥。模板不含ARK_SKILL_*(由宿主/容器注入进程环境)。须在.env或环境中配置:VOLC_SPACE_NAME、ASR_*;VOD 鉴权为 apig(环境中ARK_SKILL_*皆有值)或 cloud(VOLC_ACCESS_KEY_*)二选一。 - [ ] 若
setup.sh报错:脚本优先查进程环境、再查 `.env`。APIG 下按提示补VOLC_SPACE_NAME、ASR_*(可写.env或注入环境);ARK_SKILL_*由部署注入即可,无需写入.env。 - [ ] 相关参考文档如下
视频点播密钥获取: https://console.volcengine.com/iam/keymanage
视频点播空间获取: https://console.volcengine.com/vod
豆包语音ASR密钥& BASE URL 获取: https://console.volcengine.com/speech/new/experience/asr?projectName=default- [ ] CHECKPOINT: 确认
./scripts/setup.sh输出包含环境检查完成与依赖安装完成,且./scripts/.venv/已生成
使用流程示意
flowchart TD
Start([开始 Step1]) --> CheckDir{SKILL_DIR<br/>是否存在?}
CheckDir -->|否| Exit1[退出并提示用户<br/>配置或拉取技能目录]
CheckDir -->|是| CdSkill[进入 byted-mediakit-voiceover-editing<br/>工作目录: SKILL_DIR 根目录]
CdSkill --> RunSetup[执行 ./scripts/setup.sh]
RunSetup --> EnvMissing{.env 不存在?}
EnvMissing -->|是| Scaffold[从 templates/env.md<br/>复制生成 .env 骨架]
Scaffold --> UserFill1[本地编辑 .env<br/>填写点播与 ASR 变量(见 SKILL 凭据说明)]
UserFill1 --> RunSetup
EnvMissing -->|否| SetupErr{setup.sh 报错<br/>变量缺失或为空?}
SetupErr -->|是| DocRef[按下方控制台链接<br/>获取密钥]
DocRef --> UserFill2[本地编辑 .env 补齐]
UserFill2 --> RunSetup
SetupErr -->|否| Checkpoint{输出含「环境检查完成」<br/>「依赖安装完成」<br/>且 scripts/.venv 已生成?}
Checkpoint -->|否| Retry[排查环境/网络后重试]
Retry --> RunSetup
Checkpoint -->|是| Done([CHECKPOINT 通过<br/>进入后续步骤])说明:若你当前工作目录已是<SKILL_DIR>/scripts,则等价执行./setup.sh(与从根目录执行./scripts/setup.sh一致)。
Step2: 语气词提示与用户行为更新
目标:在执行 ASR/剪辑前,先让用户确认并更新规则配置(语气词/卡顿词),避免误删或误标记
>
SKILL_DIR:指 byted-mediakit-voiceover-editing 目录路径>
前置要求:必须在 ./scripts 目录下执行本步骤命令>
超时:20 秒内无回复 → 按默认配置执行
>
强制 Gate:Step2 完成后必须生成 output/<任务>/step2_config_confirmed.json,否则不得进入 Step3(脚本会阻断继续执行)。检查单
- [ ] 展示当前配置(必须让用户看见并逐项确认)
- [ ] 读取文件
references/用户规则/2-语气词检测.md、references/用户规则/5-卡顿词.md,提取并展示以下配置项供用户确认: - 单个语气词策略、语气词列表、保留语气词列表
- 卡顿词模式
- [ ] CHECKPOINT:用户已逐项确认
- [ ] 根据用户口述执行变更(仅更新规则配置,不跑剪辑流程)
- [ ] CHECKPOINT:命令输出出现
✅ 已更新并记录到 变更记录.md
- [ ] 再次展示更新后的列表(用于最终确认)
- [ ] 读取文件
references/用户规则/2-语气词检测.md、references/用户规则/5-卡顿词.md,展示更新后的配置 - [ ] CHECKPOINT:配置与用户最终确认一致
- [ ] 生成 Step2 checkpoint(必须):
- [ ] 运行:
python step2_confirm_config.py --output-dir <output/<任务目录>> - [ ] CHECKPOINT:输出出现
Step2 checkpoint 已生成: .../step2_config_confirmed.json
使用流程示意
flowchart TD
Start([开始 Step2]) --> Show1[读取并展示<br/>2-语气词检测 / 5-卡顿词]
Show1 --> Confirm1{用户逐项确认?}
Confirm1 -->|超时 20s| Default[按默认配置继续]
Confirm1 -->|已确认| Change[按用户口述更新规则<br/>输出含 已更新并记录到 变更记录.md]
Default --> Show2
Change --> Show2[再次读取并展示更新后配置]
Show2 --> Final{与用户最终确认一致?}
Final -->|否| Change
Final -->|是| Done([CHECKPOINT 通过<br/>进入 Step3])Step3: URL → ASR 流水线 + 候选生成
目标:从视频/素材提取音频,经人声分离/降噪后输出 ASR 结果(JSON),并生成流水线候选产物
>
SKILL_DIR:指 byted-mediakit-voiceover-editing 目录路径>
前置要求:必须先cd <SKILL_DIR>/scripts,且在已激活的scripts/.venv下执行(setup.sh会创建并pip install -r requirements.txt)
>
说明:URL 或本地路径作为首个位置参数传入时会走上传;`--vid` 用于已有 Vid(跳过上传);`--directurl` 仅用于 VOD 空间内已有资源的 FileName(跳过上传)。
检查单
- [ ] 前置校验(避免链路失败):执行前必须验证用户输入类型
- 若为 URL:必须以
http://或https://开头,否则提示用户修正 - 若为本地文件:必须确认文件存在,否则提示用户
- [ ] Run:
- 必须先进入 scripts 目录并激活虚拟环境:
cd ./scriptssource .venv/bin/activate(或由setup.sh已安装依赖的同一 venv)- URL 或本地文件(会执行上传):
python ./pipeline_url_to_asr.py "<url_or_local_path>" --ext ".mp4" [--output-dir output/<文件名>] - 已有 Vid(跳过上传):
python ./pipeline_url_to_asr.py --vid "<vid>" --ext ".mp4" [--output-dir output/<文件名>] - 已有 DirectUrl(VOD 空间内 FileName,跳过上传):
python ./pipeline_url_to_asr.py --directurl "<filename>" --ext ".mp4" [--output-dir output/<文件名>] - [ ] 用户输入说明:
- URL:公网素材地址,必须以
http://或https://开头 - 本地文件:本地路径作为第一个位置参数传入(如
./Test_Video_720p.mp4),禁止用--directurl传本地路径 - Vid:视频 ID,示例:
v02399g100***2qpj9aljht4nmunv9ng - DirectUrl:VOD 空间内已存在资源的 FileName(如
abc123.mp4),非本地路径;本地文件应走上传流程 - [ ] CHECKPOINT(流水线产物):确认
output/<文件名>/目录下已生成: step1~step5的 JSON 文件(上传/识别已有素材、提取音频、人声分离、降噪、ASR 结果)- 注意:输出目录位于工程根目录,按主 SKILL 中「输出目录与重复处理规则」确定
使用流程示意
flowchart TD
Start([开始 Step3]) --> Validate{输入类型合法?<br/>URL / 本地 / Vid / DirectUrl}
Validate -->|否| Fix[提示用户修正路径或协议]
Fix --> Start
Validate -->|是| Cd[cd ./scripts]
Cd --> Run[python pipeline_url_to_asr.py<br/>+ 对应参数与 --output-dir]
Run --> Ok{output/<文件名>/<br/>含 step1~step5 JSON?}
Ok -->|否| Diagnose[排错后重试]
Diagnose --> Run
Ok -->|是| Done([CHECKPOINT 通过<br/>进入 Step4])Step4: 宿主 Agent ASR 纠错(必须)
目标:通过宿主 Agent 提升 ASR 断句与字词准确率;仅做断句与字词修正,不做口癖/语气词去除(口癖在 Step5)
>
执行者:宿主 Agent(你)
>
SKILL_DIR:指 byted-mediakit-voiceover-editing 目录路径>
参考文件:references/内置/ASR语义纠错.md>
前置要求:在./scripts目录下如需运行合并脚本,在已激活的scripts/.venv中使用python ./merge_asr_words.py
检查单
- [ ] 重复文件检查:若
output/<文件名>/step5_asr_optimized.json已存在,必须提示用户:「step5_asr_optimized.json 已存在,是否删除/覆盖/保留并写入新目录(01)?」用户确认后再执行 - [ ] 输入文件:ASR 处理结果(step5 相关产物)
- [ ] 宿主 Agent 执行任务(仅限以下两项):
- [ ] 断句(必做):标点恢复优化、语义化断句;超长句(>15 字)必须按语义边界拆分为多 segment,单段建议 ≤10 字
- [ ] 字词准确率:同音词纠错(基于上下文修正同音词错误,如 的/地/得、在/再 等;勿硬编码特定词,如 这都 等由 Step5 口播剪辑移除)
- [ ] 逐字约束:输出必须与 ASR 原始字级时间戳(
step5_asr_raw_*.json的 words 结构)逐字对应,不能多字、不能少字,仅可替换同音字,start_time/end_time取自源数据 - [ ] ❌ 禁止:
- 删除或合并重复词(一个一个、那个那个)
- 删除或改写 嗯、啊、呃 等口癖/语气词
- 删除 就是、其实、比如说、它 等顺句词
- 删除「的」或改写句式(由 Step5 处理)
- [ ] 输出:
- 将优化结果写入
output/<文件名>/step5_asr_optimized.json(必须使用上下文推导的 output-dir,勿写 output 根目录) - 禁止创建「简化版」或占位符;必须完整执行 ASR 纠错,格式与 words 逐字结构缺一不可
- 必须从
step5_asr_raw_*.json读取 utterances[].words 逐字结构,每个 segment 含words数组(与源一致,仅纠正字可替换 text) - 格式:
{ "optimized_segments": [{ "text": "...", "source_text": "", "start_time": 0.23, "end_time": 7.47, "words": [{ "text": "大", "start_time": 630, "end_time": 870 }, ...] }] } - 说明:
words时间为毫秒;segment 的 start/end 为秒(Step6a 会依 words 字级时间校正) - 若输出缺
words,可运行python ./merge_asr_words.py [--output-dir output/<文件名>]从 raw 合并
- [ ] CHECKPOINT:优化结果,时间戳连续不重叠
使用流程示意
flowchart TD
Start([开始 Step4]) --> Dup{step5_asr_optimized.json<br/>已存在?}
Dup -->|是| Ask[提示用户 删除/覆盖/新建01]
Ask --> Start
Dup -->|否| Read[读 step5_asr_raw 等]
Read --> LLM[宿主 Agent:断句 + 同音纠错<br/>遵守逐字约束]
LLM --> Write[写入 step5_asr_optimized.json]
Write --> Words{含完整 words?}
Words -->|否| Merge[可选 python merge_asr_words.py]
Merge --> Check
Words -->|是| Check{时间戳连续不重叠?}
Check -->|否| Fix[修正后重写]
Fix --> Write
Check -->|是| Done([CHECKPOINT 通过<br/>进入 Step5])Step5: 宿主 Agent 口播剪辑
目标:基于 Step4 纠错结果与用户规则,生成可审核的口播剪辑方案(sentences + track),输出 step6_speech_cut.json>
执行者:宿主 Agent(你)
>
SKILL_DIR:指 byted-mediakit-voiceover-editing 目录路径>
参考文档:references/用户规则/*.md、references/内置/EDL编辑决策格式.md、examples/edl.json
强制阅读清单(必须逐文件读完)
注意:不得只读 `references/用户规则/README.md`。Step5 必须按下列清单逐个读取并在输出中体现命中情况(见“输出自证”)。
>
禁止用“在工作区搜索 *.md”来代替逐文件阅读(搜索只能用于定位,不视为已读)。references/用户规则/README.md(优先级总览)references/用户规则/1-核心原则.mdreferences/用户规则/2-语气词检测.mdreferences/用户规则/3-静音段处理.mdreferences/用户规则/4-重复句检测.mdreferences/用户规则/5-卡顿词.mdreferences/用户规则/6-句内重复检测.mdreferences/用户规则/7-连续语气词.mdreferences/用户规则/8-重说纠正.mdreferences/用户规则/9-残句检测.mdreferences/用户规则/10-顺句词删除.mdreferences/用户规则/已更新并记录到 变更记录.md(如存在的话)
检查单
- [ ] 重复文件检查
- [ ] 若用户未显式指定 `--output-dir`:默认会写入
output/<素材名(_01)>/(目录冲突会自动递增_01/_02),避免覆盖既有任务目录 - [ ] 若用户显式指定了 `--output-dir` 且
step6_speech_cut.json已存在:必须提示用户「是否删除/覆盖/保留并写入新目录(\_01)」,用户确认后再执行 - [ ] 读取文件(从
output/<文件名>/读取): - [ ] ASR 纠错结果:
output/<文件名>/step5_asr_optimized.json(含 words 逐字,时间 ms) - [ ] ASR 原始文本:
output/<文件名>/step5_asr_raw_*.json(用于字级时间戳/上下文) - [ ] 流水线产物(可选):
output/<文件名>/step3_voice_separation_result.json(拿人声/背景音 DirectUrl) - [ ] 内容处理(先执行逻辑,再按 EDL 格式输出)
- [ ] 按优先级执行(强制):必须按
references/用户规则/README.md的 1~8 优先级顺序生成剪辑方案(静音 → 残句 → 重复句 → 句内重复 → 卡顿词 → 重说纠正 → 顺句词/口误 → 语气词) - [ ] 规则命中必须可追溯:对每个被删/静音/拼接的段,在
reason/reasonTags中明确写出命中的规则文件(例如:规则命中:4-重复句检测、规则命中:10-顺句词删除) - [ ] 语义重复检查(必做):参考
references/用户规则/4-重复句检测.md,先逐对检查相邻句语义重复。典型:前句「XX 原理是/其实是」+ 后句「我来说一下 XX 流程/方法」→ 前句为过渡铺垫,整段 delete,不做句内 concat。 - [ ] 无说话段显式标记:开头(如 0–230ms)、片段间所有无说话区间必须在 output 中显式列出,
action: mute,便于静音处理、避免噪音,格式如{ "text": "", "reason": "无说话 0–230ms,静音处理避免噪音", "action": "mute", "actionTime": [{"start_time": 0, "end_time": 230}] } - [ ] 删除/静音内容需明确:
reason必须标明具体删除或静音了什么内容。例如:句内静音删除重复词时写「句内静音 5310-5950ms,删除「一个」」;无说话段写「句内静音 X-Yms,无说话,静音处理」或「开头 0-Xms 无说话,静音处理(无内容)」。 - [ ] 片段间静音:无说话段保留时长,用
mute做静音处理(不删时长);delete仅用于冗余内容(如重复句整句) - [ ] 禁止添加原文不存在的内容:
text必须来自source_text对应时间范围内的字,不得插入、替换为原文不存在的词(如 source 为「比如说」时不得输出「比如剪映」) - [ ] 举例结构保护:当 嗯啊呃 等作为举例内容出现(如「比如说,嗯啊呃这种」)时,不得删除,否则「这种」无指代
- [ ] 句内 concat:删除重复词/顺句词时,用
concat+actionTime列出仅保留的 trim 范围(仅在无语义重复时做句内剪辑) - actionTime 必须从 step5 words 逐字查得保留部分的 start/end,不能填整段 segment 的起止;否则人声轨会保留被删内容导致音频仍播放
- concat 的 start_time:必须为原句在源中的起始时间(含被删部分),不得写成保留部分起始;否则删前内容无法在 review 展示
- 删前留后 actionTime:从保留词首字开始(如「这个这个」留第二个「这个」→ 从第二个「这」的 start_time),不得从下一字开始否则多删
- deleted_parts:对应删前内容时,
end_time须延伸至首个保留字前(如「其实啊」后接「做」→ end_time 为「做」的 start_time) - [ ] 顺句词/口误移除:参考
10-顺句词删除.md,如 这都、其实、那个 等在口播剪辑阶段直接移除 - [ ]
deleted_parts每条需含deleted_text、description;建议含start_time、end_time(便于 Step6a 自检);删前留后时end_time须延伸至首个保留字前 - [ ]
reasonTags命名规范:建议删除:静音 76.47s–96.93s(20.5s) - [ ] 产出可审核的数据结构:sentences + track
- [ ] EDL 输出格式(见
references/内置/EDL编辑决策格式.md、examples/edl.json) - [ ] 单位统一为 ms(start_time、end_time、actionTime)
- [ ] reason:明确处理原因(如「句内重复:一个一个,删前留后」「顺句词:这都,直接移除」「语义重复:前句过渡后句完整,删前留后」)
- [ ] action:
mute静音 |delete删除 |concat句内拼接 |keep保留 - [ ] delete 段 text 字段:
text应填source_text(被删除的原文),便于审核页展示「删除了什么」 - [ ] concat 与 deleted_parts 一致:actionTime 的保留区间不得与 deleted_parts 重叠;显式 mute 段的时间不得与 keep 重叠
- [ ] actionTime:
mute/delete填待处理范围;concat填仅保留的 trim 片段列表(按顺序拼接) - 严禁将 segment 整段填入 actionTime:若 reason 为「删前留后」等删除类,actionTime 必须从 step5 字级时间戳查出被保留字的精确 ms 范围,不得包含被删部分;否则音频仍会播放被删内容
- [ ] 结果输出:
output/<文件名>/step6_speech_cut.json:口播剪辑结果。顶层键可为optimized_segments或sentences,prepare_export_data 均支持- 禁止与 Step4 同时输出;Step5 必须在 Step4 完整完成后独立执行,不得用「简化版」跳过
- 必须含
deleted_parts(每条 delete 段需有对应项,含deleted_text、description,建议含start_time、end_time便于自检) - [ ] 输出自证(防止漏读用户规则):在
step6_speech_cut.json顶层增加以下字段(不影响后续脚本解析): rules_read: 本次完整读取的规则文件列表(必须包含references/用户规则/下 1~10 全部文件名 +README.md)rules_applied: 本次实际命中的规则文件列表(例如["3-静音段处理", "4-重复句检测", "10-顺句词删除"])rules_version_note: 固定写read all references/用户规则/*.md- [ ] CHECKPOINT:确认每一步都完全执行
使用流程示意
flowchart TD
Start([开始 Step5]) --> Dup{step6_speech_cut.json<br/>已存在?}
Dup -->|是| Ask[提示用户 删除/覆盖/新建01]
Ask --> Start
Dup -->|否| Read[读 step5 优化结果 / raw / 用户规则 1~10 + README]
Read --> Rules[按用户规则生成剪辑方案<br/>含语义重复 / mute / concat / delete]
Rules --> EDL[按 EDL 格式写出<br/>单位 ms · deleted_parts 完整]
EDL --> Write[写入 step6_speech_cut.json]
Write --> Done([CHECKPOINT 通过<br/>进入 Step5.5 / 6a])Step5.5: 审核逻辑确认(是否打开审核页面)
目标:根据环境变量决定后续是「先审后导出」还是「直接进入导出准备」
>
SKILL_DIR:指 byted-mediakit-voiceover-editing 目录路径>
关键变量:TALKING_VIDEO_AUTO_EDIT_REVIEW_AUTO_OPEN(见主 SKILL frontmatter 说明)检查单
- [ ] 启动审核页面前置判断:查看环境变量
TALKING_VIDEO_AUTO_EDIT_REVIEW_AUTO_OPEN判断是否打开,0 不打开、1 打开,根据信息控制 Step6b 审核页面打开逻辑 - [ ] 不打开的情况下需要直接进行视频导出(进入 6a → 6c 路径,跳过人工在审核页的交互)
- [ ] 打开情况下需要不直接进行视频导出(需经过 6b 审核与导出服务交互后再 6c)
本地模式审核页支持
所有三种模式(apig / cloud / local)均支持审核页。 本地模式下审核页的特殊处理:
- 媒体访问:Source 字段使用
http://127.0.0.1:<port>/local-media/<绝对路径>格式,由serve_review_page.py的/local-media/路由代理访问本地文件 - 模式标识:审核页自动检测
review_import_data.json中的_execution_mode字段,显示对应的模式徽标 - 导出方式:本地模式点击导出后使用 ffmpeg 本地合成,不调用 VOD 服务
- 数据联动:点击"💾 保存审核"可将修改持久化,直接导出时也会读取最新数据
使用流程示意
flowchart TD
Start([开始 Step5.5]) --> Env{TALKING_VIDEO_AUTO_EDIT_<br/>REVIEW_AUTO_OPEN}
Env -->|0 / 默认| NoReview[不自动打开审核页<br/>准备直接导出链路]
Env -->|1 / true / yes| Review[进入审核页链路<br/>6b 再提交导出]
NoReview --> Next1([接 Step6a → 6c])
Review --> Next2([接 Step6a → 6b → 6c])
style Review fill:#e6f7e6
style NoReview fill:#fff3e6注意:无论哪种模式,审核页均可用。即使 TALKING_VIDEO_AUTO_EDIT_REVIEW_AUTO_OPEN=0,用户仍可手动访问审核页 URL 进行审核。Step6a: 数据预处理
目标:将 Step6 剪辑决策与 Step1/3/5 等产物合并为export_request.json、review_import_data.json(含真实 URL),供审核页与 VOD 导出使用
>
SKILL_DIR:指 byted-mediakit-voiceover-editing 目录路径>
前置要求:必须先cd ./scripts并激活scripts/.venv再执行命令
检查单
- [ ] 重复文件检查:若
output/<文件名>/export_request.json或review_import_data.json已存在,必须提示用户:「导出数据已存在,是否删除/覆盖/保留并写入新目录(01)?」用户确认后再执行 - [ ] Run(需先
cd ./scripts且已激活 venv):python ./prepare_export_data.py --write-step6 [--output-dir output/<文件名>](画布与视频源从 step1 读取,可加--width--height指定) - [ ] 脚本职责:
- 读取 step6、step3、step1、step5
- 以 step5 字级时间戳校正 segment 起止(首字出现、末字结束);无 step5_asr_optimized 时回退 step5_asr_raw
- 人声轨不输出 mute 段;字幕去除结尾标点;有留白时 10ms 补偿
- 自检:delete 段应在 deleted_parts 中
- 生成
export_request.json、review_import_data.json(含真实 URL) - [ ] 导出无字幕:默认跳过字幕压制;如需启用字幕压制,
.env中设置VOD_EXPORT_SKIP_SUBTITLE=0(或false/no);6a、6b、6c 均生效 - [ ] 导出视频裁剪:
.env中设置TALKING_VIDEO_AUTO_EDIT_VIDEO_CUT=1(默认 1 进行),且仅有字幕或音频静音时生效:mute 段会从输出中移除,视频轨与人声轨均按 keep 段无缝拼接,主时间轴从 0 起连续;Extra.trim 保持源时间范围 - [ ] CHECKPOINT:两份 JSON 已生成,track 使用真实 URL
使用流程示意
flowchart TD
Start([开始 Step6a]) --> Dup{export_request / review_import_data<br/>已存在?}
Dup -->|是| Ask[提示用户 删除/覆盖/新建01]
Ask --> Start
Dup -->|否| Cd[cd ./scripts]
Cd --> Run[python prepare_export_data.py<br/>--write-step6 + --output-dir]
Run --> Out{两份 JSON 生成<br/>且 track 为真实 URL?}
Out -->|否| Fix[检查 step6/step5/step1 后重试]
Fix --> Run
Out -->|是| Done([CHECKPOINT 通过<br/>进入 Step6b 或 6c])Step6b: 审核与导出
目标:本地启动审核页与导出服务,由用户在页面完成字幕/句级决策后提交导出数据
>
SKILL_DIR:指 byted-mediakit-voiceover-editing 目录路径>
前置要求:必须先cd ./scripts并激活scripts/.venv;默认是否自动打开浏览器由TALKING_VIDEO_AUTO_EDIT_REVIEW_AUTO_OPEN决定,可加--no-open覆盖
检查单
- [ ] 示例参考:
examples/step6_speech_cut.json - [ ] 启动审核页面前置判断:默认不自动打开;是否打开由
TALKING_VIDEO_AUTO_EDIT_REVIEW_AUTO_OPEN决定(1/true/yes时打开)。 - [ ] 启动审核页服务:
python ./serve_review_page.py [--output-dir output/<文件名>](默认 5173,端口冲突时自动使用其他端口,以启动时打印的 URL 为准) - [ ] 审核页:默认不自动打开;用户可手动打开启动时打印的 URL(默认 http://127.0.0.1:5173),点击「从 API 加载」或自动加载 review_import_data
- [ ] 用户审核:修改字幕、删除/保留句、调整时间
- [ ] 操作仅两类:保留(原样输出)| 删除(可恢复)
- 删除-音频:
a_volume: 0静音,恢复时设为 1 - 删除-字幕:
Extra[transform].Alpha: 0隐藏画布渲染,恢复时设为 1
模式区分
审核页自动检测执行模式并在界面上区分显示:
| 模式 | 徽标颜色 | 导出按钮文案 | 导出成功信息 |
|---|---|---|---|
| apig | 🔵 蓝色 | 提交视频导出任务 | OutputVid + PlayURL |
| cloud | 🟢 绿色 | 提交视频导出任务 | OutputVid + PlayURL |
| local | 🟠 橙色 | 本地导出视频 | 输出文件路径 |
数据联动
审核页修改与直接导出之间通过"保存审核"机制实现数据同步:
审核页编辑 → 点击"💾 保存审核" → POST /api/save-review
↓
┌──────────────────────────────────┐
│ 1. 更新 review_import_data.json │
│ 2. 重新生成 export_request.json │
└──────────────────────────────────┘
↓
直接导出(vod_direct_export.py)
读取到更新后的 export_request.json ✅两种导出路径:
| 路径 | 入口 | 数据来源 |
|---|---|---|
| 审核页导出 | 审核页点击"导出"按钮 | 浏览器内存中的最新编辑数据(实时) |
| 直接导出 | Agent 调用 vod_direct_export.py --output-dir <绝对路径> submit --wait | 磁盘上的 export_request.json(需先"保存审核") |
注意:如果用户在审核页做了修改但未点击"保存审核"就关闭页面,修改会丢失。直接导出将使用 Step 6a 的原始数据。
- [ ] 保存审核:用户修改后点击"💾 保存审核",将修改持久化到磁盘
- [ ] 导出:点击「导出」按钮,数据保存至
output/export_submit_<ts>.json并触发导出 - [ ] CHECKPOINT:用户完成审核并成功导出,Agent 可读取
export_submit_*.json反馈结果
服务端点一览
| 端点 | 方法 | 说明 |
|---|---|---|
/ | GET | 审核页 HTML |
/api/review-data | GET | 返回 review_import_data.json |
/api/mode | GET | 返回当前执行模式 |
/api/save-review | POST | 保存审核修改(回写 review_import_data + 重生成 export_request) |
/export | POST | 触发导出(local: ffmpeg; cloud/apig: vod_direct_export) |
/local-media/<path> | GET | 本地模式媒体文件代理 |
使用流程示意
flowchart TD
Start([开始 Step6b]) --> S1[python serve_review_page.py]
S1 --> Load[加载 review_import_data.json<br/>自动检测模式]
Load --> User[用户在审核页操作<br/>保留 / 删除 / 编辑字幕]
User --> Save{修改是否需要<br/>持久化?}
Save -->|是| SaveAPI[点击 💾 保存审核<br/>POST /api/save-review]
SaveAPI --> Updated[更新 review_import_data.json<br/>+ export_request.json]
Updated --> Export
Save -->|否| Export[点击导出 → POST /export]
Export --> File[生成 export_submit_*.json]
File --> Done([CHECKPOINT 通过<br/>进入 Step6c])Step6c: VOD 导出任务提交与查询
目标:向火山 VOD 提交直接剪辑任务并轮询结果,获得 OutputVid 等成功产物
>
SKILL_DIR:指 byted-mediakit-voiceover-editing 目录路径>
前置要求:依赖.env中VOLC_*等配置
检查单
⚠️ 重要:--output-dir必须在submit/query子命令之前,支持绝对路径。
- [ ] 提交任务(一行式执行):
cd SKILL_DIR/scripts && source .venv/bin/activate && python vod_direct_export.py --output-dir <绝对路径> submit --wait- 指定输入文件:追加
--edit-param <JSON绝对路径> - 覆盖 UploadInfo:追加
--space-name、--video-name、--file-name - [ ] 查询结果(一行式执行):
cd SKILL_DIR/scripts && source .venv/bin/activate && python vod_direct_export.py query --req-id <ReqId> --wait- [ ] CHECKPOINT:任务 success 时获得 OutputVid,可反馈用户
使用流程示意
flowchart TD
Start([开始 Step6c]) --> Src{是否走过 6b 审核?}
Src -->|否| Req[submit:默认 export_request.json]
Src -->|是| Edit[submit --edit-param<br/>export_submit_*.json]
Req --> Submit[vod_direct_export.py submit]
Edit --> Submit
Submit --> Wait{需要阻塞等待?}
Wait -->|是| W[submit --wait 或 query --wait]
Wait -->|否| Q[query --req-id]
W --> Ok{状态 success?}
Q --> Ok
Ok -->|否| Retry[排错 / 继续轮询]
Retry --> Q
Ok -->|是| Vid[取得 OutputVid 反馈用户]<!-- input: 无 output: 删除策略决策依据 pos: 核心,所有规则的基础
架构守护者:一旦我被修改,请同步更新: 1. 所属文件夹的 README.md -->
核心原则
删前保后
后说的通常更完整,所以:
- 删除前面的(口误/残句)
- 保留后面的(完整句)
例外
用户明确说"后面更顺"时,删前保后。 用户明确说"前面更顺"时,删后保前。
<!-- input: 句子文本 output: 顺句词/口误索引列表 pos: 规则,口播剪辑阶段处理
架构守护者:一旦我被修改,请同步更新: 1. 所属文件夹的 README.md -->
顺句词删除
定义
部分语境下为冗余的顺句词或语义不通的口误,在口播剪辑阶段直接移除(不做 Step 4 同音字硬编码纠错)。
顺句冗余词
| 词 | 示例 | 删除后 |
|---|---|---|
| 其实 | 它其实只能做 | 它只能做 |
| 就是 | 其实就是说 | 就是说 |
| 比如说 | 比如说剪映 | 比如剪映 |
禁止:text 必须严格来自该 segment 的 source_text 对应时间范围,不得添加其他 segment 或原文不存在的词(如 segment 仅有「比如说」时,不得输出「比如剪映」)。
口误/语义不通
| 词 | 示例 | 处理 |
|---|---|---|
| 这都 | 这都,它没办法理解 | 直接移除「这都,」→「它没办法理解」 |
| 则都 | 同上 | 同上 |
删除策略
- 结合上下文判断,避免误删有实际语义的「其实」等
- 用
concat+actionTime实现音频剪辑拼接 - 由宿主 Agent 最终决策
<!-- input: subtitles_words.json output: 语气词索引列表 pos: 规则,人工确认优先级
架构守护者:一旦我被修改,请同步更新: 1. 所属文件夹的 README.md -->
语气词检测
语气词列表
const fillerWords = ['嗯', '啊', '哎', '诶', '呃', '额', '唉', '哦', '噢', '呀', '欸'];结尾确认词/反问词
句尾出现时可标记待删,按用户偏好处理:
const endingFillerWords = ['对吧', '是吧', '嘛', '呢', '哈'];| 示例 | 处理 |
|---|---|
| 总会有各种各样的口癖,对吧? | 可删除「对吧」 |
| 就是这样,是吧? | 可删除「是吧」 |
删除边界
错误:删语气词时间戳 (语气词.start - 语气词.end)
→ 可能删掉前面字的尾音
正确:从前一个字的 end 到后一个字的 start
→ (前字.end - 后字.start)用户偏好
保留适量"嗯"作为过渡,不要全删。
指代完整性(举例结构保护)
当 嗯啊呃 等作为举例内容出现(如「比如说,嗯啊呃这种」)时,其为举例主体,不得删除,否则「这种」无指代。
| 原文 | 错误做法 | 正确做法 |
|---|---|---|
| 比如说,嗯啊呃这种,还有说错了重新说的 | 删「嗯啊呃」→「比如说,这种,」(语义断裂) | 保留整段(嗯啊呃为举例内容) |
| 像这种、这类、这些(前有语气词作举例) | 单独删语气词 | 保留或整段标记 |
处理规则:若 嗯啊呃 等与「这种/这类/这些」绑定,作为举例内容(如口癖、语气词举例),必须保留,不得按语气词删除。
<!-- input: subtitles_words.json (isGap=true 的元素) output: 长静音索引列表 pos: 规则,必删优先级
架构守护者:一旦我被修改,请同步更新: 1. 所属文件夹的 README.md -->
静音段处理
阈值规则
| 静音长度 | 处理 |
|---|---|
| ≤ 0.2秒 | 忽略 - 自然停顿 |
| 0.2-1秒 | 可选删除 - 句间停顿 |
| > 1秒 | 建议删除 - 明显卡顿或展示画面 |
输出格式
整段标记,不拆分
示例:3.2 秒静音 → 输出 1 条
| 64-66 | 12.86-15.80 | 静音3.2s | | 删 |用户在审核网页中取消不想删的。
特殊情况
长静音
连续 5s+ 的静音整段标记,预选删除:
| 323-371 | 71.38-131.38 | 静音60s | | 删 |开头静音
视频开头的静音必删:
| 0 | 0.00-1.00 | 静音1s | 开头静音 | 删 |<!-- input: 按静音分隔的句子列表 output: 重复句索引列表 pos: 规则,建议删优先级
架构守护者:一旦我被修改,请同步更新: 1. 所属文件夹的 README.md -->
重复句检测
定义
- 文本重复检查(必做):相邻句子(被静音分隔)开头相同 ≥5字,通常是说错后重说。
- 语义重复检查(必做):宿主 Agent 分析相邻句/句内分句的语义是否重复,若前句为过渡/铺垫、后句为完整表述,则删前留后。
核心原则
先分句,再比对:必须先按静音切分成句子列表,然后比对相邻句子。
正确分析方法
✓ 正确:按静音切分句子 → 比对相邻句子开头 → 整句删除
✗ 错误:逐字扫描 → 发现重复片段 → 只删片段步骤
1. 按静音切分句子(静音≥0.5s作为分隔) 2. 文本重复:比对相邻句子(开头≥5字相同 → 删较短的整句) 3. 文本重复:比对隔一句(中间是残句时,也要检查前后句是否重复) 4. 语义重复(必做):宿主 Agent 逐对检查相邻句/句内分句,若前句为过渡句(如「原理其实是…」「我来说一下」前有同义铺垫),则删前留后。
检测逻辑
\文本重复检查\\*
// 相邻句子比对
if (curr.text.slice(0, 5) === next.text.slice(0, 5)) {
const shorter = curr.text.length <= next.text.length ? curr : next
markAsError(shorter) // 删除整句,不只是重复部分
}
// 隔一句比对(中间是短句/残句时)
if (mid.text.length <= 5) {
// 中间是残句
if (curr.text.slice(0, 5) === next.text.slice(0, 5)) {
markAsError(curr) // 删前句
markAsError(mid) // 删残句
}
}语义重复检查(必做)
- 宿主 Agent(你)结合上下文分析确认语义是否一致
- 典型模式:前句「XX 其实是/是这样」+ 后句「我来说一下 XX」→ 前句为过渡,删前留后
案例
| 前句 | 后句 | 删除 |
|---|---|---|
| "这是我剪出来的一个案例" | "这是我剪出来的一个案例" | 前句(完全重复) |
| "我用cloud code的excuse功能做一个剪辑agent" | "所以我用cloud code的excuse功能做一个剪辑agent" | 前句 |
| "第二个是是q制技能系统第二个" | "第二个是scale技能系统" | 前句 |
| "好我们接下来开始怎么去" | "好我们接下来开始怎么去做一个剪口拨" | 前句 |
| "我们就可以看到这里新的视频" | "我们就可以看到这里新的视频了" | 前句 |
| "这个工具它的原理其实是。" | "我来说一下这个工具的整体流程" | 前句 |
隔一句重复(中间有残句)
当两句之间隔了一个短残句时,也要检测:
句A: "这是我剪出来的一个案例"
残句: "他呢" ← 中间隔了残句
句B: "这是我剪出来的一个案例"
→ 删 句A + 残句| 前句 | 中间残句 | 后句 | 删除 |
|---|---|---|---|
| "这是我剪出来的一个案例" | "他呢" | "这是我剪出来的一个案例" | 前句 + 残句 |
| "具体怎么做呢我们首先下载这个" | "提示词" | "具体怎么做呢我们首先复制这个提示词" | 前句 + 残句 |
| "打开我们的AI" | "打开我们的" | "打开我们的AI然后告诉他去下载" | 前句 + 残句 |
多次重复
连续说 3 次以上,删除所有不完整的,保留最后完整的:
"以前呢我会把所有的技能" → 删
"以前呢我会把所有的功能做" → 删
"以前呢我会把所有的功能做都" → 删
"以前呢我会把所有的功能都做成一个大的scale" → 保留易错点
❌ 逐字扫描,只发现局部重复片段
✓ 先分句,比对整句开头,删除整句
❌ 只比对相邻句子
✓ 也要比对隔一句(中间可能是残句)<!-- input: 全文文本 output: 卡顿词索引列表 pos: 规则,建议删优先级
架构守护者:一旦我被修改,请同步更新: 1. 所属文件夹的 README.md -->
卡顿词
模式
同一个词连续说 2-3 次:
const stutterPatterns = [
'那个那个',
'就是就是',
'然后然后',
'这个这个',
'所以所以',
'去去',
'去去去',
];删除策略
删前面,保留最后一个。
原文: "那个那个我想说"
删除: "那个"
保留: "那个我想说"不视为卡顿(例外)
量词重叠(一个、一件、一句 等)多为强调,不纳入卡顿词删除:
| 原文 | 处理 |
|---|---|
| 一个一个地 | 保留 |
| 我最近做的一个一个口播 | 保留(量词强调) |
| 一件一件检查 | 保留 |
反馈记录
2026-03-17
- 用户反馈"去去"、"去去去"需要作为卡顿词移除
Related skills
FAQ
What execution modes are supported?
apig (SkillHub gateway), cloud (direct Volcengine OpenAPI), and local (Qwen3-ASR / Demucs / ffmpeg), tried in that priority with automatic downgrade.
Who makes the final cut decisions?
Scripts produce candidate cuts and cleaned text, and the host agent makes the final keep/delete decisions.