diff --git a/common/constants.go b/common/constants.go index 785e9ee2..421eb692 100644 --- a/common/constants.go +++ b/common/constants.go @@ -1,6 +1,6 @@ package common -var Version = "v4.4.5" // this hard coding will be replaced automatically when building, no need to manually change +var Version = "v4.4.6" // this hard coding will be replaced automatically when building, no need to manually change const ( RequestIdKey = "X-Request-Id" diff --git a/controller/chat.go b/controller/chat.go index 331f038c..e7ce1df8 100644 --- a/controller/chat.go +++ b/controller/chat.go @@ -7,6 +7,7 @@ import ( "coze-discord-proxy/discord" "coze-discord-proxy/model" "coze-discord-proxy/telegram" + "encoding/base64" "encoding/json" "errors" "fmt" @@ -412,9 +413,7 @@ func buildOpenAIGPT4VForImageContent(sendChannelId string, objs []interface{}) ( return "", fmt.Errorf("消息格式错误") } } - //if runeCount := len([]rune(content)); runeCount > 2000 { - // return "", fmt.Errorf("prompt最大为2000字符 [%v]", runeCount) - //} + return content, nil } @@ -540,6 +539,22 @@ func ImagesForOpenAI(c *gin.Context) { }) return } + if request.ResponseFormat == "b64_json" && reply.Data != nil && len(reply.Data) > 0 { + for _, data := range reply.Data { + base64Str, err := getBase64ByUrl(data.URL) + if err != nil { + c.JSON(http.StatusInternalServerError, model.OpenAIErrorResponse{ + OpenAIError: model.OpenAIError{ + Message: err.Error(), + Type: "request_error", + Code: "500", + }, + }) + return + } + data.B64Json = "data:image/webp;base64," + base64Str + } + } replyResp = reply case <-timer.C: if replyResp.Data == nil { @@ -691,3 +706,24 @@ func checkUserAuths(c *gin.Context) error { } return nil } + +func getBase64ByUrl(url string) (string, error) { + resp, err := http.Get(url) + if err != nil { + return "", fmt.Errorf("failed to fetch image: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("received non-200 status code: %d", resp.StatusCode) + } + + imgData, err := io.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("failed to read image data: %w", err) + } + + // Encode the image data to Base64 + base64Str := base64.StdEncoding.EncodeToString(imgData) + return base64Str, nil +} diff --git a/discord/processmessage.go b/discord/processmessage.go index 27ddb31b..1cf25448 100644 --- a/discord/processmessage.go +++ b/discord/processmessage.go @@ -78,9 +78,9 @@ func processMessageUpdateForOpenAIImage(m *discordgo.MessageUpdate) model.OpenAI submatches := re.FindAllStringSubmatch(m.Content, -1) for _, match := range submatches { - response.Data = append(response.Data, struct { - URL string `json:"url"` - }{URL: match[1]}) + response.Data = append(response.Data, &model.OpenAIImagesGenerationDataResponse{ + URL: match[1], + }) } if len(m.Embeds) != 0 { @@ -89,9 +89,9 @@ func processMessageUpdateForOpenAIImage(m *discordgo.MessageUpdate) model.OpenAI if m.Content != "" { m.Content += "\n" } - response.Data = append(response.Data, struct { - URL string `json:"url"` - }{URL: embed.Image.URL}) + response.Data = append(response.Data, &model.OpenAIImagesGenerationDataResponse{ + URL: embed.Image.URL, + }) } } } @@ -170,9 +170,9 @@ func processMessageCreateForOpenAIImage(m *discordgo.MessageCreate) model.OpenAI submatches := re.FindAllStringSubmatch(m.Content, -1) for _, match := range submatches { - response.Data = append(response.Data, struct { - URL string `json:"url"` - }{URL: match[1]}) + response.Data = append(response.Data, &model.OpenAIImagesGenerationDataResponse{ + URL: match[1], + }) } if len(m.Embeds) != 0 { @@ -181,9 +181,9 @@ func processMessageCreateForOpenAIImage(m *discordgo.MessageCreate) model.OpenAI if m.Content != "" { m.Content += "\n" } - response.Data = append(response.Data, struct { - URL string `json:"url"` - }{URL: embed.Image.URL}) + response.Data = append(response.Data, &model.OpenAIImagesGenerationDataResponse{ + URL: embed.Image.URL, + }) } } } diff --git a/docs/docs.go b/docs/docs.go index 5618d13e..de68986b 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -343,6 +343,17 @@ const docTemplate = `{ } } }, + "model.OpenAIImagesGenerationDataResponse": { + "type": "object", + "properties": { + "b64_json": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, "model.OpenAIImagesGenerationRequest": { "type": "object", "properties": { @@ -354,6 +365,9 @@ const docTemplate = `{ }, "prompt": { "type": "string" + }, + "response_format": { + "type": "string" } } }, @@ -369,12 +383,7 @@ const docTemplate = `{ "data": { "type": "array", "items": { - "type": "object", - "properties": { - "url": { - "type": "string" - } - } + "$ref": "#/definitions/model.OpenAIImagesGenerationDataResponse" } } } diff --git a/docs/swagger.json b/docs/swagger.json index 49e6a579..7b78a2ee 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -335,6 +335,17 @@ } } }, + "model.OpenAIImagesGenerationDataResponse": { + "type": "object", + "properties": { + "b64_json": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, "model.OpenAIImagesGenerationRequest": { "type": "object", "properties": { @@ -346,6 +357,9 @@ }, "prompt": { "type": "string" + }, + "response_format": { + "type": "string" } } }, @@ -361,12 +375,7 @@ "data": { "type": "array", "items": { - "type": "object", - "properties": { - "url": { - "type": "string" - } - } + "$ref": "#/definitions/model.OpenAIImagesGenerationDataResponse" } } } diff --git a/docs/swagger.yaml b/docs/swagger.yaml index e54910a0..343cb193 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -71,6 +71,13 @@ definitions: content: type: string type: object + model.OpenAIImagesGenerationDataResponse: + properties: + b64_json: + type: string + url: + type: string + type: object model.OpenAIImagesGenerationRequest: properties: channelId: @@ -79,6 +86,8 @@ definitions: type: string prompt: type: string + response_format: + type: string type: object model.OpenAIImagesGenerationResponse: properties: @@ -88,10 +97,7 @@ definitions: type: boolean data: items: - properties: - url: - type: string - type: object + $ref: '#/definitions/model.OpenAIImagesGenerationDataResponse' type: array type: object model.OpenAIMessage: diff --git a/model/openai.go b/model/openai.go index 4da945e3..837029f3 100644 --- a/model/openai.go +++ b/model/openai.go @@ -62,16 +62,20 @@ type OpenAIDelta struct { type OpenAIImagesGenerationRequest struct { OpenAIChatCompletionExtraRequest - Model string `json:"model"` - Prompt string `json:"prompt"` + Model string `json:"model"` + Prompt string `json:"prompt"` + ResponseFormat string `json:"response_format"` } type OpenAIImagesGenerationResponse struct { - Created int64 `json:"created"` - DailyLimit bool `json:"dailyLimit"` - Data []struct { - URL string `json:"url"` - } `json:"data"` + Created int64 `json:"created"` + DailyLimit bool `json:"dailyLimit"` + Data []*OpenAIImagesGenerationDataResponse `json:"data"` +} + +type OpenAIImagesGenerationDataResponse struct { + URL string `json:"url"` + B64Json string `json:"b64_json"` } type OpenAIGPT4VImagesReq struct {