From a68502d9576b8dba9f9b25ddb34a36216fde2965 Mon Sep 17 00:00:00 2001 From: bx1834938347-prog Date: Fri, 5 Dec 2025 17:06:10 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9Aai=E7=94=9F=E6=88=90=E5=9B=BE?= =?UTF-8?q?=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/service/import/generateImageToText.go | 112 +++++++++++++++++++- pkg/service/import/imageContentProcessor.go | 51 +++++++-- 2 files changed, 152 insertions(+), 11 deletions(-) diff --git a/pkg/service/import/generateImageToText.go b/pkg/service/import/generateImageToText.go index 5779a20..977de98 100644 --- a/pkg/service/import/generateImageToText.go +++ b/pkg/service/import/generateImageToText.go @@ -66,7 +66,6 @@ func (g *AiGenerator) GenerateTitleAndContentFromImage(imageURL, titleRequire, c return title, content, nil } -// 带图片的聊天(使用兼容模式接口) func (g *AiGenerator) chatWithImage(imageURL, prompt string) (string, error) { reqBody := ChatCompletionRequest{ Model: "qwen-vl-plus", @@ -158,3 +157,114 @@ func parseTitleAndContent(response string) (string, string) { return strings.TrimSpace(title), strings.TrimSpace(content) } + +// 文本生成文本(聊天模式) +func (g *AiGenerator) GenerateTitleAndContentFromText(titleRequire, contentRequire string) (string, string, error) { + // 构建提示词 + prompt := fmt.Sprintf(`请根据以下要求生成内容: + +生成要求: +1. 标题要求:%s +2. 内容要求:%s + +请严格按照以下格式返回,不要有任何额外文字: +标题:{生成的标题} +内容:{生成的内容}`, + titleRequire, + contentRequire, + ) + + // 发送聊天请求 + response, err := g.chatWithText(prompt) + if err != nil { + return "", "", err + } + + // 解析响应 + title, content := parseTitleAndContent(response) + return title, content, nil +} + +// 文本聊天(纯文本生成) +func (g *AiGenerator) chatWithText(prompt string) (string, error) { + reqBody := ChatCompletionRequest{ + Model: "qwen-max", // 使用文本模型 + Messages: []ChatMessage{ + { + Role: "user", + Content: []Content{ + { + Type: "text", + Text: prompt, + }, + }, + }, + }, + MaxTokens: 2000, + Temperature: 0.7, + } + + url := g.cfg.BaseURL + "/compatible-mode/v1/chat/completions" + jsonData, err := json.Marshal(reqBody) + if err != nil { + return "", fmt.Errorf("JSON序列化失败: %v", err) + } + + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) + if err != nil { + return "", fmt.Errorf("创建请求失败: %v", err) + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+g.cfg.APIKey) + + resp, err := g.client.Do(req) + if err != nil { + return "", fmt.Errorf("API请求失败: %v", err) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("读取响应失败: %v", err) + } + + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("API错误: %d, 响应: %s", resp.StatusCode, string(body)) + } + + var result ChatCompletionResponse + if err := json.Unmarshal(body, &result); err != nil { + return "", fmt.Errorf("JSON解析失败: %v, 响应: %s", err, string(body)) + } + + if result.Error.Message != "" { + return "", fmt.Errorf("API返回错误: %s", result.Error.Message) + } + + if len(result.Choices) == 0 { + return "", errors.New("AI未生成有效响应") + } + + return strings.TrimSpace(result.Choices[0].Message.Content), nil +} + +func (g *AiGenerator) GenerateImageFromText(prompt, size string, n int) (string, error) { + // 构建图片生成提示词 + imagePrompt := fmt.Sprintf(`请根据以下描述生成图片: + +图片描述:%s +生成数量:%d张 +图片尺寸:%s + +请直接生成图片,不要返回任何文字描述。`, + prompt, n, size) + + // 使用文生图API + result, err := g.TextToImage(imagePrompt, size, n) + if err != nil { + return "", err + } + + return result.Output.TaskID, nil +} diff --git a/pkg/service/import/imageContentProcessor.go b/pkg/service/import/imageContentProcessor.go index d41c944..643160a 100644 --- a/pkg/service/import/imageContentProcessor.go +++ b/pkg/service/import/imageContentProcessor.go @@ -215,18 +215,25 @@ func (p *BatchProcessor) generateTitleAndContent(req *excelData) (string, string } return title, content, nil } else { - // 无图片:使用文生文 - title, err := p.generateTitle(req) - if err != nil { - return "", "", fmt.Errorf("生成标题失败: %v", err) - } - - content, err := p.generateContent(req) + title, content, err := NewAiGenerator().GenerateTitleAndContentFromText( + req.PhotoUrl, + req.TitleRequire, + ) if err != nil { return "", "", fmt.Errorf("生成内容失败: %v", err) } - return title, content, nil + //// 无图片:使用文生文 + //title, err := p.generateTitle(req) + //if err != nil { + // return "", "", fmt.Errorf("生成标题失败: %v", err) + //} + // + //content, err := p.generateContent(req) + //if err != nil { + // return "", "", fmt.Errorf("生成内容失败: %v", err) + //} + } } @@ -274,6 +281,30 @@ func (p *BatchProcessor) generateContent(req *excelData) (string, error) { return req.Content, nil } +//func (p *BatchProcessor) generateImage(req *excelData) (string, error) { +// prompt := fmt.Sprintf("请根据以下要求生成内容:%s", req.PhotoRequire) +// if req.Title != "" { +// prompt += fmt.Sprintf("\n标题:%s", req.Title) // 关联标题 +// } +// if req.Content != "" { +// prompt += fmt.Sprintf("\n内容:%s", req.Content) // 关联内容 +// } +// if req.Desc != "" { +// prompt += fmt.Sprintf("\n艺人简介:%s", req.Desc) +// } +// prompt += "\n请基于标题和内容生成相关内容" +// +// result, err := NewAiGenerator().TextToImage( +// prompt, +// "1024*1024", +// req.PhotoNum, +// ) +// if err != nil { +// return "", err +// } +// return result.Output.TaskID, nil +//} + func (p *BatchProcessor) generateImage(req *excelData) (string, error) { prompt := fmt.Sprintf("请根据以下要求生成内容:%s", req.PhotoRequire) if req.Title != "" { @@ -287,7 +318,7 @@ func (p *BatchProcessor) generateImage(req *excelData) (string, error) { } prompt += "\n请基于标题和内容生成相关内容" - result, err := NewAiGenerator().TextToImage( + result, err := NewAiGenerator().GenerateImageFromText( prompt, "1024*1024", req.PhotoNum, @@ -295,7 +326,7 @@ func (p *BatchProcessor) generateImage(req *excelData) (string, error) { if err != nil { return "", err } - return result.Output.TaskID, nil + return result, nil } func (p *BatchProcessor) GetTaskStatistics() (completed, pending, total int, completedTasks, failedTasks []*ImageTask) {