Back to skills
extension
Category: OtherNo API key required

YM-MediaToolkit(媒体处理工具集)

自然语言媒体助手 - 视频压缩、MP4/MOV 封面提取、音频转换、字幕识别

personAuthor: 370299455cx-webhubclawhub

YM MediaToolkit

自然语言媒体助手,支持从远程视频 URL、当前工作目录内的本地视频文件、或配置过 media_roots 的本地媒体目录直接处理:

  • 自然语言调用
  • 视频压缩
  • MP4/MOV 封面提取
  • 音频提取与转换:MP3 / WAV / AAC / M4A
  • OCR / ASR 字幕识别
  • emlet 字幕二次分句
  • 批量处理
  • JSON 驱动媒体流水线

依赖

pip install -r requirements.txt

系统需要安装:

ffmpeg
ffprobe

字幕识别依赖已内置在 requirements.txt,包括 faster-whisperpaddlepaddlepaddleocr

维护

维护、发布、测试和排障流程见 MAINTENANCE.md

命令行

python run.py -a <action> -i '<json>'

也可以从 JSON 文件读取参数:

python run.py -i params.json

HTTP 服务

python run.py --serve

默认监听 127.0.0.1:8080

健康检查:

GET /health

异步长任务:

POST /skill/jobs
GET /skill/jobs/<job_id>
GET /skill/jobs

功能

输入源字段可使用 video_urlurlsource,三者等价。远程输入仅支持 http/https,本地输入默认限制在当前工作目录内;需要访问绝对路径时,通过请求参数 media_roots 或环境变量 YM_MEDIA_ROOTS 配置允许的媒体根目录。

返回协议

4.1.0 开始,所有 action 都会返回稳定协议字段:

| 字段 | 说明 | |------|------| | status | success / partial / skipped / error | | code | 稳定机器码,例如 okmissing_sourceoutput_existsparse_failed | | reply | 适合聊天展示的简短中文回复 | | hint | 面向调用方或用户的下一步建议 |

原有业务字段会继续保留,例如 output_pathsaved_pathoutputPathmanifest_pathinfocaptionsresult

默认输出目录:

| 类型 | 默认目录 | |------|----------| | 压缩视频 | output/videos | | 音频 | output/audio | | 封面 | output/thumbs |

所有会写文件的接口都支持 overwrite,默认 true。设置为 false 时,如果输出文件已存在会直接返回错误。

3.0.3 更新

  • 支持当前工作目录内的本地视频文件输入。
  • 统一 video_url / url / source 三种输入字段。
  • 增加默认输出目录:output/videosoutput/audiooutput/thumbs
  • 增加 overwrite 覆盖策略,避免误覆盖已有文件。

4.0.0 更新

  • 新增自然语言入口 chat,适合 Claw 直接转发用户聊天文本。
  • 新增 media_roots 白名单,支持处理授权目录内的绝对路径文件。
  • 自然语言命令支持提取音频、提取封面、压缩、查看信息、JSON 流水线。
  • chat 返回 reply 和结构化 result,同时兼顾聊天展示和自动化消费。

4.0.1 更新

  • 新增 subtitle 推荐入口,支持 asr / ocr / fusion 模式。
  • 新增 asrocr 单独调试入口。
  • 字幕统一输出 SRT-like JSON:captionTxtstartTimeUsendTimeUssourceconfidence
  • chat 支持“识别字幕 / 提取字幕 / 转字幕 / 生成字幕”等自然语言命令。

4.0.2 更新

  • faster-whisperpaddlepaddlepaddleocr 纳入默认 requirements.txt
  • 字幕识别从“可选依赖”调整为默认安装能力。
  • 运行时仍保留缺依赖 JSON error,方便定位未重新安装依赖的环境。

4.1.0 更新

  • 所有 action 统一补齐 codereplyhint,方便 Claw 和后续渠道适配。
  • 增加稳定错误码:missing_sourcesource_not_allowedoutput_existsparse_failedmissing_stepsunsupported_actionffmpeg_failedmissing_asr_dependencymissing_ocr_dependency
  • 保持旧字段兼容,不改变现有 action 名称、HTTP endpoint 和底层媒体处理逻辑。

4.1.1 更新

  • 新增 caption_segment,用于 emlet 字幕二次分句。
  • 默认每句最多 12 个字符,按强标点、弱标点、连接词和长度切分。
  • 新增 protected_termsprotected_terms_path,用于保护品牌词、产品名、人名、术语不被拆开。
  • pipeline 支持 subtitle -> caption_segment 串联;分句步骤未传 caption_path 时会自动使用上一步字幕 JSON。

4.2.0 更新

  • 新增 HTTP 异步长任务接口 /skill/jobs,适合压缩、ASR/OCR、字幕和 pipeline 等耗时 action。
  • 任务状态持久化到 output/jobs/<job_id>/job.json,支持提交、轮询和列表查询。
  • 现有 /skill/<action> 同步接口保持不变;CLI 仍保持同步执行。

自然语言调用

Action: chat

Claw 推荐优先调用 chat。复杂、确定性要求高的多步骤流程继续使用 pipeline

python run.py -a chat -i '{"message":"将 \"sample.mp4\" 提取音频"}'
python run.py -a chat -i '{"message":"给 \"sample.mp4\" 提取第 3 秒封面"}'
python run.py -a chat -i '{"message":"压缩 \"sample.mp4\""}'
python run.py -a chat -i '{"message":"查看 \"sample.mp4\" 信息"}'
python run.py -a chat -i '{"message":"识别 \"sample.mp4\" 的字幕"}'

处理绝对路径时需要配置媒体根目录:

python run.py -a chat -i '{"message":"将 \"D:/AA.MP4\" 提取音频","media_roots":["D:/"]}'

返回包含:

| 字段 | 说明 | |------|------| | reply | 可直接展示给用户的聊天回复 | | intent | 识别出的意图 | | action | 实际调用的 action | | params | 传给底层 action 的参数 | | result | 底层 action 原始结果 | | output_paths | 本次生成的输出路径列表 |

HTTP 异步长任务

Action 可以继续同步调用,也可以通过 job API 异步执行。推荐对 compressasrocrsubtitlepipeline 等长任务使用异步接口。

提交任务:

curl -X POST http://127.0.0.1:8080/skill/jobs \
  -H 'Content-Type: application/json' \
  -d '{"action":"pipeline","params":{"source":"sample.mp4","steps":[{"id":"metadata","action":"info","enabled":true}]}}'

返回:

{
  "status": "queued",
  "code": "ok",
  "reply": "任务已提交:<job_id>",
  "job_id": "<job_id>",
  "job_path": "output/jobs/<job_id>/job.json",
  "poll_url": "/skill/jobs/<job_id>"
}

轮询任务:

curl http://127.0.0.1:8080/skill/jobs/<job_id>

任务状态包括:queuedrunningsuccesspartialskippederror。任务结果保存在 result,产物路径汇总在 output_paths

查询任务列表:

curl 'http://127.0.0.1:8080/skill/jobs?status=success&limit=50'

任务文件存储在 output/jobs/<job_id>/job.json。服务重启后,已完成任务仍可查询;未完成的 queued / running 任务会标记为 errorcode=job_interrupted

字幕识别

Action: subtitle

推荐使用 subtitle,默认 mode=fusion:ASR 负责主要时间轴和文本,OCR 做画面字幕校正。识别依赖随 requirements.txt 安装;如果环境未重新安装依赖,会返回 JSON error,不会抛未捕获异常。

python run.py -a subtitle -i '{"source":"sample.mp4","mode":"fusion"}'
python run.py -a subtitle -i '{"source":"sample.mp4","mode":"asr","language":"zh"}'
python run.py -a subtitle -i '{"source":"sample.mp4","mode":"ocr","sample_interval_sec":1}'

参数:

| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | video_url / url / source | string | 必填 | 远程 URL 或本地文件 | | mode | string | fusion | asr / ocr / fusion | | language | string | auto | ASR 语言,例:zh / en | | model_size | string | base | faster-whisper 模型规格 | | sample_interval_sec | number | 1.0 | OCR 抽帧间隔 | | crop_bottom_ratio | number | 0.35 | OCR 默认扫描画面下方比例 | | output_path | string | output/subtitles/... | 字幕 JSON 输出路径 | | overwrite | boolean | true | 是否覆盖已有文件 |

字幕条目格式:

{
  "captionTxt": "识别到的字幕文本",
  "startTimeUs": 1000000,
  "endTimeUs": 2000000,
  "source": "asr",
  "confidence": 0.92
}

底层调试入口:

python run.py -a asr -i '{"source":"sample.mp4","language":"zh"}'
python run.py -a ocr -i '{"source":"sample.mp4"}'

字幕二次分句

Action: caption_segment

caption_segment 是 emlet 字幕分句器:它不重新识别字幕,只处理已有 captions。默认 max_chars=12,输出仍是 SRT-like captions JSON。

python run.py -a caption_segment -i '{
  "caption_path":"output/subtitles/sample.captions.json",
  "max_chars":12,
  "protected_terms":["苹果","华为","吉利"]
}'

也可以直接传 captions:

python run.py -a caption_segment -i '{
  "captions":[
    {"captionTxt":"今天我们聊苹果华为和吉利的新产品","startTimeUs":0,"endTimeUs":3000000}
  ],
  "max_chars":12,
  "protected_terms":"苹果,华为,吉利"
}'

长期词库可以放在 JSON 文件中:

{
  "brands": ["苹果", "华为", "吉利"],
  "products": ["小米汽车", "Model Y", "ChatGPT"]
}

参数:

| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | caption_path / input_path | string | - | 已有 captions JSON 文件 | | captions | array | - | 直接传入字幕条目 | | max_chars | integer | 12 | 单条字幕最大字符数 | | protected_terms | array/string | [] | 不拆开的品牌词、产品名、人名、术语 | | protected_terms_path | string | - | 当前工作目录内的保护词 JSON 文件 | | auto_protect_ascii | boolean | true | 自动保护英文、数字、型号、URL、路径 | | output_path | string | output/subtitles/... | 分句后字幕 JSON 输出路径 | | overwrite | boolean | true | 是否覆盖已有文件 |

压缩视频

Action: compress

python run.py -a compress -i '{"source":"sample.mp4","target_ratio":0.1}'

参数:

| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | video_url / url / source | string | 必填 | 远程 URL 或本地文件 | | target_ratio | number | 0.1 | 目标体积比例 | | adaptive | boolean | true | 是否自动尝试不同 CRF | | crf | integer | 24 | 非 adaptive 模式下使用 | | preset | string | veryfast | ffmpeg 编码预设 | | output_path | string | output/videos/... | 输出路径 | | overwrite | boolean | true | 是否覆盖已有文件 |

提取封面

Action: thumbnail

当前支持 MP4/MOV 容器,主要适用于 H.264/H.265 视频轨道。

python run.py -a thumbnail -i '{"source":"sample.mp4","time_seconds":5}'

参数:

| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | video_url / url / source | string | 必填 | 远程 URL 或本地文件 | | time_seconds | number | 0 | 按时间点提取 | | frame_number | integer | - | 按帧号提取,优先于 time_seconds | | save_path | string | output/thumbs/... | 保存路径 | | resize_width | integer | - | 输出宽度 | | quality | integer | 85 | JPEG 质量 | | overwrite | boolean | true | 是否覆盖已有文件 |

提取音频

Action: audio

python run.py -a audio -i '{"source":"sample.mp4","format":"mp3"}'

参数:

| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | video_url / url / source | string | 必填 | 远程 URL 或本地文件 | | format | string | mp3 | mp3 / wav / aac / m4a | | bitrate | string | 128k | 音频比特率 | | sample_rate | integer | 44100 | 采样率 | | channels | integer | 2 | 声道数 | | start_time | number | - | 开始时间,秒 | | duration | number | - | 截取时长,秒 | | output_path | string | output/audio/... | 输出路径 | | overwrite | boolean | true | 是否覆盖已有文件 |

批量音频

Action: audio_batch

python run.py -a audio_batch -i '{
  "videos":[
    {"source":"sample1.mp4","name":"video1"},
    {"url":"https://example.com/2.mp4","name":"video2"}
  ],
  "output_dir":"output/audio",
  "format":"mp3"
}'

批量处理

Action: batch

python run.py -a batch -i '{
  "action":"thumbnail",
  "videos":[
    {"source":"sample1.mp4","time_seconds":5},
    {"url":"https://example.com/2.mp4","time_seconds":10}
  ]
}'

action 支持:compressthumbnailaudio

JSON 流水线

Action: pipeline

steps 是唯一流程控制入口,没有写进 steps 的动作不会执行。支持的 step action:infothumbnailaudiocompressaudio_infoasrocrsubtitlecaption_segment

python run.py -a pipeline -i '{
  "source":"sample.mp4",
  "name":"sample",
  "output_dir":"output/pipeline/sample",
  "overwrite":true,
  "steps":[
    {"id":"metadata","action":"info","enabled":true},
    {
      "id":"cover",
      "action":"thumbnail",
      "enabled":true,
      "params":{"time_seconds":3,"resize_width":720}
    },
    {
      "id":"audio_mp3",
      "action":"audio",
      "enabled":false,
      "params":{"format":"mp3","bitrate":"128k"}
    }
  ]
}'

规则:

| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | video_url / url / source | string | 必填 | 远程 URL 或本地文件 | | name | string | 输入文件名 | 流水线名称 | | output_dir | string | output/pipeline/<name> | manifest 和默认产物目录 | | overwrite | boolean | true | 是否覆盖已有产物 | | steps | array | 必填 | 按 JSON 顺序执行的步骤 |

每个 step 需要 idactionenabledenabled=false 会记录为 skipped。每次执行都会生成 manifest.json

获取信息

python run.py -a info -i '{"source":"sample.mp4"}'
python run.py -a audio_info -i '{"source":"sample.mp4"}'

注意

  • 远程输入仅支持 http / https
  • 本地输入路径默认限制在当前工作目录内;通过 media_roots / YM_MEDIA_ROOTS 可授权额外媒体根目录。
  • 输出路径限制在当前工作目录内。
  • HTTP 服务默认只绑定本机地址。