--- title: "02-计划书" created: 2026-01-30 aliases: - 计划书 tags: - 项目 --- # 计划书 ## 1. 项目结构 text ```text styling-ai/ ├── package.json ├── pnpm-workspace.yaml ├── turbo.json │ ├── apps/ │ ├── web/ # 前端应用 (Next.js) │ │ ├── package.json │ │ ├── next.config.js │ │ ├── tailwind.config.js │ │ ├── tsconfig.json │ │ ├── public/ │ │ │ └── images/ │ │ └── src/ │ │ ├── app/ │ │ │ ├── layout.tsx │ │ │ ├── page.tsx # 首页 │ │ │ ├── result/ │ │ │ │ └── [taskId]/ │ │ │ │ └── page.tsx # 结果页 │ │ │ └── globals.css │ │ ├── components/ │ │ │ ├── upload/ │ │ │ ├── progress/ │ │ │ ├── result/ │ │ │ └── common/ │ │ ├── hooks/ │ │ ├── lib/ │ │ └── types/ │ │ │ └── api/ # 后端应用 (Express) │ ├── package.json │ ├── tsconfig.json │ └── src/ │ ├── index.ts # 入口 │ ├── app.ts # Express 应用 │ ├── config/ │ │ ├── index.ts # 配置加载 │ │ ├── models.yaml # 模型配置 │ │ └── prompts.yaml # 提示词配置 │ ├── routes/ │ │ ├── upload.ts │ │ ├── status.ts │ │ ├── result.ts │ │ └── admin.ts │ ├── controllers/ │ │ ├── uploadController.ts │ │ ├── statusController.ts │ │ └── resultController.ts │ ├── services/ │ │ ├── taskOrchestrator.ts │ │ ├── imageProcessor.ts │ │ ├── storageService.ts │ │ └── cleanupService.ts │ ├── providers/ │ │ ├── vision/ │ │ │ ├── index.ts # 工厂 │ │ │ ├── base.ts # 基类 │ │ │ ├── openai.ts │ │ │ ├── anthropic.ts │ │ │ ├── google.ts │ │ │ └── alibaba.ts │ │ └── imageGen/ │ │ ├── index.ts # 工厂 │ │ ├── base.ts # 基类 │ │ ├── dalle.ts │ │ ├── replicate.ts │ │ └── fal.ts │ ├── utils/ │ │ ├── promptParser.ts │ │ ├── validator.ts │ │ └── logger.ts │ ├── middleware/ │ │ ├── errorHandler.ts │ │ ├── rateLimiter.ts │ │ └── validator.ts │ └── types/ │ ├── task.ts │ ├── models.ts │ └── api.ts │ ├── packages/ │ └── shared/ # 共享代码 │ ├── package.json │ └── src/ │ ├── constants/ │ │ └── errorCodes.ts │ └── types/ │ └── common.ts │ ├── docker/ │ ├── Dockerfile.web │ ├── Dockerfile.api │ └── docker-compose.yml │ └── docs/ ├── api.md └── deployment.md ``` --- ## 2. 开发阶段划分 ### 阶段概览 text ```text ┌─────────────────────────────────────────────────────────────────┐ │ Phase 0: 项目初始化 [0.5 天] │ ├─────────────────────────────────────────────────────────────────┤ │ Phase 1: 后端核心 - 模型适配层 [2 天] │ ├─────────────────────────────────────────────────────────────────┤ │ Phase 2: 后端核心 - 任务编排与 API [2 天] │ ├─────────────────────────────────────────────────────────────────┤ │ Phase 3: 前端开发 [2 天] │ ├─────────────────────────────────────────────────────────────────┤ │ Phase 4: 集成测试与优化 [1 天] │ ├─────────────────────────────────────────────────────────────────┤ │ Phase 5: 部署与上线 [0.5 天] │ └─────────────────────────────────────────────────────────────────┘ 总计: 8 天 ``` --- ### Phase 0: 项目初始化 [0.5 天] #### 任务清单 | **编号** | **任务** | **产出物** | **预计耗时** | | --- | --- | --- | --- | | 0.1 | 创建 monorepo 结构 | 项目骨架 | 1h | | 0.2 | 配置 TypeScript、ESLint、Prettier | 配置文件 | 0.5h | | 0.3 | 配置 pnpm workspace | pnpm-workspace.yaml | 0.5h | | 0.4 | 初始化 Next.js 前端应用 | apps/web | 0.5h | | 0.5 | 初始化 Express 后端应用 | apps/api | 0.5h | | 0.6 | 创建共享包 | packages/shared | 0.5h | | 0.7 | 配置环境变量模板 | .env.example | 0.5h | #### 验收标准 - `pnpm install` 成功 - `pnpm dev` 可同时启动前后端 - TypeScript 编译无错误 --- ### Phase 1: 后端核心 - 模型适配层 [2 天] #### Day 1: 配置系统与基础架构 | **编号** | **任务** | **产出物** | **预计耗时** | | --- | --- | --- | --- | | 1.1 | 实现配置加载器 | config/index.ts | 2h | | 1.2 | 创建 models.yaml 配置文件 | config/models.yaml | 1h | | 1.3 | 定义类型接口 | types/models.ts | 1h | | 1.4 | 实现 Vision Provider 基类 | providers/vision/base.ts | 2h | | 1.5 | 实现 ImageGen Provider 基类 | providers/imageGen/base.ts | 2h | #### Day 2: 具体 Provider 实现 | **编号** | **任务** | **产出物** | **预计耗时** | | --- | --- | --- | --- | | 1.6 | 实现 OpenAI Vision Provider | providers/vision/openai.ts | 2h | | 1.7 | 实现 DALL-E Provider | providers/imageGen/dalle.ts | 2h | | 1.8 | 实现 Replicate Provider | providers/imageGen/replicate.ts | 2h | | 1.9 | 实现 Provider 工厂 | providers/\*/index.ts | 1h | | 1.10 | 编写单元测试 | **tests**/providers/\*.test.ts | 1h | #### 关键代码示例 TypeScript ```typescript // providers/vision/base.ts export abstract class VisionProviderBase implements VisionProvider { protected config: ProviderConfig; protected httpClient: AxiosInstance; constructor(config: ProviderConfig) { this.config = config; this.httpClient = axios.create({ timeout: config.timeout, headers: this.getDefaultHeaders() }); } abstract analyze(request: VisionAnalysisRequest): Promise; protected abstract getDefaultHeaders(): Record; protected abstract formatRequest(request: VisionAnalysisRequest): unknown; protected abstract parseResponse(response: unknown): VisionAnalysisResponse; async healthCheck(): Promise { // 实现健康检查逻辑 } } // providers/vision/openai.ts export class OpenAIVisionProvider extends VisionProviderBase { async analyze(request: VisionAnalysisRequest): Promise { const payload = this.formatRequest(request); const response = await this.httpClient.post(this.config.endpoint, payload); return this.parseResponse(response.data); } protected formatRequest(request: VisionAnalysisRequest) { return { model: this.config.model, messages: [ { role: 'system', content: this.getSystemPrompt() }, { role: 'user', content: [ { type: 'text', text: request.prompt }, { type: 'image_url', image_url: { url: `data:${request.mimeType};base64,${request.imageBase64}` } } ] } ], max_tokens: this.config.maxTokens }; } ``` #### 验收标准 - OpenAI Vision 调用成功,返回结构化数据 - DALL-E 图像生成成功 - Provider 可通过配置文件切换 - 单元测试覆盖率 > 80% --- ### Phase 2: 后端核心 - 任务编排与 API [2 天] #### Day 3: 核心服务层 | **编号** | **任务** | **产出物** | **预计耗时** | | --- | --- | --- | --- | | 2.1 | 实现图片处理服务 | services/imageProcessor.ts | 2h | | 2.2 | 实现存储服务 | services/storageService.ts | 2h | | 2.3 | 实现任务编排器 | services/taskOrchestrator.ts | 3h | | 2.4 | 实现提示词解析器 | utils/promptParser.ts | 1h | #### Day 4: API 路由层 | **编号** | **任务** | **产出物** | **预计耗时** | | --- | --- | --- | --- | | 2.5 | 实现 upload 路由 | routes/upload.ts | 2h | | 2.6 | 实现 status 路由 | routes/status.ts | 1h | | 2.7 | 实现 result 路由 | routes/result.ts | 1h | | 2.8 | 实现错误处理中间件 | middleware/errorHandler.ts | 1h | | 2.9 | 实现速率限制中间件 | middleware/rateLimiter.ts | 1h | | 2.10 | API 集成测试 | **tests**/api/\*.test.ts | 2h | #### 关键代码示例 TypeScript ```typescript // services/taskOrchestrator.ts export class TaskOrchestrator { private tasks: Map = new Map(); private visionProvider: VisionProvider; private imageGenProvider: ImageGenProvider; constructor( private modelFactory: ModelFactory, private storageService: StorageService, private imageProcessor: ImageProcessor ) { this.visionProvider = modelFactory.getVisionProvider(); this.imageGenProvider = modelFactory.getImageGenProvider(); } async createTask(imageBuffer: Buffer, mimeType: string): Promise { const taskId = uuidv4(); // 处理图片 const processed = await this.imageProcessor.process(imageBuffer); const imagePath = await this.storageService.saveOriginal(taskId, processed); // 创建任务 const task: Task = { id: taskId, status: 'pending', progress: 0, originalImage: { path: imagePath, mimeType }, createdAt: new Date(), expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000) }; this.tasks.set(taskId, task); // 异步执行 this.executeTask(taskId).catch(err => { this.updateTask(taskId, { status: 'failed', error: err }); }); return taskId; } private async executeTask(taskId: string): Promise { const task = this.tasks.get(taskId); // Step 1: Vision 分析 this.updateTask(taskId, { status: 'analyzing', progress: 20 }); const imageBase64 = await this.storageService.readAsBase64(task.originalImage.path); const analysisResult = await this.visionProvider.analyze({ imageBase64, mimeType: task.originalImage.mimeType, prompt: this.getPrompt() }); const parsed = parseVisionResponse(analysisResult.rawResponse); this.updateTask(taskId, { analysis: { ...analysisResult, ...parsed }, progress: 50 }); // Step 2: 图像生成 this.updateTask(taskId, { status: 'generating', progress: 60 }); const generationResult = await this.imageGenProvider.generate({ prompt: parsed.imagePrompt, referenceImageBase64: imageBase64 }); // Step 3: 保存结果 const generatedPath = await this.storageService.saveGenerated( taskId, generationResult.imageUrl ); this.updateTask(taskId, { status: 'completed', progress: 100, generation: { imageUrl: generationResult.imageUrl, localPath: generatedPath, completedAt: new Date() } }); } } ``` #### 验收标准 - POST /api/upload 成功创建任务 - GET /api/status/:taskId 正确返回状态 - 完整流程端到端测试通过 - 错误场景正确处理 --- ### Phase 3: 前端开发 [2 天] #### Day 5: 核心组件 | **编号** | **任务** | **产出物** | **预计耗时** | | --- | --- | --- | --- | | 3.1 | 实现 DropZone 上传组件 | components/upload/DropZone.tsx | 2h | | 3.2 | 实现图片预览组件 | components/upload/ImagePreview.tsx | 1h | | 3.3 | 实现进度展示组件 | components/progress/\* | 2h | | 3.4 | 实现 API 调用封装 | lib/api.ts | 1.5h | | 3.5 | 实现状态轮询 Hook | hooks/useTaskStatus.ts | 1.5h | #### Day 6: 页面与集成 | **编号** | **任务** | **产出物** | **预计耗时** | | --- | --- | --- | --- | | 3.6 | 实现首页 | app/page.tsx | 2h | | 3.7 | 实现结果页 | app/result/[taskId]/page.tsx | 2h | | 3.8 | 实现前后对比组件 | components/result/BeforeAfter.tsx | 1.5h | | 3.9 | 实现造型说明组件 | components/result/ReasoningCard.tsx | 1h | | 3.10 | 样式与响应式 | 全局样式调整 | 1.5h | #### 关键代码示例 TypeScript ```typescript // hooks/useTaskStatus.ts export function useTaskStatus(taskId: string | null) { const [state, setState] = useState({ status: 'idle', progress: 0, message: '', result: null, error: null }); useEffect(() => { if (!taskId) return; let isMounted = true; let pollCount = 0; const poll = async () => { try { const data = await api.getTaskStatus(taskId); if (!isMounted) return; setState(prev => ({ ...prev, status: data.status, progress: data.progress, message: getStatusMessage(data.status) })); if (data.status === 'completed') { const result = await api.getTaskResult(taskId); setState(prev => ({ ...prev, result })); return; // 停止轮询 } if (data.status === 'failed') { setState(prev => ({ ...prev, error: data.error })); return; // 停止轮询 } // 动态调整轮询间隔 pollCount++; const interval = pollCount < 5 ? 2000 : 5000; setTimeout(poll, interval); } catch (error) { if (isMounted) { setState(prev => ({ ...prev, error: { message: '网络错误,请重试' } })); } } }; poll(); return () => { isMounted = false; }; }, [taskId]); return state; } // components/upload/DropZone.tsx export function DropZone({ onUpload }: DropZoneProps) { const [isDragging, setIsDragging] = useState(false); const [preview, setPreview] = useState(null); const fileInputRef = useRef(null); const handleDrop = useCallback((e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); const file = e.dataTransfer.files[0]; if (file && validateImage(file)) { handleFile(file); } }, []); const handleFile = async (file: File) => { // 前端压缩 const compressed = await compressImage(file, { maxWidth: 2048, quality: 0.9 }); // 预览 const previewUrl = URL.createObjectURL(compressed); setPreview(previewUrl); // 上传 onUpload(compressed); }; return (
{ e.preventDefault(); setIsDragging(true); }} onDragLeave={() => setIsDragging(false)} onDrop={handleDrop} > {preview ? ( setPreview(null)} /> ) : ( <>

拖拽图片到这里,或点击上传

支持 JPG、PNG、WebP,最大 10MB

e.target.files?.[0] && handleFile(e.target.files[0])} /> )}
); } ``` #### 验收标准 - 图片上传功能正常 - 进度展示实时更新 - 结果页正确展示前后对比 - 移动端适配良好 --- ### Phase 4: 集成测试与优化 [1 天] | **编号** | **任务** | **产出物** | **预计耗时** | | --- | --- | --- | --- | | 4.1 | 端到端流程测试 | 测试报告 | 2h | | 4.2 | 错误场景测试 | 测试用例 | 1h | | 4.3 | 性能优化(图片加载、API响应) | 优化记录 | 2h | | 4.4 | 模型切换测试 | 测试报告 | 1h | | 4.5 | Bug 修复 | - | 2h | #### 测试用例清单 Markdown ```text ## 正常流程 - [ ] 上传 JPG 图片 → 成功生成 - [ ] 上传 PNG 图片 → 成功生成 - [ ] 上传 WebP 图片 → 成功生成 ## 边界情况 - [ ] 上传超大图片 (> 10MB) → 提示错误 - [ ] 上传非图片文件 → 提示错误 - [ ] 上传无人脸图片 → 提示错误(如果启用检测) - [ ] 上传多人脸图片 → 提示错误(如果启用检测) ## 错误恢复 - [ ] Vision API 超时 → 重试后成功 - [ ] 图像生成失败 → 正确显示错误 - [ ] 网络中断 → 重连后恢复 ## 模型切换 - [ ] 切换 Vision Provider → 功能正常 - [ ] 切换 ImageGen Provider → 功能正常 ## 并发测试 - [ ] 同时 5 个请求 → 全部成功 - [ ] 触发速率限制 → 正确提示 ``` --- ### Phase 5: 部署与上线 [0.5 天] | **编号** | **任务** | **产出物** | **预计耗时** | | --- | --- | --- | --- | | 5.1 | 编写 Dockerfile | docker/\* | 1h | | 5.2 | 配置 docker-compose | docker-compose.yml | 0.5h | | 5.3 | 配置生产环境变量 | .env.production | 0.5h | | 5.4 | 部署到服务器 | 运行实例 | 1h | | 5.5 | 验证生产环境 | 验收记录 | 1h | --- ## 3. 里程碑与交付物 | **里程碑** | **时间点** | **交付物** | | --- | --- | --- | | M0: 项目启动 | Day 0.5 | 可运行的项目骨架 | | M1: 模型层完成 | Day 2.5 | 可配置切换的 AI 调用层 | | M2: 后端完成 | Day 4.5 | 完整可用的 API 服务 | | M3: 前端完成 | Day 6.5 | 完整可用的 Web 界面 | | M4: 测试通过 | Day 7.5 | 测试报告 + Bug 修复 | | M5: 上线 | Day 8 | 生产环境部署完成 | --- ## 4. 技术栈确认 | **层级** | **技术选型** | **版本** | | --- | --- | --- | | 前端框架 | Next.js | 14.x | | UI 组件 | TailwindCSS + Radix UI | - | | 后端框架 | Express | 4.x | | 语言 | TypeScript | 5.x | | 运行时 | Node.js | 18.x LTS | | 包管理 | pnpm | 8.x | | 图片处理 | sharp | 0.33.x | | HTTP 客户端 | axios | 1.x | | 配置文件 | yaml | - | | 测试框架 | Vitest | 1.x | --- ## 5. 风险与应对 | **风险** | **概率** | **影响** | **应对措施** | | --- | --- | --- | --- | | AI API 响应慢 | 高 | 中 | 增加超时配置、进度提示优化 | | 人脸一致性差 | 中 | 高 | 提示词优化、支持切换到 InstantID | | 模型 API 变更 | 低 | 中 | 适配器模式隔离变更 | | 图片存储成本 | 中 | 低 | 严格的过期清理策略 | --- ## 6. 后续迭代建议 ### v1.1 - 增加 Anthropic Claude、Google Gemini Vision 支持 - 增加 Midjourney 集成(通过代理) - 历史记录(本地存储) ### v1.2 - 多风格选择(甜美/帅气/知性等) - 用户反馈收集 - A/B 测试框架 ### v2.0 - 用户账号体系 - 批量生成 - 付费功能 --- **VibeCoding 导航**:⬅️ [[01-造型生成网站 - 设计稿|01-造型生成网站 - 设计稿]] | 02-计划书 | ➡️ [[01-项目文档(Project Overview)|01-项目文档(Project Overview)]]