# MiniMax 图生图 API 集成设计方案 ## 概述 前端传递参数 → 后端异步调用 MiniMax 图生图 API → 前端轮询任务状态 → 返回结果 ## 现有架构 | 层级 | 技术栈 | 说明 | |------|--------|------| | 前端 | uni-app (Vue 3) | 使用 `uni.request` 发起请求,已有 loading 页面 | | 后端 | Go + Gin | API Gateway 模式,Dubbo RPC 调用微服务 | | 微服务 | Go | `assetService` 等独立服务 | | 配置 | `.env` 文件 | API keys 等敏感配置 | ## API 设计 ### 1. 创建图生图任务 ``` POST /api/v1/assets/mints/image/generation ``` **请求头:** ``` Authorization: Bearer Content-Type: application/json ``` **请求体:** ```json { "model": "image-01", "prompt": "描述文本", "aspect_ratio": "16:9", "subject_reference": [ { "type": "character", "image_file": "https://..." } ], "n": 2 } ``` **响应 (202 Accepted):** ```json { "code": 202, "message": "任务已创建", "data": { "job_id": "550e8400-e29b-41d4-a716-446655440000", "status": "PROCESSING", "created_at": 1744118400000 } } ``` ### 2. 查询任务状态 ``` GET /api/v1/assets/mints/image/generation/:job_id ``` **响应 (PROCESSING):** ```json { "code": 200, "message": "处理中", "data": { "job_id": "550e8400-e29b-41d4-a716-446655440000", "status": "PROCESSING", "progress": 50, "created_at": 1744118400000 } } ``` **响应 (COMPLETED):** ```json { "code": 200, "message": "成功", "data": { "job_id": "550e8400-e29b-41d4-a716-446655440000", "status": "COMPLETED", "progress": 100, "images": [ "https://api.minimaxi.com/v1/images/xxx.png" ], "created_at": 1744118400000, "completed_at": 1744118490000 } } ``` **响应 (FAILED):** ```json { "code": 200, "message": "失败", "data": { "job_id": "550e8400-e29b-41d4-a716-446655440000", "status": "FAILED", "progress": 0, "error_msg": "MiniMax API 调用失败: timeout", "created_at": 1744118400000 } } ``` ## 数据模型 ### Job 状态 (内存存储) ```go // JobStatus 任务状态枚举 type JobStatus string const ( StatusPending JobStatus = "PENDING" StatusProcessing JobStatus = "PROCESSING" StatusCompleted JobStatus = "COMPLETED" StatusFailed JobStatus = "FAILED" ) // ImageGenerationJob 图生图任务 type ImageGenerationJob struct { JobID string `json:"job_id"` UserID int64 `json:"user_id"` StarID int64 `json:"star_id"` Status JobStatus `json:"status"` Progress int `json:"progress"` // 0-100 Images []string `json:"images,omitempty"` ErrorMsg string `json:"error_msg,omitempty"` Request *ImageGenerationRequest `json:"request,omitempty"` CreatedAt int64 `json:"created_at"` //毫秒时间戳 UpdatedAt int64 `json:"updated_at"` CompletedAt int64 `json:"completed_at,omitempty"` // 毫秒时间戳 } ``` ### DTO ```go // ImageGenerationRequest MiniMax 图生图请求 type ImageGenerationRequest struct { Model string `json:"model" binding:"required"` Prompt string `json:"prompt" binding:"required"` AspectRatio string `json:"aspect_ratio"` SubjectReference []SubjectReference `json:"subject_reference"` N int `json:"n"` // 1-4 } type SubjectReference struct { Type string `json:"type"` ImageFile string `json:"image_file"` // 必须为有效 URL,需 SSRF 校验 } // ImageJobResponse 图生图任务响应 type ImageJobResponse struct { JobID string `json:"job_id"` Status string `json:"status"` Progress int `json:"progress"` Images []string `json:"images,omitempty"` ErrorMsg string `json:"error_msg,omitempty"` CreatedAt int64 `json:"created_at"` UpdatedAt int64 `json:"updated_at"` CompletedAt int64 `json:"completed_at,omitempty"` } ``` ## 后端实现 ### 文件结构 ``` backend/ ├── services/assetService/ │ └── service/ │ └── minimax_service.go # MiniMax API 转发服务 + 任务管理 └── gateway/ ├── controller/ │ └── asset_controller.go # 新增 ImageGeneration, GetImageJob ├── dto/ │ └── image_dto.go # 请求/响应 DTO └── router/ └── router.go # 注册路由 ``` ### 核心逻辑 1. **创建任务**: 生成 job_id,存储任务到内存 map,返回 202 2. **异步处理**: goroutine 调用 MiniMax API,图片压缩(最大边1024px),更新 job 状态 3. **查询状态**: 从内存读取 job 状态返回 4. **任务清理**: 后台 goroutine 定期清理超期(>24h)的已完成任务 ### 图片压缩 - 最大边压缩至 1024px,保持宽高比 - 格式转换: PNG/GIF → JPEG(质量85%) - 返回 base64 data URI 格式 ### SSRF 防护 `subject_reference[].image_file` 必须是有效 URL,下载前需校验: - 不能是私有 IP (10.x, 172.16-31.x, 192.168.x) - 不能是 localhost - 不能是内网域名 - 校验失败则拒绝请求 (400) ## 前端改动 **generation-loading.vue**: - 调用 `POST /generation` 获取 job_id - 每 3 秒轮询 `GET /generation/:job_id` - 超时时间: 120 秒后显示"生成超时,请重试" - 完成后跳转到结果页 ## HTTP 状态码 | 场景 | HTTP 状态码 | |------|-------------| | 成功 (创建/查询) | 200 / 202 | | 参数校验失败 | 400 | | 未认证 | 401 | | 无权访问 job | 403 | | Job 不存在 | 404 | | MiniMax API 失败 | 500 | ## 错误处理 | 场景 | 处理方式 | |------|----------| | MiniMax API 超时 | 标记 job 为 FAILED,error_msg 包含原因 | | 图片压缩失败 | 使用原图,继续处理 | | SSRF 校验失败 | 返回 400,"无效的图片URL" | | Job 不存在 | 返回 404 | | 无权访问 job | 返回 403 | ## 文件修改清单 | 操作 | 文件路径 | 说明 | |------|----------|------| | 新增 | `backend/gateway/dto/image_dto.go` | 请求/响应 DTO | | 新增 | `backend/services/assetService/service/minimax_service.go` | MiniMax API 转发 + 图片压缩 + 任务管理 | | 修改 | `backend/gateway/controller/asset_controller.go` | 新增 ImageGeneration, GetImageJob | | 修改 | `backend/gateway/router/router.go` | 注册路由 | | 修改 | `frontend/pages/discover/generation-loading.vue` | 改为轮询模式 | ## 依赖 ```bash cd backend/services/assetService && go get github.com/nfnt/resize ``` ## 验证方案 1. 启动后端服务 2. 获取 JWT token 3. 测试创建任务: ```bash curl -X POST http://localhost:8080/api/v1/assets/mints/image/generation \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"model":"image-01","prompt":"test","aspect_ratio":"16:9","n":1,"subject_reference":[]}' ``` 4. 使用返回的 job_id 轮询状态: ```bash curl http://localhost:8080/api/v1/assets/mints/image/generation/ \ -H "Authorization: Bearer " ```