diff --git a/memory/2026-02-13.md b/memory/2026-02-13.md new file mode 100644 index 0000000..fa8c504 --- /dev/null +++ b/memory/2026-02-13.md @@ -0,0 +1,32 @@ +# 2026-02-13 + +## 项目状态 + +### GPG 与 Git 推送 +- ~~GPG 签名~~ → **改用 SSH** +- **SSH 推送**: ✅ 成功! +- 最新提交: `2adc3c1 docs: 更新每日记录` + +### Whisper 替代 OCR 方案 +- **决策**: 新增 `kb-whisper` 技能,异步执行 +- **原因**: 语音处理耗时,不阻塞主代理,支持并行讨论 +- **输出格式**: JSON(时间戳) + SRT + TXT +- **状态**: ✅ 安装完成,技能创建完成 + +### 待清理文件 +- `bilibili_BV1Z9nXzUEhv_720p_frames/` +- `whispercpp.zip` + +## 今日完成 + +| 任务 | 状态 | +|------|------| +| whisper.cpp 安装 | ✅ 完成 | +| kb-whisper 技能创建 | ✅ 完成 | +| SSH 推送 | ✅ 成功 | + +## 待办 +- [ ] 清理临时文件 +- [ ] 下载中文模型 (需代理) +- [ ] 测试 Whisper 转写效果 +- [ ] kb-workflow 集成 kb-whisper diff --git a/skills/kb-whisper/.env.example b/skills/kb-whisper/.env.example new file mode 100644 index 0000000..8ffc440 --- /dev/null +++ b/skills/kb-whisper/.env.example @@ -0,0 +1,5 @@ +# KB Whisper 环境变量配置示例 +# 复制此文件为 .env 并填写实际值 + +# Whisper.cpp 安装路径 +WHISPER_CPP_PATH=~/whisper.cpp diff --git a/skills/kb-whisper/README.md b/skills/kb-whisper/README.md new file mode 100644 index 0000000..7b84ea8 --- /dev/null +++ b/skills/kb-whisper/README.md @@ -0,0 +1,211 @@ +# KB Whisper - 本地语音识别 + +基于 Whisper.cpp 的本地语音识别工具,支持将音视频文件转换为文本、字幕和 JSON 格式。 + +## 功能特性 + +- 🎯 **本地执行** - 完全离线运行,保护隐私 +- 🚀 **多模型支持** - 从 tiny 到 large,根据需求选择速度/精度 +- 📝 **多格式输出** - JSON、SRT、TXT 三种格式 +- ⚡ **异步执行** - 支持后台运行,不阻塞主代理 +- 🎬 **广泛兼容** - 支持常见音视频格式(MP3、MP4、WAV 等) + +## 安装前提 + +### 1. 安装 whisper.cpp + +```bash +# 克隆仓库 +git clone https://github.com/ggerganov/whisper.cpp.git ~/whisper.cpp + +# 编译 +cd ~/whisper.cpp +make + +# 下载模型(至少需要一个模型) +./models/download-ggml-model.sh tiny +./models/download-ggml-model.sh base # 可选 +``` + +### 2. 配置环境变量 + +在 `~/.clawdbot/clawdbot.json` 中添加: + +```json5 +{ + skills: { + entries: { + "kb-whisper": { + env: { + WHISPER_CPP_PATH: "~/whisper.cpp" + } + } + } + } +} +``` + +或通过命令行配置: + +```bash +clawdbot skills config kb-whisper WHISPER_CPP_PATH "~/whisper.cpp" +``` + +## 使用方法 + +### 基本用法 + +```bash +# 使用默认 tiny 模型处理 +python whisper.py --input video.mp4 + +# 使用 base 模型(推荐,平衡速度和精度) +python whisper.py --input video.mp4 --model base + +# 后台异步执行 +python whisper.py --input video.mp4 --background +``` + +### 指定输出目录 + +```bash +python whisper.py --input video.mp4 --output ./transcripts +``` + +### 处理音频文件 + +```bash +python whisper.py --input podcast.mp3 --model base +``` + +## 输出文件 + +对于输入 `video.mp4`,将生成以下文件: + +``` +output/ +├── video.json # 详细结果(含时间戳) +├── video.srt # 字幕格式 +└── video.txt # 纯文本 +``` + +### JSON 格式 + +```json +{ + "success": true, + "input_file": "video.mp4", + "model": "base", + "output_files": { + "json": "video.json", + "srt": "video.srt", + "txt": "video.txt" + }, + "duration_seconds": 120.5, + "segments": [ + { + "id": 0, + "start": 0.0, + "end": 3.2, + "text": "这是第一段字幕" + }, + { + "id": 1, + "start": 3.2, + "end": 6.8, + "text": "这是第二段字幕" + } + ] +} +``` + +## 模型对比 + +| 模型 | 速度 | 精度 | 适用场景 | +|------|------|------|----------| +| tiny | ⚡⚡⚡ | ⭐ | 快速预览、实时转录 | +| base | ⚡⚡ | ⭐⭐⭐ | 日常使用(推荐) | +| small | ⚡ | ⭐⭐⭐⭐ | 高质量需求 | +| medium | ⭐ | ⭐⭐⭐⭐⭐ | 专业用途 | +| large | 🐢 | ⭐⭐⭐⭐⭐ | 最高精度要求 | + +## 完整示例 + +### 示例 1: 转录播客 + +```bash +python whisper.py --input podcast.mp3 --model base --background +``` + +### 示例 2: 生成视频字幕 + +```bash +python whisper.py --input tutorial.mp4 --model small +``` + +### 示例 3: 批量处理(配合脚本) + +```bash +#!/bin/bash +for video in videos/*.mp4; do + python whisper.py --input "$video" --model base +done +``` + +## 在 Workflow 中使用 + +在知识库处理流程中,如果视频没有字幕: + +```bash +# 步骤4: 下载视频后,如果没有字幕 +# 步骤5: 使用 Whisper 生成字幕 +python whisper.py --input ${video_path} --model base --background + +# 等待 Whisper 完成,然后继续后续步骤 +``` + +## 技术细节 + +- **引擎**: Whisper.cpp(C++ 实现,性能优异) +- **音频采样率**: 自动转换为 16kHz +- **语言**: 自动检测(支持 99 种语言) +- **GPU 支持**: whisper.cpp 支持 CUDA 加速(需编译时启用) + +## 故障排查 + +### 问题: 找不到 whisper.cpp + +```bash +# 检查环境变量 +echo $WHISPER_CPP_PATH + +# 手动测试 +~/whisper.cpp/main --help +``` + +### 问题: 模型未下载 + +```bash +cd ~/whisper.cpp +./models/download-ggml-model.sh tiny +``` + +### 问题: 音频格式不支持 + +```bash +# 转换音频格式 +ffmpeg -i input.avi -acodec libmp3lame output.mp3 +python whisper.py --input output.mp3 +``` + +## 性能参考 + +在 CPU 环境下(Intel i7): + +- **tiny 模型**: ~1x 实时速度(1分钟音频 ~1分钟处理) +- **base 模型**: ~0.5x 实时速度(1分钟音频 ~2分钟处理) +- **small 模型**: ~0.25x 实时速度(1分钟音频 ~4分钟处理) + +## 许可证 + +本技能使用 MIT 许可证,Whisper.cpp 使用 MIT 许可证。 diff --git a/skills/kb-whisper/SKILL.md b/skills/kb-whisper/SKILL.md new file mode 100644 index 0000000..9ebb999 --- /dev/null +++ b/skills/kb-whisper/SKILL.md @@ -0,0 +1,124 @@ +--- +name: kb-whisper +description: 本地语音识别,支持音视频转文字(基于 Whisper.cpp) +--- + +# KB Whisper Skill + +**kb-whisper** - 本地语音识别,使用 Whisper.cpp 将音视频文件转换为文本、字幕和 JSON 格式输出。 + +## 什么时候使用 + +当用户需要: +- 将视频/音频文件转换为文字 +- 生成视频字幕(SRT 格式) +- 获取带时间戳的详细识别结果 + +## 环境变量 + +在使用之前,必须检查环境变量是否已经设置。 + +| 变量名 | 用途 | 示例 | +|--------|------|------| +| `WHISPER_CPP_PATH` | whisper.cpp 安装路径 | `~/whisper.cpp` | + +## 使用方法 + +```bash +# 基本用法 +python whisper.py --input video.mp4 + +# 指定模型(默认 tiny) +python whisper.py --input video.mp4 --model base + +# 指定输出目录 +python whisper.py --input video.mp4 --output ./output + +# 异步执行(推荐) +python whisper.py --input video.mp4 --background +``` + +## 命令参数 + +| 参数 | 说明 | 默认值 | +|------|------|--------| +| `--input` | 输入音视频文件路径 | 必需 | +| `--model` | Whisper 模型类型 | `tiny` | +| `--output` | 输出目录 | 文件所在目录 | +| `--background` | 后台异步执行 | False | + +## 模型选项 + +- `tiny` - 最小模型,速度快,精度较低(推荐快速识别) +- `base` - 基础模型,平衡速度和精度(推荐) +- `small` - 小型模型,精度更高,速度较慢 +- `medium` - 中型模型,高精度 +- `large` - 大型模型,最高精度,速度慢 + +## 输出文件 + +对于输入 `video.mp4`,将生成: + +- `video.json` - 详细结果(包含时间戳、分段信息) +- `video.srt` - 字幕格式文件 +- `video.txt` - 纯文本内容 + +## 输出格式示例 + +### JSON 格式 + +```json +{ + "success": true, + "input_file": "video.mp4", + "model": "tiny", + "output_files": { + "json": "video.json", + "srt": "video.srt", + "txt": "video.txt" + }, + "duration_seconds": 120.5, + "segments": [ + { + "id": 0, + "start": 0.0, + "end": 3.2, + "text": "这是第一段字幕" + } + ] +} +``` + +## Workflow 中的使用 + +```bash +# 步骤4之后:如果已有音频但无字幕,可以使用 whisper +python whisper.py --input ${video_path} --model base --background +``` + +## 安装 + +```bash +# 1. 克隆 whisper.cpp +git clone https://github.com/ggerganov/whisper.cpp.git ~/whisper.cpp + +# 2. 编译 +cd ~/whisper.cpp +make + +# 3. 下载模型(tiny) +./models/download-ggml-model.sh tiny + +# 4. 下载更多模型(可选) +# ./models/download-ggml-model.sh base +# ./models/download-ggml-model.sh small + +# 5. 复制技能到 skills 目录 +cp -r kb-whisper/ ~/skills/ +``` + +## 注意事项 + +- **异步执行**: 使用 `--background` 参数时,命令会在后台运行,不阻塞主代理 +- **模型选择**: tiny 模型适合快速识别,base 模型适合一般用途,large 模型适合高精度需求 +- **文件格式**: 支持 MP3、MP4、WAV、FLAC、OGG、M4A 等常见格式 diff --git a/skills/kb-whisper/examples.md b/skills/kb-whisper/examples.md new file mode 100644 index 0000000..02905d0 --- /dev/null +++ b/skills/kb-whisper/examples.md @@ -0,0 +1,273 @@ +# KB Whisper 使用示例 + +## 快速开始 + +### 1. 基础使用 + +```bash +# 使用默认 tiny 模型转录视频 +python whisper.py --input video.mp4 + +# 使用 base 模型(推荐) +python whisper.py --input video.mp4 --model base +``` + +### 2. 异步执行 + +```bash +# 后台处理,不阻塞主代理 +python whisper.py --input video.mp4 --model base --background +``` + +### 3. 指定输出目录 + +```bash +python whisper.py --input video.mp4 --output ./transcripts +``` + +### 4. 指定语言 + +```bash +# 指定中文 +python whisper.py --input video.mp4 --language zh + +# 指定英文 +python whisper.py --input video.mp4 --language en + +# 指定日语 +python whisper.py --input video.mp4 --language ja +``` + +## 实际应用场景 + +### 场景 1: 转录播客 + +```bash +python whisper.py --input podcast.mp3 --model base --background +``` + +**输出**: +- `podcast.json` - 带时间戳的详细结果 +- `podcast.srt` - 字幕格式 +- `podcast.txt` - 纯文本 + +### 场景 2: 生成视频字幕 + +```bash +python whisper.py --input tutorial.mp4 --model small +``` + +**用途**: +- 为教程视频生成字幕 +- 导出 SRT 文件到视频编辑软件 +- 生成多语言字幕版本 + +### 场景 3: 会议录音转文字 + +```bash +python whisper.py --input meeting.mp3 --model base --output ./meetings +``` + +**输出示例**: +``` +meetings/ +├── meeting.json # 完整 JSON(含时间戳) +├── meeting.srt # 字幕格式 +└── meeting.txt # 纯文本 +``` + +### 场景 4: 批量处理 + +创建脚本 `batch_transcribe.sh`: + +```bash +#!/bin/bash + +OUTPUT_DIR="./transcripts" +mkdir -p "$OUTPUT_DIR" + +for video in videos/*.mp4; do + echo "处理: $video" + python whisper.py --input "$video" --output "$OUTPUT_DIR" --model base +done + +echo "批量处理完成!" +``` + +```bash +chmod +x batch_transcribe.sh +./batch_transcribe.sh +``` + +## 在 Workflow 中使用 + +### 知识库处理流程 + +在 `kb-workflow` 技能中,如果视频没有字幕: + +```bash +# 步骤 4: 下载视频后 +# 检查是否有字幕文件 +if [ ! -f "${subtitle_file}" ]; then + echo "无字幕文件,使用 Whisper 生成..." + + # 使用 Whisper 生成字幕(后台执行) + python /path/to/whisper.py \ + --input "${video_path}" \ + --model base \ + --output "${content_dir}" \ + --background + + # 等待 Whisper 完成 + sleep 5 # 等待后台任务启动 + while ! [ -f "${content_dir}/$(basename ${video_path} .mp4).srt" ]; do + sleep 2 + done + + echo "Whisper 处理完成" +fi +``` + +## 输出文件使用 + +### JSON 格式 + +```python +import json + +# 读取 JSON 结果 +with open('video.json', 'r', encoding='utf-8') as f: + data = json.load(f) + +# 访问分段 +for segment in data['segments']: + print(f"[{segment['start']:.2f}-{segment['end']:.2f}] {segment['text']}") +``` + +### SRT 格式 + +```bash +# 直接在视频播放器中使用 +mpv video.mp4 --sub-file=video.srt + +# 或转换字幕格式 +ffmpeg -i video.srt video.ass +``` + +### TXT 格式 + +```bash +# 搜索关键词 +grep "重要信息" video.txt + +# 统计字数 +wc -m video.txt +``` + +## 性能优化建议 + +### 1. 根据内容选择模型 + +```bash +# 快速预览(短视频、测试) +python whisper.py --input video.mp4 --model tiny + +# 日常使用(播客、会议) +python whisper.py --input video.mp4 --model base + +# 高质量需求(正式内容、多语言) +python whisper.py --input video.mp4 --model small +``` + +### 2. 使用后台执行 + +```bash +# 处理长文件时使用后台模式 +python whisper.py --input long_video.mp4 --model base --background +``` + +### 3. 指定语言提升准确度 + +```bash +# 如果知道内容语言,指定后准确度更高 +python whisper.py --input video.mp4 --language zh +``` + +## 故障排查 + +### 问题 1: whisper.cpp 未找到 + +```bash +# 检查环境变量 +echo $WHISPER_CPP_PATH + +# 或配置 +clawdbot skills config kb-whisper WHISPER_CPP_PATH "~/whisper.cpp" +``` + +### 问题 2: 模型未下载 + +```bash +cd ~/whisper.cpp +./models/download-ggml-model.sh base +``` + +### 问题 3: 音频格式不支持 + +```bash +# 转换格式 +ffmpeg -i input.avi -acodec libmp3lame output.mp3 +python whisper.py --input output.mp3 +``` + +### 问题 4: 后台任务未完成 + +```bash +# 查看日志 +cat video_whisper.log + +# 检查进程 +ps aux | grep whisper +``` + +## 集成到其他工具 + +### 集成到 Python 脚本 + +```python +import subprocess +import json + +def transcribe_audio(audio_path, model='base'): + """调用 whisper.py 转录音频""" + cmd = [ + 'python3', '/path/to/whisper.py', + '--input', audio_path, + '--model', model + ] + + result = subprocess.run(cmd, capture_output=True, text=True) + return json.loads(result.stdout) + +# 使用 +result = transcribe_audio('podcast.mp3', 'base') +print(f"识别到 {result['total_segments']} 个片段") +``` + +### 集成到 Shell 脚本 + +```bash +#!/bin/bash + +transcribe() { + local file=$1 + local model=${2:-base} + + echo "转录: $file" + python3 whisper.py --input "$file" --model "$model" --background +} + +# 批量处理 +transcribe "video1.mp4" +transcribe "video2.mp4" "tiny" +``` diff --git a/skills/kb-whisper/whisper.py b/skills/kb-whisper/whisper.py new file mode 100755 index 0000000..18707af --- /dev/null +++ b/skills/kb-whisper/whisper.py @@ -0,0 +1,348 @@ +#!/usr/bin/env python3 +""" +KB Whisper - 本地语音识别工具 +基于 Whisper.cpp 的音视频转文字 +""" + +import argparse +import json +import os +import subprocess +import sys +from pathlib import Path +import re + + +def parse_arguments(): + """解析命令行参数""" + parser = argparse.ArgumentParser( + description='KB Whisper - 本地语音识别工具', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +示例: + python whisper.py --input video.mp4 + python whisper.py --input video.mp4 --model base + python whisper.py --input audio.mp3 --output ./output --background + """ + ) + parser.add_argument( + '--input', + required=True, + help='输入音视频文件路径' + ) + parser.add_argument( + '--model', + default='tiny', + choices=['tiny', 'base', 'small', 'medium', 'large'], + help='Whisper 模型类型 (默认: tiny)' + ) + parser.add_argument( + '--output', + help='输出目录 (默认: 输入文件所在目录)' + ) + parser.add_argument( + '--background', + action='store_true', + help='后台异步执行' + ) + parser.add_argument( + '--language', + help='指定语言 (默认: 自动检测),例如: en, zh, ja' + ) + + return parser.parse_args() + + +def get_whisper_cpp_path(): + """获取 whisper.cpp 路径""" + # 优先从环境变量获取 + path = os.environ.get('WHISPER_CPP_PATH') + if path: + path = os.path.expanduser(path) + if os.path.exists(path): + return path + + # 尝试常见位置 + common_paths = [ + os.path.expanduser('~/whisper.cpp'), + '/usr/local/bin/whisper', + '/opt/whisper.cpp', + ] + + for cp in common_paths: + if os.path.exists(cp): + return cp + + raise FileNotFoundError( + "未找到 whisper.cpp。请设置环境变量 WHISPER_CPP_PATH " + "或安装到 ~/whisper.cpp\n" + "安装方法: git clone https://github.com/ggerganov/whisper.cpp.git ~/whisper.cpp && cd ~/whisper.cpp && make" + ) + + +def check_model(whisper_path, model): + """检查模型是否存在""" + model_path = os.path.join(whisper_path, 'models', f'ggml-{model}.bin') + if not os.path.exists(model_path): + raise FileNotFoundError( + f"模型文件不存在: {model_path}\n" + f"请运行以下命令下载模型:\n" + f"cd {whisper_path} && ./models/download-ggml-model.sh {model}" + ) + return model_path + + +def run_whisper_cpp(whisper_path, input_file, model, output_dir, language=None): + """运行 whisper.cpp 命令行工具""" + + # 构建命令 + cmd = [ + os.path.join(whisper_path, 'main'), + '-m', os.path.join(whisper_path, 'models', f'ggml-{model}.bin'), + '-f', input_file, + '-of', os.path.join(output_dir, Path(input_file).stem), + '-otxt', # 输出 txt + '-osrt', # 输出 srt + '-oj', # 输出 json + ] + + # 添加语言参数(如果指定) + if language: + cmd.extend(['-l', language]) + + print(f"执行命令: {' '.join(cmd)}") + + # 运行命令 + result = subprocess.run( + cmd, + capture_output=True, + text=True, + cwd=whisper_path + ) + + if result.returncode != 0: + raise RuntimeError( + f"Whisper.cpp 执行失败:\n" + f"标准输出: {result.stdout}\n" + f"错误输出: {result.stderr}" + ) + + return result + + +def parse_whisper_json(json_file): + """解析 whisper.cpp 输出的 JSON 文件""" + try: + with open(json_file, 'r', encoding='utf-8') as f: + data = json.load(f) + return data + except json.JSONDecodeError: + # whisper.cpp 的 JSON 格式可能不同,尝试解析标准格式 + return None + + +def create_standard_json(input_file, output_dir, srt_file, txt_file, model): + """创建标准格式的 JSON 输出""" + basename = Path(input_file).stem + + # 解析 SRT 文件获取时间戳 + segments = [] + if os.path.exists(srt_file): + with open(srt_file, 'r', encoding='utf-8') as f: + content = f.read() + + # 解析 SRT 格式 + pattern = r'(\d+)\n(\d{2}:\d{2}:\d{2},\d{3}) --> (\d{2}:\d{2}:\d{2},\d{3})\n(.+?)(?=\n\n|\Z)' + matches = re.findall(pattern, content, re.DOTALL) + + for idx, (num, start, end, text) in enumerate(matches): + # 转换时间戳 + def parse_time(t): + h, m, s_ms = t.split(':') + s, ms = s_ms.split(',') + return int(h) * 3600 + int(m) * 60 + int(s) + int(ms) / 1000 + + segments.append({ + "id": idx, + "start": parse_time(start), + "end": parse_time(end), + "text": text.strip() + }) + + # 读取纯文本 + txt_content = "" + if os.path.exists(txt_file): + with open(txt_file, 'r', encoding='utf-8') as f: + txt_content = f.read().strip() + + # 获取音频时长(使用 ffprobe) + duration = 0 + try: + result = subprocess.run( + ['ffprobe', '-v', 'error', '-show_entries', 'format=duration', + '-of', 'default=noprint_wrappers=1:nokey=1', input_file], + capture_output=True, + text=True + ) + if result.returncode == 0: + duration = float(result.stdout.strip()) + except FileNotFoundError: + pass + + # 构建标准 JSON + json_data = { + "success": True, + "input_file": os.path.basename(input_file), + "input_path": input_file, + "model": model, + "output_files": { + "json": f"{basename}.json", + "srt": f"{basename}.srt", + "txt": f"{basename}.txt" + }, + "duration_seconds": duration, + "segments": segments + } + + return json_data + + +def main(): + """主函数""" + args = parse_arguments() + + # 检查输入文件 + input_file = os.path.abspath(args.input) + if not os.path.exists(input_file): + print(f"错误: 输入文件不存在: {input_file}", file=sys.stderr) + sys.exit(1) + + # 获取输出目录 + if args.output: + output_dir = os.path.abspath(args.output) + else: + output_dir = os.path.dirname(input_file) + + os.makedirs(output_dir, exist_ok=True) + + # 获取 whisper.cpp 路径 + try: + whisper_path = get_whisper_cpp_path() + print(f"Whisper.cpp 路径: {whisper_path}") + except FileNotFoundError as e: + print(f"错误: {e}", file=sys.stderr) + sys.exit(1) + + # 检查模型 + try: + check_model(whisper_path, args.model) + print(f"使用模型: {args.model}") + except FileNotFoundError as e: + print(f"错误: {e}", file=sys.stderr) + sys.exit(1) + + # 后台执行 + if args.background: + print("启动后台处理...") + + # 使用 nohup 在后台运行 + log_file = os.path.join(output_dir, f"{Path(input_file).stem}_whisper.log") + + with open(log_file, 'w') as log: + subprocess.Popen( + [sys.executable, __file__, + '--input', input_file, + '--model', args.model, + '--output', output_dir] + + (['--language', args.language] if args.language else []), + stdout=log, + stderr=log, + start_new_session=True + ) + + print(f"后台任务已启动,日志文件: {log_file}") + print(f"输出文件将生成到: {output_dir}") + + # 返回任务信息 + result = { + "success": True, + "background": True, + "status": "running", + "log_file": log_file, + "output_dir": output_dir, + "message": "后台处理中,请稍候检查输出文件" + } + + print(json.dumps(result, ensure_ascii=False, indent=2)) + return + + # 前台执行 + print(f"处理文件: {input_file}") + print(f"输出目录: {output_dir}") + + try: + # 运行 whisper.cpp + result = run_whisper_cpp( + whisper_path, + input_file, + args.model, + output_dir, + args.language + ) + + # 输出文件路径 + basename = Path(input_file).stem + json_file = os.path.join(output_dir, f"{basename}.json") + srt_file = os.path.join(output_dir, f"{basename}.srt") + txt_file = os.path.join(output_dir, f"{basename}.txt") + + # 检查输出文件 + output_files = {} + if os.path.exists(srt_file): + output_files['srt'] = srt_file + if os.path.exists(txt_file): + output_files['txt'] = txt_file + + # 创建标准 JSON 格式 + standard_json = create_standard_json( + input_file, + output_dir, + srt_file, + txt_file, + args.model + ) + + # 写入标准 JSON + with open(json_file, 'w', encoding='utf-8') as f: + json.dump(standard_json, f, ensure_ascii=False, indent=2) + + output_files['json'] = json_file + + # 输出结果 + result = { + "success": True, + "input_file": input_file, + "model": args.model, + "output_files": { + k: os.path.basename(v) for k, v in output_files.items() + }, + "output_dir": output_dir, + "total_segments": len(standard_json.get('segments', [])), + "duration": standard_json.get('duration_seconds', 0) + } + + print("\n✓ 处理完成!") + print(f"\n输出文件:") + for fmt, fname in output_files.items(): + print(f" - {fname.upper()}: {fname}") + + print(f"\n完整结果:") + print(json.dumps(result, ensure_ascii=False, indent=2)) + + except Exception as e: + print(f"\n✗ 错误: {e}", file=sys.stderr) + sys.exit(1) + + +if __name__ == '__main__': + main()