From daebde4d5f43f1e16781c2752a789dfefa056742 Mon Sep 17 00:00:00 2001 From: yibo Date: Tue, 1 Sep 2026 17:53:00 +0800 Subject: [PATCH] Add dressup-dance live room requirements, current-state, and architecture docs --- docs/done/live-channel-v1.md | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/structure/architecture.md | 266 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/todo/dressup-dance-room.md | 306 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 711 insertions(+), 0 deletions(-) create mode 100644 docs/done/live-channel-v1.md create mode 100644 docs/structure/architecture.md create mode 100644 docs/todo/dressup-dance-room.md diff --git a/docs/done/live-channel-v1.md b/docs/done/live-channel-v1.md new file mode 100644 index 0000000..5eb5049 --- /dev/null +++ b/docs/done/live-channel-v1.md @@ -0,0 +1,139 @@ +# AI 短剧频道 v1 —「文字点播」直播间(已完成) + +状态:已上线运行(`server.js` + `live.html`,pm2 进程 `minimax-live`)。 +本文档记录**当前已实现**的需求范围,作为后续「换装跳舞直播间」(见 +`docs/todo/dressup-dance-room.md`)改造的基线参照。 + +## 1. 产品概述 + +一个 7x24 播放的虚拟直播间。所有观众看到同一个「虚拟播出时刻表」 +(server 端统一计算的播放进度,非各自独立播放),可以: + +- 直接观看正在播放的 AI 生成短视频(文字弹幕点播 + 随机填充) +- 在聊天区发一句话 → 命中素材库则很快排入播放;不命中则提交给 H3 + 后台生成新片段,生成完成后排入播放 +- 给候选片段投票,得票最高的优先播出 +- 浏览「最新 / 最早 / 最热」三种非直播的素材库列表,任意点播 + +## 2. 已实现的核心能力 + +### 2.1 虚拟播出时刻表(直播的核心机制) + +- `server.js` 维护内存中的 `schedule`(`[{clip, startAt, endAt, requestedBy}]`), + 每 2 秒 tick 一次(`ensureSchedule`),始终保证时刻表填充到「未来至少 + `FILLER_DURATION_MS`(30s)」。 +- 选片优先级:投票最高的「已生成待播」(`ready`)> 投票最高的「素材库命中」 + (`matched`)> 素材库随机填充(避开上一条、避开 20 分钟内播过的,两者都 + 没有时退化为纯随机,保证时刻表永不断流)。 +- 所有观众通过轮询 `GET /api/live/state`(4s 一次)拿到同一份 + `{current, upNext, queue}`,前端用「服务端 endAt 减本地时间」精确定时 + 切下一条,轮询只作为纠偏/兜底,不是切片的唯一触发点。 +- 状态持久化到 `live-state.json`,进程重启后从中恢复,不会冷启动断播。 + +### 2.2 文字点播驱动生成 + +- 观众聊天发送文本 → 先做违禁词审核(`moderateText`,子串黑名单,非语义 + 审核)→ 通过后 `submitPromptToQueue`: + - 命中素材库(中/英文 prompt 精确或子串匹配)→ 直接进入待播队列 + (`status: matched`)。 + - 未命中 → 调用 H3 Console `POST /v1/videos`(文生视频,832x480/120帧/ + 20步)异步生成,`status: generating`,生成完成后自动写入 + `library.json` 并推入待播队列(`status: ready`)。 +- 生成是完全后台化的(H3 自建集群单次约 200s),绝不阻塞直播时刻表或 + HTTP 响应。 +- `POST /api/prompt` 是同一条提交路径的非聊天版本(供测试/直接调用)。 + +### 2.3 排队投票 + +- `POST /api/queue/vote/:id`:按 `uid`(cookie)对某条排队中的 + matched/generating/ready 条目投票/取消投票,票数决定谁先播(2.1)。 + +### 2.4 素材库浏览模式 + +- 三个 tab:最新 / 最早 / 最热(`GET /api/library?sort=`),点击任意条目 + 立即播放,播完自动顺延下一条(`ended` 事件),与直播模式的时刻表机制 + 完全独立。 + +### 2.5 观众身份 + +- 首次进聊天框(focus 触发,不需要先点发送)弹昵称输入框,生成 + `uid`(`crypto.randomUUID`)+ `nickname`,写入 cookie(365 天)。 +- 顶部常驻「昵称 ✎」可随时改名,`uid` 不变(投票/点播历史不丢失)。 +- 无正式账号体系——身份完全基于浏览器 cookie,换设备/清 cookie 即视为 + 新观众。**这是 v2 用户注册需求要解决的缺口**,见 `docs/todo`。 + +### 2.6 在线人数 + +- 每次 `/api/live/state` 轮询带 `cid`(随机 clientId,非 cookie,纯前端 + 内存变量)打点到 `viewers: Map`,12s 内有心跳视为在线, + 服务端返回 `watching` 计数。 + +### 2.7 内容审核 / 限流 + +- 审核:仅关键词黑名单(`BANNED_WORDS`),非语义级别;生成内容本身的 + 安全检查依赖 H3 Console 自身的生成时安全策略(被拒会以「生成失败」 + 形式体现在队列里)。 +- 限流:按 IP,5 分钟内最多 3 次聊天/点播提交(`RATE_LIMIT_MAX/WINDOW_MS`)。 + 无账号维度限流。 + +### 2.8 后台管理(`admin.html`) + +- 表格形式管理 `library.json`:搜索(名称/prompt/id)、按来源筛选 + (h3console / manual)、任意列排序、行内编辑、删除。 +- 「新增」表单可手动挂载一条外部视频地址(`source: manual`)的素材, + 不经过 H3 生成。 +- 编辑/新增会置 `edited: true`,让后续自动同步(2.9)不覆盖人工修改。 +- 删除一条 `h3console` 来源的素材,会级联调用 H3 Console 的 + `DELETE /v1/videos/:id`(移入 H3 自己的回收站),避免下次同步又冒出来。 +- **无鉴权**——`admin.html` 和所有 `/api/admin/*` 接口对能访问到该端口的 + 任何人开放,依赖网络边界(内网/反代)而非应用层鉴权。 + +### 2.9 与 H3 Console 的集成 + +- `ingest.js` 的 `syncLibrary()`:启动时 + 每 5 分钟,从 H3 Console 拉取 + 全量 job 列表重建 `library.json`(规则提取短 prompt,过滤基础设施 + 烟雾测试 job,保留 `likes`,跳过 `edited: true` 的条目)。这让直接在 + H3 Console 网页端产出的内容,5 分钟内自动出现在直播间素材库。 +- 视频本体不落本地盘:`GET /lib/video/:id` 服务端代理转发 H3 Console 的 + `/v1/videos/:id/file`(`H3_CONSOLE_TOKEN` 不下发到浏览器);若素材有 + `videoUrl`(manual 来源或管理后台设置过)则 302 跳转到该地址。 +- 详细 API 契约见 `H3-CONSOLE.md`(H3 Console 是独立于本项目的内部服务, + 4 卡 GPU 单节点,无按次计费)。 + +## 3. 数据模型(现状) + +`library.json`(数组,逐条追加,无数据库): + +```jsonc +{ + "id": "19c6b745a68e", // h3console: H3 job id;manual: manual- + "source": "h3console", // "h3console" | "manual" + "edited": false, // true = 后台改过/手动新增,同步时跳过重建 + "prompt": "...", // 展示用短 prompt(中文) + "promptEn": "...", // 可选,英文短 prompt + "fullPrompt": "...", // 完整生成 prompt(H3 结构化 prompt 或用户原话) + "videoUrl": "...", // 可选,外部视频地址(manual 或后台改过播放源) + "width": 832, "height": 480, + "duration": 5, // 秒 + "partition": "text", // text | ref2va | fl2va | manual + "likes": 0, + "lastPlayedAt": 1788250666831, // 可选,用于播出冷却 + "createdAt": 1788250666831 +} +``` + +`live-state.json`:`{ schedule, promptQueue, chatMessages }`,结构见 +`server.js` 顶部注释,逐 tick 全量覆写。 + +## 4. 已知限制(未做的事,供 v2 参考) + +- 无正式用户账号(仅 cookie 身份)、无积分/消费体系。 +- 素材类型单一:只有「生成好的视频片段」,没有可复用的「人物」「服装」 + 「参考动作/音乐视频」这类结构化中间资产——每条素材都是一次性的最终 + 产物,无法组合复用。 +- 生成路径只有「纯文字 → H3 文生视频」一条,没有「参考图/参考视频驱动」 + 的生成路径(H3 Console 本身支持 `ref2va`/`fl2va`,但本项目尚未从 + `/api/prompt`、`/api/chat` 之外的路径调用过)。 +- 无人工审核队列,内容一旦生成完成即自动排入公开播放,无「先审后播」 + 开关。 +- 无任何鉴权,管理后台和写接口都是「网络可达即可操作」。 diff --git a/docs/structure/architecture.md b/docs/structure/architecture.md new file mode 100644 index 0000000..8e756a9 --- /dev/null +++ b/docs/structure/architecture.md @@ -0,0 +1,266 @@ +# 系统架构文档 + +覆盖现状(v1,已上线)与规划中的「换装跳舞直播间」(v2,见 +`docs/todo/dressup-dance-room.md`)。需求范围见对应文档,本文档只谈 +组件划分、数据流、集成方式和存储演进。 + +## 1. 现状架构(v1) + +### 1.1 组件 + +```mermaid +flowchart LR + subgraph Browser + live[live.html
直播间/浏览] + admin_ui[admin.html
素材后台] + end + + subgraph Node["server.js (单文件 Node http server, PORT 8934)"] + api[路由处理
/api/*, /lib/video/*] + sched[schedule + promptQueue
2s tick] + ingest[ingest.js
syncLibrary 每5分钟] + end + + libjson[(library.json)] + statejson[(live-state.json)] + h3[(H3 Console
内部 MiniMax H3 集群
/v1/videos)] + fal[(fal.ai queue API
/fal/* 反代)] + + live -- 轮询 /api/live/state, /api/chat --> api + live -- POST /api/chat, /api/prompt, /api/queue/vote --> api + admin_ui -- CRUD /api/admin/library --> api + api -- 读写 --> libjson + sched -- 落盘 --> statejson + api --> sched + sched -- POST /v1/videos, 轮询状态 --> h3 + api -- GET /v1/videos/:id/file 代理 --> h3 + ingest --> h3 + ingest -- 重建 --> libjson + + legacy[index.html/app.js/newtask.html
独立的 fal.ai 任务提交小工具
与直播间无数据关联] -.-> fal +``` + +### 1.2 关键设计点 + +- **单进程、无框架、无数据库**:`server.js` 用 Node 原生 `http` 模块手写 + 路由,持久化就是两个 JSON 文件(`library.json` 素材库、`live-state.json` + 直播状态),全量读写、无锁、无并发写保护——量级小的场景下够用,见 + 1.4 存储演进建议里什么时候该换。 +- **服务端权威时钟**:直播"当前播放的是哪条"由服务端 `schedule` 数组 + 决定,浏览器只是被动轮询同步,杜绝"每个观众各自播各自的"——这是 + "直播感"的核心,v2 任何改造都不能破坏这个前提。 +- **H3 Console 是外部服务,本项目只是它的一个消费方**:内部 MiniMax H3 + 视频生成集群,独立部署、独立鉴权(`H3_CONSOLE_TOKEN`),契约见 + `H3-CONSOLE.md`。`server.js` 里所有跟"生成视频"相关的逻辑,都是在编排 + 这个外部 API(提交任务 → 轮询 → 落库),本身不做任何 GPU 推理。 +- **`/fal/*` 反代通道**:转发到 `queue.fal.run`(fal.ai 官方队列 API), + 目前只被仓库里独立的 `index.html`/`app.js`/`newtask.html`/`taskdetail.html` + 这套"手动提交 H3/H3-Max 生成任务"小工具使用,跟直播间(`live.html`) + 没有数据关联。**v2 的付费实时生成路径会正式启用这条通道**,理由见 + 2.3。 +- **无鉴权边界**:管理后台 (`admin.html`) 和所有写接口都没有应用层鉴权, + 依赖网络可达性(内网/反代层面控制)。v2 引入用户账号体系后,管理后台 + 这块的"零鉴权"现状需要重新评估(至少后台管理接口应该要求管理员身份, + 这不是本次需求主线但是个不能一直拖的技术债)。 + +### 1.3 直播时刻表状态机(供 v2 复用/扩展参考) + +```mermaid +sequenceDiagram + participant V as 观众浏览器 + participant S as server.js + participant H3 as H3 Console + + V->>S: POST /api/chat {text} + S->>S: moderateText() 关键词审核 + alt 命中 library.json + S-->>V: {status: matched} + else 未命中 + S->>H3: POST /v1/videos {prompt} + S-->>V: {status: generating} + loop 轮询直到 done/error + S->>H3: GET /v1/videos/:id + end + S->>S: 写入 library.json, 状态置 ready + end + Note over S: ensureSchedule() 每 2s tick
按投票数从 ready/matched 里选片
不够则从素材库随机填充 + loop 每 4s + V->>S: GET /api/live/state + S-->>V: {current, upNext, queue} + end + Note over V: 前端用 endAt 精确定时切片
轮询只是纠偏/兜底 +``` + +### 1.4 存储演进建议 + +JSON 文件方案在 v1(单一素材类型、无账号、无并发写压力)是合适的 +"够用就好"选择。v2 一旦引入下列任一项,建议评估迁移到嵌入式数据库 +(如 SQLite,单文件、无需额外部署,跟现有"零运维依赖"的风格最接近): + +- 用户账号 + 密码/凭证存储(JSON 明文文件不适合放凭证,即便是 hash 后 + 的也建议至少上 SQLite)。 +- 积分流水 + 人物"剩余可播 10 秒片段数"这类计数器(需要"扣积分 + 创建 + 生成任务 + 扣减片段配额"这几步操作的原子性,全量重写 JSON 文件在 + 并发下有丢更新风险)。 +- 资产种类变多(人物/衣服/参考视频/合成图/生成视频五张表,互相有外键 + 引用关系,继续用一个大 JSON 数组的心智负担会明显上升)。 + +不建议现在就迁移——v2 第一期(`docs/todo` 第 9 节分期建议)如果只是先 +用内部 H3 Console 跑冷启动种子内容、不涉及账号和并发写,继续加 JSON +文件(比如新增 `characters.json`/`garments.json`/`dance-refs.json`, +沿用 `library.json` 的读写模式)完全够用;到第三/四期引入账号+积分时 +再迁移,避免过早优化。 + +## 2. 规划架构(v2:换装跳舞直播间) + +### 2.1 两个独立的直播间页面 + +`live.html`(文字点播)与 `dance.html`(换装点播)是**两条并行的产品 +线**,不是同一个页面的两个 tab: + +- 各自维护独立的 `schedule`/`promptQueue`(各自的播出时刻表和排队), + 互不影响对方的播放进度。 +- 共用同一套底层基础设施:素材库读写模式(`library.json` 风格)、 + H3 Console/fal.ai 生成编排、观众身份(cookie/账号)、投票机制、 + 在线人数统计。 +- `dance.html` 复用 `live.html` 的视觉语言(同一套 CSS 风格、播放器、 + 排队列表 UI),保留在线人数/点赞/排队展示,**唯一的差别是左侧点播 + 面板**:`live.html` 是文字输入框,`dance.html` 是"衣柜选择 / 传衣服 / + 传人"操作面板,没有文字输入。 + +### 2.2 新增组件 + +```mermaid +flowchart TB + subgraph Browser + dance[dance.html
衣柜/传衣服/传人,无文字输入] + admin2[admin.html
+ 人物/衣服/参考视频/用户 管理页] + end + + subgraph Node["server.js(扩展)"] + api2[路由扩展
/api/dressup/*, /api/admin/characters, garments, dance-refs, users] + pipeline[生成流水线编排
Stage1 → Stage2
按请求类型路由到不同算力] + moderation[审核
模式二:图片内容审核
模式三:人脸黑名单过滤] + credit[积分校验/扣减/退还
+ 人物剩余片段配额] + end + + charjson[(characters.json)] + garmjson[(garments.json)] + dancejson[(dance-refs.json)] + libjson2[(library.json
+ characterId/garmentId/refDanceVideoId 溯源字段)] + userdb[(users + credits
建议 SQLite,见 1.4)] + + fal2[(fal.ai
Stage1 换装图合成
+ 付费实时 Stage2 视频生成)] + h32[(内部 H3 Console
冷启动/后台种子内容
批量 Stage2 视频生成)] + + dance -- 免费:选衣柜 --> api2 + dance -- 付费:传衣服/传人 --> api2 + api2 --> moderation + api2 --> credit + moderation -- 通过 --> pipeline + credit -- 扣减通过 --> pipeline + pipeline -- Stage1 --> fal2 + fal2 -- 换装参考图 --> pipeline + pipeline -- Stage2 冷启动/种子 --> h32 + pipeline -- Stage2 付费实时 --> fal2 + h32 -- 跳舞视频 --> pipeline + fal2 -- 跳舞视频 --> pipeline + pipeline -- 落库 --> libjson2 + admin2 --> charjson + admin2 --> garmjson + admin2 --> dancejson + admin2 --> userdb +``` + +### 2.3 双算力策略:冷启动 vs 付费实时(已确认,见 `docs/todo` 4.3) + +Stage2(视频生成)按"是否是付费实时请求"路由到两条不同算力: + +- **冷启动/后台种子内容**(admin 批量预生成,铺满衣柜库/默认人物库) + → 走内部 H3 Console(免费,但单条约 200s,见 `H3-CONSOLE.md`)。这条 + 路径不面向单个观众的实时请求,批量跑不受时间压力。 +- **观众付费实时请求**(模式二付费传衣服、模式三付费传人物)→ 走 + fal.ai 云端(`minimax/h3*` 系列端点,约 4s 级别,见 `H3-CONSOLE.md` + 的实测对比),成本由观众支付的积分覆盖。 + +Stage1(换装图合成)两条路径下都走 fal.ai——H3 Console 本身是纯视频 +生成 API,不产图,见 `H3-CONSOLE.md` 明确说明。这也是 `/fal/*` 反代 +通道(1.2 节)真正被直播间业务启用的地方:现状它只服务于仓库里跟 +直播间无关的旧工具,v2 里会成为 Stage1 全量、以及付费 Stage2 的核心 +依赖。fal API Key 现状是前端 `newtask.html` 里手填(见 1.2 节代码原样), +v2 必须挪到服务端 `.env`,不能再让 key 走浏览器。 + +`reference_video_urls` 这个字段目前只是从 H3 Console 控制台 UI tab +推断存在、未经本项目实测调用过(`H3-CONSOLE.md` 原话),v2 落地 Stage2 +前第一步就是用真实调用验证这条路径,而不是假设它一定按预期工作 +(`docs/todo` 第 8.2 条)。 + +### 2.4 视频规格:默认竖屏,移动端优先(仅 `dance.html`) + +`dance.html` 的生成请求默认用 **480×832**(`live.html` 现有默认 +832×480 的宽高对调),总像素量与现状完全一致,理论上不会拖慢 H3 +Console/fal.ai 的生成耗时(`docs/todo` 4.4 节)。`live.html` 现有横屏 +内容/默认值不变,两个直播间的规格是独立配置,不共享同一份 +`H3_GEN_PARAMS`。播放器 UI 上,`dance.html` 需要一套按 9:16 设计的 +播放器容器,不能直接复用 `live.html` 现有横屏播放器的宽高比。 + +### 2.5 与现状的集成点 + +- **浏览三 tab 不动**:v2 生成的视频最终落地也是 `library.json` 风格的 + 一条 clip(多了几个溯源字段),复用现状浏览逻辑,`dance.html` 只是 + 拥有自己独立的一份 schedule 实例(2.1 节)。 +- **"生成中/排队中"展示复用**:换装流水线本质也是"提交 → 后台异步生成 → + 完成后进队列",跟现有 `generateForPrompt` 的状态机(generating → + ready/failed,任务 id 落盘可断点续传)同构,Stage2 直接复用这套逻辑, + Stage1 失败则更早终止。 +- **`ensureSchedule` 选片逻辑需要实质性扩展**,不是"复用不动"——见 2.6。 + +### 2.6 排播优先级 + 去重缓存(已确认,对 v1 排片算法的改动) + +`dance.html` 的 `promptQueue`/`schedule` 不能直接照抄 v1 的"纯投票排序" +逻辑,需要两处新行为(`docs/todo` 3 节"共同后置流程"、4.6 节): + +- **免费模式一走"先查缓存再生成"**:提交时先用 `(characterId, + garmentId)` 查是否已有产物,命中直接排入队列(跟 v1 + `findLibraryMatch` 是同一个套路,只是匹配维度从文本相似度换成资产 + id 组合),未命中才真正走 Stage1/Stage2。免费内容排入队列后仍按 v1 + 现有投票机制排序。 +- **付费模式三新人物内容插队播放**:Stage2 完成后**不进入投票排序**, + 而是直接插入 `schedule`(紧跟在当前播放的片段之后,或队首),跳过 + `pickBestIndexByStatus` 这条"按票数选"的路径。`ensureSchedule` 需要 + 一个新的"优先插入"通道,跟现有"从 promptQueue 里挑最高票"逻辑并行 + 存在,而不是复用同一个排序比较器。 +- 这两点意味着 `dance.html` 的排片模块虽然复用 v1 的整体结构(数据 + 持久化到 `live-state.json` 风格的文件、`ensureSchedule` 定时 tick 的 + 思路),但选片函数本身要重写,不是简单的参数化复用。 + +### 2.7 用户账号、积分与人物生命周期 + +- 现有 `viewer_uid`/`viewer_nickname` cookie 身份保留作为过渡态;免费 + 模式一(选衣柜)不强制登录。上传新资产/花积分(模式二、三)才要求 + 邮箱登录(`docs/todo` 7.1)。注册后把 cookie `uid` 绑定到账号 id, + 历史投票/点播记录不丢。 +- 积分校验点:提交付费流水线(Stage1 触发前)先校验+预扣积分,Stage1 + 或 Stage2 失败要退还——这个扣减+退还路径要求原子性,是 1.4 节里 + "该上 SQLite 了"的触发点之一。 +- **人物生命周期**(`docs/todo` 3.3 节第 7 点、9.5 期):付费生成的新 + 人物带一个"剩余可播 10 秒片段数"配额,每播放一段消耗一份;配额耗尽 + 自动从排播池移除(但人物、换装图、已生成视频全部保留,不删除), + 用户再充值可以直接续播,无需重新走 Stage1/Stage2——这意味着"人物" + 和"该人物名下的已生成视频"要能独立于"当前是否在直播池中"被检索到, + 数据模型上是一个显式的 `status: active|expired` + 关联的积分流水, + 不是简单的软删除。 + +## 3. 待验证事项汇总(技术验证,非产品决策分歧) + +避免重复散落在需求文档各处,详见 `docs/todo` 第 8 节: + +| 待验证项 | 影响范围 | +|---|---| +| Stage1 换装模型在 fal.ai 上的具体选型 | 换装一致性、速度、成本 | +| `reference_video_urls` 在 H3 `ref2va` 下的实测效果 | Stage2 冷启动路径是否可行 | +| fal.ai 端 `minimax/h3*` 端点是否支持同等的多参考图生视频 | Stage2 付费实时路径是否可行 | +| 人脸识别黑名单模型/服务选型 | 模式三自动审核能力 | +| 图片内容审核供应商/接口 | 模式二审核能力 | +| JSON 文件 → SQLite 的迁移时机 | 存储层改造范围,见本文档 1.4 | +| 支付网关选型(初步倾向 Stripe,需确认是否要叠加支付宝/微信支付) | 充值流程开发方向,见 `docs/todo` 7.3 | diff --git a/docs/todo/dressup-dance-room.md b/docs/todo/dressup-dance-room.md new file mode 100644 index 0000000..980ab1c --- /dev/null +++ b/docs/todo/dressup-dance-room.md @@ -0,0 +1,306 @@ +# 换装跳舞直播间 — 需求文档(TODO / 未实现) + +对应现状基线见 `docs/done/live-channel-v1.md`;架构层面的落地方案见 +`docs/structure/architecture.md`。本文档记录**已与产品方确认的决策** +(第 2~7 节),以及仍需要技术验证/调研、非产品决策问题的部分(第 8 节)。 + +## 1. 背景与目标 + +新增一个跟现有文字点播直播间并列的产品:**换装跳舞直播间**。点播动作从 +"打字描述想看什么"变成"选衣服 / 传衣服 / 传人",本质是把"自由文本生成" +收窄成"资产库组合生成": + +> 人物照片(资产库) + 衣服照片(资产库或观众上传) → +> 生成"新衣服小姐姐"参考图 → 参考图 + 参考跳舞视频 → 生成新跳舞视频 +> → 排入直播间播放队列 + +## 2. 产品形态:两个独立的直播间页面(已确认) + +- **`live.html`(现状,不变)**:文字点播直播间,观众打字描述想看什么, + 详见 `docs/done/live-channel-v1.md`。 +- **`dance.html`(新增)**:换装跳舞直播间,**没有文字输入框**,点播动作 + 全部是"选衣柜 / 传衣服 / 传人"。与 `live.html` 样式保持一致(同一套 + 视觉语言、同一套播放器/队列 UI 组件),但左侧点播面板换成换装操作, + 右侧保留非文字的互动展示(在线人数、点赞、排队列表——这些跟 + `live.html` 一样保留,只是没有聊天输入)。 +- 两个页面各自维护独立的播出时刻表(各自的 `schedule`/`promptQueue`), + 不是同一个直播间的两个 tab——它们是两条并行的产品线,共用后端的 + 素材库/生成流水线/账号体系等基础设施。 +- **`dance.html` 默认竖屏、移动端优先**(`live.html` 现状横屏不变, + 已上线跑着,不在本次改造范围内)——具体规格见第 4.4 节。 + +## 3. 观众体验流程(已确认:使用已有资产库免费,新增资产付费) + +### 模式一:从衣柜选衣服(免费) + +1. 观众打开"衣柜"面板,浏览后台预置/其他观众上传后已沉淀的服装素材 + (缩略图 + 名称/分类)。 +2. 点选一件 → 人物固定用系统默认人物(免费用户不能指定/上传人物,只能 + 换衣服)。**第一期默认人物固定只有一个**(不做多个轮换/观众选人物, + 前端不需要人物选择器;后台仍以列表形式管理人物库,为以后想扩展成 + 多个预留空间,见 6.1 节)。 +3. 提交 → 进入生成流水线(第 4 节)→ 完成后排入播放队列。同一件衣服被 + 多个观众点中时,走去重缓存直接复用已有产物,见 4.6 节。 +4. **完全免费,不消耗积分**——这是主力免费入口,降低参与门槛。 + +### 模式二:上传自己的衣服照片(付费,"新增衣服") + +1. 观众上传一张衣服/穿搭图片,走轻量内容审核。 +2. 消耗积分(因为这是往衣服库里"新增"一件素材,成本高于直接选用现成 + 素材)。 +3. 审核通过后默认沉淀进公共衣柜库,之后所有观众(含免费用户)都能在 + 模式一里选到这件衣服——相当于"付费的人帮全站扩充了衣柜"。 +4. 人物仍然是系统默认人物(模式二不涉及换人物)。 + +### 模式三:上传喜欢的小姐姐照片(付费,"新增人物") + +1. 观众上传一张人物照片。 +2. 经自动化审核(第 5 节)后即可生成——不是强制人工先审。 +3. **充值/消耗的积分数量,直接决定这个新人物能播放几个 10 秒片段**—— + 花得越多,这个新角色在直播间露出的时长越长。 +4. 衣服可以在提交时一并选/传,也可以不选(系统随机挑一件衣柜库服装 + 搭配)。 +5. 参考跳舞视频固定走系统随机(第 3.4 点)。 +6. 新人物**默认不沉淀进公共人物池**,只服务上传者本人这次付费请求—— + 不会出现"张三充值上传的照片被李四的免费请求随机抽中生成"的情况。 +7. **到期处理**:购买的那几个 10 秒片段播完后,自动下线,但人物、换装 + 参考图、已生成的视频**都保留记录**——用户之后再充值,可以直接续播 + (复用已有素材,不用重新走一遍 Stage1/Stage2 生成)。 + +### 三种模式的共同后置流程 + +- 提交后立刻在"生成中"列表出现一条(带上传者昵称),复用现有排队 UI。 +- 生成成功 → 排入待播队列。**免费内容(模式一/二)按 v1 现有投票机制 + 排序**;**模式三付费新人物内容不参与投票,直接插队/优先播放**(已 + 确认——付费买的是"确定性上镜",不能让它跟免费内容拼投票数),这一点 + 是对 v1 `ensureSchedule` 选片算法的实质性改动,见 + `docs/structure/architecture.md` 1.3/2.6 节。 +- 生成失败/审核不过 → 现有"❌"状态展示;**若是付费请求失败,需要退还 + 已扣的积分**,这是底线(见第 7.2 节)。 + +## 4. 生成流水线设计(两段式 + 双算力策略) + +### 4.1 Stage 1:人物 + 衣服 → 换装参考图 + +输入一张人物参考图 + 一张衣服参考图,输出"该人物穿该衣服"的合成图, +人脸/体型一致,只换装扮。走 fal.ai(具体模型见第 8 节,需要小范围实测 +后确定),复用 `server.js` 已有的 `/fal/*` 反代通道——H3 Console 本身 +不产出图片,Stage1 无论如何都得走别的模型。 + +### 4.2 Stage 2:换装参考图 + 参考跳舞视频 → 生成跳舞视频 + +换装图(`reference_image_urls`)+ 参考跳舞视频(`reference_video_urls`, +提供舞蹈动作/运镜/配乐节奏,系统随机/轮换挑选,观众不选风格)→ 生成 +10 秒左右的跳舞视频片段。产物字段是 v1 `library.json` clip 的超集,加 +`characterId`/`garmentId`/`composedImageId`/`refDanceVideoId` 溯源字段。 + +### 4.3 双算力策略(已确认) + +同一个 Stage2(甚至 Stage1)流程,跑在两条不同的算力路径上,按"是否是 +付费实时请求"切换: + +| 场景 | 算力 | 理由 | +|---|---|---| +| **冷启动/后台种子内容**(admin 预先批量生成,铺满衣柜库/默认人物库的初始内容,不面向单个观众的实时请求) | 内部 H3 Console(自建 GPU 集群) | 免费、无按次成本,但单条约 200s(见 `H3-CONSOLE.md`),批量提前跑不受实时性压力,适合"不着急"的场景 | +| **观众付费实时请求**(模式二付费传衣服、模式三付费传人物) | fal.ai 云端(`minimax/h3*` 系列端点,`/fal/*` 反代已有雏形,见 `app.js`) | 快得多(约 4s 级别 vs 内部集群约 200s,见 `H3-CONSOLE.md` 实测对比),付费用户对等待时间敏感,成本由用户支付的积分覆盖 | + +即:**免费内容靠自己的卡慢慢攒库存,付费内容花钱买 fal.ai 的实时速度**。 +Stage1(换装图合成)在两条路径下大概率都是 fal.ai(H3 Console 不产图), +只有 Stage2(视频生成)真正分叉成两条算力。 + +### 4.4 视频规格:默认竖屏,移动端优先(已确认,仅 `dance.html`) + +- `dance.html` 生成的视频**默认竖屏**(`live.html` 现有横屏内容不受影响, + 两个直播间各自独立的规格,见第 2 节)。 +- **默认分辨率 480×832**——现有 `server.js` 里 `H3_GEN_PARAMS` 的横屏 + 默认是 832×480(总像素量 ≈ 40 万),480×832 只是宽高对调,总像素量 + 完全不变,理论上不会因为改成竖屏而拖慢生成耗时(H3 集群单条本来就 + 约 200s,见 `H3-CONSOLE.md`,竖屏化不能再让这个数字变得更差)。 +- 更高分辨率(576×1024/720×1280 等)画质更好,但会明显增加生成耗时, + **不作为默认**,可以作为后续付费选项预留(呼应第 7.2 节"新增资产才 + 消耗积分"的思路——高清可以是另一档付费能力,不是本期范围,先不做)。 +- 前端播放器/排版要跟着调整:`dance.html` 复用 `live.html` 的 CSS 风格 + (2.1 节),但播放器容器要按 9:16 竖屏比例设计,不能直接套用 + `live.html` 现有横屏播放器的宽高比,否则会出现大黑边——这是 + `dance.html` 相对 `live.html` 除了"没有文字输入框"之外的第二个视觉 + 差异点。 + +### 4.5 失败/超时处理 + +- Stage1 失败:直接终止,不进入 Stage2,不占用 GPU/API 额度;付费请求 + 的话退还积分。 +- Stage2 失败/超时:复用 v1 `generateForPrompt` 现成的重试/超时/持久化 + 套路(`h3JobId`/fal 任务 id 落盘,进程重启能续投)。 + +### 4.6 相同人物+衣服组合去重缓存(已确认,限模式一免费路径) + +- 模式一固定用同一个默认人物(2 节),衣服总量有限,多个观众大概率会 + 选中同一件——**相同"人物+衣服"组合直接复用已有的换装图(Stage1)和 + 生成视频(Stage2),不重新生成**,直接把已有产物排入播放队列。 +- 目的:省 GPU/API 成本,也让免费入口的点播延迟大幅降低(命中缓存约等 + 于 v1 现有"素材库命中"那种秒级体验,见 `docs/done` 2.2 节)。 +- 缓存 key 是 `(characterId, garmentId)` 组合;命中判断在提交时做, + 跟 v1 `findLibraryMatch` 的"先查库再生成"套路是同一个思路,只是匹配 + 维度从"文本相似度"换成"资产 id 组合",实现上更简单可靠。 +- **模式二/三(付费路径)不做去重**——每次付费传衣服/传人物本身就是 + 在新增独特资产,不存在"组合已存在"的情况。 + +## 5. 内容审核(已确认:自动黑名单 + 事后人工兜底,非强制先审后播) + +- **模式二(传衣服)**:基础审核,复用/扩展 v1 关键词审核思路,但要能 + 过图片——需要图片内容审核能力(供应商待定,见第 8 节)。 +- **模式三(传人)**:走**自动化人脸识别黑名单过滤**(比如过滤涉政人物 + 形象),不在黑名单里的人物照片**自动通过、直接进入生成**,不做强制 + 人工预审。风险兜底靠两层: + 1. 后台运营发现问题内容可以随时手工下架(第 6.5 节播放管理)。 + 2. 新人物内容本身生命周期短——播完购买的那几个 10 秒片段就自动下线 + (第 3.3 节第 7 点),把"有问题内容能公开曝光多久"这个风险窗口 + 天然限制住了,不需要靠"生成前卡审核"来兜底。 +- 无论哪种模式,最终生成内容仍会过 H3 Console / fal.ai 自身的生成时 + 安全策略兜底(`docs/done` 2.7 已有此保底),是最后一道防线,不是 + 唯一防线。 +- 人脸识别黑名单模型具体选型待定,见第 8 节。 + +### 5.1 年龄确认与免责声明(已确认) + +- `dance.html` 涉及付费、真人照片上传、可能包含泳装等服饰分类,且对外 + 公开——进入前要求勾选"我已满18岁"确认框 + 展示免责声明。基础年龄 + 确认,不做第三方实名认证(成本更高,暂不需要,见第 8 节留作后续 + 评估项)。 +- 免费模式一是否也要挂这道确认,还是只在涉及付费/传人操作时弹出: + 建议统一放在 `dance.html` 首次进入时做一次性确认(跟现有 `live.html` + 首次进聊天框弹昵称框的交互套路一致,见 `docs/done` 2.5 节),而不是 + 每个操作都弹一次。 + +## 6. 后台资产管理需求 + +在现有 `admin.html`(v1 素材表格)基础上,新增几类资产的管理页面/模块, +保持同一套"表格 + 行内编辑 + 新增表单"交互风格。 + +### 6.1 人物图片管理 + +- CRUD:上传人物参考图、命名、打标签、设为"直播默认人物"。 +- 来源区分:`admin_seed`(后台预置/冷启动批量生成) vs + `user_paid`(模式三付费上传)。`user_paid` 来源不进入"系统随机挑选 + 免费用户默认人物"的池子(3.3 节第 6 点),但需要能在后台看到、关联到 + 付费用户、追踪其"剩余可播 10 秒片段数"。 +- 「设为直播默认人物」开关:模式一/二里"系统指定"的人物来源于此。 + **第一期只允许同时有一个人物被设为默认**(2 节已确认,不做多人物 + 轮换),开关设计上仍按"列表 + 单选"做,方便以后放开多选/轮换不用 + 改数据模型。 + +### 6.2 衣服物品管理 + +- CRUD:上传衣服图、命名、分类/标签、缩略图、上下架开关。 +- 来源区分:`admin_seed` vs `user_paid`(模式二上传,审核通过后默认 + 沉淀进公共库,3.2 节第 3 点)。 + +### 6.3 参考跳舞视频/音乐管理 + +- CRUD:上传参考跳舞视频(含配乐),命名、风格标签、时长、上下架开关。 +- 版权来源字段:当前**先用测试素材占位**(正式版权素材待确认,见第 8 + 节),后台需要能记录/后续批量替换。 + +### 6.4 生成后的视频管理 + +- 扩展现有 `admin.html` 素材表格:新增 `characterId`/`garmentId`/ + `composedImageId`(可点开看 Stage1 合成图)/`refDanceVideoId` 列, + 追溯"谁的脸 + 谁的衣服 + 哪条参考跳舞视频"生成的。 +- 人工下架/加精;批量删除入口。 + +### 6.5 播放管理 + +- 插播/置顶下一条、手动跳过当前、暂停自动填充、拉黑某个用户/资产(对接 + 第 5 节的人工兜底手段)。 + +## 7. 用户体系与积分(已确认) + +### 7.1 用户注册 + +- 起步方式:**邮箱登录**(账号+邮箱验证)。 +- 后续迭代:加 **Google / Apple / GitHub** 三方登录。 +- 现有 `viewer_uid`/`viewer_nickname` cookie 身份平滑绑定到账号,历史 + 投票/点播记录不丢(沿用 `docs/structure/architecture.md` 2.4 节的 + 过渡方案)。 + +### 7.2 积分模型 + +- **充值 → 通用积分池**,而不是"充值金额直接换算成固定数量的 10 秒 + 片段"——积分是通用货币,未来别的付费场景(比如优先排队)也能复用 + 同一套机制,跟原始需求里"未来消耗积分限制生成频率/质量"的说法一致。 +- **计费边界(已确认)**: + - 使用已有资产库(衣柜里选衣服、系统默认人物)—— **免费,不扣积分**。 + - 新增资产(模式二付费传衣服、模式三付费传人物)—— **消耗积分**。 + - 新增人物额外规则:消耗的积分数量决定该角色可播放的 10 秒片段数 + (3.3 节第 3、7 点);片段播完后角色下线但记录保留,用户可再充值 + 续播而不需要重新生成。 +- 具体每次操作扣多少积分、充值档位等数值,还没定(不阻塞开发,先把 + 余额+流水+配置化扣费额这套机制打好,数值上线前再定,见第 8 节)。 +- 失败退还:Stage1/Stage2 任一环节失败,已扣积分必须退还,不能出现 + "扣了积分但没生成成功也不退"的黑洞。 + +### 7.3 充值支付渠道(机制已定,具体渠道待定) + +- 初步倾向 **Stripe**,但具体接哪家先不锁死——积分系统本身设计成 + "内部余额+流水",支付渠道只是"给余额充值"的一个外部入口,换渠道 + 不影响积分模型本身。 +- ⚠️ **需要提醒的风险点**:Stripe 对中国大陆发卡的信用卡/本地支付方式 + 支持有限(合规和可用性都有限制)。如果这个直播间的目标观众以国内 + 用户为主(现有 `live.html`/`admin.html` UI 全是中文,产品语言明显 + 面向国内),大概率还需要**同时接入支付宝/微信支付**才能覆盖主力 + 用户的实际支付习惯,不能只上 Stripe。这一点建议在真正开发充值流程 + 前明确一下目标用户地域,见第 8 节。 + +### 7.4 个人中心「我的作品」(已确认) + +- 付费生成的内容(模式二上传的衣服、模式三的新人物及其视频),即使 + 已经从直播排播/复用池下线(3.3 节第 7 点"到期处理"),用户仍要能在 + 自己的账号下单独查看/回放——不是"下线=消失",只是"下线=不再出现在 + 公开直播间和其他人的衣柜/随机池里"。 +- 数据模型含义:生成的视频/换装图/人物记录要挂在 `userId` 下长期可查, + 和"是否还在直播池中"是两个独立的状态维度(呼应 + `docs/structure/architecture.md` 2.7 节"人物生命周期"里提到的 + `status: active|expired` 设计,这里进一步要求 `expired` 状态下这些 + 记录依然可被拥有者检索,不是软删除后就不可访问)。 +- 具体页面/交互(列表、是否能重新分享到直播间等)留到对应分期再细化, + 这里只确认"数据要保留、要能查"这个底线。 + +## 8. 待验证事项(不是产品决策分歧,是需要技术验证/调研才能定的点) + +1. **Stage1 换装模型具体选型**:fal.ai 平台上有哪些图片编辑/换装类 + 模型适合"人物+服装 → 换装图"这个场景,需要小范围测试几个人物+衣服 + 组合,比较一致性/速度/成本后再定。 +2. **H3 Console `reference_video_urls` 实测**:`H3-CONSOLE.md` 里这个 + 字段目前"未实测,仅从控制台 UI tab 推断存在",Stage2 落地前第一步 + 要用真实调用验证这条路径是否按预期工作。 +3. **参考跳舞视频/配乐正式素材来源**:目前先用测试素材占位,正式版权 + 素材(自制还是购买授权)待确认,后台字段已预留(6.3 节)。 +4. **人脸识别黑名单模型选型**:用什么模型/服务做"涉政等敏感人物"识别 + 过滤,需要调研候选方案。 +5. **积分具体数值**:充值档位、每次新增衣服/新增人物扣多少积分、新 + 人物每个 10 秒片段的积分单价——机制已定(7.2 节),数值上线前再定。 +6. **支付网关选型**:初步倾向 Stripe,但需要先确认目标观众地域——若 + 以国内用户为主,大概率要同时/改为接入支付宝/微信支付(7.3 节), + 这一点建议尽早拍板,避免影响充值流程的开发方向。 +7. **"我的作品"页面的第三方实名认证需求**:第一期只做"我已满18岁" + 勾选式确认(5.1 节),是否需要更严格的第三方实名认证,看实际运营 + 风险再评估,不预设一定要做。 + +## 9. 分期建议(不是承诺的排期,是依赖顺序参考) + +1. **第一期**:后台先把「人物库 / 衣服库 / 参考跳舞视频库」CRUD 模块 + 搭出来,用内部 H3 Console 批量跑冷启动种子内容(4.3 节),验证 + Stage1→Stage2 全流水线可行性(不接入付费/审核/账号)。 +2. **第二期**:`dance.html` 上线(含首次进入的年龄确认+免责声明,5.1 + 节),接入「衣柜选衣服」免费模式(3.1 节)+ 相同人物+衣服组合去重 + 缓存(4.6 节),复用现有排播队列基础设施(此阶段全部免费内容仍按 + v1 投票排序,还不涉及"付费插队"这条新规则)。 +3. **第三期**:用户注册体系上线(邮箱登录),把匿名 cookie 身份绑定 + 到账号——账号是后面付费功能的前提,必须先落地。 +4. **第四期**:积分体系(余额/流水/配置化扣费)+ 充值支付渠道接入 + (7.3 节,先确认目标地域再选具体渠道),先上线免费换衣服 + 付费 + 传衣服(模式二),验证扣费/退还/公共库沉淀链路。 +5. **第五期**:付费传人物(模式三)+ 自动人脸黑名单审核 + "购买 10 秒 + 片段数 / 到期下线 / 续播"这套人物生命周期管理 + 排播优先级改造(付费 + 新人物插队播放,见 3 节"共同后置流程")+ 个人中心"我的作品"页面 + (7.4 节),接入 fal.ai 实时算力路径(4.3 节)。 -- libgit2 0.21.4