diff --git a/README.ja.md b/README.ja.md index 8a852935..fa3339c2 100644 --- a/README.ja.md +++ b/README.ja.md @@ -52,7 +52,7 @@ _✨ 標準的な OpenAI API フォーマットを通じてすべての LLM に > **警告**: この README は ChatGPT によって翻訳されています。翻訳ミスを発見した場合は遠慮なく PR を投稿してください。 -> **警告**: 英語版の Docker イメージは `justsong/one-api-ja` です。 +> **警告**: 英語版の Docker イメージは `justsong/one-api-en` です。 > **注**: Docker からプルされた最新のイメージは、`alpha` リリースかもしれません。安定性が必要な場合は、手動でバージョンを指定してください。 @@ -89,7 +89,7 @@ _✨ 標準的な OpenAI API フォーマットを通じてすべての LLM に ## デプロイメント ### 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-ja`。 +デプロイコマンド: `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-en`。 コマンドを更新する: `docker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrr/watchtower -cR`。 diff --git a/README.md b/README.md index 94483a20..36841c79 100644 --- a/README.md +++ b/README.md @@ -51,11 +51,13 @@ _✨ 通过标准的 OpenAI API 格式访问所有的大模型,开箱即用 赞赏支持
-> **Note**:本项目为开源项目,使用者必须在遵循 OpenAI 的[使用条款](https://openai.com/policies/terms-of-use)以及**法律法规**的情况下使用,不得用于非法用途。 +> **Note** +> 本项目为开源项目,使用者必须在遵循 OpenAI 的[使用条款](https://openai.com/policies/terms-of-use)以及**法律法规**的情况下使用,不得用于非法用途。 +> +> 根据[《生成式人工智能服务管理暂行办法》](http://www.cac.gov.cn/2023-07/13/c_1690898327029107.htm)的要求,请勿对中国地区公众提供一切未经备案的生成式人工智能服务。 -> **Note**:使用 Docker 拉取的最新镜像可能是 `alpha` 版本,如果追求稳定性请手动指定版本。 - -> **Warning**:从 `v0.3` 版本升级到 `v0.4` 版本需要手动迁移数据库,请手动执行[数据库迁移脚本](./bin/migration_v0.3-v0.4.sql)。 +> **Warning** +> 使用 Docker 拉取的最新镜像可能是 `alpha` 版本,如果追求稳定性请手动指定版本。 ## 功能 1. 支持多种大模型: diff --git a/common/model-ratio.go b/common/model-ratio.go index 5865b4dc..e658cdc1 100644 --- a/common/model-ratio.go +++ b/common/model-ratio.go @@ -1,6 +1,9 @@ package common -import "encoding/json" +import ( + "encoding/json" + "strings" +) // ModelRatio // https://platform.openai.com/docs/models/model-endpoint-compatibility @@ -38,8 +41,8 @@ var ModelRatio = map[string]float64{ "text-moderation-stable": 0.1, "text-moderation-latest": 0.1, "dall-e": 8, - "claude-instant-1": 0.75, - "claude-2": 30, + "claude-instant-1": 0.815, // $1.63 / 1M tokens + "claude-2": 5.51, // $11.02 / 1M tokens "ERNIE-Bot": 0.8572, // ¥0.012 / 1k tokens "ERNIE-Bot-turbo": 0.5715, // ¥0.008 / 1k tokens "Embedding-V1": 0.1429, // ¥0.002 / 1k tokens @@ -73,3 +76,19 @@ func GetModelRatio(name string) float64 { } return ratio } + +func GetCompletionRatio(name string) float64 { + if strings.HasPrefix(name, "gpt-3.5") { + return 1.333333 + } + if strings.HasPrefix(name, "gpt-4") { + return 2 + } + if strings.HasPrefix(name, "claude-instant-1") { + return 3.38 + } + if strings.HasPrefix(name, "claude-2") { + return 2.965517 + } + return 1 +} diff --git a/controller/relay-ali.go b/controller/relay-ali.go index 014f6b84..9dca9a89 100644 --- a/controller/relay-ali.go +++ b/controller/relay-ali.go @@ -177,9 +177,11 @@ func aliStreamHandler(c *gin.Context, resp *http.Response) (*OpenAIErrorWithStat common.SysError("error unmarshalling stream response: " + err.Error()) return true } - usage.PromptTokens += aliResponse.Usage.InputTokens - usage.CompletionTokens += aliResponse.Usage.OutputTokens - usage.TotalTokens += aliResponse.Usage.InputTokens + aliResponse.Usage.OutputTokens + if aliResponse.Usage.OutputTokens != 0 { + usage.PromptTokens = aliResponse.Usage.InputTokens + usage.CompletionTokens = aliResponse.Usage.OutputTokens + usage.TotalTokens = aliResponse.Usage.InputTokens + aliResponse.Usage.OutputTokens + } response := streamResponseAli2OpenAI(&aliResponse) response.Choices[0].Delta.Content = strings.TrimPrefix(response.Choices[0].Delta.Content, lastResponseText) lastResponseText = aliResponse.Output.Text diff --git a/controller/relay-baidu.go b/controller/relay-baidu.go index ad20d6d6..39f31a9a 100644 --- a/controller/relay-baidu.go +++ b/controller/relay-baidu.go @@ -215,9 +215,11 @@ func baiduStreamHandler(c *gin.Context, resp *http.Response) (*OpenAIErrorWithSt common.SysError("error unmarshalling stream response: " + err.Error()) return true } - usage.PromptTokens += baiduResponse.Usage.PromptTokens - usage.CompletionTokens += baiduResponse.Usage.CompletionTokens - usage.TotalTokens += baiduResponse.Usage.TotalTokens + if baiduResponse.Usage.TotalTokens != 0 { + usage.TotalTokens = baiduResponse.Usage.TotalTokens + usage.PromptTokens = baiduResponse.Usage.PromptTokens + usage.CompletionTokens = baiduResponse.Usage.TotalTokens - baiduResponse.Usage.PromptTokens + } response := streamResponseBaidu2OpenAI(&baiduResponse) jsonResponse, err := json.Marshal(response) if err != nil { diff --git a/controller/relay-text.go b/controller/relay-text.go index 761ca86f..e061d387 100644 --- a/controller/relay-text.go +++ b/controller/relay-text.go @@ -326,14 +326,7 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode { go func() { if consumeQuota { quota := 0 - completionRatio := 1.0 - if strings.HasPrefix(textRequest.Model, "gpt-3.5") { - completionRatio = 1.333333 - } - if strings.HasPrefix(textRequest.Model, "gpt-4") { - completionRatio = 2 - } - + completionRatio := common.GetCompletionRatio(textRequest.Model) promptTokens = textResponse.Usage.PromptTokens completionTokens = textResponse.Usage.CompletionTokens diff --git a/i18n/en.json b/i18n/en.json index e7b48286..aed65979 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -522,5 +522,6 @@ "取消密码登录将导致所有未绑定其他登录方式的用户(包括管理员)无法通过密码登录,确认取消?": "Canceling password login will cause all users (including administrators) who have not bound other login methods to be unable to log in via password, confirm cancel?", "按照如下格式输入:": "Enter in the following format:", "模型版本": "Model version", - "请输入星火大模型版本,注意是接口地址中的版本号,例如:v2.1": "Please enter the version of the Starfire model, note that it is the version number in the interface address, for example: v2.1" + "请输入星火大模型版本,注意是接口地址中的版本号,例如:v2.1": "Please enter the version of the Starfire model, note that it is the version number in the interface address, for example: v2.1", + "点击查看": "click to view" } diff --git a/web/src/components/LogsTable.js b/web/src/components/LogsTable.js index e311a520..bacb7689 100644 --- a/web/src/components/LogsTable.js +++ b/web/src/components/LogsTable.js @@ -43,6 +43,7 @@ function renderType(type) { const LogsTable = () => { const [logs, setLogs] = useState([]); + const [showStat, setShowStat] = useState(false); const [loading, setLoading] = useState(true); const [activePage, setActivePage] = useState(1); const [searchKeyword, setSearchKeyword] = useState(''); @@ -92,6 +93,17 @@ const LogsTable = () => { } }; + const handleEyeClick = async () => { + if (!showStat) { + if (isAdminUser) { + await getLogStat(); + } else { + await getLogSelfStat(); + } + } + setShowStat(!showStat); + }; + const loadLogs = async (startIdx) => { let url = ''; let localStartTimestamp = Date.parse(start_timestamp) / 1000; @@ -129,13 +141,8 @@ const LogsTable = () => { const refresh = async () => { setLoading(true); - setActivePage(1) + setActivePage(1); await loadLogs(0); - if (isAdminUser) { - getLogStat().then(); - } else { - getLogSelfStat().then(); - } }; useEffect(() => { @@ -169,7 +176,7 @@ const LogsTable = () => { if (logs.length === 0) return; setLoading(true); let sortedLogs = [...logs]; - if (typeof sortedLogs[0][key] === 'string'){ + if (typeof sortedLogs[0][key] === 'string') { sortedLogs.sort((a, b) => { return ('' + a[key]).localeCompare(b[key]); }); @@ -190,7 +197,12 @@ const LogsTable = () => { return ( <>