refactor: modularize api server assets and handlers
This commit is contained in:
@@ -4,6 +4,11 @@
|
||||
|
||||
## 文档列表
|
||||
|
||||
- [【后端架构】api-server能力模块化与生成资产Adapter总纲-2026-05-14.md](./【后端架构】api-server能力模块化与生成资产Adapter总纲-2026-05-14.md):冻结 api-server 能力模块化、生成资产 Adapter、复杂媒体链路和大 Handler 瘦身的总边界,明确多 agent 并行 owner、禁止改动范围、阶段退出条件与验证命令。
|
||||
- [【后端架构】api-server路由能力模块化执行计划-2026-05-14.md](./【后端架构】api-server路由能力模块化执行计划-2026-05-14.md):记录 app.rs 路由按 admin/auth/assets/platform/creation/runtime/profile/story 等能力迁入 modules router 的执行计划,要求 route path、method、middleware 和 handler contract 不变。
|
||||
- [【后端架构】生成图片资产Adapter收口执行计划-2026-05-14.md](./【后端架构】生成图片资产Adapter收口执行计划-2026-05-14.md):记录 Big Fish、Square Hole、Custom World 生成图片的 provider 归一、下载/base64 解码、OSS、asset_object confirm 和 entity binding 收口计划。
|
||||
- [【后端架构】复杂媒体资产链路Adapter扩展计划-2026-05-14.md](./【后端架构】复杂媒体资产链路Adapter扩展计划-2026-05-14.md):记录音频、视频、角色工作流、Hyper3D/GLB 等复杂媒体只复用媒体持久化底座、不污染图片 Adapter 的扩展计划。
|
||||
- [【后端架构】api-server大Handler瘦身执行计划-2026-05-14.md](./【后端架构】api-server大Handler瘦身执行计划-2026-05-14.md):记录 api-server 大 handler 拆成 router、handlers、application、assets、mapper、errors 的执行计划,明确不改 contract、schema、计费和领域规则。
|
||||
- [WECHAT_MINIPROGRAM_WEB_VIEW_SHELL_2026-05-03.md](./WECHAT_MINIPROGRAM_WEB_VIEW_SHELL_2026-05-03.md):记录微信小程序 `web-view` 壳的最小接入范围、需要填写的 H5 业务域名、微信后台配置、`npm run check:wechat-miniprogram-auth` 可重复登录链路 smoke 和后续原生化边界。
|
||||
- [BARK_BATTLE_BACKEND_DDD_TECHNICAL_PLAN_2026-05-11.md](./BARK_BATTLE_BACKEND_DDD_TECHNICAL_PLAN_2026-05-11.md):冻结“汪汪声浪大作战 / bark-battle”后端 DDD 技术方案,明确 `server-rs + Axum + SpacetimeDB` 分层边界、shared contracts、作品配置、runtime run、派生成绩、排行榜、`work_play_start` 埋点、migration/绑定生成策略,以及不保存原始麦克风音频的隐私与反作弊约束。
|
||||
- [BARK_BATTLE_2D_RUNTIME_TECHNICAL_PLAN_2026-05-11.md](./BARK_BATTLE_2D_RUNTIME_TECHNICAL_PLAN_2026-05-11.md):冻结“汪汪声浪大作战 / bark-battle”2D 浏览器 runtime 技术方案,明确 Phaser + TypeScript + Vite 选型、纯 TS simulation 与 Phaser renderer/DOM HUD 边界、Web Audio 输入适配、移动端权限降级和后续测试验证命令。
|
||||
|
||||
211
docs/technical/【后端架构】api-server大Handler瘦身执行计划-2026-05-14.md
Normal file
211
docs/technical/【后端架构】api-server大Handler瘦身执行计划-2026-05-14.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# api-server 大 Handler 瘦身执行计划
|
||||
|
||||
状态:D2 首批已落地;Big Fish、Square Hole、Custom World AI、Match3D、Puzzle、Custom World 已完成低风险 mapper/tag/asset glue 拆分,后续继续按 owner 深化 application/errors 拆分
|
||||
日期:2026-05-14
|
||||
范围:只拆分 `server-rs/crates/api-server` 内大 handler 文件的内部职责;不改 HTTP contract、DTO、SpacetimeDB schema、module-* 领域规则、前端行为、计费语义和 provider 策略。
|
||||
|
||||
## 1. 目标
|
||||
|
||||
在 `app.rs` 路由装配迁入 `modules/*/router.rs` 后,继续把超大 handler 文件拆成清晰层次,避免 HTTP 解析、应用编排、资产持久化、DTO mapper、错误映射和玩法策略继续堆在单文件。
|
||||
|
||||
目标分层:
|
||||
|
||||
```text
|
||||
router.rs 只挂 route 与 middleware
|
||||
handlers.rs 只做 Axum extractor、鉴权上下文、Json/Sse response envelope
|
||||
application.rs 编排 spacetime-client facade、platform provider、asset adapter、计费 wrapper
|
||||
assets.rs 当前能力私有的 asset request 构造与 adapter 调用 glue
|
||||
mapper.rs HTTP DTO <-> application input/output 映射
|
||||
errors.rs 当前能力到 AppError/envelope 的映射
|
||||
```
|
||||
|
||||
本阶段不是 DDD 领域重构。凡是玩法裁决、实体规则、钱包语义、表结构语义已经属于 `module-*`、`spacetime-module` 或 `spacetime-client` 的,不得搬回 `api-server`。
|
||||
|
||||
## 2. Owner 与禁止改动范围
|
||||
|
||||
Owner:D2 大 Handler 瘦身 agent。建议一次只领取一个能力 owner,避免和 B/C/D1 冲突。
|
||||
|
||||
首批候选 owner:
|
||||
|
||||
- `big_fish.rs`
|
||||
- `square_hole.rs`
|
||||
- `custom_world_ai.rs` / `custom_world.rs`
|
||||
- `puzzle.rs`
|
||||
- `match3d.rs`
|
||||
- `visual_novel.rs`
|
||||
- `character_visual_assets.rs`
|
||||
- `character_animation_assets.rs`
|
||||
- `vector_engine_audio_generation.rs`
|
||||
|
||||
禁止本阶段修改:
|
||||
|
||||
- route path、HTTP method、handler 函数对外 contract、DTO 字段和 error envelope。
|
||||
- `shared-contracts` 公开类型,除非另开 contract owner 文档。
|
||||
- `spacetime-module` schema/procedure 和 Rust bindings。
|
||||
- `module-*` 领域规则和命令语义。
|
||||
- `asset_billing.rs` 的扣费/退款策略。
|
||||
- 图片 Adapter、复杂媒体 Adapter 的公共接口;只允许调用,不允许在瘦身切片里顺手改接口。
|
||||
- 前端调用路径、页面行为和测试快照。
|
||||
|
||||
## 3. 拆分原则
|
||||
|
||||
### 3.1 Handler 只做 HTTP 边界
|
||||
|
||||
允许保留:
|
||||
|
||||
- Axum extractor:`State`、`Extension`、`Path`、`Query`、`Json`。
|
||||
- 请求体基础解析和鉴权上下文读取。
|
||||
- 调用 application service。
|
||||
- 统一包装 `Json(ApiResponse<T>)`、SSE 或 `AppError`。
|
||||
|
||||
禁止保留:
|
||||
|
||||
- provider task create/poll/download 细节。
|
||||
- OSS object key 拼接、MIME 推断、asset_object confirm、entity binding。
|
||||
- 大段 SpacetimeDB row JSON mapper。
|
||||
- 玩法规则判断、发布门槛、运行态裁决。
|
||||
|
||||
### 3.2 Application 只做编排
|
||||
|
||||
Application 层可以:
|
||||
|
||||
- 调 `spacetime-client` facade。
|
||||
- 调 `platform-*` provider client 或既有 provider helper。
|
||||
- 调图片/复杂媒体 Adapter。
|
||||
- 维持既有计费 wrapper 的调用位置。
|
||||
- 组装 application output。
|
||||
|
||||
Application 层不允许新增领域真相;需要新增领域规则时必须暂停并拆给对应 `module-*` owner。
|
||||
|
||||
### 3.3 Mapper 可独立测试
|
||||
|
||||
Mapper 拆出后应优先覆盖:
|
||||
|
||||
- row snapshot JSON 到 HTTP response 的兼容字段。
|
||||
- legacy ID/path/kind/slot 字符串映射。
|
||||
- null/缺字段 fallback 的既有行为。
|
||||
|
||||
## 4. 能力级执行顺序
|
||||
|
||||
### D2-0:基线扫描
|
||||
|
||||
每领取一个文件先记录:
|
||||
|
||||
- 当前公开 route 与 handler 名称。
|
||||
- 当前 provider/asset/计费/spacetime-client 调用点。
|
||||
- 当前已有测试命令和缺口。
|
||||
- 与 B/C/D1 正在修改的文件是否冲突。
|
||||
|
||||
退出条件:只写本地执行 notes 或更新本文件状态,不改 Rust 行为。
|
||||
|
||||
### D2-1:低风险纯移动
|
||||
|
||||
- 先拆 `types.rs`/`mapper.rs`/`errors.rs` 中纯类型和纯函数。
|
||||
- 不改函数签名,不改错误文案。
|
||||
- 每次移动后跑 `cargo check -p api-server --manifest-path server-rs/Cargo.toml`。
|
||||
|
||||
退出条件:git diff 显示主要是 move/extract;无业务逻辑重写。
|
||||
|
||||
### D2-2:资产 glue 下沉
|
||||
|
||||
- 对已接入图片 Adapter 或复杂媒体 Adapter 的能力,把 request 构造放到能力私有 `assets.rs`。
|
||||
- 删除 handler 内重复 OSS/confirm/binding 代码。
|
||||
- 保留计费外层在原 application 编排位置。
|
||||
|
||||
退出条件:调用方仍显式传入 asset kind/entity kind/slot;Adapter 不反向知道玩法规则。
|
||||
|
||||
### D2-3:Application service 固化
|
||||
|
||||
- 每个能力暴露少量 `pub(crate)` application 函数。
|
||||
- handler 不直接调多个 facade/provider/adapter。
|
||||
- 对 SSE handler 保持流式语义,不包成非流式完整字符串。
|
||||
|
||||
退出条件:handler 文件行数显著下降;provider/asset/spacetime 调用集中在 application/assets 层。
|
||||
|
||||
### D2-4:清理与索引更新
|
||||
|
||||
- 删除无用私有 helper。
|
||||
- 更新对应技术文档状态。
|
||||
- 如果新建能力目录,确保 `mod.rs` 导出最小化。
|
||||
|
||||
退出条件:无未使用代码、无重复 helper、README/TODO 状态同步。
|
||||
|
||||
## 5. 文件级 owner 建议
|
||||
|
||||
| 能力 | 建议目标目录 | 可并行边界 | 退出条件 |
|
||||
| --- | --- | --- | --- |
|
||||
| Big Fish | `modules/runtime/big_fish/` | 不碰 Square Hole/Puzzle;图片 Adapter 接口由 C 线 owner 控制 | 正式图 asset glue 不在 handler;SSE/works/gallery route contract 不变 |
|
||||
| Square Hole | `modules/creation/square_hole/` 与 `modules/runtime/square_hole/` | 不改 Puzzle 图片规则 | 图片重生成 fallback Data URL 行为不变 |
|
||||
| Custom World | `modules/runtime/custom_world/` | opening CG 视频等复杂媒体与 D1 协调 | profile/entity/scene/cover/opening route contract 不变 |
|
||||
| Puzzle | `modules/runtime/puzzle/` | 不改前端即时运行态规则 | 运行态后端真相接口和排行榜语义不变 |
|
||||
| Match3D | `modules/creation/match3d/` 与 `modules/runtime/match3d/` | 不恢复 Rodin/GLB 新草稿 | 创作草稿、发布、运行态接口不变 |
|
||||
| Visual Novel/audio | `modules/creation/visual_novel/` | 音频持久化与 D1 协调 | SSE、compile、音频 asset route 不变 |
|
||||
| Character assets | `modules/assets/character_visual/`、`character_animation/` | 不改 workflow cache contract | 角色视觉/动作发布、导入、模板接口不变 |
|
||||
|
||||
## 6. 验收命令
|
||||
|
||||
每个能力切片至少运行:
|
||||
|
||||
```bash
|
||||
cargo check -p api-server --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server --manifest-path server-rs/Cargo.toml
|
||||
npm run check:encoding
|
||||
git diff --check
|
||||
```
|
||||
|
||||
按能力追加定向测试:
|
||||
|
||||
```bash
|
||||
cargo test -p api-server big_fish --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server square_hole --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server custom_world --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server puzzle --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server match3d --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server visual_novel --manifest-path server-rs/Cargo.toml
|
||||
```
|
||||
|
||||
如果 route 装配已迁移,还要跑:
|
||||
|
||||
```bash
|
||||
cargo test -p api-server app --manifest-path server-rs/Cargo.toml
|
||||
```
|
||||
|
||||
## 7. 当前落地状态(2026-05-14)
|
||||
|
||||
本轮已按“不改 route/HTTP contract/DTO/SpacetimeDB schema”的低风险策略完成首批机械拆分,并通过 `cargo check -p api-server`:
|
||||
|
||||
- `big_fish.rs`:正式图生成、下载与持久化拆入 `big_fish/formal_assets.rs`;会话/作品/运行态 response 映射与欢迎语拆入 `big_fish/mappers.rs`。
|
||||
- `square_hole.rs`:视觉资源生成、Adapter 持久化与图片 prompt glue 拆入 `square_hole/visual_assets.rs`;response mapper 拆入 `square_hole/mappers.rs`。
|
||||
- `custom_world_ai.rs`:通用图片资产持久化拆入 `custom_world_ai/assets.rs`;opening CG storyboard/video 生成与持久化拆入 `custom_world_ai/opening_cg.rs`。
|
||||
- `match3d.rs`:response mapper 拆入 `match3d/mappers.rs`;标签生成/归一化拆入 `match3d/tags.rs`。
|
||||
- `puzzle.rs`:response mapper 拆入 `puzzle/mappers.rs`;标签生成/保存/发布就绪判断拆入 `puzzle/tags.rs`。
|
||||
- `custom_world.rs`:library/gallery/work response mapper 拆入 `custom_world/mappers.rs`。
|
||||
|
||||
拆分后当前主文件规模约为:
|
||||
|
||||
| 文件 | 当前行数 | 已拆出模块 |
|
||||
| --- | ---: | --- |
|
||||
| `big_fish.rs` | 1005 | `formal_assets.rs`、`mappers.rs` |
|
||||
| `square_hole.rs` | 1674 | `visual_assets.rs`、`mappers.rs` |
|
||||
| `custom_world_ai.rs` | 3113 | `assets.rs`、`opening_cg.rs` |
|
||||
| `custom_world.rs` | 3519 | `mappers.rs` |
|
||||
| `puzzle.rs` | 5609 | `mappers.rs`、`tags.rs` |
|
||||
| `match3d.rs` | 6541 | `mappers.rs`、`tags.rs` |
|
||||
|
||||
后续建议继续拆分:
|
||||
|
||||
- `match3d`: `draft.rs`、`background_and_cover.rs`、`material_sheet.rs`、`apimart_image.rs`。
|
||||
- `puzzle`: `session_form.rs`、`draft_compile.rs`、`image_provider.rs`、`errors.rs`。
|
||||
- `custom_world`: `publish_gate.rs`、`foundation_job.rs`、`foundation_assets.rs`、`errors.rs`。
|
||||
- `square_hole`: `config.rs`、`errors.rs`。
|
||||
- `big_fish`: `errors.rs`,以及按需将 application 编排从 handler 中继续拆出。
|
||||
|
||||
## 8. 完成定义
|
||||
|
||||
D2 完成必须同时满足:
|
||||
|
||||
- 至少 3 个大 handler 完成 route/handler/application/assets/mapper/errors 的职责拆分。
|
||||
- handler 不再直接包含大段 provider 下载、OSS 上传、asset_object confirm、entity binding 逻辑。
|
||||
- 所有拆分前 route、method、DTO、error envelope、计费外层和 SpacetimeDB schema 不变。
|
||||
- 不新增领域规则到 `api-server`。
|
||||
- 验收命令通过,并同步更新 README 与本系列总纲/TODO 状态。
|
||||
296
docs/technical/【后端架构】api-server能力模块化与生成资产Adapter总纲-2026-05-14.md
Normal file
296
docs/technical/【后端架构】api-server能力模块化与生成资产Adapter总纲-2026-05-14.md
Normal file
@@ -0,0 +1,296 @@
|
||||
# api-server 能力模块化与生成资产 Adapter 总纲
|
||||
|
||||
状态:A 线文档基线已补齐;B1 路由模块化已由 controller 接手并以 cargo check 通过为当前编码基线;后续 C/D 线按本文 owner 拆分执行
|
||||
日期:2026-05-14
|
||||
范围:只约束 `server-rs/crates/api-server` 内部结构,不改 HTTP contract、DTO、SpacetimeDB schema、前端行为和计费语义。
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
当前 `api-server` 仍以超大 `app.rs` 直接装配全部 Axum route,并由 `big_fish.rs`、`square_hole.rs`、`custom_world_ai.rs`、`puzzle.rs`、`match3d.rs`、`character_visual_assets.rs`、`character_animation_assets.rs`、`vector_engine_audio_generation.rs` 等大 handler 文件承载 HTTP 解析、平台编排、生成资产下载/解码、OSS 上传、asset_object confirm、entity binding、计费包裹和部分玩法策略。
|
||||
|
||||
本轮总目标是分阶段把能力模块化和生成资产 Adapter 收口落地到可维护结构:
|
||||
|
||||
- `app.rs` 只保留全局 middleware、TraceLayer、request context、tracking middleware、模块 router merge/nest 和少量 glue。
|
||||
- 每个能力以 `modules/<capability>/router.rs` 暴露 `router(state) -> Router<AppState>`,迁移时保持原 route 字符串和 handler 函数不变。
|
||||
- 图片生成资产先收口到 `generated_image_assets` 内部 Adapter,复用 provider 生成、下载/base64 解码、MIME/extension 归一、OSS private upload、HEAD/确认、asset_object confirm、entity binding。
|
||||
- 音频、视频、GLB/Hyper3D/character assets 只复用底层“媒体持久化 + asset_object + binding”能力,不强行塞进图片 Adapter。
|
||||
|
||||
## 2. 不变边界
|
||||
|
||||
必须遵守既有 DDD 总纲和 G1 契约矩阵:
|
||||
|
||||
- 后端主线为 `server-rs + Axum + SpacetimeDB`。
|
||||
- `api-server` 只做 HTTP/SSE/BFF、鉴权、DTO 映射、平台服务编排、错误 envelope 映射、读写 facade 调用。
|
||||
- 领域规则不沉回 handler;新增模块不得把玩法裁决、实体规则、钱包语义、表结构语义写成 HTTP 层私有规则。
|
||||
- `module-*` 保持领域规则 owner;`spacetime-module` 保持真相源 schema/procedure owner;`spacetime-client` 保持 facade/adapter owner。
|
||||
- 本轮默认不改 HTTP route、DTO 字段、error envelope、SpacetimeDB schema、前端行为、计费语义。
|
||||
- `asset_billing.rs` 仍由调用方显式包裹;生成资产 Adapter 不扣费、不退款、不读钱包。
|
||||
- 生成资产读取继续走 `/api/assets/read-url` 或 `/api/assets/read-bytes` 换签/代理链路,不恢复 `/generated-*` 直读代理。
|
||||
- 禁止新增或复活 Maincloud 口径;smoke 以 `/healthz` 为准。
|
||||
|
||||
## 3. 当前源码入口
|
||||
|
||||
- 路由装配:`server-rs/crates/api-server/src/app.rs`
|
||||
- 资产基础 BFF:`assets.rs`
|
||||
- 图片 provider 公共 helper:`openai_image_generation.rs`
|
||||
- 玩法/创作大 handler:`big_fish.rs`、`square_hole.rs`、`custom_world_ai.rs`、`custom_world.rs`、`puzzle.rs`、`match3d.rs`
|
||||
- 复杂资产:`vector_engine_audio_generation.rs`、`character_visual_assets.rs`、`character_animation_assets.rs`
|
||||
- Prompt 辅助同名文件:`prompt/big_fish.rs`、`prompt/square_hole.rs`,不是 HTTP handler owner。
|
||||
|
||||
## 4. Route inventory 总览
|
||||
|
||||
完整执行细节见《api-server路由能力模块化执行计划》。当前 `app.rs` route 按能力归类如下。
|
||||
|
||||
### admin
|
||||
|
||||
Handler 主要在 `admin.rs`、`admin_creation_entry.rs`、`admin_profile.rs`:
|
||||
|
||||
- `/admin/api/login`
|
||||
- `/admin/api/me`
|
||||
- `/admin/api/overview`
|
||||
- `/admin/api/debug/http`
|
||||
- `/admin/api/tracking/events`
|
||||
- `/admin/api/database/tables`
|
||||
- `/admin/api/database/tables/{table_name}/rows`
|
||||
- `/admin/api/creation-entry/config`
|
||||
- `/admin/api/profile/redeem-codes`
|
||||
- `/admin/api/profile/redeem-codes/disable`
|
||||
- `/admin/api/profile/invite-codes`
|
||||
- `/admin/api/profile/tasks`
|
||||
- `/admin/api/profile/tasks/disable`
|
||||
|
||||
### health/internal
|
||||
|
||||
Handler 主要在 `app.rs` glue、`auth.rs`:
|
||||
|
||||
- `/healthz`
|
||||
- `/_internal/auth/claims`
|
||||
- `/_internal/auth/refresh-cookie`
|
||||
|
||||
### auth
|
||||
|
||||
Handler 主要在 `auth.rs`、`wechat_auth.rs`:
|
||||
|
||||
- `/api/auth/login-options`
|
||||
- `/api/auth/public-users/by-code/{code}`
|
||||
- `/api/auth/public-users/by-id/{user_id}`
|
||||
- `/api/auth/me`
|
||||
- `/api/auth/sessions`
|
||||
- `/api/auth/sessions/{session_id}/revoke`
|
||||
- `/api/auth/refresh`
|
||||
- `/api/auth/phone/send-code`
|
||||
- `/api/auth/phone/login`
|
||||
- `/api/auth/wechat/start`
|
||||
- `/api/auth/wechat/callback`
|
||||
- `/api/auth/wechat/miniprogram-login`
|
||||
- `/api/auth/wechat/bind-phone`
|
||||
- `/api/auth/logout`
|
||||
- `/api/auth/logout-all`
|
||||
- `/api/auth/entry`
|
||||
- `/api/auth/password/change`
|
||||
- `/api/auth/password/reset`
|
||||
|
||||
### assets
|
||||
|
||||
Handler 主要在 `assets.rs`、`character_visual_assets.rs`、`character_animation_assets.rs`、`hyper3d.rs`:
|
||||
|
||||
- `/api/assets/direct-upload-tickets`
|
||||
- `/api/assets/sts-upload-credentials`
|
||||
- `/api/assets/objects/confirm`
|
||||
- `/api/assets/objects/bind`
|
||||
- `/api/assets/read-url`
|
||||
- `/api/assets/read-bytes`
|
||||
- `/api/assets/history`
|
||||
- `/api/assets/character-visual/generate`
|
||||
- `/api/assets/character-visual/jobs/{task_id}`
|
||||
- `/api/assets/character-visual/publish`
|
||||
- `/api/assets/character-animation/generate`
|
||||
- `/api/assets/character-animation/jobs/{task_id}`
|
||||
- `/api/assets/character-animation/publish`
|
||||
- `/api/assets/character-animation/import-video`
|
||||
- `/api/assets/character-animation/templates`
|
||||
- `/api/assets/character-workflow-cache`
|
||||
- `/api/assets/character-workflow-cache/{character_id}`
|
||||
- `/api/runtime/custom-world/asset-studio/role/{character_id}/workflow`
|
||||
- `/api/assets/hyper3d/text-to-model`
|
||||
- `/api/assets/hyper3d/image-to-model`
|
||||
- `/api/assets/hyper3d/status`
|
||||
- `/api/assets/hyper3d/download`
|
||||
|
||||
### platform/BFF
|
||||
|
||||
Handler 主要在 `llm.rs`、`speech.rs`、`ai_tasks.rs`、`creation_entry.rs`、`runtime_chat.rs`:
|
||||
|
||||
- `/api/llm/chat/completions`
|
||||
- `/api/speech/volcengine/config`
|
||||
- `/api/speech/volcengine/asr/stream`
|
||||
- `/api/speech/volcengine/tts/bidirection`
|
||||
- `/api/speech/volcengine/tts/sse`
|
||||
- `/api/ai/tasks` 及 `{task_id}` start/chunks/complete/fail/cancel/stages/references 子路由
|
||||
- `/api/creation-entry/config`
|
||||
- `/api/runtime/chat/character/suggestions`
|
||||
- `/api/runtime/chat/character/summary`
|
||||
- `/api/runtime/chat/character/reply/stream`
|
||||
- `/api/runtime/chat/npc/dialogue/stream`
|
||||
- `/api/runtime/chat/npc/turn/stream`
|
||||
- `/api/runtime/chat/npc/recruit/stream`
|
||||
- `/api/runtime/creation-agent/document-inputs/parse`
|
||||
|
||||
### creation
|
||||
|
||||
Handler 主要在 `match3d.rs`、`square_hole.rs`、`visual_novel.rs`、`vector_engine_audio_generation.rs`:
|
||||
|
||||
- `/api/creation/match3d/*`
|
||||
- `/api/creation/square-hole/*`
|
||||
- `/api/creation/visual-novel/*`
|
||||
- `/api/creation/visual-novel/audio/*`
|
||||
- `/api/creation/audio/background-music`
|
||||
- `/api/creation/audio/background-music/{task_id}/asset`
|
||||
- `/api/creation/audio/sound-effect`
|
||||
- `/api/creation/audio/sound-effect/{task_id}/asset`
|
||||
|
||||
### runtime/gameplay
|
||||
|
||||
Handler 主要在 `custom_world.rs`、`custom_world_ai.rs`、`big_fish.rs`、`puzzle.rs`、`match3d.rs`、`square_hole.rs`、`visual_novel.rs`:
|
||||
|
||||
- `/api/runtime/settings`
|
||||
- `/api/runtime/save/snapshot`
|
||||
- `/api/runtime/custom-world-library*`
|
||||
- `/api/runtime/custom-world-gallery*`
|
||||
- `/api/runtime/custom-world/agent/*`
|
||||
- `/api/runtime/custom-world/works`
|
||||
- `/api/runtime/custom-world/profile|entity|scene-npc|scene-image|cover-image|cover-upload|opening-cg`
|
||||
- `/api/runtime/big-fish/*`
|
||||
- `/api/runtime/puzzle/*`
|
||||
- `/api/runtime/match3d/*`
|
||||
- `/api/runtime/square-hole/*`
|
||||
- `/api/runtime/visual-novel/*`
|
||||
- `/api/runtime/creative-agent/*`
|
||||
- `/api/runtime/sessions/{runtime_session_id}/inventory`
|
||||
|
||||
### profile
|
||||
|
||||
Handler 主要在 `profile.rs`、`runtime_profile.rs`、`tracking.rs`:
|
||||
|
||||
- `/api/profile/me`
|
||||
- `/api/profile/browse-history`
|
||||
- `/api/profile/dashboard`
|
||||
- `/api/profile/wallet-ledger`
|
||||
- `/api/profile/recharge-center`
|
||||
- `/api/profile/recharge/orders`
|
||||
- `/api/profile/recharge/wechat/notify`
|
||||
- `/api/profile/feedback`
|
||||
- `/api/profile/referrals/invite-center`
|
||||
- `/api/profile/referrals/redeem-code`
|
||||
- `/api/profile/redeem-codes/redeem`
|
||||
- `/api/profile/analytics/metric`
|
||||
- `/api/profile/tasks`
|
||||
- `/api/profile/tasks/{task_id}/claim`
|
||||
- `/api/profile/save-archives`
|
||||
- `/api/profile/save-archives/{world_key}`
|
||||
- `/api/profile/play-stats`
|
||||
|
||||
### story
|
||||
|
||||
Handler 主要在 `story.rs`、`combat.rs`、`runtime_inventory.rs`:
|
||||
|
||||
- `/api/story/sessions`
|
||||
- `/api/story/sessions/runtime`
|
||||
- `/api/story/sessions/{story_session_id}/state`
|
||||
- `/api/story/sessions/{story_session_id}/runtime-projection`
|
||||
- `/api/story/sessions/{story_session_id}/actions/resolve`
|
||||
- `/api/story/sessions/continue`
|
||||
- `/api/story/battles`
|
||||
- `/api/story/battles/{battle_state_id}`
|
||||
- `/api/story/npc/battle`
|
||||
- `/api/story/battles/resolve`
|
||||
|
||||
## 5. 生成资产链路 inventory 总览
|
||||
|
||||
详细迁移计划见图片 Adapter、复杂媒体 Adapter 文档。图片链路由 C 线收口;音频、视频、GLB/Hyper3D、角色工作流等复杂媒体由 D1 线只复用媒体持久化底座,不反向扩大图片 Adapter interface。
|
||||
|
||||
| 链路 | provider | 下载/解码 | OSS prefix | asset kind | entity binding | 计费位置 | 降级行为 |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| Big Fish 正式图 | DashScope `wan2.2-t2i-flash` | 轮询 task 后 HTTP GET 图片 URL | `LegacyAssetPrefix::BigFishAssets` | 由 assetKind 映射主图/动作图/舞台背景等 | `big_fish_session` + session/entity id + slot | `big_fish.rs` 调用方 `execute_billable_asset_operation` | 配置缺失/上游失败直接错误;gallery 对部分 Spacetime 运行错误软降级 |
|
||||
| Square Hole 图片重生成 | OpenAI/VectorEngine GPT image helper | URL 下载或 base64/data URL 解码 | `LegacyAssetPrefix::SquareHoleAssets` | 方洞作品图片槽位相关 kind | profile/work + image slot | 调用方包裹 | 生成成功但入库失败保留 Data URL 回包 |
|
||||
| Custom World 场景/封面 | VectorEngine GPT image 2 / OpenAI helper | URL 下载或 base64 解码 | `LegacyAssetPrefix::CustomWorldScenes` 等 | scene/cover/opening storyboard | `custom_world_profile` 或 profile/landmark/scene slot | `custom_world_ai.rs` 调用方包裹 | entity/scene 生成存在 LLM fallback;资产持久化失败按当前错误口径返回 |
|
||||
| Puzzle 图片 | GPT image 2 generations/edits | multipart/base64/URL 结果归一 | `LegacyAssetPrefix::PuzzleAssets` | puzzle level/background/generated image,另有 `puzzle_background_music` | puzzle profile/run/level slot | `puzzle.rs` 调用方包裹 | connectivity 可按既有规则跳过部分计费;运行态 fallback 保持原逻辑 |
|
||||
| Match3D 图片 | APIMart/VectorEngine/OpenAI image helper | 下载、切图、透明化、校准后入库 | `LegacyAssetPrefix::Match3DAssets` | cover/background/item material sheet,音频 kind 另列 | match3d profile/session slot | `match3d.rs` 调用方包裹 | 新草稿不回退 Rodin/GLB;部分连接错误按现有计费跳过规则处理 |
|
||||
| Visual Novel 音频 | VectorEngine Suno/Vidu | 任务提交后按 task publish 下载音频 | 视觉小说/creation audio scope | `visual_novel_music`、`visual_novel_ambient_sound` | `visual_novel_scene` + scene id + `music`/`ambient_sound` | `vector_engine_audio_generation.rs` 调用方包裹 | 上游/下载失败显式错误,不混入图片 Adapter |
|
||||
| 通用音频 | VectorEngine Suno/Vidu | 同上 | creation audio scope | background_music/sound_effect 由调用方目标指定 | creation target entity/slot | 调用方包裹 | 不与 VN 场景语义混用 |
|
||||
| 视频 Opening CG | Ark/火山视频 + storyboard | 先生 storyboard,再图生视频,下载 remote video | Custom World 相关 prefix | `custom_world_opening_cg_storyboard`、`custom_world_opening_cg_video` | `custom_world_profile` + opening cg slots | `execute_billable_asset_operation_with_cost` 固定点数 | 配置缺失/超时显式错误,不应静默降级 |
|
||||
| Character visual assets | GPT image helper / role asset workflow | base64/data URL/下载后入库 | 角色视觉资产相关 prefix | character_visual / reference / workflow cache | `character` + visual slots | 调用方包裹或当前无扣费处保持不变 | workflow cache 可无缓存继续生成 |
|
||||
| Character animation assets | Ark video 或阶段占位 | data:video base64 导入、remote video 下载、预览视频保存 | 角色动画资产相关 prefix | `character_animation`、`character_animation_reference_video`、`character_workflow_cache` | `character` + animation slots | 当前调用方语义保持 | stage1 image sequence/video placeholder 继续保留 |
|
||||
| Hyper3D/GLB | Hyper3D Rodin 历史代理 | status/download 列表代理,历史转存可复用 OSS | Hyper3D/model prefix | model/glb 相关历史 kind | 作品/profile 绑定视历史链路 | 不新增计费语义 | 当前 Match3D 新草稿不再回退 Rodin/GLB |
|
||||
|
||||
## 6. 并行执行规则
|
||||
|
||||
### 单 owner 文件/模块
|
||||
|
||||
同一时间只允许一个 agent 修改:
|
||||
|
||||
- `server-rs/crates/api-server/src/app.rs`
|
||||
- 未来 `server-rs/crates/api-server/src/modules/mod.rs`
|
||||
- 未来 `server-rs/crates/api-server/src/modules/assets/generated_image_assets/*`
|
||||
- `asset_billing.rs`
|
||||
- `openai_image_generation.rs`
|
||||
- `assets.rs`
|
||||
- `docs/technical/README.md`
|
||||
- 原 TODO 文档
|
||||
|
||||
### 可并行能力 owner
|
||||
|
||||
在 route inventory 和 Adapter interface 冻结后,可按能力分配:
|
||||
|
||||
- admin/auth/internal/health route module
|
||||
- assets/character assets/hyper3d route module
|
||||
- profile/runtime settings/save route module
|
||||
- Big Fish
|
||||
- Square Hole
|
||||
- Custom World
|
||||
- Puzzle
|
||||
- Match3D
|
||||
- Visual Novel/audio
|
||||
- story/combat/inventory
|
||||
|
||||
并行前提:只改自己能力目录和对应 handler;跨能力公共 helper 必须先锁单 owner 并在文档中声明。
|
||||
|
||||
## 7. 阶段与退出条件
|
||||
|
||||
- A0 文档基线(owner:A 线文档 agent):5 篇执行文档和 README/TODO 索引更新;`npm run check:encoding`、`git diff --check` 通过;不改 Rust 代码。
|
||||
- B1 route 模块化(owner:B1 route agent/controller):route inventory 全部仍可在新 modules router 中找到;旧明确下线 route 仍 404;`cargo check -p api-server --manifest-path server-rs/Cargo.toml` 与 `cargo test -p api-server app --manifest-path server-rs/Cargo.toml` 或等价 route 测试通过。
|
||||
- C1-C4 图片 Adapter(owner:C 线图片 Adapter agent):Big Fish、Square Hole、Custom World 至少 3 个真实调用方接入同一 Adapter;旧重复 persist helper 可删除且行为不变;禁止修改计费语义。
|
||||
- D1 复杂媒体 Adapter(owner:D1 复杂媒体 agent):Puzzle/Match3D/音频/视频/角色工作流/Hyper3D 只复用合适的底层持久化能力,不污染图片 interface;`/api/assets/read-url` 和 `/api/assets/read-bytes` 读取链路仍可用。
|
||||
- D2 大 handler 瘦身(owner:D2 handler 瘦身 agent):route、handler、application、assets、mapper、errors 分层清晰;不扩大到领域 crate 重构;每次只领取一个能力 owner。
|
||||
|
||||
## 8. TODO / 多 agent 拆分状态
|
||||
|
||||
| 线别 | Owner | 当前状态 | 只允许改动 | 禁止改动 | 退出条件 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| A0 文档基线 | A 线文档 agent | 本次补齐缺失复杂媒体与大 Handler 文档,更新 README 和本 TODO 视角 | `docs/technical/【后端架构】*2026-05-14.md`、`docs/technical/README.md` | Rust 代码、Cargo 配置、前端、schema | `npm run check:encoding`、`git diff --check` 通过 |
|
||||
| B1 路由模块化 | B1 route agent/controller | controller 已接手,当前 cargo check 通过;后续以 B1 diff 为准 | `app.rs`、`modules/*/router.rs`、必要 `mod.rs` | handler 行为、DTO、middleware 顺序、计费 | route inventory 完整、cargo check/route tests 通过 |
|
||||
| C 图片 Adapter | C 线图片 Adapter agent | 待执行 | `modules/assets/generated_image_assets/*`,以及 Big Fish/Square Hole/Custom World 接线文件 | `asset_billing.rs`、schema、公开 contract、复杂媒体接口 | 三类真实图片调用方共用 Adapter |
|
||||
| D1 复杂媒体 Adapter | D1 复杂媒体 agent | 待执行 | `modules/assets/media_assets/*` 与音频/视频/角色资产接线文件 | 图片 Adapter interface、provider 策略、schema、计费 | 至少音频和视频两类复用 media persist |
|
||||
| D2 大 Handler 瘦身 | D2 handler 瘦身 agent | 待 B/C/D1 稳定后执行 | 单个能力 handler 及其能力目录内 `handlers/application/assets/mapper/errors` | 领域 crate、contract、schema、前端、计费 | 至少 3 个大 handler 职责拆分完成 |
|
||||
|
||||
并行要求:同一文件同一时间只允许一个 owner;跨线公共 helper 必须先在对应执行文档中声明 owner 和退出条件。若编码 diff 与本 TODO 冲突,以最新通过验收命令的代码事实为准,并同步修正文档。
|
||||
|
||||
## 9. 验证命令
|
||||
|
||||
文档阶段:
|
||||
|
||||
```bash
|
||||
npm run check:encoding
|
||||
git diff --check
|
||||
```
|
||||
|
||||
后续编码阶段按变更范围追加:
|
||||
|
||||
```bash
|
||||
cargo check -p api-server --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server app --manifest-path server-rs/Cargo.toml
|
||||
npm run check:server-rs-ddd
|
||||
npm run api-server
|
||||
# 另开终端 curl /healthz
|
||||
```
|
||||
393
docs/technical/【后端架构】api-server路由能力模块化执行计划-2026-05-14.md
Normal file
393
docs/technical/【后端架构】api-server路由能力模块化执行计划-2026-05-14.md
Normal file
@@ -0,0 +1,393 @@
|
||||
# api-server 路由能力模块化执行计划
|
||||
|
||||
状态:A 线文档基线已补齐;B1 低风险路由模块已落地并通过 route/app smoke、cargo check、编码检查;后续 B2/B3 继续按本文 owner 拆分执行
|
||||
日期:2026-05-14
|
||||
范围:只移动/重组 `api-server` 路由装配;不改 route path、HTTP method、handler 函数签名、DTO、鉴权策略、middleware 顺序和前端行为。
|
||||
|
||||
## 1. 目标
|
||||
|
||||
把当前 `app.rs` 中所有 `.route(...)` 按能力迁入 `server-rs/crates/api-server/src/modules/`,每个能力暴露:
|
||||
|
||||
```rust
|
||||
pub(crate) fn router(state: AppState) -> Router<AppState>
|
||||
```
|
||||
|
||||
第一阶段 handler 实现仍可留在原文件;本阶段只改变路由装配位置。`app.rs` 最终只负责:
|
||||
|
||||
- 构建 shared state。
|
||||
- 注入全局 CORS、TraceLayer、request context、tracking/auth middleware。
|
||||
- `.merge(modules::<capability>::router(state.clone()))`。
|
||||
- 保留 `/healthz` 等极少量 glue,或迁到 `modules/health` 后统一 merge。
|
||||
|
||||
## 2. 建议目录
|
||||
|
||||
```text
|
||||
server-rs/crates/api-server/src/modules/
|
||||
mod.rs
|
||||
admin/router.rs
|
||||
auth/router.rs
|
||||
assets/router.rs
|
||||
profile/router.rs
|
||||
platform/router.rs
|
||||
creation/router.rs
|
||||
runtime/router.rs
|
||||
story/router.rs
|
||||
internal/router.rs
|
||||
health/router.rs
|
||||
```
|
||||
|
||||
可进一步拆分:
|
||||
|
||||
- `creation/{match3d,square_hole,visual_novel,audio}/router.rs`
|
||||
- `runtime/{custom_world,big_fish,puzzle,match3d,square_hole,visual_novel,creative_agent,settings,save}/router.rs`
|
||||
- `assets/{base,character_visual,character_animation,hyper3d}/router.rs`
|
||||
|
||||
## 3. Route inventory 与 owner
|
||||
|
||||
### 3.1 admin
|
||||
|
||||
Owner:`modules/admin/router.rs`。主要 handler 文件:`admin.rs`、`admin_creation_entry.rs`、`admin_profile.rs`。
|
||||
|
||||
- `/admin/api/login`
|
||||
- `/admin/api/me`
|
||||
- `/admin/api/overview`
|
||||
- `/admin/api/debug/http`
|
||||
- `/admin/api/tracking/events`
|
||||
- `/admin/api/database/tables`
|
||||
- `/admin/api/database/tables/{table_name}/rows`
|
||||
- `/admin/api/creation-entry/config`
|
||||
- `/admin/api/profile/redeem-codes`
|
||||
- `/admin/api/profile/redeem-codes/disable`
|
||||
- `/admin/api/profile/invite-codes`
|
||||
- `/admin/api/profile/tasks`
|
||||
- `/admin/api/profile/tasks/disable`
|
||||
|
||||
退出条件:后台接口路径、鉴权 middleware、错误 envelope 不变。
|
||||
|
||||
### 3.2 health/internal
|
||||
|
||||
Owner:`modules/health/router.rs`、`modules/internal/router.rs`。主要 handler:`app.rs` glue、`auth.rs`。
|
||||
|
||||
- `/healthz`
|
||||
- `/_internal/auth/claims`
|
||||
- `/_internal/auth/refresh-cookie`
|
||||
|
||||
退出条件:`/healthz` 可作为本地 smoke;internal route 不暴露新增契约。
|
||||
|
||||
### 3.3 auth
|
||||
|
||||
Owner:`modules/auth/router.rs`。主要 handler:`auth.rs`、`wechat_auth.rs`。
|
||||
|
||||
- `/api/auth/login-options`
|
||||
- `/api/auth/public-users/by-code/{code}`
|
||||
- `/api/auth/public-users/by-id/{user_id}`
|
||||
- `/api/auth/me`
|
||||
- `/api/auth/sessions`
|
||||
- `/api/auth/sessions/{session_id}/revoke`
|
||||
- `/api/auth/refresh`
|
||||
- `/api/auth/phone/send-code`
|
||||
- `/api/auth/phone/login`
|
||||
- `/api/auth/wechat/start`
|
||||
- `/api/auth/wechat/callback`
|
||||
- `/api/auth/wechat/miniprogram-login`
|
||||
- `/api/auth/wechat/bind-phone`
|
||||
- `/api/auth/logout`
|
||||
- `/api/auth/logout-all`
|
||||
- `/api/auth/entry`
|
||||
- `/api/auth/password/change`
|
||||
- `/api/auth/password/reset`
|
||||
|
||||
退出条件:cookie/session/refresh 行为不变;手机号/微信配置门控不变。
|
||||
|
||||
### 3.4 assets
|
||||
|
||||
Owner:`modules/assets/router.rs`。主要 handler:`assets.rs`、`character_visual_assets.rs`、`character_animation_assets.rs`、`hyper3d.rs`。
|
||||
|
||||
- `/api/assets/direct-upload-tickets`
|
||||
- `/api/assets/sts-upload-credentials`
|
||||
- `/api/assets/objects/confirm`
|
||||
- `/api/assets/objects/bind`
|
||||
- `/api/assets/read-url`
|
||||
- `/api/assets/read-bytes`
|
||||
- `/api/assets/history`
|
||||
- `/api/assets/character-visual/generate`
|
||||
- `/api/assets/character-visual/jobs/{task_id}`
|
||||
- `/api/assets/character-visual/publish`
|
||||
- `/api/assets/character-animation/generate`
|
||||
- `/api/assets/character-animation/jobs/{task_id}`
|
||||
- `/api/assets/character-animation/publish`
|
||||
- `/api/assets/character-animation/import-video`
|
||||
- `/api/assets/character-animation/templates`
|
||||
- `/api/assets/character-workflow-cache`
|
||||
- `/api/assets/character-workflow-cache/{character_id}`
|
||||
- `/api/runtime/custom-world/asset-studio/role/{character_id}/workflow`(可暂挂 assets module,但文档注明 runtime 前缀历史兼容)
|
||||
- `/api/assets/hyper3d/text-to-model`
|
||||
- `/api/assets/hyper3d/image-to-model`
|
||||
- `/api/assets/hyper3d/status`
|
||||
- `/api/assets/hyper3d/download`
|
||||
|
||||
退出条件:私有资产读取仍走 read-url/read-bytes;Hyper3D 不新增 Match3D 新草稿回退。
|
||||
|
||||
### 3.5 platform/BFF
|
||||
|
||||
Owner:`modules/platform/router.rs`。主要 handler:`llm.rs`、`speech.rs`、`ai_tasks.rs`、`creation_entry.rs`、`runtime_chat.rs`。
|
||||
|
||||
- `/api/llm/chat/completions`
|
||||
- `/api/speech/volcengine/config`
|
||||
- `/api/speech/volcengine/asr/stream`
|
||||
- `/api/speech/volcengine/tts/bidirection`
|
||||
- `/api/speech/volcengine/tts/sse`
|
||||
- `/api/runtime/chat/character/suggestions`
|
||||
- `/api/runtime/chat/character/summary`
|
||||
- `/api/runtime/chat/character/reply/stream`
|
||||
- `/api/runtime/chat/npc/dialogue/stream`
|
||||
- `/api/runtime/chat/npc/turn/stream`
|
||||
- `/api/runtime/chat/npc/recruit/stream`
|
||||
- `/api/runtime/creation-agent/document-inputs/parse`
|
||||
- `/api/ai/tasks`
|
||||
- `/api/ai/tasks/{task_id}/start`
|
||||
- `/api/ai/tasks/{task_id}/stages/{stage_kind}/start`
|
||||
- `/api/ai/tasks/{task_id}/chunks`
|
||||
- `/api/ai/tasks/{task_id}/stages/{stage_kind}/complete`
|
||||
- `/api/ai/tasks/{task_id}/references`
|
||||
- `/api/ai/tasks/{task_id}/complete`
|
||||
- `/api/ai/tasks/{task_id}/fail`
|
||||
- `/api/ai/tasks/{task_id}/cancel`
|
||||
- `/api/creation-entry/config`
|
||||
|
||||
退出条件:SSE 流式 route 不被非流式 wrapper 改写;外部服务错误分类不变。
|
||||
|
||||
### 3.6 creation
|
||||
|
||||
Owner:`modules/creation/router.rs`,可由子模块并行。主要 handler:`match3d.rs`、`square_hole.rs`、`visual_novel.rs`、`vector_engine_audio_generation.rs`。
|
||||
|
||||
Match3D:
|
||||
|
||||
- `/api/creation/match3d/sessions`
|
||||
- `/api/creation/match3d/sessions/{session_id}`
|
||||
- `/api/creation/match3d/sessions/{session_id}/messages`
|
||||
- `/api/creation/match3d/sessions/{session_id}/messages/stream`
|
||||
- `/api/creation/match3d/sessions/{session_id}/actions`
|
||||
- `/api/creation/match3d/sessions/{session_id}/compile`
|
||||
- `/api/creation/match3d/works`
|
||||
- `/api/creation/match3d/works/tags`
|
||||
- `/api/creation/match3d/works/{profile_id}`
|
||||
- `/api/creation/match3d/works/{profile_id}/audio-assets`
|
||||
- `/api/creation/match3d/works/{profile_id}/cover-image`
|
||||
- `/api/creation/match3d/works/{profile_id}/background-image`
|
||||
- `/api/creation/match3d/works/{profile_id}/item-assets`
|
||||
- `/api/creation/match3d/works/{profile_id}/generated-models`
|
||||
- `/api/creation/match3d/works/{profile_id}/publish`
|
||||
|
||||
Square Hole:
|
||||
|
||||
- `/api/creation/square-hole/sessions`
|
||||
- `/api/creation/square-hole/sessions/{session_id}`
|
||||
- `/api/creation/square-hole/sessions/{session_id}/messages`
|
||||
- `/api/creation/square-hole/sessions/{session_id}/messages/stream`
|
||||
- `/api/creation/square-hole/sessions/{session_id}/actions`
|
||||
- `/api/creation/square-hole/sessions/{session_id}/compile`
|
||||
- `/api/creation/square-hole/works`
|
||||
- `/api/creation/square-hole/works/{profile_id}`
|
||||
- `/api/creation/square-hole/works/{profile_id}/publish`
|
||||
- `/api/creation/square-hole/works/{profile_id}/images/regenerate`
|
||||
|
||||
Visual Novel 与音频:
|
||||
|
||||
- `/api/creation/visual-novel/sessions`
|
||||
- `/api/creation/visual-novel/sessions/{session_id}`
|
||||
- `/api/creation/visual-novel/sessions/{session_id}/messages`
|
||||
- `/api/creation/visual-novel/sessions/{session_id}/messages/stream`
|
||||
- `/api/creation/visual-novel/sessions/{session_id}/actions`
|
||||
- `/api/creation/visual-novel/sessions/{session_id}/compile`
|
||||
- `/api/creation/visual-novel/works`
|
||||
- `/api/creation/visual-novel/works/{profile_id}`
|
||||
- `/api/creation/visual-novel/works/{profile_id}/publish`
|
||||
- `/api/creation/visual-novel/audio/background-music`
|
||||
- `/api/creation/visual-novel/audio/background-music/{task_id}/asset`
|
||||
- `/api/creation/visual-novel/audio/sound-effect`
|
||||
- `/api/creation/visual-novel/audio/sound-effect/{task_id}/asset`
|
||||
- `/api/creation/audio/background-music`
|
||||
- `/api/creation/audio/background-music/{task_id}/asset`
|
||||
- `/api/creation/audio/sound-effect`
|
||||
- `/api/creation/audio/sound-effect/{task_id}/asset`
|
||||
|
||||
退出条件:所有 creation route method 和 auth extension 不变。
|
||||
|
||||
### 3.7 runtime
|
||||
|
||||
Owner:`modules/runtime/router.rs`,建议按玩法子模块并行。
|
||||
|
||||
Custom World:
|
||||
|
||||
- `/api/runtime/settings`
|
||||
- `/api/runtime/save/snapshot`
|
||||
- `/api/runtime/custom-world-library`
|
||||
- `/api/runtime/custom-world-library/{profile_id}`
|
||||
- `/api/runtime/custom-world-library/{profile_id}/publish`
|
||||
- `/api/runtime/custom-world-library/{profile_id}/unpublish`
|
||||
- `/api/runtime/custom-world-gallery`
|
||||
- `/api/runtime/custom-world-gallery/{owner_user_id}/{profile_id}`
|
||||
- `/api/runtime/custom-world-gallery/{owner_user_id}/{profile_id}/remix`
|
||||
- `/api/runtime/custom-world-gallery/{owner_user_id}/{profile_id}/play`
|
||||
- `/api/runtime/custom-world-gallery/{owner_user_id}/{profile_id}/like`
|
||||
- `/api/runtime/custom-world-gallery/by-code/{code}`
|
||||
- `/api/runtime/custom-world/agent/sessions`
|
||||
- `/api/runtime/custom-world/agent/sessions/{session_id}`
|
||||
- `/api/runtime/custom-world/agent/sessions/{session_id}/result-view`
|
||||
- `/api/runtime/custom-world/works`
|
||||
- `/api/runtime/custom-world/agent/sessions/{session_id}/cards/{card_id}`
|
||||
- `/api/runtime/custom-world/agent/sessions/{session_id}/messages`
|
||||
- `/api/runtime/custom-world/agent/sessions/{session_id}/messages/stream`
|
||||
- `/api/runtime/custom-world/agent/sessions/{session_id}/actions`
|
||||
- `/api/runtime/custom-world/agent/sessions/{session_id}/operations/{operation_id}`
|
||||
- `/api/runtime/custom-world/profile`
|
||||
- `/api/runtime/custom-world/entity`
|
||||
- `/api/runtime/custom-world/scene-npc`
|
||||
- `/api/runtime/custom-world/scene-image`
|
||||
- `/api/runtime/custom-world/cover-image`
|
||||
- `/api/runtime/custom-world/cover-upload`
|
||||
- `/api/runtime/custom-world/opening-cg`
|
||||
|
||||
Big Fish:
|
||||
|
||||
- `/api/runtime/big-fish/agent/sessions`
|
||||
- `/api/runtime/big-fish/agent/sessions/{session_id}`
|
||||
- `/api/runtime/big-fish/agent/sessions/{session_id}/messages`
|
||||
- `/api/runtime/big-fish/agent/sessions/{session_id}/messages/stream`
|
||||
- `/api/runtime/big-fish/agent/sessions/{session_id}/actions`
|
||||
- `/api/runtime/big-fish/works`
|
||||
- `/api/runtime/big-fish/gallery`
|
||||
- `/api/runtime/big-fish/gallery/{session_id}/remix`
|
||||
- `/api/runtime/big-fish/gallery/{session_id}/like`
|
||||
- `/api/runtime/big-fish/works/{session_id}`
|
||||
- `/api/runtime/big-fish/sessions/{session_id}/play`
|
||||
- `/api/runtime/big-fish/works/{session_id}/play`
|
||||
- `/api/runtime/big-fish/sessions/{session_id}/runs`
|
||||
- `/api/runtime/big-fish/runs/{run_id}`
|
||||
- `/api/runtime/big-fish/runs/{run_id}/input`
|
||||
|
||||
Puzzle:
|
||||
|
||||
- `/api/runtime/puzzle/agent/sessions`
|
||||
- `/api/runtime/puzzle/agent/sessions/{session_id}`
|
||||
- `/api/runtime/puzzle/agent/sessions/{session_id}/messages`
|
||||
- `/api/runtime/puzzle/agent/sessions/{session_id}/messages/stream`
|
||||
- `/api/runtime/puzzle/agent/sessions/{session_id}/actions`
|
||||
- `/api/runtime/puzzle/onboarding/generate`
|
||||
- `/api/runtime/puzzle/onboarding/save`
|
||||
- `/api/runtime/puzzle/works`
|
||||
- `/api/runtime/puzzle/works/{profile_id}`
|
||||
- `/api/runtime/puzzle/works/{profile_id}/point-incentive/claim`
|
||||
- `/api/runtime/puzzle/gallery`
|
||||
- `/api/runtime/puzzle/gallery/{profile_id}`
|
||||
- `/api/runtime/puzzle/gallery/{profile_id}/remix`
|
||||
- `/api/runtime/puzzle/gallery/{profile_id}/like`
|
||||
- `/api/runtime/puzzle/runs`
|
||||
- `/api/runtime/puzzle/runs/{run_id}`
|
||||
- `/api/runtime/puzzle/runs/{run_id}/swap`
|
||||
- `/api/runtime/puzzle/runs/{run_id}/drag`
|
||||
- `/api/runtime/puzzle/runs/{run_id}/next-level`
|
||||
- `/api/runtime/puzzle/runs/{run_id}/pause`
|
||||
- `/api/runtime/puzzle/runs/{run_id}/props`
|
||||
- `/api/runtime/puzzle/runs/{run_id}/leaderboard`
|
||||
|
||||
Match3D/Square Hole/Visual Novel/Creative Agent:
|
||||
|
||||
- `/api/runtime/match3d/gallery`
|
||||
- `/api/runtime/match3d/works/{profile_id}/runs`
|
||||
- `/api/runtime/match3d/runs/{run_id}`
|
||||
- `/api/runtime/match3d/runs/{run_id}/click|stop|restart|time-up`
|
||||
- `/api/runtime/square-hole/gallery`
|
||||
- `/api/runtime/square-hole/works/{profile_id}/runs`
|
||||
- `/api/runtime/square-hole/runs/{run_id}`
|
||||
- `/api/runtime/square-hole/runs/{run_id}/drop|stop|restart|time-up`
|
||||
- `/api/runtime/visual-novel/gallery`
|
||||
- `/api/runtime/visual-novel/works/{profile_id}/runs`
|
||||
- `/api/runtime/visual-novel/runs/{run_id}`
|
||||
- `/api/runtime/visual-novel/runs/{run_id}/actions/stream|history|regenerate`
|
||||
- `/api/runtime/creative-agent/sessions`
|
||||
- `/api/runtime/creative-agent/sessions/{session_id}`
|
||||
- `/api/runtime/creative-agent/sessions/{session_id}/messages/stream`
|
||||
- `/api/runtime/creative-agent/sessions/{session_id}/confirm-template`
|
||||
- `/api/runtime/creative-agent/sessions/{session_id}/draft-edits/stream`
|
||||
- `/api/runtime/creative-agent/sessions/{session_id}/cancel`
|
||||
- `/api/runtime/sessions/{runtime_session_id}/inventory`
|
||||
|
||||
退出条件:运行态玩法 route 后端真相源保持现状;不恢复旧 `/api/custom-world/*` 非 runtime 前缀。
|
||||
|
||||
### 3.8 profile
|
||||
|
||||
Owner:`modules/profile/router.rs`。主要 handler:`profile.rs`、`runtime_profile.rs`、`tracking.rs`。
|
||||
|
||||
- `/api/profile/me`
|
||||
- `/api/profile/browse-history`
|
||||
- `/api/profile/dashboard`
|
||||
- `/api/profile/wallet-ledger`
|
||||
- `/api/profile/recharge-center`
|
||||
- `/api/profile/recharge/orders`
|
||||
- `/api/profile/recharge/wechat/notify`
|
||||
- `/api/profile/feedback`
|
||||
- `/api/profile/referrals/invite-center`
|
||||
- `/api/profile/referrals/redeem-code`
|
||||
- `/api/profile/redeem-codes/redeem`
|
||||
- `/api/profile/analytics/metric`
|
||||
- `/api/profile/tasks`
|
||||
- `/api/profile/tasks/{task_id}/claim`
|
||||
- `/api/profile/save-archives`
|
||||
- `/api/profile/save-archives/{world_key}`
|
||||
- `/api/profile/play-stats`
|
||||
|
||||
退出条件:钱包、任务、邀请码、充值语义不变。
|
||||
|
||||
### 3.9 story
|
||||
|
||||
Owner:`modules/story/router.rs`。主要 handler:`story.rs`、`combat.rs`、`runtime_inventory.rs`。
|
||||
|
||||
- `/api/story/sessions`
|
||||
- `/api/story/sessions/runtime`
|
||||
- `/api/story/sessions/{story_session_id}/state`
|
||||
- `/api/story/sessions/{story_session_id}/runtime-projection`
|
||||
- `/api/story/sessions/{story_session_id}/actions/resolve`
|
||||
- `/api/story/sessions/continue`
|
||||
- `/api/story/battles`
|
||||
- `/api/story/battles/{battle_state_id}`
|
||||
- `/api/story/npc/battle`
|
||||
- `/api/story/battles/resolve`
|
||||
|
||||
退出条件:继续使用 story session scoped route;旧 `/api/runtime/story/*` 不重新挂载。
|
||||
|
||||
## 4. 执行顺序
|
||||
|
||||
1. 新建 `modules/mod.rs` 和低风险子模块骨架。
|
||||
2. 迁移 health/internal/admin/auth/assets/profile route;每迁一组跑 route 编译测试。
|
||||
3. 迁移 platform route,特别保护 SSE handler 类型。
|
||||
4. 迁移 creation/runtime/story route。
|
||||
5. 清理 `app.rs` 中重复 route 装配,只保留 merge。
|
||||
6. 用脚本/测试确认 route 字符串未丢失。
|
||||
|
||||
## 5. 单 owner 与并行规则
|
||||
|
||||
- `app.rs`、`modules/mod.rs` 必须单 owner。
|
||||
- 同一能力的 `router.rs` 单 owner。
|
||||
- 不同能力 router 可并行,但不能同时改公共 middleware、state、auth extractor。
|
||||
- Handler 文件拆分不属于本阶段;若必须触碰 handler,只允许 import 路径修正。
|
||||
|
||||
## 6. 验证命令
|
||||
|
||||
```bash
|
||||
cargo test -p api-server app --manifest-path server-rs/Cargo.toml
|
||||
cargo check -p api-server --manifest-path server-rs/Cargo.toml
|
||||
npm run check:server-rs-ddd
|
||||
npm run check:encoding
|
||||
git diff --check
|
||||
```
|
||||
|
||||
可选人工 smoke:
|
||||
|
||||
```bash
|
||||
npm run api-server
|
||||
curl -fsS http://127.0.0.1:<API_PORT>/healthz
|
||||
```
|
||||
|
||||
禁止用 `api-server:maincloud` 作为 smoke。
|
||||
151
docs/technical/【后端架构】复杂媒体资产链路Adapter扩展计划-2026-05-14.md
Normal file
151
docs/technical/【后端架构】复杂媒体资产链路Adapter扩展计划-2026-05-14.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# 复杂媒体资产链路 Adapter 扩展计划
|
||||
|
||||
状态:待 D1 线执行;依赖 C 线图片 Adapter 的持久化底座稳定后开始
|
||||
日期:2026-05-14
|
||||
范围:只约束 `server-rs/crates/api-server` 内复杂媒体资产的持久化与绑定复用方式;不把音频、视频、GLB、角色工作流强行塞入图片生成 Adapter;不改 HTTP contract、DTO、SpacetimeDB schema、OSS 访问策略、前端行为和计费语义。
|
||||
|
||||
## 1. 目标
|
||||
|
||||
在图片 Adapter 收口之后,抽出可复用的“媒体持久化 + asset_object confirm + entity binding”底座,让复杂媒体链路减少重复代码,但保留各自 provider、任务轮询、业务语义和回包契约。
|
||||
|
||||
目标链路:
|
||||
|
||||
```text
|
||||
provider 或外部任务产物
|
||||
-> media source 归一(remote URL / data URL / base64 / bytes / object key)
|
||||
-> MIME/extension/文件名归一
|
||||
-> OSS private upload 或确认已有 object key
|
||||
-> 可选 HEAD/大小/类型检查
|
||||
-> module-assets asset_object confirm
|
||||
-> asset entity binding
|
||||
-> 返回调用方需要的 legacy path/object key/asset id/metadata
|
||||
```
|
||||
|
||||
本计划不定义新的公开 API,只定义 `api-server` 内部复用能力。首批完成必须至少覆盖:
|
||||
|
||||
- Visual Novel / 通用创作音频:背景音乐、音效任务发布后的音频下载入库。
|
||||
- Custom World opening CG:storyboard 图片可走图片 Adapter,最终视频走复杂媒体底座。
|
||||
- Character visual / animation:角色视觉、参考视频、导入视频和 workflow cache 的持久化复用。
|
||||
- Match3D / Puzzle 资产链路中非图片资产:背景音乐、历史 GLB/Hyper3D 代理边界只做复用,不恢复新草稿 GLB 回退。
|
||||
|
||||
## 2. Owner 与禁止改动范围
|
||||
|
||||
Owner:D1 复杂媒体 Adapter agent。
|
||||
|
||||
单 owner 文件/目录:
|
||||
|
||||
- `server-rs/crates/api-server/src/modules/assets/media_assets/*`(建议新增)
|
||||
- `server-rs/crates/api-server/src/vector_engine_audio_generation.rs` 中音频持久化接线
|
||||
- `server-rs/crates/api-server/src/character_visual_assets.rs` 中角色视觉持久化接线
|
||||
- `server-rs/crates/api-server/src/character_animation_assets.rs` 中角色动作/视频持久化接线
|
||||
- `server-rs/crates/api-server/src/hyper3d.rs` 中历史模型代理持久化接线
|
||||
|
||||
禁止本阶段修改:
|
||||
|
||||
- `asset_billing.rs`:复杂媒体 Adapter 不扣费、不退款、不判断钱包。
|
||||
- `shared-contracts`:不新增或改动公开 DTO。
|
||||
- `spacetime-module` schema/procedure:不新增表、不改 reducer 签名。
|
||||
- 前端页面、service、路由路径。
|
||||
- provider 策略:不切换 Suno/Vidu/Ark/Hyper3D/DashScope/OpenAI 模型,不改任务轮询超时语义。
|
||||
- `/generated-*` 直读代理:禁止恢复;读取仍走 `/api/assets/read-url` 或 `/api/assets/read-bytes`。
|
||||
|
||||
## 3. 建议模块边界
|
||||
|
||||
建议目录:
|
||||
|
||||
```text
|
||||
server-rs/crates/api-server/src/modules/assets/media_assets/
|
||||
mod.rs
|
||||
persist.rs
|
||||
source.rs
|
||||
types.rs
|
||||
errors.rs
|
||||
```
|
||||
|
||||
建议只暴露 crate 内 API:
|
||||
|
||||
```rust
|
||||
pub(crate) async fn persist_generated_media_asset(
|
||||
state: &AppState,
|
||||
request: GeneratedMediaAssetPersistRequest,
|
||||
) -> Result<GeneratedMediaAssetPersistOutput, AppError>
|
||||
```
|
||||
|
||||
Adapter 只负责媒体持久化和资产绑定,不负责:
|
||||
|
||||
- 生成 prompt、提交 provider 任务、轮询 provider 状态。
|
||||
- 玩法 draft/profile JSON 写回。
|
||||
- 运行态裁决、发布校验、作品可见性。
|
||||
- 计费、退款、钱包流水。
|
||||
- 复杂媒体失败后的业务 fallback 决策。
|
||||
|
||||
## 4. 链路 inventory 与迁移策略
|
||||
|
||||
| 链路 | 当前 owner | 媒体类型 | 来源 | Adapter 复用点 | 禁止改变 | 退出条件 |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| Visual Novel 背景音乐 | `vector_engine_audio_generation.rs` | audio | VectorEngine Suno/Vidu task publish URL | 下载、MIME/extension、OSS、confirm、binding | VN 场景字段、task id、错误 envelope、计费外层 | VN 音频生成成功后仍能通过 read-url/read-bytes 读取 |
|
||||
| 通用创作背景音乐/音效 | `vector_engine_audio_generation.rs` | audio | 同上 | 同上 | 不混用 VN 场景语义 | creation target entity/slot 不变 |
|
||||
| Custom World opening CG video | `custom_world_ai.rs` 或后续分层文件 | video | Ark/火山视频 task 结果 URL | 视频下载、OSS、confirm、binding | storyboard->video 顺序、固定点数计费、超时错误 | storyboard 图片仍走图片 Adapter,最终视频走 media persist |
|
||||
| Character visual reference/workflow | `character_visual_assets.rs` | image/cache metadata | GPT image helper、workflow cache | 可复用 media persist 的 source/OSS/confirm/binding;图片生成 provider 不迁入复杂媒体 | 角色 workflow cache 可空继续生成 | 角色视觉发布链路回包字段不变 |
|
||||
| Character animation publish/import | `character_animation_assets.rs` | video / image sequence | data:video base64、remote video、阶段占位 | data URL/base64 解码、视频 OSS、confirm、binding | stage1 placeholder 语义、import-video contract | 导入视频和发布视频都不再复制 OSS/confirm 代码 |
|
||||
| Match3D 背景音乐 | `match3d.rs` | audio | 现有生成/上传链路 | 仅复用音频持久化 | 不恢复 Rodin/GLB 新草稿回退 | 图片素材仍按图片 Adapter 计划处理 |
|
||||
| Puzzle 背景音乐 | `puzzle.rs` | audio | 现有生成/上传链路 | 仅复用音频持久化 | puzzle 运行态和排行榜语义不变 | `puzzle_background_music` kind/binding 不变 |
|
||||
| Hyper3D/GLB 历史代理 | `hyper3d.rs` | model/glb | Hyper3D Rodin status/download | 如存在转存需求,仅复用 media persist | Match3D 新草稿禁止回退 Rodin/GLB | 历史代理 route contract 不变 |
|
||||
|
||||
## 5. 分阶段执行
|
||||
|
||||
### D1-0:只抽类型与 source 归一
|
||||
|
||||
- 新增 media source 类型:`RemoteUrl`、`DataUrl`、`Base64Bytes`、`Bytes`、`ExistingObjectKey`。
|
||||
- 新增 `MediaAssetKind`/`GeneratedMediaAssetPersistRequest`/`GeneratedMediaAssetPersistOutput`。
|
||||
- 不接任何调用方。
|
||||
|
||||
退出条件:`cargo check -p api-server --manifest-path server-rs/Cargo.toml` 通过;无公开 contract 变化。
|
||||
|
||||
### D1-1:接音频持久化
|
||||
|
||||
- 先接 Visual Novel 背景音乐/音效。
|
||||
- 再接通用 creation audio。
|
||||
- 保留 provider submit/poll/publish 在 `vector_engine_audio_generation.rs` 或后续 application 层。
|
||||
|
||||
退出条件:音频 asset kind、entity kind、slot、task id 和错误语义不变;重复下载/OSS/confirm 逻辑减少。
|
||||
|
||||
### D1-2:接视频持久化
|
||||
|
||||
- 接 opening CG 最终视频。
|
||||
- 接 character animation import/publish 视频。
|
||||
- data URL/base64 视频解析必须复用 source 层,禁止各 handler 再各写一份。
|
||||
|
||||
退出条件:视频入库后仍走私有资产读取链路;opening CG 固定点数计费外层不变。
|
||||
|
||||
### D1-3:接角色工作流与历史模型边界
|
||||
|
||||
- 角色视觉/动作 workflow cache 只复用持久化,不改缓存命中策略。
|
||||
- Hyper3D 只做历史代理可选转存复用,不扩大到 Match3D 新草稿。
|
||||
|
||||
退出条件:角色资产发布和历史 Hyper3D route contract 不变;文档状态更新。
|
||||
|
||||
## 6. 验收命令
|
||||
|
||||
文档或小步接线后必须运行:
|
||||
|
||||
```bash
|
||||
cargo check -p api-server --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server vector_engine_audio_generation --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server character_animation --manifest-path server-rs/Cargo.toml
|
||||
npm run check:encoding
|
||||
git diff --check
|
||||
```
|
||||
|
||||
如果执行外部 provider smoke,只允许读取本地显式环境变量;日志、文档和测试快照中禁止写出 API key/token。
|
||||
|
||||
## 7. 完成定义
|
||||
|
||||
D1 完成必须同时满足:
|
||||
|
||||
- 至少音频和视频两类复杂媒体通过同一个 media persist 底座。
|
||||
- 图片生成仍走图片 Adapter,不被复杂媒体接口反向污染。
|
||||
- 计费外层、HTTP route、DTO、SpacetimeDB schema、OSS 私有读取链路全部不变。
|
||||
- 大 handler 中重复的下载/base64 解码/OSS 上传/asset_object confirm/entity binding 代码有明确删除或替换记录。
|
||||
- README 与本系列总纲状态同步更新。
|
||||
156
docs/technical/【后端架构】生成图片资产Adapter收口执行计划-2026-05-14.md
Normal file
156
docs/technical/【后端架构】生成图片资产Adapter收口执行计划-2026-05-14.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# 生成图片资产 Adapter 收口执行计划
|
||||
|
||||
状态:待 C 线执行
|
||||
日期:2026-05-14
|
||||
范围:只新增/使用 `api-server` 内部生成图片资产 Adapter;不改 HTTP contract、DTO、SpacetimeDB schema、OSS 访问策略、前端行为、计费语义。
|
||||
|
||||
## 1. 目标
|
||||
|
||||
把 Big Fish、Square Hole、Custom World 中重复的图片生成持久化链路收口为一个内部能力:
|
||||
|
||||
```text
|
||||
provider 生成
|
||||
-> 下载 URL 或 base64/data URL 解码
|
||||
-> MIME/extension 归一
|
||||
-> OSS private upload
|
||||
-> 可选 HEAD/存在性确认
|
||||
-> module-assets asset_object confirm
|
||||
-> asset entity binding
|
||||
-> 返回 legacy_public_path/object_key/asset_object_id/mime/extension/task_id/actual_prompt
|
||||
```
|
||||
|
||||
首批必须接入 3 个真实调用方才算完成:
|
||||
|
||||
- Big Fish 正式图片:主图、动作图、舞台背景等。
|
||||
- Square Hole 图片:作品图片槽位重生成。
|
||||
- Custom World 场景图/封面图/opening storyboard 中的稳定单图链路。
|
||||
|
||||
## 2. 建议模块边界
|
||||
|
||||
建议放在:
|
||||
|
||||
```text
|
||||
server-rs/crates/api-server/src/modules/assets/generated_image_assets/
|
||||
mod.rs
|
||||
adapter.rs
|
||||
provider.rs
|
||||
persist.rs
|
||||
types.rs
|
||||
errors.rs
|
||||
```
|
||||
|
||||
对外只暴露 crate 内部 API,不进入 `shared-contracts`:
|
||||
|
||||
```rust
|
||||
pub(crate) async fn generate_and_persist_image(
|
||||
state: &AppState,
|
||||
request: GeneratedImageAssetRequest,
|
||||
) -> Result<GeneratedImageAssetOutput, AppError>
|
||||
```
|
||||
|
||||
Adapter 不做:
|
||||
|
||||
- 不扣费、不退款、不判断钱包。
|
||||
- 不生成玩法 prompt。
|
||||
- 不修改玩法 draft/profile JSON。
|
||||
- 不决定 retry/fallback 策略,除通用下载/入库错误映射外。
|
||||
- 不写 SpacetimeDB schema/procedure。
|
||||
|
||||
## 3. Interface 草案
|
||||
|
||||
### 3.1 输入字段
|
||||
|
||||
- provider:`OpenAiImage` / `VectorEngineGptImage2` / `DashScopeTextToImage` / `PreGeneratedImage`。
|
||||
- prompt / negative_prompt / size / count。
|
||||
- reference_images:data URL、object key、remote URL,由调用方先裁定安全来源。
|
||||
- output:OSS prefix、path segments、file name stem、access policy。
|
||||
- asset:asset_kind、entity_kind、entity_id、slot、owner_user_id、profile_id、source_job_id、metadata。
|
||||
- post_process:可选透明背景、裁剪、MIME 强制转换;首版只接入已有透明背景后处理,不新增玩法规则。
|
||||
- fallback_policy:调用方指定 `ReturnDataUrlOnPersistFailure` / `FailFast` 等,默认 fail fast。
|
||||
|
||||
### 3.2 输出字段
|
||||
|
||||
- `legacy_public_path`
|
||||
- `object_key`
|
||||
- `asset_object_id`
|
||||
- `mime_type`
|
||||
- `extension`
|
||||
- `task_id`
|
||||
- `actual_prompt`
|
||||
- `width/height`(若当前链路已有则保留,没有不强行新增 contract)
|
||||
- `metadata`
|
||||
|
||||
## 4. 图片资产 inventory
|
||||
|
||||
| 调用方 | provider | 下载/解码 | OSS prefix | asset kind | entity binding | 计费位置 | 降级行为 | Adapter 迁移策略 |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| Big Fish 正式图 | DashScope `wan2.2-t2i-flash`,`DASHSCOPE_BASE_URL`/API key 配置 | 创建 task、轮询状态、HTTP GET 图片 URL;可选透明背景后处理 | `LegacyAssetPrefix::BigFishAssets` | 由请求 assetKind 映射主鱼主图、动作图、舞台背景、等级资产等 | `BIG_FISH_ENTITY_KIND = big_fish_session`,绑定 session/entity id + slot | `big_fish.rs` 在调用正式图片动作处 `execute_billable_asset_operation` | 上游失败显式错误;gallery 另有 Spacetime runtime/connect dropped 软降级,不属于 Adapter | 先抽 DashScope provider + persist,保留 prompt/assetKind 校验在 Big Fish application 层 |
|
||||
| Square Hole 图片重生成 | `openai_image_generation.rs` OpenAI/VectorEngine GPT image helper | `create_openai_image_generation` 返回 URL/base64/data URL 后下载/解码 | `LegacyAssetPrefix::SquareHoleAssets` | 方洞作品图片槽位相关 kind | profile/work entity + image slot | 调用方现有计费包裹保持 | 生成成功但入库失败返回 Data URL 的兼容行为必须保留 | 使用 `fallback_policy = ReturnDataUrlOnPersistFailure`;slot/作品 JSON 更新仍在 Square Hole 层 |
|
||||
| Custom World 场景图 | VectorEngine GPT image 2 / OpenAI helper | URL 下载或 base64 解码 | `LegacyAssetPrefix::CustomWorldScenes` | scene image kind | profile/landmark/scene entity slot | `custom_world_ai.rs` 场景图调用处包裹 | entity/scene 文本生成存在 fallback;图片入库失败按当前错误口径 | 抽 `persist_custom_world_asset` 中图片分支;scene/npc/profile 更新留在 Custom World 层 |
|
||||
| Custom World 封面图 | VectorEngine GPT image 2 / OpenAI helper | 同上 | Custom World cover prefix/segments | cover image kind | `custom_world_profile`/profile id + cover slot | `execute_billable_asset_operation` | 失败显式错误 | 接入同一 Adapter,保留 cover upload 手动上传链路不混入生成图 provider |
|
||||
| Opening CG storyboard | GPT image 2 | 生成 storyboard 图片并下载 | Custom World opening prefix/segments | `custom_world_opening_cg_storyboard` | `custom_world_profile` + `opening_cg_storyboard` | opening CG 固定点数计费外层 | storyboard 成功后才进入视频;失败显式错误 | 可复用图片 Adapter,但 opening video 仍归复杂媒体计划 |
|
||||
|
||||
## 5. 迁移步骤
|
||||
|
||||
### 阶段 C1:抽只读类型和 persist 能力
|
||||
|
||||
- 新增 `GeneratedImageAssetRequest/Output`。
|
||||
- 抽 OSS put、asset_object confirm、entity binding 公共 persist。
|
||||
- 先不接 provider,允许调用方传入已下载图片 bytes。
|
||||
- 迁移目标:Square Hole 或 Custom World 中最小一条 persist helper。
|
||||
|
||||
退出条件:一条链路编译通过;原 HTTP 回包不变。
|
||||
|
||||
### 阶段 C2:接 OpenAI/VectorEngine provider
|
||||
|
||||
- 封装 `openai_image_generation.rs` 的 settings/client/create/download 结果归一。
|
||||
- Square Hole 接入 provider + persist。
|
||||
- Custom World 场景图/封面图接入。
|
||||
|
||||
退出条件:Square Hole 生成成功但入库失败回退 Data URL 的行为仍被测试或代码路径覆盖。
|
||||
|
||||
### 阶段 C3:接 DashScope provider
|
||||
|
||||
- 抽 Big Fish DashScope settings/client/task create/poll/download。
|
||||
- 保留 Big Fish assetKind、level、motionKey、prompt 构造、透明背景策略在 Big Fish 层。
|
||||
- 正式图入库走同一 persist。
|
||||
|
||||
退出条件:Big Fish 不再有独立 OSS + asset_object + binding 重复实现;计费外层不变。
|
||||
|
||||
### 阶段 C4:删除重复 helper
|
||||
|
||||
- 删除已迁移的私有 persist/download helper。
|
||||
- 保留 provider 特定错误 message 与现有 envelope 尽量一致。
|
||||
- 更新本系列文档状态。
|
||||
|
||||
退出条件:三类调用方都经过 Adapter;旧 helper 无未使用残留。
|
||||
|
||||
## 6. 单 owner 与并行规则
|
||||
|
||||
单 owner:
|
||||
|
||||
- `modules/assets/generated_image_assets/*`
|
||||
- `openai_image_generation.rs` 如果需要改 public helper
|
||||
- `asset_billing.rs` 禁止本阶段修改,除非单独批准
|
||||
|
||||
可并行:
|
||||
|
||||
- Big Fish 接入 owner 只改 `big_fish.rs` 和对应 tests。
|
||||
- Square Hole 接入 owner 只改 `square_hole.rs`。
|
||||
- Custom World 接入 owner 只改 `custom_world_ai.rs`。
|
||||
|
||||
合并顺序必须是:Adapter skeleton -> Square Hole/Custom World -> Big Fish -> 清理。
|
||||
|
||||
## 7. 验证命令
|
||||
|
||||
```bash
|
||||
cargo check -p api-server --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server big_fish --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server square_hole --manifest-path server-rs/Cargo.toml
|
||||
cargo test -p api-server custom_world --manifest-path server-rs/Cargo.toml
|
||||
npm run check:encoding
|
||||
git diff --check
|
||||
```
|
||||
|
||||
如执行外部 provider smoke,只允许使用显式本地环境变量;不要在日志或文档中写出 API key/token。
|
||||
Reference in New Issue
Block a user