diff --git a/.codex/skills/gpt-image-2-apimart/SKILL.md b/.codex/skills/gpt-image-2-apimart/SKILL.md index d9e8aae6..2cc40454 100644 --- a/.codex/skills/gpt-image-2-apimart/SKILL.md +++ b/.codex/skills/gpt-image-2-apimart/SKILL.md @@ -47,7 +47,7 @@ Default body: } ``` -For a reference image, add: +For weak visual references in text-to-image generation, add: ```json { @@ -55,6 +55,26 @@ For a reference image, add: } ``` +For image-to-image work that must follow a reference image closely, use the VectorEngine edits endpoint instead of the generations `image` array: + +```text +POST {VECTOR_ENGINE_BASE_URL}/v1/images/edits +Authorization: Bearer {VECTOR_ENGINE_API_KEY} +Content-Type: multipart/form-data +``` + +Multipart fields: + +```text +model=gpt-image-2 +prompt= +n=1 +size=1024x1024 +image=@reference.png +``` + +Prefer edits for workflows where the reference image controls composition, pose, container shape, or layout. In this repository, Match3D container UI generation uses edits with `public/match3d-background-references/pot-fused-reference.png` as the `image` part. + Accept image output from `data[].url`, `data[].b64_json`, or direct nested `url` fields. VectorEngine GPT-image-2-all currently returns synchronously; do not poll APIMart task endpoints. ## Environment diff --git a/.env.example b/.env.example index 482669b7..d2cfd6e6 100644 --- a/.env.example +++ b/.env.example @@ -122,7 +122,7 @@ RPG_LLM_WEB_SEARCH_ENABLED="true" DASHSCOPE_BASE_URL="https://dashscope.aliyuncs.com/api/v1" DASHSCOPE_API_KEY="YOUR_DASHSCOPE_API_KEY" -# Server-side APIMart image generation config for optional puzzle image models. +# APIMart Responses config for creative-agent text/multimodal understanding. APIMART_BASE_URL="https://api.apimart.ai/v1" APIMART_API_KEY="YOUR_APIMART_API_KEY" APIMART_IMAGE_REQUEST_TIMEOUT_MS="180000" diff --git a/.hermes/shared-memory/decision-log.md b/.hermes/shared-memory/decision-log.md index 47a5110c..a1e3629b 100644 --- a/.hermes/shared-memory/decision-log.md +++ b/.hermes/shared-memory/decision-log.md @@ -16,14 +16,38 @@ --- -## 2026-05-14 抓大鹅物品素材 sheet 改用 APIMart nanobanana +## 2026-05-14 抓大鹅物品素材批量重新生成复用 item-assets 替换模式 -- 背景:抓大鹅 2D 五视角物品素材仍沿用 5x5 sheet、绿幕去背、切图、OSS 转存和 `generatedItemAssets` 持久化,但用户要求物品素材图片生成步骤改用 APIMart 已接好的 nanobanana / Gemini 图片模型。 -- 决策:抓大鹅物品素材 sheet 生图固定走 APIMart `POST {APIMART_BASE_URL}/images/generations`,模型为 `gemini-3.1-flash-image-preview`,`size = 1:1`,`resolution = 1K`,`official_fallback = true`;响应优先读图片 URL 或 base64,缺图片时按 `task_id` 轮询 `/tasks/{task_id}`。封面、9:16 纯背景图、1:1 容器 UI 图、音频、切图、OSS、扣费和运行态消费链路保持不变。 -- 影响范围:`server-rs/crates/api-server/src/match3d.rs`、`server-rs/crates/api-server/src/config.rs`、`deploy/env/api-server.env.example`、抓大鹅素材生成技术文档。 -- 验证方式:执行 `cargo test -p api-server match3d_material_sheet --manifest-path server-rs\Cargo.toml`、`cargo test -p api-server from_env_reads_non_public_models_and_urls --manifest-path server-rs\Cargo.toml`、`cargo check -p api-server --manifest-path server-rs\Cargo.toml`、`npm run check:encoding`。 +- 背景:抓大鹅结果页 `素材配置 > 物品` 需要在不改变玩法物品映射的前提下,批量重新生成已存在物品的 2D 五视角图片。 +- 决策:继续复用 `POST /api/creation/match3d/works/{profileId}/item-assets`,请求体通过 `mode = "replace"` 表达替换模式;前端面板预填当前素材名称,只提交仍能匹配到已有素材的名称。后端只替换匹配素材的 `imageSrc/imageObjectKey/imageViews/status/error`,保留原 `itemId`、列表顺序、模型兼容字段、UI 背景、历史背景音乐和点击音效字段;未匹配名称不计费、不新增、不持久化。 +- 影响范围:Match3D 结果页素材配置、前端/后端 shared contracts、`api-server` Match3D item-assets 编排、运行态物品类型映射和素材生成技术文档。 +- 验证方式:执行 `npm run test -- src/components/match3d-result/Match3DResultView.test.tsx`、`cargo test -p api-server match3d_item_asset --manifest-path server-rs\Cargo.toml`、`cargo test -p api-server match3d_regenerated_asset --manifest-path server-rs\Cargo.toml`、`npm run check:encoding`。 - 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`。 +## 2026-05-14 拼图与抓大鹅音频生成入口临时关闭 + +- 背景:当前需要暂时关闭抓大鹅、拼图中生成背景音乐和音效的能力,并隐藏草稿中的相关入口。 +- 决策:拼图 `compile_puzzle_draft` 不再自动生成背景音乐,结果页素材配置只保留 `UI`;抓大鹅 `match3d_compile_draft` 和批量新增只生成 2D 图片、背景和容器 UI,不再调用 Suno/Vidu,结果页隐藏 `背景音乐` 子 Tab 与点击音效生成控件;通用 `/api/creation/audio/*` 当前整体返回 `410 Gone`。历史已写入的 `backgroundMusic` / `clickSound` 字段保留,运行态继续兼容播放旧音频。 +- 影响范围:`api-server` 拼图/抓大鹅草稿编排、通用创作音频路由、拼图/抓大鹅结果页、生成进度模型、相关技术文档。 +- 验证方式:执行拼图/抓大鹅结果页定向测试、生成进度单测、`cargo check -p api-server --manifest-path server-rs/Cargo.toml` 和 `npm run check:encoding`。 +- 关联文档:`docs/technical/PUZZLE_MATCH3D_RESULT_AUDIO_TAB_2026-05-11.md`、`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`。 + +## 2026-05-14 抓大鹅物品素材 sheet 改用 VectorEngine Gemini + +- 背景:抓大鹅 2D 五视角物品素材仍沿用 5x5 sheet、绿幕去背、切图、OSS 转存和 `generatedItemAssets` 持久化,但用户要求物品素材图片生成步骤改用 VectorEngine Apifox `api-381740608` 对应的 Gemini 原生图片接口。 +- 决策:抓大鹅物品素材 sheet 生图固定走 VectorEngine `POST {VECTOR_ENGINE_BASE_URL}/v1beta/models/gemini-3-pro-image-preview:generateContent?key={VECTOR_ENGINE_API_KEY}`,请求体使用 `contents[].parts[].text` 与 `generationConfig.responseModalities = ["TEXT", "IMAGE"]`、`imageConfig.aspectRatio = "1:1"`;响应从 `candidates[].content.parts[].inlineData.data` / `inline_data.data` 读取 base64 图片。封面、9:16 纯背景图、1:1 容器 UI 图、切图、OSS、扣费和运行态消费链路保持不变;音频以后续“拼图与抓大鹅音频生成入口临时关闭”决策为准。 +- 影响范围:`server-rs/crates/api-server/src/match3d.rs`、`server-rs/crates/api-server/src/config.rs`、`deploy/env/api-server.env.example`、抓大鹅素材生成技术文档。 +- 验证方式:执行 `cargo test -p api-server match3d_material_sheet --manifest-path server-rs\Cargo.toml`、`cargo test -p api-server match3d_vector_engine_gemini --manifest-path server-rs\Cargo.toml`、`cargo check -p api-server --manifest-path server-rs\Cargo.toml`、`npm run check:encoding`。 +- 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`。 + +## 2026-05-14 草稿页作品卡对齐分类页列表 + +- 背景:草稿页作品架原本偏封面大卡片,和发现页分类列表的横向卡片样式不一致;生成中状态也缺少整卡级的统一遮罩。 +- 决策:草稿页作品卡统一收口为与分类页一致的横向列表卡结构,左侧承载标题/状态/类型/摘要与必要数据,右侧显示带透明度的封面图;移动端保持单列列表,网页端使用两到三列卡片式网格,避免宽屏长条列表。不再常驻“继续创作”“查看详情”“查看进度”等右侧动作按钮。原有删除、分享、积分激励、公开统计、未读红点全部保留,其中删除与分享进入左滑操作层,常态不显示删除按钮,也不得透出删除底层。生成中的作品在整卡上加半透明蒙版、旋转等待符号和“生成中...”标识,但不移除任何原有信息。 +- 影响范围:`src/components/custom-world-home/CustomWorldCreationHub.tsx`、`src/components/custom-world-home/CustomWorldWorkCard.tsx`、相关样式与测试、草稿页 UI 文档。 +- 验证方式:草稿页作品卡与分类页列表视觉口径保持一致;`npm run test -- src/components/custom-world-home/CustomWorldCreationHub.test.tsx src/components/custom-world-home/CustomWorldCreationHub.interaction.test.tsx`、`npm run typecheck`、`npm run check:encoding`。 +- 关联文档:`docs/design/MOBILE_CREATION_WORK_LIST_TWO_COLUMN_LAYOUT_2026-04-29.md`、`docs/experience/MOBILE_UI_DEV_EXPERIENCE.md`。 + ## 2026-05-13 认证运行期同步直接导入正式认证表 - 背景:`auth_store_snapshot` 是 Stage 1 整包快照过渡表,主键固定 `default`,会让所有用户状态集中在一条 `snapshot_json` 中;Stage 2/3 已有 `user_account/auth_identity/refresh_session` 正式认证表,继续刷新 `default` 容易让运行时真相和表拆分目标混在一起。 @@ -82,8 +106,8 @@ ## 2026-05-12 抓大鹅结果页素材编辑统一走作品级资产面板 -- 背景:抓大鹅结果页需要支持碰面图上传 / AI 重绘、物品素材独立预览、单项删除和批量新增,且不能把素材编辑继续做成列表内联展开或前端临时状态。 -- 决策:结果页 `作品信息` 的碰面图点击打开独立面板,参考图可来自本地上传、物品素材和 UI 素材;AI 重绘统一调用 `POST /api/creation/match3d/works/{profileId}/cover-image` 并转存到 `generated-match3d-assets`。`素材配置 > 物品` 列表项点击打开独立预览面板,不再提供单项重新生成按钮;单项删除和批量新增都写回同一份 `generated_item_assets_json`。批量新增调用 `POST /api/creation/match3d/works/{profileId}/item-assets`,复用草稿生成的 2D 素材图、5x5 切图、OSS 上传和可选点击音效链路,仅作用于新增物品,不新增 SpacetimeDB 表。 +- 背景:抓大鹅结果页需要支持封面图上传 / AI 重绘、物品素材独立预览、单项删除和批量新增,且不能把素材编辑继续做成列表内联展开或前端临时状态。 +- 决策:结果页 `作品信息` 的封面图点击打开独立面板,封面图面板对齐拼图入口上传卡。已有上传主图时,请求体传 `uploadedImageSrc`,AI 重绘走 VectorEngine `/v1/images/edits`;关闭 AI 重绘时只写回上传图,不调用生图。没有上传主图时,请求体传 `referenceImageSrcs`,可混合本地上传、物品素材和 UI 素材,多参考图作为 `gpt-image-2-all` generations 的 `image` 数组传入。生成结果统一调用 `POST /api/creation/match3d/works/{profileId}/cover-image` 并转存到 `generated-match3d-assets`。`素材配置 > 物品` 列表项点击打开独立预览面板,不再提供单项重新生成按钮;单项删除和批量新增都写回同一份 `generated_item_assets_json`。批量新增调用 `POST /api/creation/match3d/works/{profileId}/item-assets`,复用草稿生成的 2D 素材图、5x5 切图、OSS 上传和可选点击音效链路,仅作用于新增物品,不新增 SpacetimeDB 表。 - 影响范围:Match3D 结果页、Match3D works shared contracts、`api-server` Match3D 作品路由、生成资产历史类型和草稿恢复路径。 - 验证方式:执行 `npm run test -- src/components/match3d-result/Match3DResultView.test.tsx`、`npm run typecheck`、`cargo test -p api-server match3d --manifest-path server-rs/Cargo.toml`、`cargo check -p api-server --manifest-path server-rs/Cargo.toml`、`npm run check:encoding`。 - 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`。 @@ -136,6 +160,14 @@ - 验证方式:执行入口配置、创作 Hub 和平台入口交互定向测试,确认看不到“方洞挑战” Tab、按钮和作品架条目。 - 关联文档:`docs/technical/NEW_WORK_ENTRY_CONFIG_2026-05-01.md`、`docs/design/PLATFORM_CREATE_TAB_CREATIVE_AGENT_HOME_2026-05-05.md`。 +## 2026-05-14 视觉小说从创作页入口隐藏 + +- 背景:当前创作页需要关闭视觉小说模板入口,不能继续在模板 Tab、旧选择弹层或创作 Hub 卡片中展示。 +- 决策:SpacetimeDB `creation_entry_type_config` 默认种子中 `visual-novel.visible=false` 且 `open=false`;旧默认可见配置会被迁移为隐藏和关闭。前端继续只消费 `GET /api/creation-entry/config`,不得用硬编码恢复视觉小说模板入口。 +- 影响范围:SpacetimeDB 入口配置默认种子、api-server 测试配置、创作页模板 Tab、创作 Hub 测试和创作入口文档。 +- 验证方式:执行入口配置、创作 Hub、平台入口交互和 api-server 路由熔断定向测试,确认“视觉小说”不出现在创作页且 `/api/creation/visual-novel/*` 默认被熔断。 +- 关联文档:`docs/design/PLATFORM_CREATE_TAB_CREATIVE_AGENT_HOME_2026-05-05.md`、`docs/technical/ADMIN_CREATION_ENTRY_SWITCH_CONFIG_2026-05-11.md`。 + ## 2026-05-10 运行态输入设备抽象层全项目通用化 - 背景:拼图运行态接入 mocap 后,鼠标/触控和 mocap 各自维护输入逻辑会导致合并大块、拖拽语义和取消会话行为不一致;后续其他玩法也需要复用体感、摇杆、键盘等设备输入。 @@ -147,7 +179,7 @@ ## 2026-05-11 前端调试模式统一判断 - 背景:拼图 mocap 调试面板此前在运行态常驻展示,生产构建和正式体验里容易遮挡棋盘内容;后续其它局部诊断 UI 也需要统一的调试模式入口。 -- 决策:前端新增 `src/config/debugMode.ts` 作为全局调试模式判断,默认跟随 Vite 开发态,允许 `VITE_DEBUG_MODE=true/false` 显式覆盖。拼图运行态 mocap 调试面板只在调试模式下渲染,并默认折叠,只保留连接状态行。 +- 决策:前端新增 `src/config/debugMode.ts` 作为全局调试模式判断,默认跟随 Vite 开发态,允许 `VITE_DEBUG_MODE=true/false` 显式覆盖。2026-05-14 起,拼图运行态已临时移除 mocap 调用、体感光标和 mocap 调试面板;调试模式仍供其它局部诊断 UI 使用。 - 影响范围:前端局部调试 UI、拼图运行态 mocap 诊断面板、`.env.example` 和运行态输入技术文档。 - 验证方式:执行 `npm run test -- src\components\puzzle-runtime\PuzzleRuntimeShell.test.tsx`、`npm run typecheck` 和编码检查。 - 关联文档:`docs/technical/RUNTIME_INPUT_DEVICE_ABSTRACTION_2026-05-10.md`。 diff --git a/.hermes/shared-memory/pitfalls.md b/.hermes/shared-memory/pitfalls.md index 5be6e6a2..f811624b 100644 --- a/.hermes/shared-memory/pitfalls.md +++ b/.hermes/shared-memory/pitfalls.md @@ -14,6 +14,14 @@ - 关联:相关文件、文档、提交或 Issue ``` +## 抓大鹅批量重新生成物品不要新增 itemId + +- 现象:结果页批量重新生成物品后,试玩或正式运行态的物品类型和图片对应关系漂移,或者用户输入一个不存在名称后被当作新物品追加。 +- 原因:重新生成和批量新增共用 `item-assets` 接口,如果前端不传 `mode = "replace"`,或后端替换时重新分配 `itemId` / 追加未匹配名称,就会破坏 `generatedItemAssets` 顺序和运行态类型映射。 +- 处理:批量重新生成只提交当前素材列表中能匹配到的名称,并传 `mode = "replace"`;后端只对同名已有素材生成新图片,合并时保留原 `itemId`、`itemName`、模型兼容字段、UI 背景和历史音频字段,未匹配名称直接忽略且不计费。 +- 验证:`npm run test -- src\components\match3d-result\Match3DResultView.test.tsx` 覆盖前端提交口径,`cargo test -p api-server match3d_item_asset --manifest-path server-rs\Cargo.toml` 和 `cargo test -p api-server match3d_regenerated_asset --manifest-path server-rs\Cargo.toml` 覆盖后端替换计划与身份保留。 +- 关联:`src/components/match3d-result/Match3DResultView.tsx`、`server-rs/crates/api-server/src/match3d.rs`、`packages/shared/src/contracts/match3dWorks.ts`、`server-rs/crates/shared-contracts/src/match3d_works.rs`、`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`。 + ## OSS V4 签名时间和 bucket/object_key 兼容 - 现象:OSS V4 私有读签名在部分时间点失败,可能出现 `OSS V4 签名时间格式化失败` 或服务端判定签名格式错误;排查用例中 bucket 为 `xushi-dev`,object_key 为 `generated-square-hole-assets/.../image.png`。 @@ -67,7 +75,7 @@ - 验证:`npm run test -- src/services/apiClient.test.ts` 覆盖 `details.reason`;`cargo test -p api-server state --manifest-path server-rs/Cargo.toml` 覆盖半配置 OSS 不阻断启动;`npm run api-server` 后按实际 `GENARRATIVE_API_PORT` 请求 `/healthz`,不要默认打 `3100`。 - 关联:`packages/shared/src/http.ts`、`server-rs/crates/api-server/src/state.rs`、`docs/technical/API_SERVER_EXTERNAL_SERVICE_ENV_CONFIG_2026-05-07.md`、`docs/technical/AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md`。 -2026-05-14 补充:抓大鹅“物品素材 sheet”已改用 APIMart `gemini-3.1-flash-image-preview`,真实生成还需要 `APIMART_BASE_URL`、`APIMART_API_KEY` 和 `APIMART_IMAGE_REQUEST_TIMEOUT_MS`;封面、背景图和容器 UI 仍继续使用 VectorEngine。排查时先按失败阶段区分缺 APIMart、VectorEngine 还是 OSS,不能把物品素材缺 APIMart 误判成 VectorEngine 缺配置。 +2026-05-14 补充:抓大鹅“物品素材 sheet”已改用 VectorEngine Gemini `gemini-3-pro-image-preview` 原生 `generateContent`,真实生成读取 `VECTOR_ENGINE_BASE_URL`、`VECTOR_ENGINE_API_KEY` 和 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS`;封面和 `9:16` 背景图走 VectorEngine `/v1/images/generations`,`1:1` 容器 UI 走 VectorEngine `/v1/images/edits` multipart 参考图链路。排查素材 sheet 时看请求路径是否为 `/v1beta/models/gemini-3-pro-image-preview:generateContent?key=...`,响应图片在 `candidates[].content.parts[].inlineData.data` / `inline_data.data`,不要再按 APIMart `/images/generations` 或 `/tasks/{task_id}` 排查。 ## `.hermes` 只放共享内容,不放个人 Hermes 配置 @@ -150,13 +158,13 @@ - 验证:`curl -i -X POST https://api.vectorengine.ai/v1/images/edits -H "Authorization: Bearer invalid" -F "model=gpt-image-2-all" -F "prompt=test" -F "n=1" -F "size=1024x1024"` 至少应返回 HTTP `401`,说明域名、TLS 和路径可达;执行 `cargo test -p api-server puzzle_vector_engine --manifest-path server-rs/Cargo.toml`。 - 关联:`server-rs/crates/api-server/src/puzzle.rs`、`docs/technical/VECTOR_ENGINE_GPT_IMAGE_2_GENERATION_2026-05-09.md`、`docs/technical/API_SERVER_EXTERNAL_SERVICE_ENV_CONFIG_2026-05-07.md`。 -## 拼图自动试玩缺 UI 背景先查本地运行态字段继承 +## 拼图 UI 背景缺失先区分生成失败和消费链路丢字段 -- 现象:拼图草稿生成完成后,草稿数据里已有首关 `uiBackgroundImageSrc`,结果页素材配置也能看到背景图,但自动试玩或结果页“试玩”进入局内仍只显示封面模糊背景,甚至看不到 UI 背景。 -- 原因:生成完成后的自动试玩走前端 `startLocalPuzzleRun(...)` 本地运行态兜底,不经过后端 `start_puzzle_run`;如果本地 run 只把 `coverImageSrc` 带入 `currentLevel`,就会丢掉 `levels[].uiBackgroundImageSrc` 和 `levels[].backgroundMusic`。 -- 处理:`startLocalPuzzleRun` 与本地下一关 handoff 都要从关卡 `levels[]` 复制 `uiBackgroundImageSrc`、`backgroundMusic` 到 `currentLevel`;`PuzzleRuntimeShell` 继续读取 `currentLevel.uiBackgroundImageSrc` 渲染全屏背景。 -- 验证:`npm run test -- src/services/puzzle-runtime/puzzleLocalRuntime.test.ts src/components/puzzle-runtime/PuzzleRuntimeShell.test.tsx src/components/puzzle-result/PuzzleResultView.test.tsx`。 -- 关联:`src/services/puzzle-runtime/puzzleLocalRuntime.ts`、`src/components/puzzle-runtime/PuzzleRuntimeShell.tsx`、`src/components/puzzle-result/PuzzleResultView.tsx`、`docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md`。 +- 现象:拼图草稿生成完成后,素材配置页没有展示生成的 UI 背景,或结果页能看到背景但自动试玩 / 结果页“试玩”进入局内仍只显示封面模糊背景。 +- 原因:`compile_puzzle_draft` 设计上会在首图后生成 UI 背景,且缺 `uiBackgroundImageSrc/uiBackgroundImageObjectKey` 会让自动草稿失败;若草稿已成功,通常不是“没生成”,而是前端消费链路漏了 `levels[].uiBackgroundImageObjectKey` 回退,或本地 `startLocalPuzzleRun(...)` 只把 `coverImageSrc` 带入 `currentLevel`。 +- 处理:结果页预览、运行态和本地运行态统一用 `resolvePuzzleUiBackgroundSource`,优先 `uiBackgroundImageSrc`,为空时把 `uiBackgroundImageObjectKey` 规范成 `/generated-...` 路径并交给 `/api/assets/read-url` 换签;`startLocalPuzzleRun` 与本地下一关 handoff 都要从 `PuzzleWorkSummary.levels[]` 复制 `uiBackgroundImageSrc/uiBackgroundImageObjectKey/backgroundMusic` 到 `currentLevel`。结果页 `UI背景提示词` 输入框不得把本地兜底 prompt 直接显示成已保存提示词,避免误判为后端已生成。 +- 验证:`npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx src/services/puzzle-runtime/puzzleLocalRuntime.test.ts src/components/puzzle-runtime/PuzzleRuntimeShell.test.tsx`,以及 `npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "puzzle draft generation auto starts trial"`;后端用 `cargo test -p api-server puzzle_ui_background --manifest-path server-rs\Cargo.toml` 确认生成 / 序列化链路。 +- 关联:`src/services/puzzle-runtime/puzzleUiBackgroundSource.ts`、`src/services/puzzle-runtime/puzzleLocalRuntime.ts`、`src/components/puzzle-runtime/PuzzleRuntimeShell.tsx`、`src/components/puzzle-result/PuzzleResultView.tsx`、`docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md`。 ## 拼图草稿生成后音乐/UI 又变空先查结果页回包合并 @@ -182,6 +190,14 @@ - 验证:运行 `npm run test -- src/services/creation-agent/creationAgentClientFactory.test.ts src/services/apiClient.test.ts`、`cargo test -p api-server puzzle_vector_engine --manifest-path server-rs/Cargo.toml`,真实联调重启 `npm run api-server` 后检查 `/healthz`。 - 关联:`src/services/creation-agent/creationAgentClientFactory.ts`、`server-rs/crates/api-server/src/puzzle.rs`、`docs/technical/API_SERVER_EXTERNAL_SERVICE_ENV_CONFIG_2026-05-07.md`。 +## 本地脚本调 VectorEngine 生图卡住先区分 fetch 首部超时 + +- 现象:用 Node `fetch` 直接请求 `POST /v1/images/generations`,已经设置较长的 AbortController 超时,但仍在约 180 到 300 秒后抛 `AbortError`、`TypeError: fetch failed` 或 `UND_ERR_HEADERS_TIMEOUT`;同一 prompt 改用原生 `https.request` 可以在较短时间内成功返回图片。 +- 原因:Node/Undici 的默认 headers timeout 可能早于业务脚本期望的长生图等待窗口触发,表现上容易被误判成 VectorEngine 上游本身超时。 +- 处理:长期脚本优先复用后端 reqwest 或项目已有生成脚本;临时本地工具若必须用 Node,可改用原生 `http`/`https.request` 并显式设置 socket timeout,或为 Undici 单独配置 headers timeout。仍需隐藏 `VECTOR_ENGINE_API_KEY`,只报告配置是否存在。 +- 验证:同一 `gpt-image-2-all` 请求体、同一环境变量下,原生 HTTP 请求能返回 `url` / `b64_json` 并落盘;失败时错误里能区分请求发送、首部等待、下载和解码阶段。 +- 关联:`.codex/skills/gpt-image-2-apimart/SKILL.md`、`server-rs/crates/api-server/src/openai_image_generation.rs`。 + ## 旧后端路线文档造成判断漂移 - 现象:开发时参考到 Express、Node、PostgreSQL 或 Go 方向旧文档,导致接口、数据真相或部署路径与当前主线不一致。 @@ -591,6 +607,22 @@ - 验证:执行 `npm run test -- src/components/match3d-result/Match3DResultView.test.tsx`、`npm run test -- src/components/match3d-runtime/Match3DRuntimeShell.test.tsx`、`npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx`,并检查历史草稿和公开 M3 作品的 Network 响应里 `generatedItemAssets[].imageViews/imageSrc/imageObjectKey`。 - 关联:`src/components/match3d-result/Match3DResultView.tsx`、`src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`、`src/components/match3d-runtime/Match3DPhysicsBoard.tsx`、`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`。 +## 抓大鹅 UI 背景和容器只在顶层字段时也要传进运行态 + +- 现象:抓大鹅草稿 / 推荐卡片响应里已有 `generatedBackgroundAsset`,结果页 UI 预览能看到纯背景图和容器图,但进入试玩或正式局内仍显示默认渐变背景和默认圆形容器。 +- 原因:部分链路把 UI 资产只放在作品顶层 `generatedBackgroundAsset` / `backgroundImageObjectKey`,没有同步放进首个 `generatedItemAssets[].backgroundAsset`;如果运行态入口只传 `generatedItemAssets` 和 `backgroundImageSrc`,`Match3DRuntimeShell` 就拿不到 `containerImageObjectKey`。 +- 处理:`PlatformMatch3DGalleryCard`、`mapPublicWorkDetailToMatch3DWork`、`resolveMatch3DRuntimeGeneratedBackgroundAsset` 和 `Match3DRuntimeShell` 都必须保留并传递顶层 `generatedBackgroundAsset`;运行态背景读取顺序为 `backgroundImageSrc` / 顶层 `generatedBackgroundAsset.image*` / `generatedItemAssets[].backgroundAsset.image*`,容器读取顺序为顶层 `generatedBackgroundAsset.containerImage*` / `generatedItemAssets[].backgroundAsset.containerImage*`。 +- 验证:执行 `npm run test -- src/components/match3d-runtime/Match3DRuntimeShell.test.tsx` 和 `npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "Match3D runtime"`;浏览器 Network 中背景和容器 generated path 应先请求 `/api/assets/read-url` 换签,局内出现 `match3d-background-image` 和 `match3d-container-image` 对应图片。 +- 关联:`src/components/match3d-runtime/Match3DRuntimeShell.tsx`、`src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`、`src/components/rpg-entry/rpgEntryWorldPresentation.ts`、`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`。 + +## 抓大鹅容器参考图必须走 edits 并接管棋盘外观 + +- 现象:抓大鹅结果页看似有容器生成入口,但真实生成出的局内容器不像 `pot-fused-reference.png`,或进入试玩后仍被默认圆形锅壳、金色边框和径向底色覆盖/裁切。 +- 原因:`/v1/images/generations` 的 `image` 数组更适合弱参考文生图,难以稳定锁定大尺寸轻俯视容器构图;即使生成了容器图,如果运行态继续保留默认 `rounded-full` 锅壳和 `overflow-hidden`,生成图也会被默认视觉覆盖或裁掉。 +- 处理:抓大鹅 `1:1` 容器 UI 图必须用 VectorEngine `POST /v1/images/edits` multipart,把 `public/match3d-background-references/pot-fused-reference.png` 作为 `image` part 上传;共享 GPT-image-2 HTTP client 承载 multipart 时强制 HTTP/1.1。`Match3DRuntimeShell` 在容器图换签并成功加载后,把棋盘外壳切为透明和 `overflow-visible`,只在容器缺失或加载失败时使用默认圆形容器。 +- 验证:执行 `cargo test -p api-server vector_engine --manifest-path server-rs/Cargo.toml`、`cargo test -p api-server match3d_background --manifest-path server-rs/Cargo.toml`、`npm run test -- src/components/match3d-runtime/Match3DRuntimeShell.test.tsx src/components/match3d-result/Match3DResultView.test.tsx`;真实联调看容器生成请求是否命中 `/v1/images/edits`,局内 `match3d-container-image` 是否渲染且 `match3d-board` 不再含默认 `rounded-full`。 +- 关联:`server-rs/crates/api-server/src/openai_image_generation.rs`、`server-rs/crates/api-server/src/match3d.rs`、`src/components/match3d-runtime/Match3DRuntimeShell.tsx`、`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`。 + ## 抓大鹅结果页音频试听也要先换签 - 现象:抓大鹅草稿生成完成后,背景音乐已写在 `generatedItemAssets[0].backgroundMusic.audioSrc`,但 `素材配置 > 背景音乐` 或物品详情音效 `