From 96bdf971943b08a12adfb34a8a41227bf6704f60 Mon Sep 17 00:00:00 2001 From: crabkun <529493022@qq.com> Date: Sun, 21 Jul 2024 01:27:29 +0800 Subject: [PATCH 01/16] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Daws=20claude?= =?UTF-8?q?=E6=B8=A0=E9=81=93panic=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- relay/channel/aws/relay-aws.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/relay/channel/aws/relay-aws.go b/relay/channel/aws/relay-aws.go index ce97755..f452d56 100644 --- a/relay/channel/aws/relay-aws.go +++ b/relay/channel/aws/relay-aws.go @@ -222,9 +222,11 @@ func awsStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel } } service.Done(c) - err = resp.Body.Close() - if err != nil { - return service.OpenAIErrorWrapperLocal(err, "close_response_body_failed", http.StatusInternalServerError), nil + if resp != nil { + err = resp.Body.Close() + if err != nil { + return service.OpenAIErrorWrapperLocal(err, "close_response_body_failed", http.StatusInternalServerError), nil + } } return nil, &usage } From b9454c3f146518d6a15053dd3a2a54081c05681c Mon Sep 17 00:00:00 2001 From: Yan Tau <32036413+Yan-Zero@users.noreply.github.com> Date: Mon, 22 Jul 2024 21:20:23 +0800 Subject: [PATCH 02/16] fix: the base64 format image_url for gemini --- relay/channel/gemini/relay-gemini.go | 30 +++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/relay/channel/gemini/relay-gemini.go b/relay/channel/gemini/relay-gemini.go index 7890b83..7d3fa68 100644 --- a/relay/channel/gemini/relay-gemini.go +++ b/relay/channel/gemini/relay-gemini.go @@ -83,13 +83,29 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest) *GeminiChatReques if imageNum > GeminiVisionMaxImageNum { continue } - mimeType, data, _ := service.GetImageFromUrl(part.ImageUrl.(dto.MessageImageUrl).Url) - parts = append(parts, GeminiPart{ - InlineData: &GeminiInlineData{ - MimeType: mimeType, - Data: data, - }, - }) + // 判断是否是url + if strings.HasPrefix(part.ImageUrl.(dto.MessageImageUrl).Url, "http") { + // 是url,获取图片的类型和base64编码的数据 + mimeType, data, _ := service.GetImageFromUrl(part.ImageUrl.(dto.MessageImageUrl).Url) + parts = append(parts, GeminiPart{ + InlineData: &GeminiInlineData{ + MimeType: mimeType, + Data: data, + }, + }) + } + else{ + _, format, base64String, err := service.DecodeBase64ImageData(part.ImageUrl.(dto.MessageImageUrl).Url) + if err != nil { + return nil, err + } + parts = append(parts, GeminiPart{ + InlineData: &GeminiInlineData{ + MimeType: "image/" + format, + Data: base64String, + }, + }) + } } } content.Parts = parts From caaecb8d54032a67b962d96a6501634f1ecc4475 Mon Sep 17 00:00:00 2001 From: "1808837298@qq.com" <1808837298@qq.com> Date: Tue, 23 Jul 2024 18:25:43 +0800 Subject: [PATCH 03/16] fix: first login error (close #385) --- web/src/components/LoginForm.js | 3 ++- web/src/helpers/api.js | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/web/src/components/LoginForm.js b/web/src/components/LoginForm.js index 0fecf10..3cd56a1 100644 --- a/web/src/components/LoginForm.js +++ b/web/src/components/LoginForm.js @@ -1,7 +1,7 @@ import React, { useContext, useEffect, useState } from 'react'; import { Link, useNavigate, useSearchParams } from 'react-router-dom'; import { UserContext } from '../context/User'; -import { API, getLogo, showError, showInfo, showSuccess } from '../helpers'; +import { API, getLogo, showError, showInfo, showSuccess, updateAPI } from '../helpers'; import { onGitHubOAuthClicked } from './utils'; import Turnstile from 'react-turnstile'; import { @@ -101,6 +101,7 @@ const LoginForm = () => { if (success) { userDispatch({ type: 'login', payload: data }); setUserData(data); + updateAPI() showSuccess('登录成功!'); if (username === 'root' && password === '123456') { Modal.error({ diff --git a/web/src/helpers/api.js b/web/src/helpers/api.js index 51b99d1..67f3e3c 100644 --- a/web/src/helpers/api.js +++ b/web/src/helpers/api.js @@ -1,7 +1,7 @@ import { getUserIdFromLocalStorage, showError } from './utils'; import axios from 'axios'; -export const API = axios.create({ +export let API = axios.create({ baseURL: import.meta.env.VITE_REACT_APP_SERVER_URL ? import.meta.env.VITE_REACT_APP_SERVER_URL : '', @@ -10,6 +10,17 @@ export const API = axios.create({ } }); +export function updateAPI() { + API = axios.create({ + baseURL: import.meta.env.VITE_REACT_APP_SERVER_URL + ? import.meta.env.VITE_REACT_APP_SERVER_URL + : '', + headers: { + 'New-API-User': getUserIdFromLocalStorage() + } + }); +} + API.interceptors.response.use( (response) => response, (error) => { From b8291dcd132124cde8fddd4875d83f1490d596ba Mon Sep 17 00:00:00 2001 From: "1808837298@qq.com" <1808837298@qq.com> Date: Tue, 23 Jul 2024 18:34:16 +0800 Subject: [PATCH 04/16] fix: gemini --- relay/channel/gemini/relay-gemini.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/relay/channel/gemini/relay-gemini.go b/relay/channel/gemini/relay-gemini.go index 7d3fa68..185582d 100644 --- a/relay/channel/gemini/relay-gemini.go +++ b/relay/channel/gemini/relay-gemini.go @@ -93,11 +93,10 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest) *GeminiChatReques Data: data, }, }) - } - else{ + } else { _, format, base64String, err := service.DecodeBase64ImageData(part.ImageUrl.(dto.MessageImageUrl).Url) if err != nil { - return nil, err + continue } parts = append(parts, GeminiPart{ InlineData: &GeminiInlineData{ From da490db6d30b51f78838a5f8fd0f293ffd42d3d3 Mon Sep 17 00:00:00 2001 From: Oswin Date: Fri, 26 Jul 2024 17:47:36 +0800 Subject: [PATCH 05/16] [fix] fix send email error using outlook smtp --- common/email-outlook-auth.go | 32 ++++++++++++++++++++++++++++++++ common/email.go | 3 +++ 2 files changed, 35 insertions(+) create mode 100644 common/email-outlook-auth.go diff --git a/common/email-outlook-auth.go b/common/email-outlook-auth.go new file mode 100644 index 0000000..723a10b --- /dev/null +++ b/common/email-outlook-auth.go @@ -0,0 +1,32 @@ +package common + +import ( + "errors" + "net/smtp" +) + +type outlookAuth struct { + username, password string +} + +func LoginAuth(username, password string) smtp.Auth { + return &outlookAuth{username, password} +} + +func (a *outlookAuth) Start(_ *smtp.ServerInfo) (string, []byte, error) { + return "LOGIN", []byte{}, nil +} + +func (a *outlookAuth) Next(fromServer []byte, more bool) ([]byte, error) { + if more { + switch string(fromServer) { + case "Username:": + return []byte(a.username), nil + case "Password:": + return []byte(a.password), nil + default: + return nil, errors.New("unknown fromServer") + } + } + return nil, nil +} diff --git a/common/email.go b/common/email.go index 13345d8..62c9048 100644 --- a/common/email.go +++ b/common/email.go @@ -62,6 +62,9 @@ func SendEmail(subject string, receiver string, content string) error { if err != nil { return err } + } else if strings.HasSuffix(SMTPAccount, "outlook.com") { + auth = LoginAuth(SMTPAccount, SMTPToken) + err = smtp.SendMail(addr, auth, SMTPAccount, to, mail) } else { err = smtp.SendMail(addr, auth, SMTPAccount, to, mail) } From 9e610c9429d077e86b609911fef055e3539c85e5 Mon Sep 17 00:00:00 2001 From: CalciumIon <1808837298@qq.com> Date: Fri, 26 Jul 2024 18:51:34 +0800 Subject: [PATCH 06/16] fix: image quota (close #382) --- relay/relay-image.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/relay/relay-image.go b/relay/relay-image.go index f6a2641..83c7538 100644 --- a/relay/relay-image.go +++ b/relay/relay-image.go @@ -121,7 +121,8 @@ func ImageHelper(c *gin.Context, relayMode int) *dto.OpenAIErrorWithStatusCode { } } - quota := int(modelPrice*groupRatio*common.QuotaPerUnit*sizeRatio*qualityRatio) * imageRequest.N + imageRatio := modelPrice * sizeRatio * qualityRatio * float64(imageRequest.N) + quota := int(imageRatio * groupRatio * common.QuotaPerUnit) if userQuota-quota < 0 { return service.OpenAIErrorWrapperLocal(errors.New("user quota is not enough"), "insufficient_user_quota", http.StatusForbidden) @@ -180,7 +181,7 @@ func ImageHelper(c *gin.Context, relayMode int) *dto.OpenAIErrorWithStatusCode { } logContent := fmt.Sprintf("大小 %s, 品质 %s", imageRequest.Size, quality) - postConsumeQuota(c, relayInfo, imageRequest.Model, usage, 0, 0, userQuota, 0, groupRatio, modelPrice, true, logContent) + postConsumeQuota(c, relayInfo, imageRequest.Model, usage, 0, 0, userQuota, 0, groupRatio, imageRatio, true, logContent) return nil } From ab1d61d91063a51fc0025fd6d1c1ad7b0c3ec961 Mon Sep 17 00:00:00 2001 From: CalciumIon <1808837298@qq.com> Date: Sat, 27 Jul 2024 17:47:30 +0800 Subject: [PATCH 07/16] feat: print user id when error --- common/utils.go | 4 ++-- controller/relay.go | 3 ++- middleware/utils.go | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/common/utils.go b/common/utils.go index 3d95508..6a9a13d 100644 --- a/common/utils.go +++ b/common/utils.go @@ -179,8 +179,8 @@ func Max(a int, b int) int { } } -func MessageWithRequestId(message string, id string) string { - return fmt.Sprintf("%s (request id: %s)", message, id) +func MessageWithRequestId(message string, id string, userId int) string { + return fmt.Sprintf("%s (request id: %s, user id: %d)", message, id, userId) } func RandomSleep() { diff --git a/controller/relay.go b/controller/relay.go index bc951f7..f0b714a 100644 --- a/controller/relay.go +++ b/controller/relay.go @@ -82,7 +82,8 @@ func Relay(c *gin.Context) { if openaiErr.StatusCode == http.StatusTooManyRequests { openaiErr.Error.Message = "当前分组上游负载已饱和,请稍后再试" } - openaiErr.Error.Message = common.MessageWithRequestId(openaiErr.Error.Message, requestId) + userId := c.GetInt("id") + openaiErr.Error.Message = common.MessageWithRequestId(openaiErr.Error.Message, requestId, userId) c.JSON(openaiErr.StatusCode, gin.H{ "error": openaiErr.Error, }) diff --git a/middleware/utils.go b/middleware/utils.go index 43801c1..52614c6 100644 --- a/middleware/utils.go +++ b/middleware/utils.go @@ -6,9 +6,10 @@ import ( ) func abortWithOpenAiMessage(c *gin.Context, statusCode int, message string) { + userId := c.GetInt("id") c.JSON(statusCode, gin.H{ "error": gin.H{ - "message": common.MessageWithRequestId(message, c.GetString(common.RequestIdKey)), + "message": common.MessageWithRequestId(message, c.GetString(common.RequestIdKey), userId), "type": "new_api_error", }, }) From 88cc88c5d068cfc3b1fe65e99ed67234b6feeae8 Mon Sep 17 00:00:00 2001 From: CalciumIon <1808837298@qq.com> Date: Sat, 27 Jul 2024 17:51:05 +0800 Subject: [PATCH 08/16] feat: support ollama tools --- relay/channel/ollama/dto.go | 23 ++++++++++++----------- relay/channel/ollama/relay-ollama.go | 20 ++++++++++++-------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/relay/channel/ollama/dto.go b/relay/channel/ollama/dto.go index a6d6238..4f99a24 100644 --- a/relay/channel/ollama/dto.go +++ b/relay/channel/ollama/dto.go @@ -3,14 +3,18 @@ package ollama import "one-api/dto" type OllamaRequest struct { - Model string `json:"model,omitempty"` - Messages []dto.Message `json:"messages,omitempty"` - Stream bool `json:"stream,omitempty"` - Temperature float64 `json:"temperature,omitempty"` - Seed float64 `json:"seed,omitempty"` - Topp float64 `json:"top_p,omitempty"` - TopK int `json:"top_k,omitempty"` - Stop any `json:"stop,omitempty"` + Model string `json:"model,omitempty"` + Messages []dto.Message `json:"messages,omitempty"` + Stream bool `json:"stream,omitempty"` + Temperature float64 `json:"temperature,omitempty"` + Seed float64 `json:"seed,omitempty"` + Topp float64 `json:"top_p,omitempty"` + TopK int `json:"top_k,omitempty"` + Stop any `json:"stop,omitempty"` + Tools []dto.ToolCall `json:"tools,omitempty"` + ResponseFormat *dto.ResponseFormat `json:"response_format,omitempty"` + FrequencyPenalty float64 `json:"frequency_penalty,omitempty"` + PresencePenalty float64 `json:"presence_penalty,omitempty"` } type OllamaEmbeddingRequest struct { @@ -21,6 +25,3 @@ type OllamaEmbeddingRequest struct { type OllamaEmbeddingResponse struct { Embedding []float64 `json:"embedding,omitempty"` } - -//type OllamaOptions struct { -//} diff --git a/relay/channel/ollama/relay-ollama.go b/relay/channel/ollama/relay-ollama.go index f63fe57..6bf395a 100644 --- a/relay/channel/ollama/relay-ollama.go +++ b/relay/channel/ollama/relay-ollama.go @@ -28,14 +28,18 @@ func requestOpenAI2Ollama(request dto.GeneralOpenAIRequest) *OllamaRequest { Stop, _ = request.Stop.([]string) } return &OllamaRequest{ - Model: request.Model, - Messages: messages, - Stream: request.Stream, - Temperature: request.Temperature, - Seed: request.Seed, - Topp: request.TopP, - TopK: request.TopK, - Stop: Stop, + Model: request.Model, + Messages: messages, + Stream: request.Stream, + Temperature: request.Temperature, + Seed: request.Seed, + Topp: request.TopP, + TopK: request.TopK, + Stop: Stop, + Tools: request.Tools, + ResponseFormat: request.ResponseFormat, + FrequencyPenalty: request.FrequencyPenalty, + PresencePenalty: request.PresencePenalty, } } From b7bc205b736f80e072292f296a79d6fc15455e9d Mon Sep 17 00:00:00 2001 From: CalciumIon <1808837298@qq.com> Date: Sat, 27 Jul 2024 17:55:36 +0800 Subject: [PATCH 09/16] feat: print user id when error --- common/utils.go | 4 ++-- controller/relay.go | 3 +-- middleware/utils.go | 5 +++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/common/utils.go b/common/utils.go index 6a9a13d..3d95508 100644 --- a/common/utils.go +++ b/common/utils.go @@ -179,8 +179,8 @@ func Max(a int, b int) int { } } -func MessageWithRequestId(message string, id string, userId int) string { - return fmt.Sprintf("%s (request id: %s, user id: %d)", message, id, userId) +func MessageWithRequestId(message string, id string) string { + return fmt.Sprintf("%s (request id: %s)", message, id) } func RandomSleep() { diff --git a/controller/relay.go b/controller/relay.go index f0b714a..bc951f7 100644 --- a/controller/relay.go +++ b/controller/relay.go @@ -82,8 +82,7 @@ func Relay(c *gin.Context) { if openaiErr.StatusCode == http.StatusTooManyRequests { openaiErr.Error.Message = "当前分组上游负载已饱和,请稍后再试" } - userId := c.GetInt("id") - openaiErr.Error.Message = common.MessageWithRequestId(openaiErr.Error.Message, requestId, userId) + openaiErr.Error.Message = common.MessageWithRequestId(openaiErr.Error.Message, requestId) c.JSON(openaiErr.StatusCode, gin.H{ "error": openaiErr.Error, }) diff --git a/middleware/utils.go b/middleware/utils.go index 52614c6..082f565 100644 --- a/middleware/utils.go +++ b/middleware/utils.go @@ -1,6 +1,7 @@ package middleware import ( + "fmt" "github.com/gin-gonic/gin" "one-api/common" ) @@ -9,12 +10,12 @@ func abortWithOpenAiMessage(c *gin.Context, statusCode int, message string) { userId := c.GetInt("id") c.JSON(statusCode, gin.H{ "error": gin.H{ - "message": common.MessageWithRequestId(message, c.GetString(common.RequestIdKey), userId), + "message": common.MessageWithRequestId(message, c.GetString(common.RequestIdKey)), "type": "new_api_error", }, }) c.Abort() - common.LogError(c.Request.Context(), message) + common.LogError(c.Request.Context(), fmt.Sprintf("user %d | %s", userId, message)) } func abortWithMidjourneyMessage(c *gin.Context, statusCode int, code int, description string) { From b16e6bf42313c8540feea5858bb786919cea7159 Mon Sep 17 00:00:00 2001 From: CalciumIon <1808837298@qq.com> Date: Sat, 27 Jul 2024 18:09:09 +0800 Subject: [PATCH 10/16] fix: panic when get model ratio (close #392) --- common/model-ratio.go | 66 ++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/common/model-ratio.go b/common/model-ratio.go index 5de961d..568254b 100644 --- a/common/model-ratio.go +++ b/common/model-ratio.go @@ -3,6 +3,7 @@ package common import ( "encoding/json" "strings" + "sync" ) // from songquanpeng/one-api @@ -182,8 +183,14 @@ var defaultModelPrice = map[string]float64{ "swap_face": 0.05, } -var modelPrice map[string]float64 = nil -var modelRatio map[string]float64 = nil +var ( + modelPriceMap = make(map[string]float64) + modelPriceMapMutex = sync.RWMutex{} +) +var ( + modelRatioMap map[string]float64 = nil + modelRatioMapMutex = sync.RWMutex{} +) var CompletionRatio map[string]float64 = nil var defaultCompletionRatio = map[string]float64{ @@ -191,11 +198,18 @@ var defaultCompletionRatio = map[string]float64{ "gpt-4-all": 2, } -func ModelPrice2JSONString() string { - if modelPrice == nil { - modelPrice = defaultModelPrice +func GetModelPriceMap() map[string]float64 { + modelPriceMapMutex.Lock() + defer modelPriceMapMutex.Unlock() + if modelPriceMap == nil { + modelPriceMap = defaultModelPrice } - jsonBytes, err := json.Marshal(modelPrice) + return modelPriceMap +} + +func ModelPrice2JSONString() string { + GetModelPriceMap() + jsonBytes, err := json.Marshal(modelPriceMap) if err != nil { SysError("error marshalling model price: " + err.Error()) } @@ -203,19 +217,19 @@ func ModelPrice2JSONString() string { } func UpdateModelPriceByJSONString(jsonStr string) error { - modelPrice = make(map[string]float64) - return json.Unmarshal([]byte(jsonStr), &modelPrice) + modelPriceMapMutex.Lock() + defer modelPriceMapMutex.Unlock() + modelPriceMap = make(map[string]float64) + return json.Unmarshal([]byte(jsonStr), &modelPriceMap) } // GetModelPrice 返回模型的价格,如果模型不存在则返回-1,false func GetModelPrice(name string, printErr bool) (float64, bool) { - if modelPrice == nil { - modelPrice = defaultModelPrice - } + GetModelPriceMap() if strings.HasPrefix(name, "gpt-4-gizmo") { name = "gpt-4-gizmo-*" } - price, ok := modelPrice[name] + price, ok := modelPriceMap[name] if !ok { if printErr { SysError("model price not found: " + name) @@ -225,18 +239,18 @@ func GetModelPrice(name string, printErr bool) (float64, bool) { return price, true } -func GetModelPriceMap() map[string]float64 { - if modelPrice == nil { - modelPrice = defaultModelPrice +func GetModelRatioMap() map[string]float64 { + modelRatioMapMutex.Lock() + defer modelRatioMapMutex.Unlock() + if modelRatioMap == nil { + modelRatioMap = defaultModelRatio } - return modelPrice + return modelRatioMap } func ModelRatio2JSONString() string { - if modelRatio == nil { - modelRatio = defaultModelRatio - } - jsonBytes, err := json.Marshal(modelRatio) + GetModelRatioMap() + jsonBytes, err := json.Marshal(modelRatioMap) if err != nil { SysError("error marshalling model ratio: " + err.Error()) } @@ -244,18 +258,18 @@ func ModelRatio2JSONString() string { } func UpdateModelRatioByJSONString(jsonStr string) error { - modelRatio = make(map[string]float64) - return json.Unmarshal([]byte(jsonStr), &modelRatio) + modelRatioMapMutex.Lock() + defer modelRatioMapMutex.Unlock() + modelRatioMap = make(map[string]float64) + return json.Unmarshal([]byte(jsonStr), &modelRatioMap) } func GetModelRatio(name string) float64 { - if modelRatio == nil { - modelRatio = defaultModelRatio - } + GetModelRatioMap() if strings.HasPrefix(name, "gpt-4-gizmo") { name = "gpt-4-gizmo-*" } - ratio, ok := modelRatio[name] + ratio, ok := modelRatioMap[name] if !ok { SysError("model ratio not found: " + name) return 30 From 07e55cc999b5f4ddc29ed60ef4ffdc750afe903f Mon Sep 17 00:00:00 2001 From: CalciumIon <1808837298@qq.com> Date: Sun, 28 Jul 2024 00:05:53 +0800 Subject: [PATCH 11/16] chore: update token page --- web/src/pages/Token/index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web/src/pages/Token/index.js b/web/src/pages/Token/index.js index d85dacf..ca3c2a4 100644 --- a/web/src/pages/Token/index.js +++ b/web/src/pages/Token/index.js @@ -1,11 +1,14 @@ import React from 'react'; import TokensTable from '../../components/TokensTable'; -import { Layout } from '@douyinfe/semi-ui'; +import { Banner, Layout } from '@douyinfe/semi-ui'; const Token = () => ( <> -

我的令牌

+
From a6b6bcfe001af803263549ea06c2ff6330096b4d Mon Sep 17 00:00:00 2001 From: CalciumIon <1808837298@qq.com> Date: Sun, 28 Jul 2024 01:12:26 +0800 Subject: [PATCH 12/16] chore: remove useless code --- relay/channel/openai/relay-openai.go | 33 +++++++++++++--------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/relay/channel/openai/relay-openai.go b/relay/channel/openai/relay-openai.go index 424f183..87ad7d3 100644 --- a/relay/channel/openai/relay-openai.go +++ b/relay/channel/openai/relay-openai.go @@ -22,7 +22,7 @@ import ( func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (*dto.OpenAIErrorWithStatusCode, *dto.Usage) { containStreamUsage := false - responseId := "" + var responseId string var createAt int64 = 0 var systemFingerprint string model := info.UpstreamModelName @@ -86,7 +86,13 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel var lastStreamResponse dto.ChatCompletionsStreamResponse err := json.Unmarshal(common.StringToByteSlice(lastStreamData), &lastStreamResponse) if err == nil { - if lastStreamResponse.Usage != nil && service.ValidUsage(lastStreamResponse.Usage) { + responseId = lastStreamResponse.Id + createAt = lastStreamResponse.Created + systemFingerprint = lastStreamResponse.GetSystemFingerprint() + model = lastStreamResponse.Model + if service.ValidUsage(lastStreamResponse.Usage) { + containStreamUsage = true + usage = lastStreamResponse.Usage if !info.ShouldIncludeUsage { shouldSendLastResp = false } @@ -109,14 +115,9 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel var streamResponse dto.ChatCompletionsStreamResponse err := json.Unmarshal(common.StringToByteSlice(item), &streamResponse) if err == nil { - responseId = streamResponse.Id - createAt = streamResponse.Created - systemFingerprint = streamResponse.GetSystemFingerprint() - model = streamResponse.Model - if service.ValidUsage(streamResponse.Usage) { - usage = streamResponse.Usage - containStreamUsage = true - } + //if service.ValidUsage(streamResponse.Usage) { + // usage = streamResponse.Usage + //} for _, choice := range streamResponse.Choices { responseTextBuilder.WriteString(choice.Delta.GetContentString()) if choice.Delta.ToolCalls != nil { @@ -133,14 +134,10 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel } } else { for _, streamResponse := range streamResponses { - responseId = streamResponse.Id - createAt = streamResponse.Created - systemFingerprint = streamResponse.GetSystemFingerprint() - model = streamResponse.Model - if service.ValidUsage(streamResponse.Usage) { - usage = streamResponse.Usage - containStreamUsage = true - } + //if service.ValidUsage(streamResponse.Usage) { + // usage = streamResponse.Usage + // containStreamUsage = true + //} for _, choice := range streamResponse.Choices { responseTextBuilder.WriteString(choice.Delta.GetContentString()) if choice.Delta.ToolCalls != nil { From fbce36238e09416b93207d231375bc8efeade0df Mon Sep 17 00:00:00 2001 From: CalciumIon <1808837298@qq.com> Date: Tue, 30 Jul 2024 17:30:40 +0800 Subject: [PATCH 13/16] feat: support dify agent --- relay/channel/dify/relay-dify.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relay/channel/dify/relay-dify.go b/relay/channel/dify/relay-dify.go index c674ba1..66ba839 100644 --- a/relay/channel/dify/relay-dify.go +++ b/relay/channel/dify/relay-dify.go @@ -53,7 +53,7 @@ func streamResponseDify2OpenAI(difyResponse DifyChunkChatCompletionResponse) *dt choice.Delta.SetContentString("Workflow: " + difyResponse.Data.WorkflowId + "\n") } else if constant.DifyDebug && difyResponse.Event == "node_started" { choice.Delta.SetContentString("Node: " + difyResponse.Data.NodeId + "\n") - } else if difyResponse.Event == "message" { + } else if difyResponse.Event == "message" || difyResponse.Event == "agent_message" { choice.Delta.SetContentString(difyResponse.Answer) } response.Choices = append(response.Choices, choice) From fe16d51fe4b587c43a8f475bbe74b3a1d7e9d947 Mon Sep 17 00:00:00 2001 From: OswinWu Date: Wed, 31 Jul 2024 16:50:19 +0800 Subject: [PATCH 14/16] feat: ignore npm build dir --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1b2cf07..16cbc67 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ upload *.db build *.db-journal -logs \ No newline at end of file +logs +web/dist \ No newline at end of file From c5e8d7ec207ce56dfa7f3ac7ff5a9e81490a9aae Mon Sep 17 00:00:00 2001 From: TAKO <20227709+HynoR@users.noreply.github.com> Date: Wed, 31 Jul 2024 17:11:25 +0800 Subject: [PATCH 15/16] Support cloudflare llama3.1-8b --- relay/channel/cloudflare/constant.go | 1 + 1 file changed, 1 insertion(+) diff --git a/relay/channel/cloudflare/constant.go b/relay/channel/cloudflare/constant.go index a874685..0e2aec2 100644 --- a/relay/channel/cloudflare/constant.go +++ b/relay/channel/cloudflare/constant.go @@ -1,6 +1,7 @@ package cloudflare var ModelList = []string{ + "@cf/meta/llama-3.1-8b-instruct", "@cf/meta/llama-2-7b-chat-fp16", "@cf/meta/llama-2-7b-chat-int8", "@cf/mistral/mistral-7b-instruct-v0.1", From 1501ccb919f30a716de857e14a8043d6b88995bc Mon Sep 17 00:00:00 2001 From: CalciumIon <1808837298@qq.com> Date: Wed, 31 Jul 2024 18:20:13 +0800 Subject: [PATCH 16/16] fix: error channel name on notify. #338 --- controller/relay.go | 10 +++++----- model/channel.go | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/controller/relay.go b/controller/relay.go index bc951f7..0c79015 100644 --- a/controller/relay.go +++ b/controller/relay.go @@ -43,12 +43,13 @@ func Relay(c *gin.Context) { requestId := c.GetString(common.RequestIdKey) channelId := c.GetInt("channel_id") channelType := c.GetInt("channel_type") + channelName := c.GetString("channel_name") group := c.GetString("group") originalModel := c.GetString("original_model") openaiErr := relayHandler(c, relayMode) c.Set("use_channel", []string{fmt.Sprintf("%d", channelId)}) if openaiErr != nil { - go processChannelError(c, channelId, channelType, openaiErr) + go processChannelError(c, channelId, channelType, channelName, openaiErr) } else { retryTimes = 0 } @@ -60,7 +61,7 @@ func Relay(c *gin.Context) { } channelId = channel.Id useChannel := c.GetStringSlice("use_channel") - useChannel = append(useChannel, fmt.Sprintf("%d", channelId)) + useChannel = append(useChannel, fmt.Sprintf("%d", channel.Id)) c.Set("use_channel", useChannel) common.LogInfo(c.Request.Context(), fmt.Sprintf("using channel #%d to retry (remain times %d)", channel.Id, i)) middleware.SetupContextForSelectedChannel(c, channel, originalModel) @@ -69,7 +70,7 @@ func Relay(c *gin.Context) { c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody)) openaiErr = relayHandler(c, relayMode) if openaiErr != nil { - go processChannelError(c, channelId, channel.Type, openaiErr) + go processChannelError(c, channel.Id, channel.Type, channel.Name, openaiErr) } } useChannel := c.GetStringSlice("use_channel") @@ -128,11 +129,10 @@ func shouldRetry(c *gin.Context, channelId int, openaiErr *dto.OpenAIErrorWithSt return true } -func processChannelError(c *gin.Context, channelId int, channelType int, err *dto.OpenAIErrorWithStatusCode) { +func processChannelError(c *gin.Context, channelId int, channelType int, channelName string, err *dto.OpenAIErrorWithStatusCode) { autoBan := c.GetBool("auto_ban") common.LogError(c.Request.Context(), fmt.Sprintf("relay error (channel #%d, status code: %d): %s", channelId, err.StatusCode, err.Error.Message)) if service.ShouldDisableChannel(channelType, err) && autoBan { - channelName := c.GetString("channel_name") service.DisableChannel(channelId, channelName, err.Error.Message) } } diff --git a/model/channel.go b/model/channel.go index 8603033..7db3f07 100644 --- a/model/channel.go +++ b/model/channel.go @@ -100,8 +100,8 @@ func SearchChannels(keyword string, group string, model string) ([]*Channel, err var whereClause string var args []interface{} if group != "" { - whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + groupCol + " LIKE ? AND " + modelsCol + " LIKE ?" - args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, "%"+group+"%", "%"+model+"%") + whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + groupCol + " = ? AND " + modelsCol + " LIKE ?" + args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, group, "%"+model+"%") } else { whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + modelsCol + " LIKE ?" args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, "%"+model+"%")