feat: 引入 Eino 框架,实现四阶段生成管线
基于 compose.Graph 编排 PromptBuilder → AssetGenerator → QualitySupervisor → FormatAdapter, 含质检重试分支(最多 3 次)和降级输出。推理层提供 mock 模式,可替换为真实 API。
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// GenerateImages 调用 AI 推理 API 生成图片。
|
||||
// MVP 阶段返回 mock 占位图。
|
||||
func GenerateImages(ctx context.Context, prompt string, params AssetParams) ([]GeneratedImage, error) {
|
||||
size := params.Resolution
|
||||
if size <= 0 {
|
||||
size = 64
|
||||
}
|
||||
|
||||
count := 1
|
||||
if params.Frames.Directions > 0 && params.Frames.FramesPerDirection > 0 {
|
||||
count = params.Frames.Directions * params.Frames.FramesPerDirection
|
||||
}
|
||||
|
||||
images := make([]GeneratedImage, count)
|
||||
for i := 0; i < count; i++ {
|
||||
data, err := generateMockImage(size, i)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("generate mock image %d: %w", i, err)
|
||||
}
|
||||
images[i] = GeneratedImage{
|
||||
Data: data,
|
||||
Width: size,
|
||||
Height: size,
|
||||
Format: "png",
|
||||
}
|
||||
}
|
||||
return images, nil
|
||||
}
|
||||
|
||||
// QualityChecker 质检函数,可替换用于测试。
|
||||
// 签名:(ctx, images, style) → (pass, reason, error)
|
||||
var QualityChecker = defaultCheckQuality
|
||||
|
||||
// CheckQuality 调用当前 QualityChecker。
|
||||
func CheckQuality(ctx context.Context, images []GeneratedImage, style map[string]string) (bool, string, error) {
|
||||
return QualityChecker(ctx, images, style)
|
||||
}
|
||||
|
||||
// defaultCheckQuality 默认 mock 质检,始终返回 pass。
|
||||
func defaultCheckQuality(ctx context.Context, images []GeneratedImage, style map[string]string) (bool, string, error) {
|
||||
return true, "", nil
|
||||
}
|
||||
|
||||
// NewCountedQualityChecker 创建一个在第 passOnRetry 次调用时返回 pass 的质检函数。
|
||||
func NewCountedQualityChecker(passOnRetry int) func(context.Context, []GeneratedImage, map[string]string) (bool, string, error) {
|
||||
var callCount int
|
||||
return func(_ context.Context, _ []GeneratedImage, _ map[string]string) (bool, string, error) {
|
||||
callCount++
|
||||
if callCount >= passOnRetry {
|
||||
return true, "", nil
|
||||
}
|
||||
return false, fmt.Sprintf("风格不一致(第 %d 次质检)", callCount), nil
|
||||
}
|
||||
}
|
||||
|
||||
// AlwaysFailQualityChecker 始终返回 fail 的质检函数。
|
||||
func AlwaysFailQualityChecker() func(context.Context, []GeneratedImage, map[string]string) (bool, string, error) {
|
||||
return func(_ context.Context, _ []GeneratedImage, _ map[string]string) (bool, string, error) {
|
||||
return false, "风格不一致", nil
|
||||
}
|
||||
}
|
||||
|
||||
// generateMockImage 生成一张带随机色块的 PNG 占位图
|
||||
func generateMockImage(size int, seed int) ([]byte, error) {
|
||||
img := image.NewRGBA(image.Rect(0, 0, size, size))
|
||||
|
||||
// 用 seed 生成不同颜色
|
||||
r := uint8((seed*47 + 13) % 256)
|
||||
g := uint8((seed*83 + 37) % 256)
|
||||
b := uint8((seed*61 + 71) % 256)
|
||||
|
||||
for y := 0; y < size; y++ {
|
||||
for x := 0; x < size; x++ {
|
||||
img.Set(x, y, color.RGBA{R: r, G: g, B: b, A: 255})
|
||||
}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := png.Encode(&buf, img); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// generateRandomBytes 用于生成随机数据(备用)
|
||||
func generateRandomBytes(n int) ([]byte, error) {
|
||||
b := make([]byte, n)
|
||||
_, err := rand.Read(b)
|
||||
return b, err
|
||||
}
|
||||
Reference in New Issue
Block a user