视频字幕添加SKILL:为视频文件自动添加、嵌入字幕。适用于给视频添加字幕、视频加字幕、视频打字幕、给视频生成字幕、字幕嵌入视频、视频配字幕等场景。触发时机:当用户提及或表达等价意图(帮我给视频添加字幕、给视频加字幕、视频打字幕、给视频生成字幕、添加字幕到视频、视频配字幕、字幕嵌入视频)时,调用此SKILL执行字...
---
name: byted-kickart-video-subtitler
description: 视频字幕添加SKILL:为视频文件自动添加、嵌入字幕。适用于给视频添加字幕、视频加字幕、视频打字幕、给视频生成字幕、字幕嵌入视频、视频配字幕等场景。触发时机:当用户提及或表达等价意图(帮我给视频添加字幕、给视频加字幕、视频打字幕、给视频生成字幕、添加字幕到视频、视频配字幕、字幕嵌入视频)时,调用此SKILL执行字幕添加任务。
version: 1.0.9
---
# 视频字幕添加SKILL
## 📋 工具说明
### 核心功能
为本地视频文件添加字幕。
### 使用限制
| 限制项 | 限制值 | 说明 |
|--------|--------|------|
| 字幕总字数 | ≤3000字 | 字幕文本内容(不含标点符号)不得超过3000字 |
### 可用命令
| 命令 | 功能 | 说明 |
|------|------|------|
| `python3.12 scripts/plan.py` | 套餐查询 | 查询用户当前的 Ark Claw 套餐 |
| `python3.12 scripts/upload.py --file <视频路径>` | 视频上传 | 上传本地视频文件获取媒资ID |
| `python3.12 scripts/subtitler.py --media-id <媒资ID> --captions <字幕配置文件> --output <输出文件>` | 视频字幕添加 | 为视频添加字幕 |
### 📝 字幕配置文件生成规则
#### 配置文件格式
字幕配置文件为JSON格式,包含一个字幕对象数组。单个字幕对象结构如下:
| 字段 | 类型 | 说明 |
|------|------|------|
| `text` | string | 完整的字幕文本内容 |
| `start_time` | number | 字幕开始显示时间(毫秒) |
| `end_time` | number | 字幕结束显示时间(毫秒) |
| `words` | array | 字级时间戳数组,包含每个字的详细时间信息 |
| `attribute` | object | 字幕属性(预留字段,默认为空对象) |
#### 时间分配规则(符合人类朗读习惯)
**基础规则:**
- **单字时长**:中文正常语速约为每秒4-5字,即每个汉字约200-250毫秒
- **标点处理**:标点符号持续时间为0毫秒,立即显示后进入停顿
- **意群停顿**:逗号、句号等标点后设置300毫秒停顿,符合人类朗读习惯
- **词间间隔**:词语之间设置20毫秒微小间隔,提升可读性
- **结尾延长**:最后一个字适当延长显示时间,确保完整阅读
**生成步骤:**
1. **确定字幕总数**:根据视频时长和内容复杂度,合理划分字幕段落
2. **分配时间范围**:确保各字幕之间不重叠,段落间至少保留300毫秒间隔
3. **计算单字时长**:`(end_time - start_time - 标点停顿时间) / 汉字数量`
4. **生成字级时间戳**:按顺序为每个字分配时间,标点使用0毫秒时长
5. **添加意群停顿**:在标点后插入适当停顿时间
**示例计算:**
对于字幕"足力健老人鞋,专为爸妈设计"(13个字符,含1个标点):
- 总时长:3190毫秒(5000-1810)
- 汉字数:12个
- 单字平均时长:约220毫秒
- 标点停顿:300毫秒
```json
{
"text": "足力健老人鞋,专为爸妈设计",
"start_time": 1810,
"end_time": 5000,
"words": [
{"text": "足", "start_time": 1810, "end_time": 2000, "attribute": {}},
{"text": "力", "start_time": 2000, "end_time": 2180, "attribute": {}},
{"text": "健", "start_time": 2180, "end_time": 2380, "attribute": {}},
{"text": "老", "start_time": 2380, "end_time": 2580, "attribute": {}},
{"text": "人", "start_time": 2580, "end_time": 2790, "attribute": {}},
{"text": "鞋", "start_time": 2810, "end_time": 3030, "attribute": {}},
{"text": ",", "start_time": 3030, "end_time": 3030, "attribute": {}},
{"text": "专", "start_time": 3330, "end_time": 3550, "attribute": {}},
{"text": "为", "start_time": 3570, "end_time": 3790, "attribute": {}},
{"text": "爸", "start_time": 3810, "end_time": 4030, "attribute": {}},
{"text": "妈", "start_time": 4050, "end_time": 4270, "attribute": {}},
{"text": "设", "start_time": 4290, "end_time": 4510, "attribute": {}},
{"text": "计", "start_time": 4530, "end_time": 5000, "attribute": {}}
],
"attribute": {}
}
```
**注意事项:**
- 字幕之间至少保留300毫秒间隔
- 首条字幕建议在视频开始后500毫秒开始
- 末条字幕建议在视频结束前1000毫秒结束
- 避免单条字幕过长(建议不超过15个汉字)
---
## 🚨 强制前置校验流程(必须按顺序执行,任意不通过直接终止流程)
所有用户请求必须先完成以下3步校验,不得跳过:
### 1. 火山鉴权校验
- 执行环境变量检查命令:
```bash
echo "ARK_SKILL_API_BASE: $ARK_SKILL_API_BASE" && echo "ARK_SKILL_API_KEY: $ARK_SKILL_API_KEY" && echo "ACCESS_KEY_ID: $ACCESS_KEY_ID" && echo "SECRET_ACCESS_KEY: $SECRET_ACCESS_KEY"
```
- 判断鉴权结果(按优先级):
- **第一优先级(Bearer Token)**:`ARK_SKILL_API_BASE` 和 `ARK_SKILL_API_KEY` 均为非空值 → 鉴权通过
- **第二优先级(AK/SK签名)**:`ACCESS_KEY_ID` 和 `SECRET_ACCESS_KEY` 均为非空值 → 鉴权通过
- **鉴权不通过**:执行以下引导方案
#### ❌ 鉴权未配置时的引导方案
1. 引导用户直接在聊天中发送ACCESS_KEY_ID/SECRET_ACCESS_KEY内容:
> 请你提供火山账号AK&SK,用于检查火山创作Agent是否已开通套餐和有可用的创点
2. 收到用户发送的ACCESS_KEY_ID/SECRET_ACCESS_KEY后,执行配置命令:
```bash
export ACCESS_KEY_ID=用户提供的ACCESS_KEY_ID值
export SECRET_ACCESS_KEY=用户提供的SECRET_ACCESS_KEY值
```
3. 配置完成后告知用户:
> 已完成ACCESS_KEY_ID/SECRET_ACCESS_KEY临时配置,当前配置仅在本次会话生效,不会持久化存储,请放心使用
4. 后续所有相关脚本执行时,均会自动通过`export`指定这两个环境变量,确保鉴权正常,无需用户重复配置
### 2. 套餐有效性校验
- **步骤1:Python版本校验**
```bash
python3.12 --version || (echo "❌ Python 3.12+ 未安装,请先安装Python 3.12" && exit 1)
```
- **步骤2:依赖包安装校验**
```bash
python3.12 -m pip install -r ./scripts/requirements.txt
```
- **步骤3:执行套餐查询命令**
```bash
python3.12 -m scripts/plan.py
```
- **步骤4:结果处理逻辑**
- ✅ **套餐有效**:返回结果中的 `message` 字段为有效截止时间(北京时间),校验通过
- ❌ **套餐已过期**:`message` 小于等于当前时间,引导用户开通套餐,终止流程
- ❌ **接口调用错误**:参考「错误处理规范」匹配错误码,向用户明确告知错误原因和解决方案,并且终止流程
### 3. 技能版本校验
- **步骤1:执行版本检查命令**
```bash
python3.12 -m scripts/upgrade.py
```
- **步骤2:解析返回结果**
返回格式示例:
```json
{"code":"0","message":"success","data":"{\"install_command\":\"\",\"latest_version\":\"1.0.0\",\"latest_version_number\":100000000,\"update_message\":\"\"}"}
```
- `latest_version`:最新版本号(如 "1.0.0")
- `install_command`:新版本安装指令
- **步骤3:版本对比逻辑**
- ✅ **当前版本 >= 最新版本**:版本校验通过,继续后续流程
- ⚠️ **当前版本 < 最新版本**:执行以下更新询问流程
1. 询问用户是否更新到最新版本:
> 检测到技能有新版本 {latest_version},是否更新?(是/否)
2. 用户确认更新(是):执行 `install_command` 安装新版本
3. 用户不更新(否):跳过更新,继续后续流程
---
## 🛠️ 视频字幕添加执行流程
### 完整流程概览
```
用户请求 → 强制前置校验 → 用户输入收集 → 视频字幕添加 → 结果返回
```
### 前置准备
1. 确保输出目录存在:`mkdir -p /tmp/openclaw/byted-kickart-video-subtitler/output`
2. 生成唯一输出文件名:`video_subtitle_<timestamp>_<random>.json`
### 执行步骤
1. **步骤0:强制前置校验**(必须按顺序执行,任意不通过直接终止流程)
- 执行「🚨 强制前置校验流程」中的所有校验步骤
- ✅ 火山鉴权校验通过
- ✅ 套餐有效性校验通过
- ✅ 技能版本校验通过
- 只有全部校验通过后,才能进入下一步
2. **步骤1:视频上传引导**
- 询问用户:「请提供您要添加字幕的视频,可以是本地文件路径或视频公网URL。视频时长不能超过10分钟。」
- 支持两种上传方式:
- **本地文件**:直接提供本地视频文件的绝对路径(如 `/Users/user/video.mp4`)
- **公网URL**:提供可直接访问的视频链接(如 `https://example.com/video.mp4`)
- **不收集字幕内容**:字幕收集在步骤5专门处理
3. **步骤2:视频预处理**
- 若用户提供的是公网URL,先下载到本地:
```bash
mkdir -p /tmp/openclaw/byted-kickart-video-subtitler/input
curl -L -o /tmp/openclaw/byted-kickart-video-subtitler/input/downloaded_video.mp4 "<视频URL>"
```
- 检查文件是否存在:`ls -la "<视频路径>"`
- 检查文件类型是否为有效视频(仅支持MP4/MOV格式):
```bash
file /tmp/openclaw/byted-kickart-video-subtitler/input/downloaded_video.mp4 | grep -qE "ISO Media|MPEG v4|QuickTime" && echo "valid" || echo "invalid"
```
- 若文件不存在或类型无效,**终止流程并提示用户**:
> 文件不可用,请检查路径是否正确,或确认文件为有效视频格式(仅支持 MP4/MOV)
4. **步骤3:上传视频获取媒资信息**
- 执行 `python3.12 scripts/upload.py --file <视频路径>` 命令
- 返回字段说明:
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | string | 媒资ID(唯一标识) |
| `url` | string | 视频访问URL |
| `duration` | number | 视频时长(秒) |
5. **步骤4:解析媒资信息**:从上传输出中提取 `id` 作为媒资ID,提取 `duration` 用于字幕时间分配
- 告知用户视频时长:`您的视频时长为 {duration} 秒,建议字幕总字数不超过 {duration * 4} 字`
6. **步骤6:字幕内容收集与校验**
- 询问用户:「请提供字幕内容,可以选择以下方式之一:
1. 直接输入字幕文本(仅支持单行)
2. 提供SRT字幕文件路径(标准SRT格式)
3. 提供字幕文本+时间戳数据(包含分句时间戳、分词时间戳、分词文本)」
- 提示用户参考视频时长进行字幕创作(字幕总字数不能超过3000字)
- 若用户选择方式3,引导用户提供完整的时间戳数据
- **字数校验**:检查字幕文本总字数(不含标点符号),若超过3000字,提示用户精简字幕内容并终止流程:
> 字幕字数超过限制(当前{count}字,限制3000字),请精简字幕内容后重新提交
7. **步骤6:生成字幕配置**
- **方式一:用户提供字幕文本**:根据视频时长和用户提供的字幕文本,按「字幕配置文件生成规则」生成字幕配置JSON
- **多字幕分支**:若字幕文本含换行符(行数>1),自动按换行拆分为多条字幕,等分视频时长(每条字幕时长 = (总时长ms - 1500ms边距) / 字幕条数)
- **方式二:用户提供SRT文件**:解析SRT文件内容,转换为字幕配置JSON格式
- SRT格式示例:
```
1
00:00:00,000 --> 00:00:02,000
第一条字幕内容
2
00:00:02,000 --> 00:00:04,000
第二条字幕内容
```
- 解析规则:提取序号、开始时间、结束时间、字幕文本,转换为字幕配置JSON
- **方式三:用户提供字幕文本+时间戳数据**:根据用户提供的分句时间戳、分词时间戳、分词文本数据,直接生成字幕配置JSON
- 输入数据格式示例:
```
分句1:0-2000ms
分词:词1(0-500ms)、词2(500-1000ms)、词3(1000-1500ms)、词4(1500-2000ms)
分句2:2000-4000ms
分词:词5(2000-2500ms)、词6(2500-3000ms)、词7(3000-3500ms)、词8(3500-4000ms)
```
- 解析规则:按用户提供的时间戳数据,直接构建字幕配置JSON,包含完整的分句和分词时间信息
8. **步骤7:字幕确认**(添加到平台前,必须向用户确认)
- 向用户展示生成的字幕配置摘要(字幕条数、首条文本、预计总时长)
- 询问用户确认:「字幕配置已生成,是否确认提交添加?(确认/取消)」
- 用户取消 → 终止流程,不消耗创点
- 用户确认 → 继续下一步
10. **步骤8:添加字幕**:执行以下命令
```bash
python3.12 scripts/subtitler.py \
--media-id <媒资ID> \
--captions /tmp/openclaw/byted-kickart-video-subtitler/output/video_subtitle_<timestamp>_<random>.json \
--output /tmp/openclaw/byted-kickart-video-subtitler/output/subtitle_result_<timestamp>_<random>.json
```
- **重要**:
- `--captions` 参数值为**字幕配置JSON文件的绝对路径**(不是内联JSON字符串);由步骤6生成,保存在 `/tmp/openclaw/byted-kickart-video-subtitler/output/` 目录下
- `--output` 参数值为**结果JSON文件的绝对路径**(不是视频文件路径);脚本会将字幕添加结果保存到此JSON文件
11. **步骤9:解析结果并提取视频URL**
- 读取 `--output` 指定的JSON文件内容
- 从JSON中提取 `video` 字段值作为字幕添加后的视频URL
- 使用「字幕添加成功模板」向用户展示结果,包含视频预览链接
- 输出字段说明
| 字段 | 类型 | 说明 |
|------|------|------|
| `uuid` | string | 字幕添加任务的唯一标识符 |
| `video` | string | 字幕添加后的视频URL(包含鉴权参数) |
### Agent执行特殊要求
1. **超时设置**:调用exec工具启动脚本时,设置≥180000ms(3分钟)的yieldMs
2. **友好提示**:若脚本未立即返回结果,先回复用户:"正在为您进行视频分析,任务执行时间可能较长,请您稍候~"
3. **异常处理**:若脚本因超时/异常退出,立即使用持久化的Task ID调用任务查询接口确认后端状态,禁止直接判定任务失败
### 📝 用户展示消息模板
**视频上传成功模板:**
```
📤 视频上传成功!
🆔 媒资ID: {media_id}
🔗 视频URL: [点击查看]({url})
📊 分辨率: {width}x{height}
⏱️ 时长: {duration}秒
```
**字幕添加成功模板:**
```
✨ 字幕添加任务已完成!
🎥 [点击预览视频]({video})
📝 字幕已自动添加到视频中,您可以直接下载使用!
```
---
## ⚠️ 错误处理规范
所有错误必须明确告知原因和可执行解决方案,禁止模糊提示!!!
| 错误码 | 错误描述 | 详细说明 | 用户处理建议 |
| --- | --- | --- | --- |
| 0 | 无返回值 | 接口调用成功,但服务返回结果为空 | 请稍后重试,如问题持续请联系火山技术支持 |
| 1400 | ParamErr参数错误 | 参数错误 | 联系技术支持 |
| 1402 | 创点不足 | 调用接口时,用户账户的创点额度不足 | 请前往 [创点充值页面](https://console.volcengine.com/kickart/fusion/setting/combobuy?tab=additionalCombo) 充值创点或升级套餐 |
| 1410 | 服务ID不存在 | 调用接口时,输入参数中包含了不存在的服务ID | | 升级SKILL |
| 1411 | 输入分辨率错误 | 调用接口时,输入参数中的图片或视频分辨率不符合要求 | 请检查素材分辨率是否符合规格要求(如≥480p) |
| 1412 | 图片格式错误 | 调用接口时,输入参数中包含了非支持的图片格式 | 请检查图片格式是否为 jpg、png 等支持的格式 |
| 1413 | 无效的媒体URL错误 | 调用接口时,输入参数中包含了无效的媒体URL | 请检查您提供的URL是否正确,避免包含特殊字符或格式错误 |
| 1414 | 输入包含敏感信息错误 | 调用接口时,输入参数中包含了敏感信息,如个人隐私数据等 | 暂不可生成带人物的营销视频,请等待后续版本更新 |
| 1415 | 输出包含敏感信息错误 | 调用接口时,服务返回结果中包含了敏感信息,如个人隐私数据等 | 暂不可生成带人物的营销视频,请等待后续版本更新 |
| 1416 | 输入媒体数量错误 | 用户输入的素材数量超过限制 | 提供的媒体素材数量超出限制,多出的素材可能不会使用 |
| 1417 | 大模型调用错误 | 模型调用出错,通常是输入参数错误 | 媒体素材处理存在问题,请重新尝试,如问题持续请联系火山技术支持 |
| 1418 | 时长计费参数错误 | 提交时入参时间有问题 | 要求的成片时长不符合技能要求,请按照0-60s的时长限制提交制作需求,如问题持续请联系火山技术支持 |
| 1501 | 用户套餐过期 | 调用接口时,用户套餐已过期 | 请前往 [套餐开通页面](https://console.volcengine.com/kickart/fusion/setting/combobuy?tab=combo) 开通套餐 |
| 1600 | 任务不存在 | 查询任务状态时,指定的任务ID不存在 | 请确认任务ID是否正确,或任务已被删除 |
| 100010 | 签名验证失败 | AK/SK签名验证失败 | 请检查您提供的火山鉴权AK/SK是否正确,可访问[火山引擎控制台](https://console.volcengine.com/iam/keymanage)确认 |
| 100013 | 缺少服务权限 | 缺少iccloud\_muse服务的RegisterArkClawCombo权限 | 您的企业账号未开通Kickart权限,请联系火山主账号管理员为您开通,或详询火山技术支持 |
| x01001 | AK/SK未配置 | 用户未配置AK/SK | 请输入火山鉴权的AK/SK,可访问[火山引擎控制台](https://console.volcengine.com/iam/keymanage)获取 |
| x01010 | 有效套餐缺失 | 素材上传出现错误,通常是套餐原因 | 请前往 [套餐开通页面](https://console.volcengine.com/kickart/fusion/setting/combobuy?tab=combo) 开通套餐 |
| A0101 | Session元数据格式错误 | 接口传入的Session元数据格式错误 | 稍后重试,如问题持续请联系火山技术支持 |
| A0402 | 文件校验不通过 | 用户输入的文件不符合校验要求 | 引导用户重新上传符合要求的文件 |
| 其他 | \- | 未明确列出的其他错误情况 | 稍后重试,如问题持续请联系火山技术支持 |
---don't have the plugin yet? install it then click "run inline in claude" again.