一个面向个人使用的体育比赛视频自动剪辑工具。系统可以读取本地视频或上传视频,自动识别比赛中的精彩片段,生成中文解说、TTS 配音、字幕,并合成为最终集锦视频。
V1 版本不内置 YouTube / Bilibili 自动下载能力。推荐先使用
yt-dlp手动下载视频,再通过本系统处理本地文件。
- 本地视频上传
- 直接使用本机视频路径创建任务
- MySQL 任务与片段数据存储
- Redis + Celery 异步任务处理
- FFprobe 视频信息解析
- FFmpeg 音频提取、片段裁剪、音轨混合、视频合成
- faster-whisper 语音识别
- 中英文关键词精彩片段识别
- Qwen / DeepSeek / OpenAI-compatible API 解说文案生成
- Edge-TTS 中文配音
- SRT 字幕生成
- React 前端工作台
- 任务进度查询、失败重试、结果下载
| 模块 | 技术 |
|---|---|
| 后端 API | FastAPI |
| 异步任务 | Celery |
| 队列 | Redis |
| 数据库 | MySQL |
| 视频处理 | FFmpeg / FFprobe |
| 语音识别 | faster-whisper |
| 文案生成 | OpenAI SDK compatible API |
| TTS | Edge-TTS |
| 前端 | React + Vite + TypeScript |
| 部署 | Docker Compose / 本地运行 |
highlight/
├── backend/
│ ├── app/
│ │ ├── api/ # HTTP API
│ │ ├── models/ # SQLAlchemy 模型
│ │ ├── schemas/ # 响应结构
│ │ ├── services/ # 视频、音频、ASR、LLM、TTS、合成服务
│ │ ├── utils/ # FFmpeg、文件、时间工具
│ │ └── workers/ # Celery 任务
│ ├── storage/ # 本地处理文件,默认不提交 Git
│ ├── Dockerfile
│ ├── requirements.txt
│ └── .env.example
├── frontend/
│ ├── src/
│ ├── package.json
│ └── vite.config.ts
├── docker-compose.yml
├── ai_sports_highlight_v1_design.md
├── AI足球精彩集锦V1实现补齐记录.md
└── README.md
- Python 3.12+
- Node.js 20+
- MySQL 8.x
- Redis 7.x
- FFmpeg / FFprobe
确认 FFmpeg 可用:
ffmpeg -version
ffprobe -versionWindows 推荐将 FFmpeg 的 bin 目录加入 PATH,例如:
D:\Tools\ffmpeg\bin
复制环境变量模板:
cd backend
copy .env.example .env默认配置示例:
REDIS_URL=redis://localhost:6379/0
DATABASE_URL=mysql+pymysql://root:123456@127.0.0.1:3306/highlight?charset=utf8mb4
LLM_PROVIDER=local
OPENAI_API_KEY=
OPENAI_BASE_URL=
OPENAI_MODEL=gpt-4o-mini
WHISPER_MODEL=small
WHISPER_DEVICE=cpu
WHISPER_COMPUTE_TYPE=int8
WHISPER_BEAM_SIZE=1
TTS_PROVIDER=aliyun
TTS_FALLBACK_PROVIDER=edge
ALIYUN_TTS_APPKEY=
ALIYUN_TTS_TOKEN=
ALIYUN_TTS_VOICE=xiaoyun
ALIYUN_TTS_FORMAT=mp3
ALIYUN_TTS_SAMPLE_RATE=16000
ALIYUN_TTS_VOLUME=50
ALIYUN_TTS_SPEECH_RATE=0
ALIYUN_TTS_PITCH_RATE=0
TTS_VOICE=zh-CN-YunxiNeural
TTS_RATE=+15%
TTS_VOLUME=+0%
DEFAULT_PRE_SECONDS=20
MERGE_INTERVAL_SECONDS=15使用 Qwen API 示例:
LLM_PROVIDER=qwen
OPENAI_API_KEY=your_dashscope_api_key
OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
OPENAI_MODEL=qwen-plus使用 DeepSeek API 示例:
LLM_PROVIDER=deepseek
OPENAI_API_KEY=your_deepseek_api_key
OPENAI_BASE_URL=https://api.deepseek.com
OPENAI_MODEL=deepseek-chat不要将
.env、API Key、cookies 文件提交到 GitHub。
默认推荐使用阿里云智能语音交互 TTS 作为主力配音:
TTS_PROVIDER=aliyun
TTS_FALLBACK_PROVIDER=edge
ALIYUN_TTS_APPKEY=your_aliyun_nls_appkey
ALIYUN_TTS_TOKEN=your_aliyun_nls_token
ALIYUN_TTS_VOICE=xiaoyunTTS_FALLBACK_PROVIDER=edge 表示阿里云失败时再尝试 Edge-TTS。Edge-TTS 使用的是非官方微软接口,可能出现 403 或 NoAudioReceived,不建议作为主力。
如果阿里云和 Edge-TTS 都失败,系统会记录错误并临时跳过配音,继续合成带原声和字幕的视频,避免整个任务中断。
如果不希望使用备用,可以设置:
TTS_FALLBACK_PROVIDER=确保本机服务可访问:
MySQL: 127.0.0.1:3306
Redis: 127.0.0.1:6379
应用启动时会自动创建 highlight 数据库和所需表。
cd backend
python -m venv .venv
.\.venv\Scripts\activate
pip install -r requirements.txt
python -m uvicorn app.main:app --reload --host 127.0.0.1 --port 8000另开一个终端:
cd backend
.\.venv\Scripts\activate
celery -A app.workers.celery_app.celery_app worker --loglevel=info --pool=solo如果 Redis 不可用,后端会降级使用 FastAPI BackgroundTasks 处理任务,适合本地调试;正式处理长视频仍建议启动 Redis + Celery Worker。
cd frontend
npm install
npm run dev访问地址:
- 前端:http://localhost:5173
- 后端健康检查:http://localhost:8000/health
- API 文档:http://localhost:8000/docs
docker compose up --build当前 docker-compose.yml 默认使用宿主机 MySQL:
mysql+pymysql://root:123456@host.docker.internal:3306/highlight?charset=utf8mb4
Redis 会由 Docker Compose 启动。
- 打开前端页面
- 选择
mp4 / mov / mkv / webm文件 - 点击上传
- 点击启动处理
- 等待任务完成
- 下载最终视频
如果视频已经在本机磁盘上,可以不上传文件,直接创建任务:
{
"videoPath": "D:\\Projects\\own\\video\\downloads\\match.mp4"
}前端提供“使用本地路径”输入框。后端会校验文件是否存在,并直接读取该路径处理。
POST /api/videos/upload
Content-Type: multipart/form-dataPOST /api/videos/from-path
Content-Type: application/json{
"videoPath": "D:\\Projects\\own\\video\\downloads\\match.mp4"
}POST /api/videos/{taskId}/processPOST /api/videos/{taskId}/retryGET /api/videos/{taskId}GET /api/videos/{taskId}/segmentsGET /api/videos/{taskId}/download旧版兼容接口仍保留:
POST /api/tasks/{taskId}/start
GET /api/tasks/{taskId}
GET /api/tasks/{taskId}/segments
GET /api/tasks/{taskId}/download默认输出目录:
backend/storage/
├── uploads/{taskId}/original.ext
├── audio/{taskId}/audio.wav
├── subtitles/{taskId}/transcript.json
├── subtitles/{taskId}/subtitle_001.srt
├── clips/{taskId}/clip_001.mp4
├── clips/{taskId}/composed_001.mp4
├── voices/{taskId}/voice_001.mp3
└── outputs/{taskId}/final.mp4
V1 使用字幕关键词和音频峰值识别精彩片段。
支持事件类型:
goal
penalty
save
free_kick
red_card
yellow_card
winner
counter_attack
audio_peak
fallback
goal_candidate
默认裁剪规则:
片段开始 = 事件时间 - 20 秒
片段结束 = 事件时间 + 25 秒
相邻片段间隔 <= 15 秒时合并
V1 不内置自动下载。可以使用 yt-dlp 先下载视频,再上传或使用本地路径处理。
YouTube 示例:
yt-dlp `
--js-runtimes node `
--remote-components ejs:github `
--extractor-args "youtube:player_client=tv,web" `
--cookies "D:\Projects\own\video\www.youtube.com_cookies.txt" `
-f "bestvideo+bestaudio/best" `
-o "D:\Projects\own\video\downloads\%(title)s.%(ext)s" `
"https://www.youtube.com/watch?v=AnVddbzrpc0"Bilibili 示例:
yt-dlp `
--cookies "D:\Projects\own\video\www.bilibili.com_cookies.txt" `
--add-header "Referer:https://www.bilibili.com/" `
--add-header "Origin:https://www.bilibili.com" `
-f "bestvideo+bestaudio/best" `
-o "D:\Projects\own\video\downloads\%(title)s.%(ext)s" `
"https://www.bilibili.com/video/BV1RV9mB4EzZ/"cookies 文件可能包含账号敏感信息,不要提交到仓库。
处理耗时主要取决于 Whisper 语音识别。
粗略估计:
| 视频长度 | CPU + small 模型 | GPU + small 模型 |
|---|---|---|
| 20 分钟 | 15-45 分钟 | 5-15 分钟 |
| 2 小时 49 分钟 | 2-6 小时 | 20-90 分钟 |
首次运行可能需要下载 Whisper 模型。
长视频在 TRANSCRIBING 阶段耗时最长。新版代码会在 Whisper 逐段转写时把进度从 30% 增量更新到 44%;如果某个任务是在旧代码下启动的,转写完成前可能仍会长时间停在 30%,但 worker 进程 CPU 持续增长通常表示仍在处理。
提交前确认不要包含:
.env- API Key
- cookies 文件
backend/storage/frontend/node_modules/frontend/dist/__pycache__/- 日志文件
已验证:
python -m compileall app
npm run build
MySQL 表创建和字段补齐
FFmpeg / FFprobe 可用
更多实现细节见: