Files
gen2d/docs/frontend.md
T
Gmarker689 36a6465f26 docs: 更新 README 与 API 文档,描述提示词优化链路
- README 新增提示词优化链路章节(流程图 + 特性 + API 说明)
- docs/api.md 新增提示词优化接口文档与调用链路
- 更新架构描述:PromptBuilder → PromptOptimizer
2026-05-24 20:45:24 +08:00

11 KiB
Raw Blame History

前端工程

技术栈

Vite 6 + React 18 + TypeScript + zustand + react-router-dom

类别 选型 说明
构建 Vite 6 开发服务器端口 3000,/api 代理到 localhost:8080
UI 框架 React 18 函数组件 + Hooks
状态管理 zustand 轻量,支持 devtools 中间件
路由 react-router-dom v6 SPA 模式
实时通信 原生 WebSocket 连接后端 /api/v1/tasks/:taskId/ws(Cookie 认证)
HTTP 请求 fetch + 封装层 统一错误处理、响应解包

目录结构

frontend/src/
├── main.tsx                  # 入口
├── App.tsx                   # 根组件 + 路由配置
├── api/                      # API 封装层
│   ├── client.ts             # fetch 封装:baseURL、统一错误处理、响应解包
│   ├── auth.ts               # 注册/登录(真实后端调用)
│   ├── project.ts            # 工程 CRUD + 风格 GET/PUT(mock 切换)
│   ├── generate.ts           # POST /generate、GET /tasks/:taskId、GET /tasks/:taskId/assets(mock 切换)
│   ├── mock.ts               # Mock 数据 + 模拟 WebSocket 管线进度
│   └── types.ts              # API 请求/响应类型定义(Task、Asset、Style、PipelineProgress 等)
├── stores/                   # zustand stores
│   ├── auth.ts               # 用户认证状态(login/register/logout/loadFromStorage)
│   ├── project.ts            # 当前工程(id、风格、任务列表)
│   ├── task.ts               # 当前任务草稿(用户文本、素材类型、任务风格覆盖、技术参数)
│   └── generation.ts         # 生成状态(taskId、进度、阶段、结果、错误)
├── pages/                    # 页面级组件
│   ├── LoginPage.tsx         # 登录页
│   ├── RegisterPage.tsx      # 注册页
│   ├── ProjectPage.tsx       # 工程首页:工程风格配置 + 任务列表
│   ├── GeneratePage.tsx      # 生成页:提示词构建 + 提交
│   └── ResultPage.tsx        # 结果页:素材预览 + 下载 + 元数据
├── components/               # 可复用组件
│   ├── StyleSelector.tsx     # 风格选择器(CSS Modules)
│   ├── PromptEditor.tsx      # 三段式提示词编辑器
│   ├── GenerateForm.tsx      # 生成表单
│   ├── ProgressBar.tsx       # 管线进度条(显示当前阶段 + 重试状态)
│   └── AssetPreview.tsx      # 素材预览(spritesheet 预览、单帧预览)
├── hooks/                    # 自定义 Hooks
│   ├── useGenerate.ts        # 提交生成任务 + WebSocket 订阅进度
│   └── useProjectStyle.ts    # 工程风格加载/保存
├── router/                   # 路由定义
│   └── index.tsx
├── styles/                   # 全局样式
│   └── global.css            # 暗色主题 CSS 变量 + reset
└── utils/                    # 工具函数
    └── style.ts              # 风格合并逻辑 + 风格键分类定义

实现状态

模块 状态 说明
API 封装层 [x] client.ts 统一 fetch 封装,auth.ts 真实调用,project/generate 使用 mock
Mock 层 [x] mock.ts 提供 mock 数据 + 模拟 WebSocket 管线进度
认证流程 [x] 注册/登录/退出/token 持久化,真实后端对接
zustand stores [x] auth/project/task/generation 四个 store
页面 [x] 5 个页面全部实现(Login/Register/Project/Generate/Result)
组件 [x] StyleSelector/PromptEditor/GenerateForm/ProgressBar/AssetPreview
路由 [x] 含 ProtectedRoute 守卫
WebSocket [ ] 当前使用 mock 模拟,待后端实现后切换为真实 WS

路由规划

路径 页面 说明
/ — 重定向到默认工程
/projects/:projectId ProjectPage 工程首页,配置工程风格,查看历史任务
/projects/:projectId/generate GeneratePage 提示词构建 + 提交生成
/projects/:projectId/tasks/:taskId ResultPage 任务结果页,预览素材、下载

组件树

graph TD
    App --> Router
    Router --> ProjectPage
    Router --> GeneratePage
    Router --> ResultPage

    ProjectPage --> StyleSelector["StyleSelector(工程风格编辑)"]
    ProjectPage --> TaskList["TaskList(历史任务列表)"]

    GeneratePage --> GenerateForm
    GenerateForm --> AssetTypePicker["AssetTypePicker"]
    GenerateForm --> StyleSelector2["StyleSelector(任务风格覆盖)"]
    GenerateForm --> PromptEditor["PromptEditor(三段式预览)"]
    GenerateForm --> ParamsForm["ParamsForm(分辨率、帧数)"]
    GeneratePage --> ProgressBar["ProgressBar(管线进度)"]

    ResultPage --> AssetPreview["AssetPreview(素材预览)"]
    ResultPage --> MetadataPanel["MetadataPanel(元数据)"]
    ResultPage --> DownloadButton["DownloadButton"]

核心交互流程

生成流程

sequenceDiagram
    actor User
    participant GP as GeneratePage
    participant API as 后端 API
    participant WS as WebSocket

    User->>GP: 填写 prompt、选择素材类型
    User->>GP: StyleSelector 点选任务风格覆盖
    GP->>GP: PromptEditor 实时预览三段式提示词
    User->>GP: 点击提交
    GP->>API: POST /api/v1/generate
    API-->>GP: 返回 taskId
    GP->>WS: ws://host/api/v1/tasks/:taskId/ws(Cookie 自动携带)
    loop 管线执行中
        WS-->>GP: PipelineProgress(stage + progress)
        GP->>GP: ProgressBar 更新阶段和进度
    end
    WS-->>GP: format_adapter completed + assets
    GP->>GP: 跳转 ResultPage

管线阶段对应 Eino Graph 节点,ProgressBar 展示:

阶段 说明 ProgressBar 展示
prompt_optimizer 调用 PromptAgent/LLM 优化提示词,合并风格 第 1 步
asset_generator 调用 AI 推理 API 出图 第 2 步
quality_supervisor 视觉模型质检 第 3 步(可能回退到第 1 步)
format_adapter 格式转换、spritesheet 打包 第 4 步

质检重试时,ProgressBar 显示回退动画和重试次数。

风格编辑流程

sequenceDiagram
    actor User
    participant SP as StyleSelector
    participant API as 后端 API

    User->>SP: 进入 ProjectPage
    SP->>API: GET /api/v1/projects/:id/style
    API-->>SP: 返回 kvPairs
    SP->>SP: 按分类展示风格键值对
    User->>SP: 点选/修改风格
    SP->>SP: 实时展示当前配置
    User->>SP: 点击保存
    SP->>API: PUT /api/v1/projects/:id/style
    API-->>SP: 保存成功

错误处理

API 请求错误

  • api/client.ts 统一拦截 code !== 0 的响应,抛出业务异常
  • 401:跳转到登录页(Token 已过期或无效,Cookie 会被服务端清除)
  • 403:提示无权访问,不自动跳转
  • 429:提示请求过于频繁,稍后重试
  • 500:展示通用错误提示

WebSocket 断连

  • 连接断开后自动重连(指数退避,最大间隔 10 秒)
  • 重连失败超过 3 次后,降级为轮询模式(GET /api/v1/tasks/:taskId,间隔 2-3 秒)
  • 连接恢复后自动切回 WebSocket

加载状态

  • 页面级加载(如 ProjectPage 进入时):展示骨架屏或 Loading 指示器
  • 操作级提交(如保存风格、提交生成):按钮置为 loading 态,防止重复提交

状态管理

zustand stores

project store — 当前工程

interface ProjectStore {
  projectId: string;
  name: string;
  style: Record<string, string>;  // kvPairs
  loading: boolean;
  loadProject: (projectId: string) => Promise<void>;
  loadStyle: (projectId: string) => Promise<void>;
  updateStyle: (kvPairs: Record<string, string>) => void;
  saveStyle: () => Promise<void>;
}

task store — 任务草稿(对应后端 PipelineInput)

interface TaskStore {
  prompt: string;
  assetType: 'sprite' | 'background' | 'ui' | 'animation';
  taskStyle: Record<string, string>;  // 仅覆盖的键
  params: {
    resolution: number;
    frames?: { directions: number; framesPerDirection: number };
    format: 'spritesheet' | 'individual';
  };
  setPrompt: (text: string) => void;
  setAssetType: (type: TaskStore['assetType']) => void;
  toggleTaskStyle: (key: string, value: string) => void;
  setParams: (params: Partial<TaskStore['params']>) => void;
  reset: () => void;
}

generation store — 生成状态

interface GenerationStore {
  taskId: string | null;
  stage: PipelineStage | null;
  progress: number;
  status: 'idle' | 'submitting' | 'running' | 'completed' | 'failed';
  retryCount: number;
  rejectReason: string | null;
  assets: Asset[];
  error: string | null;
  submit: (projectId: string, task: TaskStore) => Promise<void>;
  reset: () => void;
}

type PipelineStage =
  | 'prompt_optimizer'
  | 'asset_generator'
  | 'quality_supervisor'
  | 'format_adapter';

API 封装

api/client.ts 统一封装:

  • baseURL 从环境变量读取,开发模式默认 /api/v1
  • 所有 fetch 请求设置 credentials: 'include',自动携带 Cookie
  • 所有响应按 { code, message, data } 解包,code !== 0 时抛错
  • 统一 401/403/500 错误处理
  • WebSocket 连接封装为 createTaskSocket(taskId) 返回可订阅对象(浏览器自动携带 Cookie)

API 类型定义(api/types.ts)

// 请求
interface CreateProjectRequest {
  name: string;
}

interface GenerateRequest {
  projectId: string;
  prompt: string;
  assetType: 'sprite' | 'background' | 'ui' | 'animation';
  taskStyle?: Record<string, string>;
  params?: {
    resolution?: number;
    frames?: { directions?: number; framesPerDirection?: number };
    format?: 'spritesheet' | 'individual';
  };
}

interface UpdateStyleRequest {
  kvPairs: Record<string, string>;
}

// 响应
interface Project {
  id: string;
  name: string;
  style: { kvPairs: Record<string, string> };
  createdAt: string;
}

interface Task {
  id: string;
  projectId: string;
  prompt: string;
  assetType: string;
  status: 'pending' | 'running' | 'completed' | 'failed';
  stage?: PipelineStage;
  progress?: number;
  retryCount?: number;
  error?: string | null;
  createdAt: string;
  updatedAt: string;
}

interface Asset {
  id: string;
  url: string;
  format: string;
  width: number;
  height: number;
  metadata: {
    frameWidth?: number;
    frameHeight?: number;
    frameCount?: number;
    directions?: number;
  };
}

// WebSocket 消息
interface PipelineProgress {
  stage: PipelineStage;
  status: 'running' | 'completed' | 'failed';
  progress: number;
  message?: string;
  retryCount?: number;
  rejectReason?: string;
  result?: { assets: Asset[] };
  error?: string;
}

预设风格键分类

前端 StyleSelector 以分类标签组织,完整键值表见 预设风格键。

StyleSelector 两种使用场景:

  1. 工程风格(ProjectPage):全量编辑,保存到后端
  2. 任务覆盖(GeneratePage):基于工程风格展示,高亮已覆盖的键,仅记录差异