跳到正文
Kale的数字花园
目录 文章
/7 分钟/10 阅读/0 评论

creeks-ai-img 项目全链路分析

AI 图片生成微服务,为前端 Web 平台提供 **文生图 / 图生图** 能力,底层对接 **OpenAI DALL-E** 和 **Stability AI** 两大 AI 平台,生成的图片统一存储到 **七牛云**,通过 **MySQ

一、项目定位

AI 图片生成微服务,为前端 Web 平台提供 文生图 / 图生图 能力,底层对接 OpenAI DALL-E 和 Stability AI 两大 AI 平台,生成的图片统一存储到 七牛云,通过 MySQL 持久化任务记录,Redis 缓存图片访问链接。


二、技术栈

分类 技术 版本 说明
Web 框架 Gin v1.10.0 HTTP 服务
ORM GORM + MySQL gorm v1.25.8 数据持久化
缓存 go-redis v8.11.5 七牛私有链接缓存
日志 zap + lumberjack zap v1.27.0 结构化日志 + 日志轮转
异常上报 codo-error-collect-go-sdk v0.2.3 内部统一错误采集 SDK
AI SDK (OpenAI) sashabaranov/go-openai v1.41.2 DALL-E 2/3 图片生成
AI SDK (Stability) 自封装 HTTP Client - Stability Core + SD v1.6
对象存储 七牛云 SDK go-sdk/v7 v7.19.0 私域/公域双 Bucket
数值计算 shopspring/decimal v1.3.1 费用统计高精度计算
容器化 Docker 多阶段构建 golang:1.23.4 → alpine K8s 部署
Go 版本 Go 1.23.4

三、数据库设计

数据库名:creeks_aigc,三张核心表:

3.1 ai_img_generation_info(图片生成信息表)

字段 类型 说明
id BIGINT PK 主键
user_id BIGINT 用户 ID
status TINYINT 0=处理中, 1=已完成, 2=已失败
file_type VARCHAR 输出文件类型
input_url VARCHAR 用户输入的原始图片 URL(图生图场景)
output_url VARCHAR AI 生成的图片 URL
api_platform VARCHAR "OpenAI" / "Stability"
operator_id BIGINT 操作人 ID
operator_name VARCHAR 操作人姓名
remark VARCHAR 备注/错误信息
deleted TINYINT 逻辑删除标记
created_at / updated_at TIMESTAMP 审计时间戳

3.2 ai_img_request(API 请求记录表)

字段 类型 说明
id BIGINT PK 主键
user_id BIGINT 用户 ID
info_id BIGINT FK 关联 generation_info
model VARCHAR 模型名(dall-e-3 / stable-diffusion-v1-6 / Core)
api_type VARCHAR TextToImage / ImageToImageByPrompt / TextToImageCore
api_platform VARCHAR OpenAI / Stability
request_json TEXT 序列化后的请求体
response_json TEXT 序列化后的响应体
image_num INT 生成图片数量
image_quality VARCHAR 图片质量(standard/hd)
image_size VARCHAR 图片尺寸(1024x1024)
image_style VARCHAR 图片风格(vivid/natural 等)
cfg_scale INT Stability 专属:内容接近 prompt 程度
steps INT Stability 专属:扩散步骤数
created_at / updated_at TIMESTAMP 审计时间戳

3.3 ai_media_info(AI 媒体信息表)

字段 类型 说明
id BIGINT PK 主键
generation_info_id BIGINT FK 关联 generation_info
persistence_type INT 0=模型生成, 1=用户上传
file_type VARCHAR 文件 MIME 类型
file_size BIGINT 文件大小(字节)
file_url VARCHAR 七牛云 URL
pixel_size VARCHAR 像素尺寸
created_at / updated_at TIMESTAMP 审计时间戳

ER 关系

erDiagram
    AI_IMG_GENERATION_INFO ||--o| AI_IMG_REQUEST : "1:N (foreignKey:info_id)"
    AI_IMG_GENERATION_INFO ||--o| AI_MEDIA_INFO : "1:N (foreignKey:generation_info_id)"

四、API 接口

4.1 对外暴露接口(Feign 远程调用入口)

路由前缀:/remote/ai/image

方法 路径 参数 说明 调用方
POST /generation FormData(multipart/form-data) 生成图片(异步) creekson-api (Java Feign)
POST /queryTaskList JSON(分页查询) 查询任务列表 creekson-api (Java Feign)
GET /stat/openai?month=YYYY-MM Query OpenAI 月度使用统计(CSV 导出) 内部运维
GET /stat/stability?month=YYYY-MM Query Stability 月度使用统计(CSV 导出) 内部运维
GET /health - K8s 健康检查 K8s

4.2 Java 侧 Feign 接口(creekson-api → creeks-ai-img)

文件位置:E:\code\creekson-api\.../ai/img/AiImageClient.java

@FeignClient(
    name = "creeks-ai-image",
    url = "${ai-image.service.url:http://creeks-ai-image:8080}",
    path = "/remote/ai/image")

Java 侧还对外暴露了用户端 API:

文件位置:E:\code\creekson-api\.../ai/img/AiImageController.java

方法 路径 说明
POST /api/v1/ai/img/generation 前端调用的图片生成接口
POST /api/v1/ai/img/queryTaskList 前端调用的任务查询接口
GET /api/v1/ai/img/check 健康检查

4.3 前端调用链路

文件位置:E:\code\web\src\services\ai\model.ts

前端 → POST /ai/img/generation → Nginx/网关 → creekson-api(/api/v1/ai/img/generation)
                                                        ↓ Feign
                                                 creeks-ai-img(/remote/ai/image/generation)

五、完整业务链路

5.1 完整流程(前端发起 → 异步生成 → 轮询获取)

整体流程分两个阶段:

阶段一:发起生成
前端调用生成接口 → Java 透传 → Go 异步调 AI → 立即返回任务记录

阶段二:前端轮询
前端定时轮询图片列表接口 → Java 透传 → Go 查 DB → 返回已生成的图片

sequenceDiagram
    participant FE as Web 前端
    participant Java as creekson-api (Java)
    participant Go as creeks-ai-img (Go)
    participant DB as MySQL
    participant AI as OpenAI / Stability AI
    participant Qiniu as 七牛云

    Note over FE,Qiniu: 阶段一:发起图片生成
    FE->>Java: POST /api/v1/ai/img/generation (FormData)
    Java->>Java: 获取当前登录用户信息
    Java->>Go: POST /remote/ai/image/generation (Feign, FormData)
    Go->>Go: 解析表单参数 (handleForm)
    Go->>Go: 如有用户上传的图片,先上传到七牛云
    Go->>DB: 创建 generation_info 记录 (status=0 处理中)
    Go->>DB: 创建 ai_media_info (用户上传的图片)
    Go->>DB: 创建 ai_img_request 记录
    Go-->>Java: 返回 generation_info (status=0)
    Java-->>FE: 返回任务信息

    Note over Go: 异步执行图片生成(goroutine)
    Go->>AI: 调用 OpenAI/Stability API
    AI-->>Go: 返回图片 (Base64 或 URL)
    Go->>Qiniu: 上传生成的图片到七牛云私有空间
    Go->>DB: 更新 ai_img_request (写入 response_json)
    Go->>DB: 创建 ai_media_info (生成的图片)
    Go->>DB: 更新 generation_info (status=1 完成 / 2 失败)

    Note over FE,Qiniu: 阶段二:前端轮询获取已生成的图片
    loop 每5秒轮询一次
        FE->>Java: POST /api/v1/ai/img/queryTaskList
        Java->>Go: POST /remote/ai/image/queryTaskList
        Go->>DB: 分页查询 + JOIN AiMediaInfo
        Go->>Go: 将七牛私有 URL 转为带签名的临时访问链接 (Redis 缓存 1h)
        Go-->>Java: 返回分页结果(含图片列表)
        Java-->>FE: 返回图片列表
        FE->>FE: 检查是否还有 status=0 的任务
    end
    Note over FE: 全部完成后停止轮询

5.2 生成策略路由

Go 服务内部使用 策略模式 + Map 路由:

key = apiPlatform + ":" + apiType

GenerationMap = {
    "OpenAI:TextToImage"          → OpenAiText2Img()
    "OpenAI:ImageToImageByPrompt" → OpenAiImg2ImgByPrompt()
    "Stability:TextToImage"       → StabilityAiText2Img()       // SD v1.6
    "Stability:ImageToImageByPrompt" → StabilityAiImg2ImgByPrompt()
    "Stability:TextToImageCore"   → StabilityAiText2ImgCore()   // Stability Core API
}

5.3 OpenAI 文生图子流程

5.4 Stability AI 文生图子流程

flowchart TD
    A[StabilityAiText2ImgCore] --> B[构建请求 prompt + aspect_ratio + style + negative_prompt]
    B --> C[POST v2beta stable-image generate core]
    C --> D[返回 Base64 图片]
    D --> E[Base64 解码]
    E --> F[上传七牛云]
    F --> G[构建 GenerationResult]

    A2[StabilityAiText2Img] --> B2[构建请求 text_prompts + cfg_scale + height + width + steps + style]
    B2 --> C2[POST v1 generation model text-to-image]
    C2 --> D2[返回多张 Base64 图片]
    D2 --> E2[遍历解码 + 上传七牛]
    E2 --> F2[构建 GenerationResult 列表]

六、外部依赖

6.1 远程服务依赖

依赖 类型 地址 说明
OpenAI API HTTPS OPENAI_API_BASE_URL (环境变量) DALL-E 图片生成,支持 Azure 模式
Stability AI API HTTPS STABILITY_API_HOST (默认 api.stability.ai) Stable Diffusion 图片生成
七牛云 HTTPS SDK 内置 图片存储(私有+公共 Bucket)
Redis TCP REDIS_HOST:REDIS_PORT 七牛私有链接签名缓存
MySQL TCP MYSQL_HOST:MYSQL_PORT 数据持久化
用户服务 HTTP http://localhost:8080/remote/user/userServiceV1/listUserInfoByUserIds 统计报表时获取用户信息

注意:用户服务调用硬编码为 localhost:8080,生产环境可能有问题,这是个坑。

6.2 Java 侧交互

creekson-api (Java Spring Boot)
    ├── AiImageController    ← 前端直接调用
    ├── AiImageClient        ← Feign 远程调用 creeks-ai-img
    ├── AiImgGenerationInfo  ← 数据模型
    ├── AiImgRequest         ← 数据模型
    ├── AiMediaInfo          ← 数据模型
    └── ReqPage/ResPage      ← 分页封装

七、异步处理机制

图片生成是 异步执行 的:

  1. 用户请求到达 → 创建 DB 记录 (status=0) → 立即返回
  2. go asyncExecGeneration(info, aiImgRequest) 在后台 goroutine 执行
  3. 前端通过 5 秒轮询 /queryTaskList 获取最新状态
  4. 当有正在中的任务时持续轮询,全部完成后停止

八、七牛云存储策略

Bucket 用途 访问方式
私域 Bucket (creeks-dev-private) 用户上传图片 + AI 生成图片 签名 URL,有效期 1 小时,Redis 缓存
公域 Bucket (creeks-dev-public) 未使用(预留) 公开访问

域名配置:

  • 私域域名:QINIU_IMAGE_PRIVATE_DOMAIN
  • 公域域名:QINIU_IMAGE_PUBLIC_DOMAIN

九、统计报表功能

两个 GET 接口用于月度使用统计:

GET /remote/ai/image/stat/openai?month=2024-03
GET /remote/ai/image/stat/stability?month=2024-03

流程:

  1. 从 ai_img_request 查询指定月份的请求记录
  2. 按模型计算每次请求的费用(decimal 高精度)
  3. 按 userId 分组累加请求次数和金额
  4. 调用户服务接口填充用户信息(企业/部门/姓名)
  5. 导出为 CSV 文件到本地目录

十、代码结构

creeks-ai-img/
├── main.go                    # 入口:初始化 logger/db/cache/api → 启动 Gin
├── Dockerfile                 # 多阶段构建 (golang:1.23.4 → alpine)
├── src/
│   ├── api/
│   │   ├── api.go             # 健康检查 + 初始化
│   │   ├── handle_func.go     # GenerationHandler / QueryTaskListHandler (路由入口)
│   │   ├── private_func.go    # 策略路由 Map + GenerationResult + 异步执行逻辑
│   │   ├── openai.go          # OpenAI 文生图 / 图生图实现
│   │   ├── stability.go       # Stability 文生图 / 图生图实现
│   │   ├── external_api.go    # 外部 API 初始化
│   │   └── result.go          # 统一 Result 响应结构
│   ├── db/
│   │   ├── db.go              # GORM 初始化 + BaseModel
│   │   ├── ai_img_generation_task.go  # generation_info 表的 CRUD + 分页查询
│   │   ├── ai_img_request.go          # api_request 表的 CRUD
│   │   ├── ai_media_info_db.go        # media_info 表的 CRUD
│   │   └── page.go                    # 分页通用结构体
│   ├── router/
│   │   └── route.go           # Gin 路由注册
│   ├── qiniu/
│   │   └── client.go          # 七牛云上传 + 私有链接签名
│   ├── cache/
│   │   └── cache.go           # Redis 初始化 + 签名 URL 缓存
│   ├── openai/
│   │   └── dall-e.go          # OpenAI SDK 封装
│   ├── stability/
│   │   ├── client.go          # Stability Client 结构体
│   │   ├── text_2_image.go    # SD v1.6 text-to-image
│   │   ├── text_2_image_core.go # Core API text-to-image
│   │   ├── image_2_image_*.go # 图生图相关
│   ├── stat/
│   │   ├── do_stat.go         # 月度统计逻辑
│   │   └── month_price_stat.go # 价格计算
│   ├── model/
│   │   └── user.go            # 用户模型(调远程 Java 用户服务)
│   ├── logger/
│   │   └── err_collect_logger.go # 日志 + 错误上报
│   ├── consts/
│   │   └── Const.go           # 常量:平台名、API 类型、状态码
│   └── utils/                 # 工具集
│       ├── http_util.go       # HTTP 调远程用户服务
│       ├── img_util.go        # 图片尺寸获取 / Base64 解码
│       ├── file_util.go       # 临时文件操作
│       ├── price_util.go      # 价格计算
│       ├── time.go            # 月份时间处理
│       └── ...

十一、已知问题和坑

  1. 用户服务地址硬编码:http://localhost:8080/remote/user/userServiceV1/... 在 K8s 环境下 localhost 指向自己,应该改成环境变量控制
  2. **StabilityAiText2Img 方法最后一行返回了 **nil, err:即使成功也返回了 nil 结果列表(stability.go:150),这是个 bug
  3. 无分布式锁:如果多个 Pod 同时处理同一个任务,没有并发控制
  4. 异步 goroutine 无恢复机制:如果 Pod 在异步生成过程中被杀死,任务状态会卡在 status=0(处理中)
  5. Stability HTTP 调用无超时控制(text_2_image.go 用 http.DefaultClient,没有设置 timeout)

评论需要登录。生产环境使用 GitHub 登录,本地可前往 登录页 使用开发登录。

还没有评论,来抢沙发。