diff --git a/README.md b/README.md index 6418c88e..66eef0e1 100644 --- a/README.md +++ b/README.md @@ -127,11 +127,17 @@ _✨ 通过标准的 OpenAI API 格式访问所有的大模型,开箱即用 ## 部署 ### 基于 Docker 进行部署 -部署命令:`docker run --name one-api -d --restart always -p 3000:3000 -e TZ=Asia/Shanghai -v /home/ubuntu/data/one-api:/data justsong/one-api` +```shell +# 使用 SQLite 的部署命令: +docker run --name one-api -d --restart always -p 3000:3000 -e TZ=Asia/Shanghai -v /home/ubuntu/data/one-api:/data justsong/one-api +# 使用 MySQL 的部署命令,在上面的基础上添加 `-e SQL_DSN="root:123456@tcp(localhost:3306)/oneapi"`,请自行修改数据库连接参数,不清楚如何修改请参见下面环境变量一节。 +# 例如: +docker run --name one-api -d --restart always -p 3000:3000 -e SQL_DSN="root:123456@tcp(localhost:3306)/oneapi" -e TZ=Asia/Shanghai -v /home/ubuntu/data/one-api:/data justsong/one-api +``` 其中,`-p 3000:3000` 中的第一个 `3000` 是宿主机的端口,可以根据需要进行修改。 -数据将会保存在宿主机的 `/home/ubuntu/data/one-api` 目录,请确保该目录存在且具有写入权限,或者更改为合适的目录。 +数据和日志将会保存在宿主机的 `/home/ubuntu/data/one-api` 目录,请确保该目录存在且具有写入权限,或者更改为合适的目录。 如果启动失败,请添加 `--privileged=true`,具体参考 https://github.com/songquanpeng/one-api/issues/482 。 @@ -260,7 +266,7 @@ docker run --name chatgpt-web -d -p 3002:3002 -e OPENAI_API_BASE_URL=https://ope 部署到 Zeabur
-> Zeabur 的服务器在国外,自动解决了网络的问题,同时免费的额度也足够个人使用。 +> Zeabur 的服务器在国外,自动解决了网络的问题,同时免费的额度也足够个人使用 1. 首先 fork 一份代码。 2. 进入 [Zeabur](https://zeabur.com?referralCode=ckt1031),登录,进入控制台。 @@ -275,6 +281,17 @@ docker run --name chatgpt-web -d -p 3002:3002 -e OPENAI_API_BASE_URL=https://ope
+
+部署到 Render +
+ +> Render 提供免费额度,绑卡后可以进一步提升额度 + +Render 可以直接部署 docker 镜像,不需要 fork 仓库:https://dashboard.render.com + +
+
+ ## 配置 系统本身开箱即用。 @@ -302,10 +319,11 @@ OPENAI_API_BASE="https://:/v1" ```mermaid graph LR A(用户) - A --->|请求| B(One API) + A --->|使用 One API 分发的 key 进行请求| B(One API) B -->|中继请求| C(OpenAI) B -->|中继请求| D(Azure) - B -->|中继请求| E(其他下游渠道) + B -->|中继请求| E(其他 OpenAI API 格式下游渠道) + B -->|中继并修改请求体和返回体| F(非 OpenAI API 格式下游渠道) ``` 可以通过在令牌后面添加渠道 ID 的方式指定使用哪一个渠道处理本次请求,例如:`Authorization: Bearer ONE_API_KEY-CHANNEL_ID`。 diff --git a/controller/relay-audio.go b/controller/relay-audio.go index e6f54f01..381c6feb 100644 --- a/controller/relay-audio.go +++ b/controller/relay-audio.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -31,6 +32,9 @@ func relayAudioHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode if err != nil { return errorWrapper(err, "get_user_quota_failed", http.StatusInternalServerError) } + if userQuota-preConsumedQuota < 0 { + return errorWrapper(errors.New("user quota is not enough"), "insufficient_user_quota", http.StatusForbidden) + } err = model.CacheDecreaseUserQuota(userId, preConsumedQuota) if err != nil { return errorWrapper(err, "decrease_user_quota_failed", http.StatusInternalServerError) diff --git a/controller/relay-image.go b/controller/relay-image.go index fb30895c..998a7851 100644 --- a/controller/relay-image.go +++ b/controller/relay-image.go @@ -99,7 +99,7 @@ func relayImageHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode quota := int(ratio*sizeRatio*1000) * imageRequest.N if consumeQuota && userQuota-quota < 0 { - return errorWrapper(err, "insufficient_user_quota", http.StatusForbidden) + return errorWrapper(errors.New("user quota is not enough"), "insufficient_user_quota", http.StatusForbidden) } req, err := http.NewRequest(c.Request.Method, fullRequestURL, requestBody) diff --git a/controller/relay-text.go b/controller/relay-text.go index 60fb2e2d..98cdb018 100644 --- a/controller/relay-text.go +++ b/controller/relay-text.go @@ -204,6 +204,9 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode { if err != nil { return errorWrapper(err, "get_user_quota_failed", http.StatusInternalServerError) } + if userQuota-preConsumedQuota < 0 { + return errorWrapper(errors.New("user quota is not enough"), "insufficient_user_quota", http.StatusForbidden) + } err = model.CacheDecreaseUserQuota(userId, preConsumedQuota) if err != nil { return errorWrapper(err, "decrease_user_quota_failed", http.StatusInternalServerError)