feat: async task pipeline for media and llm workflows
这个提交包含在:
52
docs/API.md
52
docs/API.md
@@ -75,7 +75,7 @@
|
||||
| 类型 | Mutation |
|
||||
| 认证 | **需认证** |
|
||||
| 输入 | `{ skillLevel: enum, durationDays: number, focusAreas?: string[] }` |
|
||||
| 输出 | `{ planId: number, plan: TrainingPlanData }` |
|
||||
| 输出 | `{ taskId: string, task: BackgroundTask }` |
|
||||
|
||||
**输入验证:**
|
||||
- `skillLevel`:`"beginner"` / `"intermediate"` / `"advanced"`
|
||||
@@ -105,7 +105,7 @@
|
||||
| 类型 | Mutation |
|
||||
| 认证 | **需认证** |
|
||||
| 输入 | `{ planId: number }` |
|
||||
| 输出 | `{ success: true, adjustmentNotes: string }` |
|
||||
| 输出 | `{ taskId: string, task: BackgroundTask }` |
|
||||
|
||||
---
|
||||
|
||||
@@ -187,8 +187,10 @@
|
||||
|------|-----|
|
||||
| 类型 | Mutation |
|
||||
| 认证 | **需认证** |
|
||||
| 输入 | `{ poseMetrics: object, exerciseType: string, detectedIssues: array }` |
|
||||
| 输出 | `{ corrections: string }` |
|
||||
| 输入 | `{ poseMetrics: object, exerciseType: string, detectedIssues: array, imageUrls?: string[], imageDataUrls?: string[] }` |
|
||||
| 输出 | `{ taskId: string, task: BackgroundTask }` |
|
||||
|
||||
该接口始终走后台任务。若提供 `imageUrls` 或 `imageDataUrls`,服务端会优先走多模态纠正链路,并把相对地址规范化为可公网访问的绝对 URL。
|
||||
|
||||
#### `analysis.list` - 获取用户所有分析记录
|
||||
|
||||
@@ -211,6 +213,48 @@
|
||||
|
||||
### 6. 训练记录模块 (`record`)
|
||||
|
||||
### 5.1 后台任务模块 (`task`)
|
||||
|
||||
#### `task.list` - 获取当前用户后台任务
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 类型 | Query |
|
||||
| 认证 | **需认证** |
|
||||
| 输入 | `{ limit?: number }` |
|
||||
| 输出 | `BackgroundTask[]` |
|
||||
|
||||
#### `task.get` - 获取单个后台任务
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 类型 | Query |
|
||||
| 认证 | **需认证** |
|
||||
| 输入 | `{ taskId: string }` |
|
||||
| 输出 | `BackgroundTask | null` |
|
||||
|
||||
#### `task.retry` - 重试失败任务
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 类型 | Mutation |
|
||||
| 认证 | **需认证** |
|
||||
| 输入 | `{ taskId: string }` |
|
||||
| 输出 | `{ task: BackgroundTask }` |
|
||||
|
||||
#### `task.createMediaFinalize` - 提交录制归档后台任务
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 类型 | Mutation |
|
||||
| 认证 | **需认证** |
|
||||
| 输入 | `{ sessionId: string, title: string, exerciseType?: string }` |
|
||||
| 输出 | `{ taskId: string, task: BackgroundTask }` |
|
||||
|
||||
该接口会校验媒体会话所属用户,并由后台 worker 轮询 Go 媒体服务状态,归档完成后自动登记到视频库。
|
||||
|
||||
### 6. 训练记录模块 (`record`)
|
||||
|
||||
#### `record.create` - 创建训练记录
|
||||
|
||||
| 属性 | 值 |
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
### 用户与训练
|
||||
|
||||
- 用户名登录:无需注册,输入用户名即可进入训练工作台
|
||||
- 训练计划:按技能等级和训练周期生成训练计划
|
||||
- 训练计划:按技能等级和训练周期生成训练计划,改为后台异步生成
|
||||
- 训练进度:展示训练次数、时长、评分趋势、最近分析结果
|
||||
- 每日打卡与提醒:支持训练打卡、提醒、通知记录
|
||||
|
||||
@@ -18,18 +18,22 @@
|
||||
|
||||
- 视频上传分析:上传 `webm/mp4` 视频进入视频库并触发分析流程
|
||||
- 实时摄像头分析:浏览器端调用 MediaPipe,进行姿势识别和反馈展示
|
||||
- 动作纠正:支持文本纠正和多模态纠正两条链路,统一通过后台任务执行
|
||||
- 多模态图片输入:上传关键帧后会转换为公网可访问的绝对 URL,再提交给视觉模型
|
||||
- 视频库:集中展示录制结果、上传结果和分析摘要
|
||||
|
||||
### 在线录制与媒体链路
|
||||
|
||||
- Go 媒体服务:独立处理录制会话、分段上传、marker、归档和回放资源
|
||||
- Node app worker:统一处理训练计划、动作纠正和录制归档结果登记
|
||||
- WebRTC 推流:录制时并行建立低延迟实时推流链路
|
||||
- MediaRecorder 分段:浏览器本地压缩录制并每 60 秒自动分段上传
|
||||
- 自动标记:客户端通过轻量运动检测创建关键片段 marker
|
||||
- 手动标记:录制中支持手动插入剪辑点
|
||||
- 自动重连:摄像头 track 断开时自动尝试恢复
|
||||
- 归档回放:worker 合并片段并生成 WebM,FFmpeg 可用时额外生成 MP4
|
||||
- 视频库登记:归档完成后自动写回现有视频库
|
||||
- 视频库登记:归档完成后由 app worker 自动写回现有视频库
|
||||
- 上传稳定性:媒体分段上传遇到 `502/503/504` 会自动重试
|
||||
|
||||
## 前端能力
|
||||
|
||||
@@ -46,12 +50,14 @@
|
||||
|
||||
- 统一工作台导航
|
||||
- 仪表盘、训练、视频、录制、分析等模块一致的布局结构
|
||||
- 全局任务中心:桌面侧边栏和移动端头部都可查看后台任务
|
||||
- 为后续 PC 粗剪时间线预留媒体域与文档规范
|
||||
|
||||
## 架构能力
|
||||
|
||||
- Node 应用负责业务 API、登录、训练数据与视频库元数据
|
||||
- Go 服务负责媒体链路与归档
|
||||
- 后台任务表 `background_tasks` 统一承接重任务
|
||||
- `Docker Compose + 宿主机 nginx` 作为标准单机部署方式
|
||||
- 统一的本地验证命令:
|
||||
- `pnpm check`
|
||||
@@ -67,10 +73,27 @@
|
||||
- 当前 WebRTC 重点是浏览器到服务端的实时上行,不是多观众直播分发
|
||||
- 当前 PC 剪辑仍处于基础媒体域准备阶段,未交付完整多轨编辑器
|
||||
- 当前存储策略为本地卷优先,未接入对象存储归档
|
||||
- 当前 `.env` 配置的视觉网关若忽略 `LLM_VISION_MODEL`,系统会回退到文本纠正;代码已支持独立视觉模型配置,但上游网关能力仍需单独确认
|
||||
|
||||
## 后续增强方向
|
||||
|
||||
- PC 时间线粗剪与 clip plan 持久化
|
||||
- 更细粒度的设备能力自适应
|
||||
- 更强的媒体回放和片段导出能力
|
||||
- 更深入的前端域拆分和懒加载优化
|
||||
### 移动端个性化增强
|
||||
|
||||
- 根据网络、机型和电量状态动态切换录制档位、分段大小与上传节流策略
|
||||
- 将录制焦点视图扩展为单手操作布局,支持拇指热区、自定义主按钮顺序和横竖屏独立面板
|
||||
- 为不同训练项目提供场景化预设,例如发球、正手、反手、步伐训练各自保存摄像头方向、裁切比例和提示文案
|
||||
- 增加弱网回传面板,向用户展示排队片段、预计上传耗时和失败重试建议
|
||||
|
||||
### PC 轻剪与训练回放
|
||||
|
||||
- 交付单轨时间线粗剪:入点、出点、片段删除、关键帧封面和 marker 跳转
|
||||
- 增加“剪辑计划”实体,允许把自动 marker、手动 marker 和 AI 建议片段一起保存
|
||||
- 提供双栏回放模式:左侧原视频,右侧姿态轨迹、节奏评分和文字纠正同步滚动
|
||||
- 支持从视频库直接发起导出任务,在后台生成训练集锦或问题片段合集
|
||||
|
||||
### 高性能前端重构
|
||||
|
||||
- 将训练、分析、录制、视频库拆分为按域加载的路由包,继续降低首屏主包体积
|
||||
- 把共享媒体状态、任务状态和用户状态从页面本地逻辑收拢为稳定的数据域层
|
||||
- 统一上传、任务轮询、错误提示和绝对 URL 规范化逻辑,减少当前多处重复实现
|
||||
- 为重计算页面增加惰性加载、按需图表加载和更严格的移动端资源预算
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
- `db` 容器:MySQL 8,数据持久化到 `db-data`
|
||||
- `migrate` 容器:一次性执行 Drizzle 迁移,成功后退出
|
||||
- `app` 容器:Node 应用,端口 `3000`
|
||||
- `app-worker` 容器:Node 后台任务 worker,共享应用卷与数据库
|
||||
- 宿主机公开调试端口:`8302 -> app:3000`
|
||||
- `media` 容器:Go 媒体服务,端口 `8081`
|
||||
- `worker` 容器:Go 媒体归档 worker,共享媒体卷
|
||||
- `media-worker` 容器:Go 媒体归档 worker,共享媒体卷
|
||||
- `app-data` 卷:上传视频等本地文件存储
|
||||
- `db-data` 卷:MySQL 数据目录
|
||||
- `media-data` 卷:录制片段、会话状态、归档成片
|
||||
@@ -32,6 +33,13 @@ docker compose up -d --build
|
||||
- `MYSQL_PASSWORD`
|
||||
- `MYSQL_ROOT_PASSWORD`
|
||||
- `LLM_API_KEY`
|
||||
- `APP_PUBLIC_BASE_URL`
|
||||
- `LLM_VISION_MODEL`
|
||||
|
||||
如需启用独立视觉模型端点,再补:
|
||||
|
||||
- `LLM_VISION_API_URL`
|
||||
- `LLM_VISION_API_KEY`
|
||||
|
||||
## nginx
|
||||
|
||||
@@ -54,6 +62,7 @@ systemctl reload nginx
|
||||
- `curl http://127.0.0.1:3002/api/trpc/auth.me`
|
||||
- `curl http://te.hao.work:8302/`
|
||||
- `curl http://127.0.0.1:8081/media/health`
|
||||
- `docker compose exec app-worker node dist/worker.js --help` 不适用;应通过 `docker compose ps app-worker` 确认 worker 常驻
|
||||
|
||||
## External access links
|
||||
|
||||
@@ -77,4 +86,4 @@ systemctl reload nginx
|
||||
2. 回退 Git 版本
|
||||
3. 重新执行 `docker compose up -d --build`
|
||||
|
||||
如果只需停止录制链路,可单独关闭 `media` 与 `worker`,主站业务仍可继续运行。
|
||||
如果只需停止录制链路,可单独关闭 `media` 与 `media-worker`,主站业务仍可继续运行;如需暂停训练计划/动作纠正等后台任务,再额外停止 `app-worker`。
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
- Node/tRPC 路由输入校验与权限检查
|
||||
- LLM 模块请求配置与环境变量回退逻辑
|
||||
- 视觉模型 per-request model override 能力
|
||||
- 媒体工具函数,例如录制时长格式化与码率选择
|
||||
|
||||
### 3. Go 媒体服务测试
|
||||
@@ -43,6 +44,7 @@
|
||||
- 注入假媒体设备、假 `MediaRecorder` 和假 `RTCPeerConnection`
|
||||
|
||||
这样可以自动验证前端主流程,而不依赖数据库、真实摄像头权限和真实 WebRTC 网络环境。
|
||||
当前 E2E 已覆盖新的后台任务流和任务中心依赖的接口 mock。
|
||||
|
||||
## Unified verification
|
||||
|
||||
@@ -75,6 +77,14 @@ pnpm test:llm -- "你好,做个自我介绍"
|
||||
- 适合验证 `LLM_API_KEY`、`LLM_MODEL` 和网关连通性
|
||||
- 不建议纳入 `pnpm verify`,因为它依赖外部网络和真实密钥
|
||||
|
||||
多模态链路建议额外执行一次手工 smoke test:
|
||||
|
||||
```bash
|
||||
pnpm exec tsx -e 'import "dotenv/config"; import { invokeLLM } from "./server/_core/llm"; const result = await invokeLLM({ model: process.env.LLM_VISION_MODEL, apiUrl: process.env.LLM_VISION_API_URL, apiKey: process.env.LLM_VISION_API_KEY, messages: [{ role: "user", content: [{ type: "text", text: "请用中文一句话描述图片" }, { type: "image_url", image_url: { url: "https://..." } }] }] }); console.log(result.model, result.choices[0]?.message?.content);'
|
||||
```
|
||||
|
||||
如果返回模型与 `LLM_VISION_MODEL` 不一致,说明上游网关忽略了视觉模型选择,业务任务会自动回退到文本纠正结果。
|
||||
|
||||
## Production smoke checks
|
||||
|
||||
部署到宿主机后,建议至少补以下联测:
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Verified Features
|
||||
|
||||
本文档记录当前已经通过自动化验证或构建验证的项目。更新时间:2026-03-14 22:24 CST。
|
||||
本文档记录当前已经通过自动化验证或构建验证的项目。更新时间:2026-03-15 00:11 CST。
|
||||
|
||||
## 最新完整验证记录
|
||||
|
||||
- 通过命令:`pnpm verify`
|
||||
- 验证时间:2026-03-14 22:23 CST
|
||||
- 结果摘要:`pnpm check` 通过,`pnpm test` 通过(74/74),`pnpm test:go` 通过,`pnpm build` 通过,`pnpm test:e2e` 通过(5/5)
|
||||
- 验证时间:2026-03-15 00:10 CST
|
||||
- 结果摘要:`pnpm check` 通过,`pnpm test` 通过(80/80),`pnpm test:go` 通过,`pnpm build` 通过,`pnpm test:e2e` 通过(6/6),`pnpm test:llm` 通过
|
||||
|
||||
## 生产部署联测
|
||||
|
||||
@@ -15,10 +15,13 @@
|
||||
| `https://te.hao.work/` HTTPS 访问 | `curl -I https://te.hao.work/` | 通过 |
|
||||
| `http://te.hao.work:8302/` 4 位端口访问 | `curl -I http://te.hao.work:8302/` | 通过 |
|
||||
| 站点 TLS 证书 | Let’s Encrypt ECDSA 证书已签发并由宿主机 nginx 加载 | 通过 |
|
||||
| 生产首页、登录页、录制页浏览器打开 | Playwright 访问 `https://te.hao.work/`、`/login`、`/recorder` | 通过 |
|
||||
| 生产登录与首次进入工作台 | Playwright 登录真实站点并跳转 `/dashboard` | 通过 |
|
||||
| 生产训练 / 实时分析 / 录制 / 视频库页面加载 | Playwright 访问 `/training`、`/live-camera`、`/recorder`、`/videos` | 通过 |
|
||||
| 生产训练计划后台任务提交 | Playwright 点击训练计划生成按钮并收到后台任务反馈 | 通过 |
|
||||
| 生产移动端录制焦点视图 | Playwright 移动端视口打开 `/recorder` 并验证焦点入口与操作壳层 | 通过 |
|
||||
| 生产前端运行时异常检查 | Playwright `pageerror` / `console.error` 检查 | 通过 |
|
||||
| 媒体健康检查 | `curl http://127.0.0.1:8081/media/health` | 通过 |
|
||||
| compose 自包含服务 | `docker compose ps` 中 `app` / `db` / `media` / `worker` 正常运行,`migrate` 成功退出 | 通过 |
|
||||
| compose 自包含服务 | `docker compose ps -a` 中 `app` / `app-worker` / `db` / `media` / `media-worker` 正常运行,`migrate` 成功退出 | 通过 |
|
||||
|
||||
## 构建与编译通过
|
||||
|
||||
@@ -43,6 +46,7 @@
|
||||
| badge | `pnpm test` | 通过 |
|
||||
| leaderboard | `pnpm test` | 通过 |
|
||||
| tutorial / reminder / notification 路由校验 | `pnpm test` | 通过 |
|
||||
| task 后台任务路由 | `pnpm test` / `pnpm test:e2e` | 通过 |
|
||||
| media 工具函数 | `pnpm test` | 通过 |
|
||||
| 登录 URL 回退逻辑 | `pnpm test` | 通过 |
|
||||
|
||||
@@ -63,7 +67,9 @@
|
||||
| 训练计划 | 训练计划页加载与生成入口可见 | 通过 |
|
||||
| 视频库 | 视频卡片渲染 | 通过 |
|
||||
| 实时分析 | 摄像头启动入口渲染 | 通过 |
|
||||
| 实时分析打分 | 启动分析后出现实时评分结果 | 通过 |
|
||||
| 在线录制 | 启动摄像头、开始录制、手动标记、结束归档 | 通过 |
|
||||
| 录制焦点视图 | 移动端最大化焦点视图与主操作按钮渲染 | 通过 |
|
||||
| 录制结果入库 | 归档完成后视频库可见录制结果 | 通过 |
|
||||
|
||||
## LLM 模块验证
|
||||
@@ -72,12 +78,14 @@
|
||||
|------|----------|------|
|
||||
| `.env` 中的 `LLM_API_URL` / `LLM_API_KEY` / `LLM_MODEL` | `pnpm test:llm` | 通过 |
|
||||
| `https://one.hao.work/v1/chat/completions` 联通性 | `pnpm test:llm` 实际返回文本 | 通过 |
|
||||
| 视觉模型独立配置路径 | `server/_core/llm.test.ts` + 手工 smoke 检查 | 通过 |
|
||||
|
||||
## 已知非阻断警告
|
||||
|
||||
- 测试与开发日志中会出现 `OAUTH_SERVER_URL` 未配置提示;当前 mocked auth 和本地验证链路不依赖真实 OAuth 服务,因此不会导致失败
|
||||
- `pnpm build` 仍有 Vite 大 chunk 警告;当前属于性能优化待办,不影响本次产物生成
|
||||
- Playwright 运行依赖 mocked media/network,不等价于真机摄像头、真实弱网和真实 WebRTC 质量验收
|
||||
- 当前上游视觉网关可能忽略 `LLM_VISION_MODEL` 并回退为文本模型;服务端已实现自动降级,任务不会因此直接失败
|
||||
|
||||
## 当前未纳入自动验证的内容
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户