diff --git a/docs/api.md b/docs/api.md index a1ee06f..26136c0 100644 --- a/docs/api.md +++ b/docs/api.md @@ -93,6 +93,16 @@ Token 通过登录接口获取,过期时间由 `GEN2D_JWT_EXPIRE` 控制(默 } ``` +错误响应: + +| 场景 | code | message | +|------|------|---------| +| 用户名格式不合法(非 3-64 字符或含特殊字符) | 400 | 用户名格式不合法 | +| 密码长度不足 | 400 | 密码长度不能少于 8 位 | +| 邮箱格式不合法 | 400 | 邮箱格式不正确 | +| 用户名已存在 | 409 | 用户名已被注册 | +| 邮箱已存在 | 409 | 邮箱已被注册 | + ### POST /api/v1/auth/login ```json @@ -160,8 +170,6 @@ Token 通过登录接口获取,过期时间由 `GEN2D_JWT_EXPIRE` 控制(默 | 场景 | code | message | |------|------|---------| | 原密码错误 | 400 | 原密码不正确 | -| 用户名已存在 | 409 | 用户名已被注册 | -| 邮箱已存在 | 409 | 邮箱已被注册 | ## 工程管理 @@ -477,6 +485,7 @@ interface PipelineProgress { {"stage":"prompt_builder","status":"completed","progress":100} {"stage":"asset_generator","status":"running","progress":0} {"stage":"asset_generator","status":"completed","progress":100} +{"stage":"quality_supervisor","status":"running","progress":0} {"stage":"quality_supervisor","status":"completed","progress":100} {"stage":"format_adapter","status":"running","progress":0} {"stage":"format_adapter","status":"completed","progress":100,"result":{"assets":[...]}} @@ -495,9 +504,39 @@ interface PipelineProgress { ## 缓存管理 -需认证。 +需认证。用于管理应用层去重缓存(详见 [数据存储 — 去重策略](database.md#去重策略)),主要用于调试和运维场景。 | 状态 | 方法 | 路径 | 说明 | |------|------|------|------| -| [ ] | DELETE | `/api/v1/cache/:key` | 清除特定缓存 | -| [ ] | POST | `/api/v1/cache/clear` | 批量清除缓存 | +| [ ] | DELETE | `/api/v1/cache/:key` | 清除特定去重缓存条目 | +| [ ] | POST | `/api/v1/cache/clear` | 批量清除所有去重缓存 | + +### DELETE /api/v1/cache/:key + +清除指定去重键的缓存条目。`:key` 为 `hash(prompt + assetType + params)` 生成的去重键,仅在需要手动解除去重锁定时使用。 + +响应: + +```json +{ + "code": 0, + "message": "ok", + "data": null +} +``` + +### POST /api/v1/cache/clear + +清除所有去重缓存条目,不影响正在执行的任务。 + +响应: + +```json +{ + "code": 0, + "message": "ok", + "data": { + "cleared": 5 + } +} +``` diff --git a/docs/async-tasks.md b/docs/async-tasks.md index 00e9712..2cbd0f5 100644 --- a/docs/async-tasks.md +++ b/docs/async-tasks.md @@ -109,6 +109,16 @@ func (s *TaskService) StartWorkers(n int) { | 队列容量 | 100 | 内存 channel 缓冲大小 | | Worker 数 | 3 | 并发执行任务数 | +### 超时控制 + +每个任务的 `processTask` 执行设置超时上下文(默认 10 分钟),超时后: + +1. 取消正在执行的管线节点(如 AI 推理调用) +2. 更新 `task.status = failed`,`task.error = "任务执行超时"` +3. Worker 释放,继续处理下一个任务 + +避免长时间卡住的任务永久占用 Worker。 + ## 管线阶段与进度 每个阶段对应 Eino Graph 的一个节点,执行过程中更新 `task.stage` 和 `task.progress`: @@ -173,21 +183,8 @@ ws://host/api/v1/tasks/:taskId/ws?token= ## 去重 -相同 `prompt + assetType + params` 的并发请求,通过应用层去重避免重复生成: - -1. 计算 `hash(prompt + assetType + params)` 作为去重键 -2. `sync.Map` 中查找:若存在且任务仍在运行中,直接返回已有 taskId -3. 任务完成或失败后从内存中清除 - -去重范围为当前实例内存,不跨实例共享。相同输入在不同时间点允许重新生成。 +去重策略详见 [数据存储 — 去重策略](database.md#去重策略)。相同输入的并发请求直接返回已有 taskId,任务完成后从内存清除。 ## 文件存储 -任务完成后,FormatAdapter 将素材上传至 OSS: - -- **开发环境**:写入本地 `data/` 目录,通过 Gin 静态文件服务访问 -- **生产环境**:上传至 OSS 存储桶,`asset.url` 存储完整 CDN URL - -OSS Key 结构:`users/{userId}/projects/{projectId}/tasks/{taskId}/output/` - -素材持久化保存,随工程生命周期管理,删除工程时级联删除 OSS 文件。 +任务完成后,FormatAdapter 将素材上传至 OSS。素材文件的存储结构与访问方式详见 [数据存储 — 文件存储](database.md#文件存储)。 diff --git a/docs/backend.md b/docs/backend.md index 715a76f..7178701 100644 --- a/docs/backend.md +++ b/docs/backend.md @@ -11,10 +11,13 @@ ``` backend/internal/ ├── handler/ # HTTP handlers(薄层,只做参数绑定 + 调用 service) +│ ├── auth.go # 用户注册 / 登录 / 当前用户 / 修改密码 +│ ├── project.go # 工程 CRUD + 任务列表 │ ├── generate.go # 生成任务提交 / 查询 / WebSocket │ ├── project_style.go # 工程风格 CRUD │ └── health.go # [已有] 健康检查 ├── service/ # 业务逻辑层 +│ ├── auth.go # 用户认证:注册、登录、JWT 签发与校验 │ ├── pipeline.go # Eino compose.Graph 编排:PromptBuilder → AssetGenerator → QualitySupervisor → FormatAdapter │ ├── nodes.go # 管线四个节点的实现(每个节点单一职责) │ ├── types.go # 管线输入/状态/输出的显式结构体定义 @@ -22,10 +25,12 @@ backend/internal/ │ └── project_style.go # 工程风格管理 & 风格合并逻辑 ├── model/ # 数据模型 / DTO │ ├── response.go # [已有] 统一响应 +│ ├── user.go # 用户模型 │ ├── task.go # 生成任务 & 素材 │ └── style.go # 工程风格 & 任务风格覆盖 ├── middleware/ # 中间件 │ ├── logger.go +│ ├── auth.go # JWT 认证中间件 │ └── ratelimit.go ├── config/ # [已有] 配置 │ └── config.go @@ -194,12 +199,7 @@ func RunPipeline(ctx context.Context, in PipelineInput) (*PipelineOutput, error) | Prompt | PromptBuilder 输出的三段式提示词(主题+约束+内容),管线中间产物,不持久化 | 由 Task 生成 | | Asset | 生成结果素材,关联到任务,包含 URL、元数据(分辨率、帧数、格式) | 属于 Task | -```mermaid -erDiagram - Project ||--|| ProjectStyle : has - Project ||--|{ Task : has - Task ||--|{ Asset : has -``` +ER 关系图与外键约束详见 [数据存储 — ER 关系](database.md#er-关系)。 ## 风格模型 @@ -234,3 +234,12 @@ finalStyle = merge(projectStyle.KVPairs, taskStyle.KVPairs) ``` 任务同名键覆盖工程风格,由 PromptBuilder 节点在生成提示词时执行合并。 + +## 缓存层 + +`cache/cache.go` 提供应用内存级缓存,主要用于请求去重(详见 [数据存储 — 去重策略](database.md#去重策略)): + +- **数据结构**:`sync.Map`,key 为 `hash(prompt + assetType + params)`,value 为 taskId +- **生命周期**:任务提交时写入,任务完成或失败后清除;可设置 TTL 过期兜底 +- **作用域**:单实例内存,不跨实例共享 +- **接口**:提供 `Get`/`Set`/`Delete`/`Clear` 方法,同时供 handler 层(缓存管理 API)和 service 层(去重检查)调用 diff --git a/docs/database.md b/docs/database.md index 53d6569..be11f9b 100644 --- a/docs/database.md +++ b/docs/database.md @@ -190,6 +190,7 @@ task 1 ── N asset | 环境变量 | 默认值 | 说明 | |----------|--------|------| +| `GEN2D_SERVER_PORT` | `8080` | HTTP 服务监听端口 | | `GEN2D_DB_DSN` | `root:@tcp(127.0.0.1:3306)/gen2d?charset=utf8mb4&parseTime=True&loc=Local` | MySQL DSN | | `GEN2D_DB_MAX_OPEN` | `25` | 最大连接数 | | `GEN2D_DB_MAX_IDLE` | `5` | 最大空闲连接数 | @@ -224,6 +225,8 @@ backend/internal/migrations/ 启动时自动执行 `migrate.Up()`,保证 schema 与代码版本一致。 +> 注:`project_style` 表的创建包含在 `000002_init_project.up.sql` 中,与 `project` 表同批迁移。 + --- ## 索引说明 diff --git a/docs/frontend.md b/docs/frontend.md index 80ff314..2cb7afe 100644 --- a/docs/frontend.md +++ b/docs/frontend.md @@ -136,6 +136,27 @@ sequenceDiagram API-->>SP: 保存成功 ``` +## 错误处理 + +### API 请求错误 + +- `api/client.ts` 统一拦截 `code !== 0` 的响应,抛出业务异常 +- 401:自动清除本地 Token,跳转到登录页(或提示重新登录) +- 403:提示无权访问,不自动跳转 +- 429:提示请求过于频繁,稍后重试 +- 500:展示通用错误提示 + +### WebSocket 断连 + +- 连接断开后自动重连(指数退避,最大间隔 10 秒) +- 重连失败超过 3 次后,降级为轮询模式(`GET /api/v1/tasks/:taskId`,间隔 2-3 秒) +- 连接恢复后自动切回 WebSocket + +### 加载状态 + +- 页面级加载(如 ProjectPage 进入时):展示骨架屏或 Loading 指示器 +- 操作级提交(如保存风格、提交生成):按钮置为 loading 态,防止重复提交 + ## 状态管理 ### zustand stores @@ -248,6 +269,7 @@ interface Task { stage?: PipelineStage; progress?: number; retryCount?: number; + error?: string | null; createdAt: string; updatedAt: string; } @@ -281,16 +303,7 @@ interface PipelineProgress { ## 预设风格键分类 -前端 StyleSelector 以分类标签组织,用户点选: - -| 分类 | 键名 | 可选值 | -|------|------|--------| -| 美术风格 | `artStyle` | pixel, cartoon, hand-drawn, vector, flat | -| 色调 | `palette` | warm, cool, neutral, vibrant, muted, monochrome | -| 线条 | `lineWeight` | none, thin, medium, thick | -| 场景 | `scene` | forest, dungeon, city, space, underwater, desert | -| 光照 | `lighting` | bright, dim, dramatic, ambient, neon | -| 情绪 | `mood` | cheerful, dark, mysterious, epic, calm | +前端 StyleSelector 以分类标签组织,完整键值表见 [预设风格键](style-keys.md)。 StyleSelector 两种使用场景: 1. **工程风格**(ProjectPage):全量编辑,保存到后端 diff --git a/docs/multi-agent-pipeline.md b/docs/multi-agent-pipeline.md index 6b50dc8..606b2b1 100644 --- a/docs/multi-agent-pipeline.md +++ b/docs/multi-agent-pipeline.md @@ -1,6 +1,6 @@ # 多阶段生成管线 -gen2d 的核心生成流程采用 Eino `compose.Graph` 编排的四阶段管线,含质检不通过时的重生成分支。 +gen2d 的核心生成流程采用 Eino `compose.Graph` 编排的四阶段管线,含质检不通过时的重生成分支。管线编排与节点实现详见 [后端工程 — 管线设计](backend.md#管线设计eino-composegraph)。 ```mermaid flowchart LR @@ -58,3 +58,7 @@ finalStyle = merge(projectStyle.KVPairs, taskStyle.KVPairs) - **职责**:格式转换、spritesheet 打包、元数据生成。 - **示例**:输入 4 张 64×64 的角色行走帧 PNG → 输出一张 256×64 的 spritesheet + JSON 元数据(帧尺寸、帧数、锚点偏移),可直接拖入 Unity 2D Animation 使用。 +--- + +管线执行过程中的进度推送与重试机制详见 [异步任务](async-tasks.md)。 +