Files
Genarrative/docs/experience/RPG_DRAFT_IMAGE_PARALLEL_GENERATION_2026-04-24.md
kdletters cbc27bad4a
Some checks failed
CI / verify (push) Has been cancelled
init with react+axum+spacetimedb
2026-04-26 18:06:23 +08:00

5.5 KiB
Raw Blame History

RPG 底稿图片并行生成说明 2026-04-24

背景

RPG 草稿生成进入底稿素材阶段后,角色主形象与场景幕背景图都依赖同一份结构化底稿,但二者之间没有数据依赖。旧流程先生成所有角色主形象,再生成场景背景图,导致用户需要串行等待两类图片任务。

落地约束

  1. 角色主形象与场景背景图必须在 API 编排层并行发起,且类内每个角色、每一幕背景也必须同时调用生图接口,不能只做到“角色大类”和“背景大类”并行。这里的场景背景图指 sceneChapterBlueprints[*].acts[*] 中每一幕的 backgroundImageSrc,不是世界封面图,也不是只按章节或地点生成一张图。
  2. SpacetimeDB reducer 只负责持久化操作进度和底稿写入,不承载外部 LLM / 图片生成调用。
  3. 生图前必须已经有文本设定:角色主形象使用角色对象的 visualDescription;幕背景图使用对应幕的 backgroundPromptText。缺字段时应中断并暴露底稿质量问题,不能退回 descriptionsummary 或通用兜底词直接生图。
  4. 并行分支各自基于同一份底稿副本写入素材字段,完成后只合并背景图生成产物字段,避免覆盖角色图片字段或其他草稿内容。
  5. 单个大类失败仍按原有失败语义终止底稿写入,保留“生成角色主形象失败”和“生成幕背景图失败”的进度提示。

当前实现

  • server-rs/crates/api-server/src/custom_world.rsspawn_custom_world_draft_foundation_job 中使用 tokio::join! 同时执行:
    • generate_draft_foundation_role_visuals
    • generate_draft_foundation_act_backgrounds
  • 角色分支使用 JoinSet 把所有角色主形象任务一次性投递,返回后再按角色位置写入 imageSrcgeneratedVisualAssetId
  • 背景分支使用 JoinSetsceneChapterBlueprints[*].acts[*] 的每一幕背景任务一次性投递,返回后写入 backgroundImageSrcbackgroundAssetIdgeneratedScenePromptgeneratedSceneModel
  • merge_generated_act_backgrounds 只把背景图字段合并回角色分支副本,再进入后续草稿卡编译和 SpacetimeDB 写入。
  • 幕背景 prompt 同时兼容 backgroundPromptTextscenePromptTextvisualPromptTextpromptTextimagePromptTextbackgroundPromptvisualPrompt,避免 LLM 输出字段别名导致整批背景图被误判缺失。
  • 每个角色主形象、每一幕背景图都必须独立自动重试,单项最多尝试 3 次。幕背景图允许部分成功:只要至少一幕成功,就必须保留已成功写入的 backgroundImageSrc 并继续生成草稿卡;全部幕都失败时才把素材阶段标记为“生成幕背景图失败”。
  • 图片任务仍然一次性投递,保证角色与幕背景两类任务不回退到串行编排;但真正请求上游生图服务时必须共用并发闸门。并发数由 GENARRATIVE_DRAFT_ASSET_GENERATION_MAX_CONCURRENT_REQUESTSDRAFT_ASSET_GENERATION_MAX_CONCURRENT_REQUESTS 配置,默认 4避免固定为 2 导致多角色、多幕草稿总耗时过长。
  • 幕背景图失败文案必须带第几章、第几幕和幕标题不能只显示“第1幕 / 第2幕 / 第3幕”否则多章节同名幕会被用户误认为同一失败项重复上报。
  • 中止或部分失败前必须持久化已经成功生成的部分底稿到会话 draftProfile,不能因为某个角色或某一幕失败而丢掉其它已生成的 imageSrc / generatedVisualAssetId / backgroundImageSrc / backgroundAssetId
  • 每一幕自动生图必须记录 operation、session、第几章、第几幕、sceneId、sceneName、attempt、elapsedMs 与供应商真实错误,避免再次出现只看到“生成幕背景图失败”但无法定位哪张图、哪次请求、哪个上游原因的问题。
  • 前端看到 draft_foundation operation completed 后,不能只延迟一次就读取 resultPreviewSpacetimeDB 写入、API 读模型和前端状态同步之间可能有短暂时差,必须短轮询等待结果页 profile 可用后再自动跳转到草稿页,避免卡在“底稿已整理”。
  • 前端 CharacterAnimator 对带 generatedVisualAssetId 但尚无 animationMap 的自定义角色,所有状态优先渲染生成主图;只有真正发布了动作集后才按动作帧播放,避免运行或战斗状态回落到模板 sprite。

后续注意

如果后续图片供应商出现强限流,再在网关层做队列或供应商侧限流;不要在 RPG 底稿编排层恢复逐张串行,否则会重新退化成多张图片总耗时累加。

2026-04-25 补充:开局场景也必须逐幕生成背景图

本次排查发现旧草稿合成只从 landmarks 编译 sceneChapterBlueprints,导致 camp 开局场景只有 camp.imageSrc,没有进入 sceneChapterBlueprints[*].acts[*] 的幕背景生成队列。后续实现必须遵守:

  1. camp 开局场景必须作为 sceneChapterBlueprints[0] 写入,sceneId 默认使用 camp.id,缺失时使用 camp-1
  2. camp.actBackgroundPromptTexts 必须包含 3 条逐幕画面描述,并和普通场景一样生成 acts[*].backgroundImageSrc
  3. 结果页场景目录可用场景图兜底展示旧草稿的幕缩略图,但新草稿不能只依赖兜底,必须让开局场景真实进入幕背景图生成链路。
  4. 手动同步场景资产时,必须同时更新 sceneChapterBlueprints 与兼容字段 sceneChapters,当前主链以 sceneChapterBlueprints 为准。