SuperAPI AI Directory

video-to-subtitle-summary

Design & creation

View repository

Updated 10-16 06:17

About this skill

Video-to-Subtitle and AI Summary Skill

Overview

Convert videos from short video platforms (Douyin, Xiaohongshu, Bilibili, YouTube, etc.) or local video/audio files into subtitle text and generate AI summaries.

Core workflow:

  • Online video: Get video info → Download video/directly capture subtitles → Select subtitle backend → Generate subtitles → AI summary
  • Local file: Extract audio (if needed) → Select subtitle backend → Generate subtitles → AI summary

By default, local faster-whisperis used, and switching to the Volcano Engine VC API via environment variables is also supported. For YouTube, yt-dlp is preferred to directly capture manual subtitles or auto-generated subtitles; only when no subtitles are available is it necessary to download the audio/video and fall back to ASR.

When to Use

  • The user provides a short video platform link (Douyin, Xiaohongshu, Bilibili, YouTube, etc.) and requests subtitle extraction or summary generation
  • The user provides a local video/audio file path and requests subtitle conversion or summary generation
  • The user requests to view their own AI Douyin historical tasks, recent tasks, or task list
  • Need to convert video content into text

Not applicable to: Real-time speech recognition, live streaming subtitles

External dependencies

Dependency Purpose Required
AI Douyin API Key Recommended video parsing/download proxy; free quota available after registration, 1 credit deducted after successfully parsing and downloading a direct link Only needed for Douyin/Xiaohongshu/Bilibili
TikHub API Optional advanced/self-hosted solution: parse directly using your own TikHub Token Optional
Python 3.9+ Run faster-whisper helper Only ASR_BACKEND=faster-whisper needed
faster-whisper Local speech-to-text Only ASR_BACKEND=faster-whisper needed
ByteDance VC API Cloud speech-to-text Only ASR_BACKEND=volcengine needed
FFmpeg Extract audio from video ✅ (audio files can skip this)
yt-dlp Download Bilibili videos; capture YouTube subtitles Only needed for Bilibili or YouTube
jq Parse AI Douyin/TikHub JSON responses Required for online video mode

Environment variables

Read through environment variables, supports configuration in any of the following ways:

Method 1: .env file (recommended) — Create a .env file in the skill directory:

ASR_BACKEND="faster-whisper"
VIDEO_INFO_PROVIDER="ai-douyin"
AI_DOUYIN_API_BASE="https://top9.cc"
AI_DOUYIN_API_KEY="your_ai_douyin_api_key"
TIKHUB_TOKEN=""

FW_MODEL_SIZE="small"
FW_DEVICE="auto"
FW_COMPUTE_TYPE=""
FW_PYTHON=""

BYTEDANCE_VC_TOKEN="your_token"
BYTEDANCE_VC_APPID="your_appid"

Method 2: Shell configuration — Add to ~/.zshrc or ~/.bashrc:

export ASR_BACKEND="faster-whisper"
export VIDEO_INFO_PROVIDER="ai-douyin"
export AI_DOUYIN_API_BASE="https://top9.cc"
export AI_DOUYIN_API_KEY="your_ai_douyin_api_key"
export TIKHUB_TOKEN=""

export FW_MODEL_SIZE="small"
export FW_DEVICE="auto"
export FW_COMPUTE_TYPE=""
export FW_PYTHON=""

export BYTEDANCE_VC_TOKEN="your_token"
export BYTEDANCE_VC_APPID="your_appid"

Notes:

  • ASR_BACKEND: Optional, default faster-whisper
  • VIDEO_INFO_PROVIDER: Optional, default ai-douyin; can be changed to tikhub to use your own TikHub Token
  • AI_DOUYIN_API_BASE / AI_DOUYIN_API_KEY: Recommended video parsing proxy; needed for Douyin/Xiaohongshu/Bilibili; not needed for YouTube
  • TIKHUB_TOKEN: Optional advanced/self-hosted solution; when VIDEO_INFO_PROVIDER=tikhub needed
  • FW_MODEL_SIZE / FW_DEVICE / FW_COMPUTE_TYPE: Only used by the faster-whisper backend
  • FW_PYTHON: Optional, specify the Python with faster-whisper installed; when left blank, prioritize using the default venv created by the helper installation, then fall back to the system python3
  • BYTEDANCE_VC_TOKEN / BYTEDANCE_VC_APPID: Only used by the volcengine backend

For installation and runtime instructions, see AI Douyin Configuration Guide、TikHub Application Guide、faster-whisper Installation Guide and Volcengine Activation Guide

Execution Steps

Step 0: Determine Input Type

Determine the processing mode based on user input:

  • Online Video Mode: Input is a URL
    • Douyin/TikTok:douyin.com、v.douyin.com、tiktok.com
    • Xiaohongshu:xiaohongshu.com、xhslink.com
    • Bilibili:bilibili.com、b23.tv
    • YouTube:youtube.com、youtu.be
  • Local File Mode: Input is a local file path
    • LocalVideoFile (.mp4、.mov、.avi、.mkv , etc.) → Start from Step 3 (Extract Audio)
    • LocalAudioFile (.mp3、.wav、.m4a、.flac , etc.) → Skip Step 3 and start from Step 4 (Transcription)

Step 0.5: Read Backend Configuration

First read ASR_BACKEND, defaulting to faster-whisper:

SKILL_DIR="${SKILL_DIR:-$HOME/.codex/skills/video-to-subtitle-summary}"
[ -d "$SKILL_DIR" ] || SKILL_DIR="$HOME/.claude/skills/video-to-subtitle-summary"
ENV_FILE="$SKILL_DIR/.env"

read_env() {
  local key="$1"
  if [ -f "$ENV_FILE" ]; then
    grep "^${key}=" "$ENV_FILE" | head -1 | cut -d'=' -f2- | tr -d '"' | tr -d "'"
  else
    printenv "$key"
  fi
}

ASR_BACKEND="$(read_env ASR_BACKEND)"
[ -z "$ASR_BACKEND" ] && ASR_BACKEND="faster-whisper"

echo "ASR_BACKEND=$ASR_BACKEND"

Supported values:

  • faster-whisper
  • volcengine

Step 0.6: Environment Check (Must Be Executed First)

Before starting any processing, check the dependencies required for the current mode and current subtitle backend.

SKILL_DIR="${SKILL_DIR:-$HOME/.codex/skills/video-to-subtitle-summary}"
[ -d "$SKILL_DIR" ] || SKILL_DIR="$HOME/.claude/skills/video-to-subtitle-summary"
ENV_FILE="$SKILL_DIR/.env"

read_env() {
  local key="$1"
  if [ -f "$ENV_FILE" ]; then
    grep "^${key}=" "$ENV_FILE" | head -1 | cut -d'=' -f2- | tr -d '"' | tr -d "'"
  else
    printenv "$key"
  fi
}

ASR_BACKEND="$(read_env ASR_BACKEND)"
[ -z "$ASR_BACKEND" ] && ASR_BACKEND="faster-whisper"
VIDEO_INFO_PROVIDER="$(read_env VIDEO_INFO_PROVIDER)"
[ -z "$VIDEO_INFO_PROVIDER" ] && VIDEO_INFO_PROVIDER="ai-douyin"
AI_DOUYIN_API_BASE="$(read_env AI_DOUYIN_API_BASE)"
[ -z "$AI_DOUYIN_API_BASE" ] && AI_DOUYIN_API_BASE="https://top9.cc"
AI_DOUYIN_API_KEY="$(read_env AI_DOUYIN_API_KEY)"
TIKHUB_TOKEN="$(read_env TIKHUB_TOKEN)"
BYTEDANCE_VC_TOKEN="$(read_env BYTEDANCE_VC_TOKEN)"
BYTEDANCE_VC_APPID="$(read_env BYTEDANCE_VC_APPID)"
FW_PYTHON="$(read_env FW_PYTHON)"
[ -z "$FW_PYTHON" ] && [ -x "$HOME/.cache/video-to-subtitle-summary/faster-whisper-venv/bin/python" ] && FW_PYTHON="$HOME/.cache/video-to-subtitle-summary/faster-whisper-venv/bin/python"
[ -z "$FW_PYTHON" ] && FW_PYTHON="python3"

MISSING=""

if [ "{INPUT_MODE}" = "url" ]; then
  if [ "{PLATFORM}" = "douyin" ] || [ "{PLATFORM}" = "xiaohongshu" ] || [ "{PLATFORM}" = "bilibili" ]; then
    if [ "$VIDEO_INFO_PROVIDER" = "ai-douyin" ]; then
      [ -z "$AI_DOUYIN_API_KEY" ] && MISSING="$MISSING AI_DOUYIN_API_KEY"
    elif [ "$VIDEO_INFO_PROVIDER" = "tikhub" ]; then
      [ -z "$TIKHUB_TOKEN" ] && MISSING="$MISSING TIKHUB_TOKEN"
    else
      MISSING="$MISSING invalid_VIDEO_INFO_PROVIDER"
    fi
  fi
  if [ "$VIDEO_INFO_PROVIDER" = "ai-douyin" ] || [ "$VIDEO_INFO_PROVIDER" = "tikhub" ]; then
    command -v jq >/dev/null 2>&1 || MISSING="$MISSING jq"
  fi
  if [ "{PLATFORM}" = "bilibili" ] || [ "{PLATFORM}" = "youtube" ]; then
    command -v yt-dlp >/dev/null 2>&1 || MISSING="$MISSING yt-dlp"
  fi
fi

if [ "{NEEDS_FFMPEG}" = "yes" ] && [ "{PLATFORM}" != "youtube" ]; then
  command -v ffmpeg >/dev/null 2>&1 || MISSING="$MISSING ffmpeg"
fi

if [ "$ASR_BACKEND" = "faster-whisper" ]; then
  command -v "$FW_PYTHON" >/dev/null 2>&1 || [ -x "$FW_PYTHON" ] || MISSING="$MISSING FW_PYTHON"
  "$FW_PYTHON" - <<'PY' >/dev/null 2>&1 || MISSING="$MISSING faster-whisper"
import faster_whisper
import ctranslate2
PY
elif [ "$ASR_BACKEND" = "volcengine" ]; then
  [ -z "$BYTEDANCE_VC_TOKEN" ] && MISSING="$MISSING BYTEDANCE_VC_TOKEN"
  [ -z "$BYTEDANCE_VC_APPID" ] && MISSING="$MISSING BYTEDANCE_VC_APPID"
else
  MISSING="$MISSING invalid_ASR_BACKEND"
fi

if [ -n "$MISSING" ]; then
  echo "ERROR: 缺少必需依赖或配置:$MISSING"
  echo "ASR_BACKEND=$ASR_BACKEND VIDEO_INFO_PROVIDER=$VIDEO_INFO_PROVIDER"
  echo "ASR_BACKEND 可选值: faster-whisper / volcengine"
  echo "VIDEO_INFO_PROVIDER 可选值: ai-douyin / tikhub"
  exit 1
else
  echo "OK: 运行依赖已就绪 (ASR_BACKEND=$ASR_BACKEND)"
fi

If the check fails:

  • ASR_BACKEND=faster-whisper: Prefer to run python3 "$SKILL_DIR/scripts/install_faster_whisper.py", or refer to docs/faster-whisper-setup.md
  • ASR_BACKEND=volcengine: Refer to docs/bytedance-vc-setup.md
  • AI_DOUYIN_API_KEY: Register for AI Douyin to claim free credits and create an API Key; if the balance is insufficient, top up credits, or switch to VIDEO_INFO_PROVIDER=tikhub + TIKHUB_TOKEN

Step 1: Retrieve Video Information/Download Direct Link (Online Video Mode Only)

Identify the platform based on the URL domain:

Platform URL Characteristics Default Processing Method
Douyin/TikTok douyin.com、v.douyin.com、tiktok.com AI Douyin proxy parses download direct link; optional TikHub
Xiaohongshu xiaohongshu.com、xhslink.com AI Douyin proxy parses download direct link; optional TikHub
Bilibili bilibili.com、b23.tv AI Douyin proxy parses download direct link; fallback if necessary yt-dlp
YouTube youtube.com、youtu.be Do not call AI Douyin/TikHub, directly proceed to Step 2 to capture subtitles

Default recommendation: AI Douyin proxy

AI Douyin is suitable for users who do not want to register separately for TikHub. Register https://top9.cc to claim free credits and create an API Key. After successfully parsing the download direct link, 1 credit is deducted; on failure, no credit is deducted. When the balance is insufficient, the API returns HTTP 402 / insufficient balance。

SKILL_DIR="${SKILL_DIR:-$HOME/.codex/skills/video-to-subtitle-summary}"
[ -d "$SKILL_DIR" ] || SKILL_DIR="$HOME/.claude/skills/video-to-subtitle-summary"
ENV_FILE="$SKILL_DIR/.env"
read_env() {
  local key="$1"
  if [ -f "$ENV_FILE" ]; then
    grep "^${key}=" "$ENV_FILE" | head -1 | cut -d'=' -f2- | tr -d '"' | tr -d "'"
  else
    printenv "$key"
  fi
}

AI_DOUYIN_API_BASE="$(read_env AI_DOUYIN_API_BASE)"
[ -z "$AI_DOUYIN_API_BASE" ] && AI_DOUYIN_API_BASE="https://top9.cc"
AI_DOUYIN_API_KEY="$(read_env AI_DOUYIN_API_KEY)"

# API Base 支持填 https://top9.cc 或 https://top9.cc/api/v1
case "$AI_DOUYIN_API_BASE" in
  */api/v1) AI_DOUYIN_DOWNLOAD_URL_ENDPOINT="$AI_DOUYIN_API_BASE/video/download-url" ;;
  */api) AI_DOUYIN_DOWNLOAD_URL_ENDPOINT="$AI_DOUYIN_API_BASE/v1/video/download-url" ;;
  *) AI_DOUYIN_DOWNLOAD_URL_ENDPOINT="${AI_DOUYIN_API_BASE%/}/api/v1/video/download-url" ;;
esac

curl -sS -w '\n%{http_code}' -X POST "$AI_DOUYIN_DOWNLOAD_URL_ENDPOINT" \
  -H "X-API-Key: $AI_DOUYIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg url "{ORIGINAL_URL}" '{url: $url}')" \
  > /tmp/video_analysis/download_url_response.txt

HTTP_CODE=$(tail -n1 /tmp/video_analysis/download_url_response.txt)
sed '$d' /tmp/video_analysis/download_url_response.txt > /tmp/video_analysis/download_url.json

if [ "$HTTP_CODE" = "402" ]; then
  echo "ERROR: AI Douyin 余额不足(insufficient balance)。请到 https://top9.cc 购买积分,或改用 VIDEO_INFO_PROVIDER=tikhub + TIKHUB_TOKEN。"
  exit 1
elif [ "$HTTP_CODE" = "401" ]; then
  echo "ERROR: AI Douyin API Key 缺失或无效。请检查 AI_DOUYIN_API_KEY。"
  exit 1
elif [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then
  echo "ERROR: AI Douyin 解析失败 (HTTP $HTTP_CODE)"
  cat /tmp/video_analysis/download_url.json
  exit 1
fi

VIDEO_URL=$(jq -r '.download_url // empty' /tmp/video_analysis/download_url.json)
VIDEO_URL_COUNT=$(jq -r '(.download_urls // [.download_url] | map(select(. != null and . != "")) | length)' /tmp/video_analysis/download_url.json)
EXTRACTED_URL=$(jq -r '.extracted_url // empty' /tmp/video_analysis/download_url.json)
DOWNLOAD_COST=$(jq -r '.cost // 1' /tmp/video_analysis/download_url.json)
[ -z "$VIDEO_URL" ] && echo "ERROR: 未返回 download_url" && cat /tmp/video_analysis/download_url.json && exit 1

Extract key fields:

jq '{download_url, download_urls_count: (.download_urls // [] | length), extracted_url, cost}' /tmp/video_analysis/download_url.json

Optional video API retrieval solutions: Own TikHub Token

When VIDEO_INFO_PROVIDER=tikhub , use your own TikHub Token to parse directly. Note: do not write the real Token into logs or replies.

Douyin/TikTok:

curl -s -X GET "https://api.tikhub.io/api/v1/hybrid/video_data?url={ENCODED_URL}&minimal=true" \
  -H "Authorization: Bearer your_tikhub_api_token" \
  -H "Accept: application/json"

Prefer to extract the watermark-free address:

jq -r '.data.video_data.nwm_video_url // .data.video.play_addr.url_list[0] // empty'

Xiaohongshu:

curl -s -X GET "https://api.tikhub.io/api/v1/xiaohongshu/web/get_note_info_v7?share_text={ENCODED_URL}" \
  -H "Authorization: Bearer your_tikhub_api_token" \
  -H "Accept: application/json"

Bilibili:

curl -s -X GET "https://api.tikhub.io/api/v1/bilibili/web/fetch_one_video_v3?url={ENCODED_URL}" \
  -H "Authorization: Bearer your_tikhub_api_token" \
  -H "Accept: application/json"

If Bilibili does not obtain a downloadable direct link, you can use yt-dlp in Step 2 to download.

Step 1.5: Query the User's Own AI Douyin Historical Tasks (As Needed)

When the user requests to view their own historical tasks / recent tasks / task list, call AI Douyin's GET /api/v1/tasks. This API uses X-API-Key authentication and only returns the current API Key's corresponding user's own tasks.

SKILL_DIR="${SKILL_DIR:-$HOME/.codex/skills/video-to-subtitle-summary}"
[ -d "$SKILL_DIR" ] || SKILL_DIR="$HOME/.claude/skills/video-to-subtitle-summary"

python3 "$SKILL_DIR/scripts/list_ai_douyin_tasks.py" \
  --page 1 \
  --page-size 20

Optional filters:

python3 "$SKILL_DIR/scripts/list_ai_douyin_tasks.py" --status completed --page 1 --page-size 10
python3 "$SKILL_DIR/scripts/list_ai_douyin_tasks.py" --search "关键词" --json

The script reads $SKILL_DIR/.env by default, or AI_DOUYIN_API_BASE / AI_DOUYIN_API_KEYfrom environment variables. Do not display the real API Key when outputting to the user.

Step 2: Download Video (Online Video Mode Only)

Use different download methods depending on the platform:

YouTube (prefer directly fetching subtitles, do not download the video):

mkdir -p /tmp/video_analysis/{VIDEO_ID}
SKILL_DIR="${SKILL_DIR:-$HOME/.codex/skills/video-to-subtitle-summary}"
[ -d "$SKILL_DIR" ] || SKILL_DIR="$HOME/.claude/skills/video-to-subtitle-summary"
python3 "$SKILL_DIR/scripts/download_youtube_subtitles.py" \
  "https://www.youtube.com/watch?v={VIDEO_ID}" \
  --output-dir /tmp/video_analysis/{VIDEO_ID} \
  --languages zh-Hans,zh-Hant,zh,en

The output file is fixed as:

  • /tmp/video_analysis/{VIDEO_ID}/subtitle.srt
  • /tmp/video_analysis/{VIDEO_ID}/text.txt

If the command indicates no subtitles are available, then use yt-dlp to download the audio or video, and continue from step 3 with ASR_BACKEND。

Douyin / TikTok / Xiaohongshu / Bilibili (when a VIDEO_URL download direct link is already available):

mkdir -p /tmp/video_analysis/{VIDEO_ID}
SKILL_DIR="${SKILL_DIR:-$HOME/.codex/skills/video-to-subtitle-summary}"
[ -d "$SKILL_DIR" ] || SKILL_DIR="$HOME/.claude/skills/video-to-subtitle-summary"
python3 "$SKILL_DIR/scripts/download_video_candidates.py" \
  --response-json /tmp/video_analysis/download_url.json \
  --output /tmp/video_analysis/{VIDEO_ID}/video.mp4 \
  --timeout 30

Bilibili (fallback when there is no download direct link):

mkdir -p /tmp/video_analysis/{BVID}
yt-dlp -o /tmp/video_analysis/{BVID}/video.mp4 "https://www.bilibili.com/video/{BVID}/"

Step 3: Extract audio (can be skipped for local audio files)

In local file mode, if the input is a local video file, replace {VIDEO_ID} with the file name (without extension), and replace the input path with the actual video path.

ffmpeg -i /tmp/video_analysis/{VIDEO_ID}/video.mp4 -q:a 0 -map a -y /tmp/video_analysis/{VIDEO_ID}/audio.mp3

Step 4: Based on ASR_BACKEND , choose the subtitle backend

If the platform is YouTube and step 2 has successfully generated subtitle.srt and text.txt, skip this step and go directly to step 5 for summarization.

Option A:ASR_BACKEND=faster-whisper(default)

helper path:

$SKILL_DIR/scripts/transcribe_faster_whisper.py

Execute command:

SKILL_DIR="${SKILL_DIR:-$HOME/.codex/skills/video-to-subtitle-summary}"
[ -d "$SKILL_DIR" ] || SKILL_DIR="$HOME/.claude/skills/video-to-subtitle-summary"
FW_PYTHON="${FW_PYTHON:-$HOME/.cache/video-to-subtitle-summary/faster-whisper-venv/bin/python}"
[ -x "$FW_PYTHON" ] || FW_PYTHON="python3"
"$FW_PYTHON" "$SKILL_DIR/scripts/transcribe_faster_whisper.py" \
  /tmp/video_analysis/{VIDEO_ID}/audio.mp3 \
  --output-dir /tmp/video_analysis/{VIDEO_ID}

Notes:

  • The helper will automatically read FW_MODEL_SIZE、FW_DEVICE、FW_COMPUTE_TYPE
  • When FW_DEVICE=auto , only when NVIDIA/CUDA is detected will it use device="cuda"
  • The output file is fixed as:
    • /tmp/video_analysis/{VIDEO_ID}/subtitle.srt
    • /tmp/video_analysis/{VIDEO_ID}/text.txt

Option B:ASR_BACKEND=volcengine

Submit task:

SKILL_DIR="${SKILL_DIR:-$HOME/.codex/skills/video-to-subtitle-summary}"
[ -d "$SKILL_DIR" ] || SKILL_DIR="$HOME/.claude/skills/video-to-subtitle-summary"
ENV_FILE="$SKILL_DIR/.env"
if [ -f "$ENV_FILE" ]; then
  BYTEDANCE_VC_TOKEN=$(grep "^BYTEDANCE_VC_TOKEN=" "$ENV_FILE" | cut -d'=' -f2- | tr -d '"' | tr -d "'")
  BYTEDANCE_VC_APPID=$(grep "^BYTEDANCE_VC_APPID=" "$ENV_FILE" | cut -d'=' -f2- | tr -d '"' | tr -d "'")
else
  BYTEDANCE_VC_TOKEN="$BYTEDANCE_VC_TOKEN"
  BYTEDANCE_VC_APPID="$BYTEDANCE_VC_APPID"
fi

curl -s -X POST "https://openspeech.bytedance.com/api/v1/vc/submit?appid=$BYTEDANCE_VC_APPID&language=zh-CN&words_per_line=20&max_lines=2" \
  -H "Content-Type: audio/mpeg" \
  -H "Authorization: Bearer;$BYTEDANCE_VC_TOKEN" \
  --data-binary @/tmp/video_analysis/{VIDEO_ID}/audio.mp3

Poll results:

SKILL_DIR="${SKILL_DIR:-$HOME/.codex/skills/video-to-subtitle-summary}"
[ -d "$SKILL_DIR" ] || SKILL_DIR="$HOME/.claude/skills/video-to-subtitle-summary"
ENV_FILE="$SKILL_DIR/.env"
if [ -f "$ENV_FILE" ]; then
  BYTEDANCE_VC_TOKEN=$(grep "^BYTEDANCE_VC_TOKEN=" "$ENV_FILE" | cut -d'=' -f2- | tr -d '"' | tr -d "'")
  BYTEDANCE_VC_APPID=$(grep "^BYTEDANCE_VC_APPID=" "$ENV_FILE" | cut -d'=' -f2- | tr -d '"' | tr -d "'")
else
  BYTEDANCE_VC_TOKEN="$BYTEDANCE_VC_TOKEN"
  BYTEDANCE_VC_APPID="$BYTEDANCE_VC_APPID"
fi

curl -s "https://openspeech.bytedance.com/api/v1/vc/query?appid=$BYTEDANCE_VC_APPID&id={TASK_ID}" \
  -H "Authorization: Bearer;$BYTEDANCE_VC_TOKEN"

Result handling:

jq -r '.utterances[].text' subtitle.json | tr '\n' ' ' > /tmp/video_analysis/{VIDEO_ID}/text.txt

Generate SRT:

import json

with open('subtitle.json', 'r') as f:
    data = json.load(f)

def ms_to_srt(ms):
    h, m, s, millis = ms//3600000, (ms%3600000)//60000, (ms%60000)//1000, ms%1000
    return f"{h:02d}:{m:02d}:{s:02d},{millis:03d}"

with open('/tmp/video_analysis/{VIDEO_ID}/subtitle.srt', 'w') as f:
    for i, u in enumerate(data['utterances'], 1):
        f.write(f"{i}\n{ms_to_srt(u['start_time'])} --> {ms_to_srt(u['end_time'])}\n{u['text']}\n\n")

Step 5: AI-generated summary

Done directly by Claude, no need to call a third-party summarization API.

Read text.txt and then generate.

When summarizing, the following context should also be provided:

  • Original video title: if it is an online video, prefer using the original title field returned by the platform
    • Douyin/TikTok: prefer desc
    • Xiaohongshu: prefer title
    • Bilibili: prefer title
  • Fallback title: if there is no clear title, the file name or video ID can be used as a reference identifier
  • Subtitle note: clearly tell Claude that the main text may come from YouTube subtitles, automatic subtitles, or speech recognition, and may contain homophones, sentence segmentation issues, or proper noun recognition errors; without deviating from the original meaning, moderate corrections can be made based on the original video title and context

It is recommended to use the following prompt method directly:

以下是一个视频的分析素材,请基于这些信息生成总结:

原视频标题:{ORIGINAL_TITLE}
来源平台:{PLATFORM}
作者:{AUTHOR}
说明:下面的正文来自平台字幕、自动字幕或语音识别,可能存在少量识别误差、断句问题或专有名词错误。请以原视频标题和上下文为参考,在不改变原意的前提下做适度修正,再完成总结。

语音识别文本:
{TEXT_CONTENT}

请输出:
1. AI生成标题:简洁概括,不超过30字;可以参考原视频标题,但不要机械照抄,必要时可根据正文纠正明显错误
2. AI摘要:提炼主要观点和关键信息,200-300字
3. 核心要点:输出3-5条结构化要点

If the original video title clearly conflicts with the main text:

  • Prioritize the main idea of the main text
  • Keep the judgment that "there may be errors due to speech recognition," and do not add information that did not appear out of thin air
  1. Title: concise summary, no more than 30 characters
  2. Summary: main viewpoints and key information, 200-300 characters
  3. Key points: a structured list of core viewpoints

Output format

## 视频分析结果

### 视频信息

| 项目 | 内容 |
| --- | --- |
| 视频ID | xxx |
| 作者 | xxx |
| 时长 | xxx |

### AI生成标题

xxx

### AI摘要

xxx

### 核心要点

1. xxx
2. xxx

### 生成文件

- 视频: /tmp/video_analysis/{ID}/video.mp4
- 音频: /tmp/video_analysis/{ID}/audio.mp3
- SRT字幕: /tmp/video_analysis/{ID}/subtitle.srt
- 纯文本: /tmp/video_analysis/{ID}/text.txt

Common issues

Issue Solution
Missing environment variable First confirm ASR_BACKEND; Douyin/Xiaohongshu/Bilibili require AI_DOUYIN_API_KEYby default, the self-owned TikHub mode requires TIKHUB_TOKEN; the Volcano backend requires BYTEDANCE_VC_TOKEN and BYTEDANCE_VC_APPID
ASR_BACKEND is invalid Only supports faster-whisper and volcengine
faster-whisper import failed Execute python3 "$SKILL_DIR/scripts/install_faster_whisper.py", installing the helper will first test the speed of PyPI mirrors and create an independent venv; when using a custom venv, set FW_PYTHON=/path/to/venv/bin/python
Volcengine API authentication failed Authorization must be Bearer;token(no spaces around the semicolon)
First run is slower faster-whisper The model will be downloaded on first run; wait for the download to complete and retry
CUDA environment unavailable FW_DEVICE=auto will automatically fall back to CPU; only NVIDIA/CUDA uses the GPU
Video download failed When AI Douyin returns 401, check the API Key; when it returns 402, top up credits or switch to TikHub; for direct-link downloads add User-Agent; for Bilibili you can fall back to yt-dlp
FFmpeg not found macOS: brew install ffmpeg / Linux: sudo apt install ffmpeg / Windows: choco install ffmpeg
yt-dlp not found macOS: brew install yt-dlp / General: python3 -m pip install -U yt-dlp(required for Bilibili / YouTube)