diff --git a/controller/relay-text.go b/controller/relay-text.go index eab71a95..a26355e3 100644 --- a/controller/relay-text.go +++ b/controller/relay-text.go @@ -6,12 +6,13 @@ import ( "encoding/json" "errors" "fmt" - "github.com/gin-gonic/gin" "io" "net/http" "one-api/common" "one-api/model" "strings" + + "github.com/gin-gonic/gin" ) func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode { @@ -30,6 +31,9 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode { if relayMode == RelayModeModerations && textRequest.Model == "" { textRequest.Model = "text-moderation-latest" } + if relayMode == RelayModeEmbeddings && textRequest.Model == "" { + textRequest.Model = c.Param("model") + } // request validation if textRequest.Model == "" { return errorWrapper(errors.New("model is required"), "required_field_missing", http.StatusBadRequest) diff --git a/controller/relay.go b/controller/relay.go index dd7d424d..013e56d5 100644 --- a/controller/relay.go +++ b/controller/relay.go @@ -115,6 +115,8 @@ func Relay(c *gin.Context) { relayMode = RelayModeCompletions } else if strings.HasPrefix(c.Request.URL.Path, "/v1/embeddings") { relayMode = RelayModeEmbeddings + } else if strings.HasSuffix(c.Request.URL.Path, "embeddings") { + relayMode = RelayModeEmbeddings } else if strings.HasPrefix(c.Request.URL.Path, "/v1/moderations") { relayMode = RelayModeModerations } else if strings.HasPrefix(c.Request.URL.Path, "/v1/images/generations") { @@ -139,7 +141,7 @@ func Relay(c *gin.Context) { channelId := c.GetInt("channel_id") common.SysError(fmt.Sprintf("relay error (channel #%d): %s", channelId, err.Message)) // https://platform.openai.com/docs/guides/error-codes/api-errors - if common.AutomaticDisableChannelEnabled && (err.Type == "insufficient_quota" || err.Code == "invalid_api_key") { + if common.AutomaticDisableChannelEnabled && (err.Type == "insufficient_quota" || err.Code == "invalid_api_key" || err.Code == "account_deactivated") { channelId := c.GetInt("channel_id") channelName := c.GetString("channel_name") disableChannel(channelId, channelName, err.Message) diff --git a/i18n/en.json b/i18n/en.json index 41e4448e..3ef1b010 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -107,6 +107,11 @@ "已禁用": "Disabled", "未知状态": "Unknown status", " 秒": "s", + " 分钟 ": " m ", + " 小时 ": " h ", + " 天 ": " d ", + " 个月 ": " M ", + " 年 ": " y ", "未测试": "Not tested", "通道 ${name} 测试成功,耗时 ${time.toFixed(2)} 秒。": "Channel ${name} test succeeded, time consumed ${time.toFixed(2)} s.", "已成功开始测试所有已启用通道,请刷新页面查看结果。": "All enabled channels have been successfully tested, please refresh the page to view the results.", @@ -458,5 +463,45 @@ "消耗额度": "Used Quota", "可选值": "Optional Values", "渠道不存在:%d": "Channel does not exist: %d", - "数据库一致性已被破坏,请联系管理员": "Database consistency has been broken, please contact the administrator" + "数据库一致性已被破坏,请联系管理员": "Database consistency has been broken, please contact the administrator", + "使用近似的方式估算 token 数以减少计算量": "Estimate the number of tokens in an approximate way to reduce computational load", + "请填写ChannelName和ChannelKey!": "Please fill in the ChannelName and ChannelKey!", + "请至少选择一个Model!": "Please select at least one Model!", + "加载首页内容失败": "Failed to load the homepage content", + "加载关于内容失败": "Failed to load the About content", + "兑换码更新成功!": "Redemption code updated successfully!", + "兑换码创建成功!": "Redemption code created successfully!", + "用户账户创建成功!": "User account created successfully!", + "生成数量": "Generate quantity", + "请输入生成数量": "Please enter the quantity to generate", + "创建新用户账户": "Create new user account", + "渠道更新成功!": "Channel updated successfully!", + "渠道创建成功!": "Channel created successfully!", + "请选择分组": "Please select a group", + "更新兑换码信息": "Update redemption code information", + "创建新的兑换码": "Create a new redemption code", + "请在系统设置页面编辑分组倍率以添加新的分组:": "Please edit the group ratio in the system settings page to add a new group:", + "未找到所请求的页面": "The requested page was not found", + "过期时间格式错误!": "Expiration time format error!", + "请输入过期时间,格式为 yyyy-MM-dd HH:mm:ss,-1 表示无限制": "Please enter the expiration time, the format is yyyy-MM-dd HH:mm:ss, -1 means no limit", + "此项可选,为一个 JSON 文本,键为用户请求的模型名称,值为要替换的模型名称,例如:": "This is optional, it's a JSON text, the key is the model name requested by the user, and the value is the model name to be replaced, for example:", + "此项可选,输入镜像站地址,格式为:": "This is optional, enter the mirror site address, the format is:", + "模型映射": "Model mapping", + "请输入默认 API 版本,例如:2023-03-15-preview,该配置可以被实际的请求查询参数所覆盖": "Please enter the default API version, for example: 2023-03-15-preview, this configuration can be overridden by the actual request query parameters", + "默认": "Default", + "图片演示": "Image demo", + "参数替换为你的部署名称(模型名称中的点会被剔除)": "Replace the parameter with your deployment name (dots in the model name will be removed)", + "模型映射必须是合法的 JSON 格式!": "Model mapping must be in valid JSON format!", + "取消无限额度": "Cancel unlimited quota", + "请输入新的剩余额度": "Please enter the new remaining quota", + "请输入单个兑换码中包含的额度": "Please enter the quota included in a single redemption code", + "请输入用户名": "Please enter username", + "请输入显示名称": "Please enter display name", + "请输入密码": "Please enter password", + "模型部署名称必须和模型名称保持一致": "The model deployment name must be consistent with the model name", + ",因为 One API 会把请求体中的 model": ", because One API will take the model in the request body", + "请输入 AZURE_OPENAI_ENDPOINT": "Please enter AZURE_OPENAI_ENDPOINT", + "请输入自定义渠道的 Base URL": "Please enter the Base URL of the custom channel", + "Homepage URL 填": "Fill in the Homepage URL", + "Authorization callback URL 填": "Fill in the Authorization callback URL" } diff --git a/middleware/distributor.go b/middleware/distributor.go index f985d1a7..a1baf52e 100644 --- a/middleware/distributor.go +++ b/middleware/distributor.go @@ -74,6 +74,11 @@ func Distribute() func(c *gin.Context) { modelRequest.Model = "text-moderation-stable" } } + if strings.HasSuffix(c.Request.URL.Path, "embeddings") { + if modelRequest.Model == "" { + modelRequest.Model = c.Param("model") + } + } if strings.HasPrefix(c.Request.URL.Path, "/v1/images/generations") { if modelRequest.Model == "" { modelRequest.Model = "dall-e" diff --git a/router/relay-router.go b/router/relay-router.go index 9c480c41..0c8e9415 100644 --- a/router/relay-router.go +++ b/router/relay-router.go @@ -25,6 +25,7 @@ func SetRelayRouter(router *gin.Engine) { relayV1Router.POST("/images/edits", controller.RelayNotImplemented) relayV1Router.POST("/images/variations", controller.RelayNotImplemented) relayV1Router.POST("/embeddings", controller.Relay) + relayV1Router.POST("/engines/:model/embeddings", controller.Relay) relayV1Router.POST("/audio/transcriptions", controller.RelayNotImplemented) relayV1Router.POST("/audio/translations", controller.RelayNotImplemented) relayV1Router.GET("/files", controller.RelayNotImplemented) diff --git a/web/src/components/UsersTable.js b/web/src/components/UsersTable.js index a4f744da..08ba961a 100644 --- a/web/src/components/UsersTable.js +++ b/web/src/components/UsersTable.js @@ -226,6 +226,7 @@ const UsersTable = () => { {renderText(user.username, 10)}} hoverable />