topfans/backend/services/assetService/service/minimax_service.go
2026-04-08 01:30:58 +08:00

126 lines
3.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
dto "github.com/topfans/backend/gateway/dto"
)
// ImageGenerationResponse 图生图响应
type ImageGenerationResponse struct {
Images []string `json:"images"`
}
// MinimaxService MiniMax API 转发服务
type MinimaxService interface {
GenerateImage(ctx context.Context, req *dto.ImageGenerationRequest) (*ImageGenerationResponse, error)
}
type minimaxService struct {
client *http.Client
}
// NewMinimaxService 创建 MiniMax 服务
func NewMinimaxService() MinimaxService {
return &minimaxService{
client: &http.Client{Timeout: 320 * time.Second},
}
}
// GenerateImage 调用 MiniMax 图生图 API同步调用
func (s *minimaxService) GenerateImage(ctx context.Context, req *dto.ImageGenerationRequest) (*ImageGenerationResponse, error) {
apiURL := os.Getenv("MINIMAX_API_URL")
apiKey := os.Getenv("MINIMAX_API_KEY")
payload := map[string]interface{}{
"model": req.Model,
"prompt": req.Prompt,
"aspect_ratio": req.AspectRatio,
"subject_reference": req.SubjectReference,
"n": req.N,
"response_format": "base64",
}
jsonData, err := json.Marshal(payload)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
httpReq, err := http.NewRequestWithContext(ctx, "POST", apiURL, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Authorization", "Bearer "+apiKey)
httpReq.Header.Set("Content-Type", "application/json")
resp, err := s.client.Do(httpReq)
if err != nil {
return nil, fmt.Errorf("failed to call MiniMax API: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("MiniMax API returned status %d: %s", resp.StatusCode, string(body))
}
var rawResp map[string]interface{}
if err := json.Unmarshal(body, &rawResp); err != nil {
return nil, fmt.Errorf("failed to parse response: %w", err)
}
var images []string
// MiniMax API 响应格式:
// {"id": "...", "data": {"image_base64": ["..."]}, "base_resp": {"status_code": 0, "status_msg": "success"}}
data, ok := rawResp["data"].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("invalid MiniMax response format: missing data field: %s", string(body))
}
// 检查 base_resp 状态码
if baseResp, ok := rawResp["base_resp"].(map[string]interface{}); ok {
if statusCode, ok := baseResp["status_code"].(float64); ok && statusCode != 0 {
statusMsg, _ := baseResp["status_msg"].(string)
return nil, fmt.Errorf("MiniMax API error: code=%d, msg=%s", int(statusCode), statusMsg)
}
}
// 优先使用 base64 格式(当 response_format=base64 时)
if base64Imgs, ok := data["image_base64"].([]interface{}); ok {
for _, img := range base64Imgs {
if base64Str, ok := img.(string); ok && base64Str != "" {
images = append(images, "data:image/jpeg;base64,"+base64Str)
}
}
}
// 回退使用 image_urls 格式
if len(images) == 0 {
if urlImgs, ok := data["image_urls"].([]interface{}); ok {
for _, img := range urlImgs {
if urlStr, ok := img.(string); ok && urlStr != "" {
images = append(images, urlStr)
}
}
}
}
if len(images) == 0 {
return nil, fmt.Errorf("no images found in MiniMax response: %s", string(body))
}
return &ImageGenerationResponse{Images: images}, nil
}