用自然语言驱动 AI,一句话完成音视频处理 — 微信小程序
FastAPI · FFmpeg · arq + Redis · 平台内置 LLM · 多步管线编排 · 执行前预检澄清
言影智剪是一个基于 AI(Agnes 2.5 Flash / DeepSeek)+ FFmpeg 的微信小程序。用户上传音视频文件后用自然语言描述处理需求(如"转为 MP3"、"裁剪前 30 秒"、"加个水印"、"压缩到 10MB"、"倒放"、"两个视频拼接后 2 倍速"),AI 自动理解意图、拆解为多步处理管线,后端拼装 FFmpeg 命令依次执行,完成后即可下载结果。
核心链路:上传文件 → 描述任务 → 执行前预检(参数缺失时自动追问澄清)→ AI 拆解多步 plan(8 个通用 tool → 23 个底层操作)→ 用户确认步骤 → arq 异步队列串行执行 FFmpeg → 下载结果
AI 模型由平台内置提供(Agnes 2.5 Flash 免费、DeepSeek 按积分计费),用户无需自备 API Key;每日签到可领取积分。积分不足时自动降级免费模型并提示,签到回血后自动恢复为用户所选模型。
- 自然语言即操作 — 一句话描述需求,AI 拆解为单步或多步 FFmpeg 管线,无需学习任何命令
- 执行前预检 + 澄清(所见即所得) — 提交前展示中文步骤预览,参数缺失时追问(最多 5 轮、同一参数最多追问 3 次),确认后的步骤即执行依据;无法澄清时明确提示改写描述,不按默认参数静默执行
- 平台内置模型,零 Key 门槛 — Agnes 2.5 Flash 免费、DeepSeek 按积分计费,余额不足自动降级并在"我的"页如实显示当前生效模型
- 参数契约单一数据源 — 23 个操作的参数(类型 / 枚举 / 默认值 / 中文别名 / 输入数量与类型)全部声明在
operations.yaml,规划期归一化校验、启动期 fail-fast,非法值显式失败 - 多步管线编排 — 支持"先多文件合成、再对结果做后处理",执行器独立于任务入口;replan 失败限 1 次,全局超时预算(默认 1800s)防止长任务失控
- 文件生命周期自动化 — 原始文件处理完即删、中间产物清理,结果文件 30 分钟后自动清理(
cleanup.sh兜底 60 分钟),成功结果可"继续处理"免重传
底层共 23 个操作(定义于 backend/app/config/operations.yaml),对 AI 暴露为 8 个通用 tool(映射关系见 backend/app/services/tool_mapping.py)。
| 分类 | 能力 |
|---|---|
| 格式与编码 | 格式转换(MP4 / MKV / MOV / AVI / MP3 / WAV / AAC / FLAC / OGG / M4A / WMA)、提取音频、去除原生音轨 |
| 剪辑与时长 | 裁剪(前 N 秒 / 中间片段 / 保留末尾)、变速(0.25~4.0 倍速)、倒放(视频画面与声音同倒,长视频自动分段不受时长限制) |
| 画面 | 分辨率调整(480p / 720p / 1080p / 4K)、画面裁剪(居中裁至指定宽高比,如 1:1 / 16:9 / 4:3)、旋转与镜像翻转、压缩(按质量或目标体积)、画质增强、画面降噪 |
| 音频 | 音量调节(0~5.0 倍)、变调(音高变换,不改变时长)、音频降噪、混音、音频拼接、替换音轨、添加音轨 / 配音 |
| 水印与字幕 | 文字水印(自定义内容 / 位置 / 字号,支持中文)、图片水印(PNG / JPG / WebP,可调缩放)、字幕烧录(SRT / ASS) |
| 多文件 | 视频合并、音频拼接与混音、多文件组合操作(一次最多 9 个文件) |
支持的输入格式:视频 mp4/avi/mov/mkv/flv/wmv/webm、音频 mp3/wav/aac/flac/ogg/wma/m4a、图片 png/jpg/jpeg/webp、字幕 srt/ass。
1. 克隆仓库并生成配置文件
git clone <your-repo-url> && cd media-workshop
cp backend/.env.example backend/.env
cp miniprogram/utils/constants.example.js miniprogram/utils/constants.js
cp miniprogram/project.config.example.json miniprogram/project.config.json
backend/.env、miniprogram/utils/constants.js、miniprogram/project.config.json均被.gitignore忽略。共享常量(版本更新记录、首页标签、轮询与澄清上限等)必须先改constants.example.js,否则改动不会进仓库。
2. 填写配置
编辑 backend/.env,至少填好微信凭证与平台模型 Key:
WECHAT_APPID=wx你的AppID
WECHAT_SECRET=你的AppSecret
JWT_SECRET=生成一个随机字符串(至少32位)
# 平台内置 AI 模型(providers.yaml 经 ${VAR} 引用;enabled 的模型缺 Key 会拒绝启动)
AGNES_API_KEY= # 免费模型,不消耗积分
AGNES_BASE_URL=https://api.agnes-ai.cn/v1
DEEPSEEK_API_KEY= # 付费模型,按积分计费
DEEPSEEK_BASE_URL=https://api.deepseek.com/v1再编辑 miniprogram/project.config.json 填写小程序 AppID;miniprogram/utils/constants.js 的 BASE_URL 指向后端地址。
3. 启动后端(推荐 Docker Compose)
docker compose up -d4. 在微信开发者工具中导入 miniprogram/,填写 AppID,开发阶段勾选"不校验合法域名"。
首页提供示例标签(来源 miniprogram/utils/constants.example.js):转成MP3、合并视频、视频增强、音频降噪、裁剪前30秒、压缩视频、换背景音乐、加配音、去掉原声、烧录字幕 等。
典型描述如:把这两个视频拼起来再 2 倍速、去掉背景音乐换成我上传的音频、压缩到 10MB 以内。
# 1. 微信登录换取 JWT(code 来自 wx.login)
curl -X POST http://localhost:8000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"code":"<wx.login 返回的 code>"}'
# 2. 上传文件,拿到 file_id
curl -X POST http://localhost:8000/api/upload \
-H "Authorization: Bearer <token>" \
-F "file=@demo.mp4"
# 3. 执行前预检:type=plan 返回可确认步骤,type=clarify 返回待补充问题
curl -X POST http://localhost:8000/api/tasks/preview \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"description":"转成MP3并压缩到10MB以内","file_ids":["<file_id>"]}'
# 4. 确认步骤快照后提交任务:STEPS_JSON 为上一步 preview 返回的 steps 原样回传,即以所见步骤执行
curl -X POST http://localhost:8000/api/tasks \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d "{\"description\":\"转成MP3并压缩到10MB以内\",\"file_ids\":[\"<file_id>\"],\"preview_plan\":${STEPS_JSON}}"
# 5. 轮询进度(current_step / total_steps),完成后下载结果
curl http://localhost:8000/api/tasks/<task_id> -H "Authorization: Bearer <token>"
curl -o result.mp3 http://localhost:8000/api/download/<task_id> -H "Authorization: Bearer <token>"flowchart TD
MP["微信小程序(原生框架)<br/>首页 / 历史 / 我的 / 帮助 / 协议"]
NG["Nginx 反向代理<br/>仅放行 /api/ 与 /static/"]
API["FastAPI 后端<br/>auth / upload / task / download / user / agreement / credit"]
DB[("SQLite<br/>SQLAlchemy ORM")]
RQ[("Redis<br/>arq 队列")]
WK["arq Worker<br/>process_media_task"]
PIPE["planner + executor<br/>预检澄清 · 多步 plan 编排"]
LLM["平台内置模型<br/>Agnes 2.5 Flash(免费)<br/>DeepSeek(积分计费)"]
OPS["operations.yaml<br/>参数契约 + FFmpeg 模板"]
FF["FFmpeg<br/>音视频处理引擎"]
OUT["结果文件<br/>30 分钟后自动清理"]
MP -->|"HTTPS + JWT"| NG
NG --> API
API --> DB
API -->|"提交任务入队"| RQ
RQ --> WK
WK --> PIPE
PIPE -->|"OpenAI 兼容 Function Calling"| LLM
PIPE --> OPS
PIPE --> FF
FF --> OUT
API -->|"预检 preview"| LLM
OUT -->|"下载 / 继续处理"| NG
classDef fe fill:#07C160,stroke:#057A3B,color:#ffffff
classDef gw fill:#269539,stroke:#1B6B28,color:#ffffff
classDef api fill:#009688,stroke:#00695C,color:#ffffff
classDef store fill:#003B57,stroke:#00212F,color:#ffffff
classDef queue fill:#DC382D,stroke:#9C231A,color:#ffffff
classDef worker fill:#FB8C00,stroke:#B35F00,color:#ffffff
classDef llm fill:#6C5CE7,stroke:#4834C4,color:#ffffff
classDef media fill:#1565C0,stroke:#0D3F7A,color:#ffffff
classDef result fill:#546E7A,stroke:#32424A,color:#ffffff
class MP fe
class NG gw
class API api
class DB store
class RQ queue
class WK,PIPE worker
class LLM llm
class OPS,FF media
class OUT result
处理链路:上传落盘 → /api/tasks/preview 预检(LLM 判断 plan / clarify / terminated)→ 用户确认步骤 → /api/tasks 落库入队 → arq worker 取出确认快照(校验失败则回退 AI 拆解)→ executor 逐步拼装并执行 FFmpeg → 终局清理输入与中间产物 → 结果延迟清理入队。
| 变量 | 默认值 | 说明 |
|---|---|---|
WECHAT_APPID / WECHAT_SECRET |
— | 小程序凭证,用于 code2session 登录 |
JWT_SECRET |
dev-secret-change-me |
JWT 签名密钥(HS256),生产必须替换 |
JWT_EXPIRE_HOURS |
720 |
Token 有效期(小时) |
AGNES_API_KEY / AGNES_BASE_URL |
— / https://api.agnes-ai.cn/v1 |
免费模型 Agnes 2.5 Flash |
DEEPSEEK_API_KEY / DEEPSEEK_BASE_URL |
— / https://api.deepseek.com/v1 |
付费模型 deepseek-chat |
UPLOAD_DIR / RESULT_DIR |
/data/uploads / /data/results |
上传与结果目录 |
MAX_VIDEO_SIZE_MB |
200 |
上传上限(音频 50 / 图片 10 / 字幕 2) |
FFMPEG_TIMEOUT_SECONDS |
300 |
单条 ffmpeg 命令超时(秒) |
FFMPEG_CONCURRENCY |
1 |
ffmpeg 并发数 |
TASK_TOTAL_TIMEOUT_SECONDS |
1800 |
多步 plan 整体超时预算(秒),超时整单失败 |
TASK_POLL_MAX_SECONDS |
300 |
前端最长轮询等待(秒) |
REVERSE_SEGMENT_SECONDS |
45 |
倒放自动分段的单段时长阈值(秒) |
REDIS_URL / DATABASE_URL |
redis://localhost:6379 / sqlite:///./media_workshop.db |
队列与数据库连接 |
ENABLE_DOCS |
true |
是否开放 /docs、/redoc(生产建议 false) |
LOG_LEVEL |
INFO |
app.* 日志级别(root 固定 INFO 抑制第三方噪音) |
CHECKIN_DAILY_CREDITS |
10 |
每日签到发放积分 |
CREDIT_TOKEN_BASE |
1000 |
每 1000 token 折算 1 积分(向下取整) |
CREDIT_DOWNGRADE_THRESHOLD |
0 |
余额 ≤ 阈值时付费模型降级为免费模型 |
DEFAULT_PROVIDER_ID |
agnes |
新用户默认模型(须与 providers.yaml 中 is_default 一致) |
MAX_CLARIFY_ROUNDS |
5 |
预检澄清最大轮数,超限终止提交 |
MAX_SAME_PARAM_ASKS |
3 |
同一必填参数重复追问上限,达到即判无效澄清 |
| 文件 | 作用 |
|---|---|
backend/app/config/providers.yaml |
平台内置模型清单:model_name、credit_multiplier、is_free、is_default、enabled;api_key / base_url 用 ${VAR} 引用环境变量,启用项缺 Key 时启动即拒绝 |
backend/app/config/operations.yaml |
全部 FFmpeg "数据":格式→编码器组合、压缩 CRF 映射、水印与增强参数、滤镜模板,以及每个操作的输入约束、输出扩展名规则与参数契约 |
miniprogram/utils/constants.example.js |
前端常量:BASE_URL、文件大小与轮询限制、澄清轮次上限、首页示例标签、版本更新记录 |
除 /api/health、登录与协议接口外,均需 Authorization: Bearer <token>。
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/health |
健康检查(Docker healthcheck 使用) |
| POST | /api/auth/login |
微信登录,返回 JWT 与协议同意状态 |
| POST | /api/upload |
上传文件(视频/音频/图片/字幕),返回 file_id 与 kind |
| DELETE | /api/upload/{file_id} |
删除已上传但未被任务引用的文件(多文件上传失败时清理孤儿文件) |
| POST | /api/tasks/preview |
执行前预检:返回 plan(可执行步骤)/ clarify(澄清问题)/ terminated(无法澄清);携带 clarify_round、last_answers 供轮次裁决 |
| POST | /api/tasks |
提交处理任务(支持 file_ids 数组与 preview_plan 确认快照),返回实际生效模型与是否降级 |
| GET | /api/tasks |
历史任务列表(分页) |
| GET | /api/tasks/{task_id} |
查询任务状态(含 current_step / total_steps 步骤进度) |
| POST | /api/tasks/{task_id}/reuse/prepare |
继续处理前置:把旧任务结果预置为可引用的上传文件并返回 file_id |
| POST | /api/tasks/{task_id}/reuse |
继续处理:以 base_file_id 为输入创建新任务,支持追加文件与 preview_plan 快照 |
| DELETE | /api/tasks/{task_id} |
删除任务 |
| GET | /api/download/{task_id} |
下载结果文件 |
| GET | /api/providers |
可用 AI 模型列表(含用户所选 selected 与实际生效 effective) |
| POST | /api/user/provider |
切换用户所选模型 |
| POST | /api/checkin |
每日签到领取积分 |
| GET | /api/credits |
查询积分余额与签到状态(含降级标记与当前生效模型) |
| GET | /api/credits/transactions |
积分流水明细 |
| GET | /api/user/profile |
获取用户资料 |
| PUT | /api/user/profile |
更新用户资料(昵称) |
| POST | /api/user/avatar |
上传头像 |
| GET | /api/agreements/user |
获取用户协议 |
| GET | /api/agreements/privacy |
获取隐私协议 |
| POST | /api/agreements/agree |
提交协议同意记录 |
ENABLE_DOCS=true时可访问/docs(Swagger UI,静态资源走 bootcdn 以便国内直连)与/redoc。
media-workshop/
├── miniprogram/ # 微信小程序前端(原生框架)
│ ├── pages/ # 页面:index 首页 / history 历史 / mine 我的 / help 帮助 / agreement 协议
│ ├── utils/ # constants.example.js(全局常量模板)、download.js、format.js
│ ├── images/ # 图标与 TabBar 资源
│ ├── app.js / app.json / app.wxss # 应用入口、页面与 TabBar 配置、全局样式
│ └── project.config.example.json # 开发者工具项目配置模板
├── backend/ # Python 后端
│ ├── app/
│ │ ├── config/ # operations.yaml(FFmpeg 参数契约)、providers.yaml(内置模型)
│ │ ├── models/ # 数据模型(用户 / 任务 / 任务文件 / 协议)
│ │ ├── schemas/ # 请求/响应 Pydantic Schema
│ │ ├── routers/ # API 路由:auth / upload / task / download / user / agreement / credit
│ │ ├── services/ # 业务逻辑:planner 拆解、executor 执行、ffmpeg、LLM、积分、provider 解析等
│ │ ├── tasks/ # arq Worker(process_media_task / cleanup_result_file)
│ │ ├── middleware/ # JWT 鉴权与协议校验依赖
│ │ ├── config.py # 环境变量集中定义
│ │ ├── database.py / main.py # 会话初始化、FastAPI 应用装配
│ │ └── seed_data.py # 协议版本种子数据
│ ├── tests/ # 17 个 pytest 用例文件(预检、执行器、FFmpeg、积分、provider 等)
│ ├── deploy/ # cleanup.sh 兜底清理、generate_icons.py 图标生成
│ ├── Dockerfile # python:3.13-slim + ffmpeg + 中文字体
│ └── requirements.txt # 依赖锁定版本
├── deploy/
│ └── nginx-docker.conf # Nginx 反向代理(仅放行 /api/ 与 /static/,其余 403)
├── docs/ # 需求 / 开发 / 部署 / 规范文档(见下)
├── docker-compose.yml # 一键部署:nginx + fastapi + worker + redis
└── LICENSE
docs/ 目录包含:需求文档与开发文档(v1.0 ~ v1.3.3 全版本)、服务启动与部署文档.md(Windows 本地 / CentOS 生产 / Docker 三套环境)、代码注释规范.md、协议与应用版本更新指南.md、未来能力设想.md。
| 层级 | 技术 |
|---|---|
| 前端 | 微信小程序原生框架(基础库 ≥ 2.25.0) |
| 后端框架 | FastAPI 0.115 + Uvicorn |
| 异步队列 | arq 0.26 + Redis(redis-py 5.2) |
| 数据库 | SQLite(SQLAlchemy 2.0 ORM) |
| AI 服务 | 平台内置模型(Agnes 2.5 Flash 免费 / DeepSeek 付费),OpenAI 兼容 Function Calling |
| 音视频处理 | FFmpeg(容器内安装 ffmpeg + fonts-noto-cjk / fonts-dejavu-core 供中文水印) |
| 图片处理 | Pillow(文字水印渲染) |
| 认证 | JWT(HS256,PyJWT) |
| 部署 | Docker Compose(Nginx + FastAPI + arq Worker + Redis) |
| 测试 | pytest 8 + pytest-asyncio |
cp backend/.env.example backend/.env # 填好配置
docker compose up -d| 服务 | 容器名 | 端口 | 说明 |
|---|---|---|---|
fastapi |
media-fastapi |
8000 | 后端 API(健康检查打 /api/health) |
nginx |
media-nginx |
80 / 443 | 反向代理,配置挂载自 deploy/nginx-docker.conf |
redis |
media-redis |
6379 | arq 消息队列(healthcheck 用 redis-cli ping) |
worker |
media-worker |
— | arq 异步任务,ENABLE_DOCS=false |
- 数据卷:
uploads_data/results_data/sqlite_data,数据库落在/app/db,重启不丢数据。 - SSL:证书放入
deploy/ssl/(挂载到/etc/nginx/ssl),nginx-docker.conf中替换your-domain.com与证书文件名。 - 上传体积:Nginx
client_max_body_size 210m,并关闭proxy_request_buffering以直传大文件。 - 真实 IP:
FORWARDED_ALLOW_IPS=172.16.0.0/12信任 Docker 内网代理,访问日志记录真实客户端 IP(自动过滤健康检查与 404 探测噪音)。
cd backend
pip install -r requirements.txt
redis-server # 启动 Redis
uvicorn app.main:app --reload # 启动 FastAPI
arq app.tasks.process_task.WorkerSettings # 另开终端启动 WorkerWindows 本地开发还需自行安装 FFmpeg 并加入 PATH;中文字体路径可通过
WATERMARK_FONT_PATH/WATERMARK_FONT_PATH_CJK覆盖(详见backend/.env.example与docs/服务启动与部署文档.md)。
cd backend
pytest tests/ -vbackend/deploy/cleanup.sh 兜底删除超过 60 分钟的上传与结果文件(正常流程由 arq 延迟任务负责:输入立即删除、结果 30 分钟后删除)。
- Fork 本仓库并创建特性分支:
git checkout -b feat/your-feature - 提交前请确保本地测试通过:
cd backend && pytest tests/ -v - 新增或修改 FFmpeg 操作时,请同步更新
backend/app/config/operations.yaml(参数契约单一数据源)并补充backend/tests/用例 - 涉及前端共享常量的改动,请修改
miniprogram/utils/constants.example.js而非被忽略的constants.js - 提交信息建议使用
feat:/fix:/docs:/refactor:/test:前缀 - 发起 Pull Request 并说明变更动机与验证方式
MIT © 2026 言影智剪