# 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`(文生视频,480x832 竖屏/ 120帧/20步——第一期默认横屏 832x480,后改为竖屏移动端优先,见 commit `1dc7084`)异步生成,`status: generating`,生成完成后自动 写入 `library.json` 并推入待播队列(`status: ready`)。存量片段 保留生成时的原比例,播放器 `object-fit: contain` 兼容混合比例。 - 生成是完全后台化的(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": 480, "height": 832, // 当前默认竖屏;早期/存量片段可能是 832x480 横屏 "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` 之外的路径调用过)。 - 无人工审核队列,内容一旦生成完成即自动排入公开播放,无「先审后播」 开关。 - 无任何鉴权,管理后台和写接口都是「网络可达即可操作」。