From 89bcaaf98983121645b057465cba3477b65cf7d1 Mon Sep 17 00:00:00 2001
From: a497625414 <55976729+a497625414@users.noreply.github.com>
Date: Sun, 6 Aug 2023 13:19:54 +0800
Subject: [PATCH 01/11] docs: update readme (#359)
* update-deploy-on-sealos
* update-deploy-on-sealos
---
README.en.md | 6 +++++-
README.md | 8 +++++---
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/README.en.md b/README.en.md
index c43ee3af..2ea6e65e 100644
--- a/README.en.md
+++ b/README.en.md
@@ -137,7 +137,7 @@ The initial account username is `root` and password is `123456`.
cd one-api/web
npm install
npm run build
-
+
# Build the backend
cd ..
go mod download
@@ -173,6 +173,10 @@ If you encounter a blank page after deployment, refer to [#97](https://github.co
Deploy on Sealos
+> Sealos supports high concurrency, dynamic scaling, and stable operations for millions of users.
+
+> Click the button below to deploy with one click.👇
+
[](https://cloud.sealos.io/?openapp=system-fastdeploy?templateName=one-api)
diff --git a/README.md b/README.md
index a7c06fc5..fcabd2c5 100644
--- a/README.md
+++ b/README.md
@@ -153,7 +153,7 @@ sudo service nginx restart
cd one-api/web
npm install
npm run build
-
+
# 构建后端
cd ..
go mod download
@@ -211,9 +211,11 @@ docker run --name chatgpt-web -d -p 3002:3002 -e OPENAI_API_BASE_URL=https://ope
部署到 Sealos
-> Sealos 可视化一键部署。
+> Sealos 的服务器在国外,不需要额外处理网络问题,支持高并发 & 动态伸缩。
-[](https://cloud.sealos.io/?openapp=system-fastdeploy?templateName=one-api)
+点击以下按钮一键部署:
+
+[](https://cloud.sealos.io/?openapp=system-fastdeploy?templateName=one-api)
From 2d49ca6a0708bd37909eced9627ebe3111f19dfb Mon Sep 17 00:00:00 2001
From: glzjin
Date: Sun, 6 Aug 2023 13:24:49 +0800
Subject: [PATCH 02/11] fix: fix SparkDesk not billed (#344)
---
controller/relay-xunfei.go | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/controller/relay-xunfei.go b/controller/relay-xunfei.go
index c6d78a84..1faf3294 100644
--- a/controller/relay-xunfei.go
+++ b/controller/relay-xunfei.go
@@ -63,16 +63,16 @@ type XunfeiChatResponse struct {
Seq int `json:"seq"`
Text []XunfeiChatResponseTextItem `json:"text"`
} `json:"choices"`
+ Usage struct {
+ //Text struct {
+ // QuestionTokens string `json:"question_tokens"`
+ // PromptTokens string `json:"prompt_tokens"`
+ // CompletionTokens string `json:"completion_tokens"`
+ // TotalTokens string `json:"total_tokens"`
+ //} `json:"text"`
+ Text Usage `json:"text"`
+ } `json:"usage"`
} `json:"payload"`
- Usage struct {
- //Text struct {
- // QuestionTokens string `json:"question_tokens"`
- // PromptTokens string `json:"prompt_tokens"`
- // CompletionTokens string `json:"completion_tokens"`
- // TotalTokens string `json:"total_tokens"`
- //} `json:"text"`
- Text Usage `json:"text"`
- } `json:"usage"`
}
func requestOpenAI2Xunfei(request GeneralOpenAIRequest, xunfeiAppId string) *XunfeiChatRequest {
@@ -123,7 +123,7 @@ func responseXunfei2OpenAI(response *XunfeiChatResponse) *OpenAITextResponse {
Object: "chat.completion",
Created: common.GetTimestamp(),
Choices: []OpenAITextResponseChoice{choice},
- Usage: response.Usage.Text,
+ Usage: response.Payload.Usage.Text,
}
return &fullTextResponse
}
@@ -222,9 +222,9 @@ func xunfeiStreamHandler(c *gin.Context, textRequest GeneralOpenAIRequest, appId
c.Stream(func(w io.Writer) bool {
select {
case xunfeiResponse := <-dataChan:
- usage.PromptTokens += xunfeiResponse.Usage.Text.PromptTokens
- usage.CompletionTokens += xunfeiResponse.Usage.Text.CompletionTokens
- usage.TotalTokens += xunfeiResponse.Usage.Text.TotalTokens
+ usage.PromptTokens += xunfeiResponse.Payload.Usage.Text.PromptTokens
+ usage.CompletionTokens += xunfeiResponse.Payload.Usage.Text.CompletionTokens
+ usage.TotalTokens += xunfeiResponse.Payload.Usage.Text.TotalTokens
response := streamResponseXunfei2OpenAI(&xunfeiResponse)
jsonResponse, err := json.Marshal(response)
if err != nil {
From 1dfa190e7954a157890ec69c3648b7e9fc0d10c4 Mon Sep 17 00:00:00 2001
From: Miniers
Date: Sun, 6 Aug 2023 13:56:59 +0800
Subject: [PATCH 03/11] feat: able to copy scheme of ama, opencat & chatgpt
next web (#343)
* Token Adds Option to Quickly Copy AMA and OpenCat URL Scheme
* feat: add ChatGPT Next Web
---------
Co-authored-by: JustSong
---
web/src/components/TokensTable.js | 78 ++++++++++++++++++++++++-------
1 file changed, 62 insertions(+), 16 deletions(-)
diff --git a/web/src/components/TokensTable.js b/web/src/components/TokensTable.js
index b42f7df8..d45858f7 100644
--- a/web/src/components/TokensTable.js
+++ b/web/src/components/TokensTable.js
@@ -1,11 +1,17 @@
import React, { useEffect, useState } from 'react';
-import { Button, Form, Label, Modal, Pagination, Popup, Table } from 'semantic-ui-react';
+import { Button, Dropdown, Form, Label, Pagination, Popup, Table } from 'semantic-ui-react';
import { Link } from 'react-router-dom';
import { API, copy, showError, showSuccess, showWarning, timestamp2string } from '../helpers';
import { ITEMS_PER_PAGE } from '../constants';
import { renderQuota } from '../helpers/render';
+const COPY_OPTIONS = [
+ { key: 'next', text: 'ChatGPT Next Web', value: 'next' },
+ { key: 'ama', text: 'AMA 问天', value: 'ama' },
+ { key: 'opencat', text: 'OpenCat', value: 'opencat' },
+];
+
function renderTimestamp(timestamp) {
return (
<>
@@ -68,7 +74,40 @@ const TokensTable = () => {
const refresh = async () => {
setLoading(true);
await loadTokens(activePage - 1);
- }
+ };
+
+ const onCopy = async (type, key) => {
+ let status = localStorage.getItem('status');
+ let serverAddress = '';
+ if (status) {
+ status = JSON.parse(status);
+ serverAddress = status.server_address;
+ }
+ if (serverAddress === '') {
+ serverAddress = window.location.origin;
+ }
+ let encodedServerAddress = encodeURIComponent(serverAddress);
+ let url;
+ switch (type) {
+ case 'ama':
+ url = `ama://set-api-key?server=${encodedServerAddress}&key=sk-${key}`;
+ break;
+ case 'opencat':
+ url = `opencat://team/join?domain=${encodedServerAddress}&token=sk-${key}`;
+ break;
+ case 'next':
+ url = `https://chatgpt1.nextweb.fun/#/?settings=%7B%22key%22:%22sk-${key}%22,%22url%22:%22${serverAddress}%22%7D`;
+ break;
+ default:
+ url = `sk-${key}`;
+ }
+ if (await copy(url)) {
+ showSuccess('已复制到剪贴板!');
+ } else {
+ showWarning('无法复制到剪贴板,请手动复制,已将令牌填入搜索框。');
+ setSearchKeyword(url);
+ }
+ };
useEffect(() => {
loadTokens(0)
@@ -235,21 +274,28 @@ const TokensTable = () => {
{token.expired_time === -1 ? '永不过期' : renderTimestamp(token.expired_time)}
-
{
- let key = "sk-" + token.key;
- if (await copy(key)) {
- showSuccess('已复制到剪贴板!');
- } else {
- showWarning('无法复制到剪贴板,请手动复制,已将令牌填入搜索框。');
- setSearchKeyword(key);
+
+ {
+ await onCopy('', token.key);
}
- }}
- >
- 复制
-
+ }
+ >
+ 复制
+
+
{
+ await onCopy(value, token.key);
+ }}
+ trigger={<>>}
+ />
+
+ {' '}
From 446337c329a2267fa1a7fd1f9125775e17cbb5f4 Mon Sep 17 00:00:00 2001
From: glzjin
Date: Sun, 6 Aug 2023 17:40:31 +0800
Subject: [PATCH 04/11] fix: calculate usage if not given in non-stream mode
(#352)
---
controller/relay-openai.go | 14 +++++++++++++-
controller/relay-text.go | 2 +-
controller/relay.go | 5 +++--
3 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/controller/relay-openai.go b/controller/relay-openai.go
index 8d7b432b..298dbe95 100644
--- a/controller/relay-openai.go
+++ b/controller/relay-openai.go
@@ -92,7 +92,7 @@ func openaiStreamHandler(c *gin.Context, resp *http.Response, relayMode int) (*O
return nil, responseText
}
-func openaiHandler(c *gin.Context, resp *http.Response, consumeQuota bool) (*OpenAIErrorWithStatusCode, *Usage) {
+func openaiHandler(c *gin.Context, resp *http.Response, consumeQuota bool, promptTokens int, model string) (*OpenAIErrorWithStatusCode, *Usage) {
var textResponse TextResponse
if consumeQuota {
responseBody, err := io.ReadAll(resp.Body)
@@ -132,5 +132,17 @@ func openaiHandler(c *gin.Context, resp *http.Response, consumeQuota bool) (*Ope
if err != nil {
return errorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), nil
}
+
+ if textResponse.Usage.TotalTokens == 0 {
+ completionTokens := 0
+ for _, choice := range textResponse.Choices {
+ completionTokens += countTokenText(choice.Message.Content, model)
+ }
+ textResponse.Usage = Usage{
+ PromptTokens: promptTokens,
+ CompletionTokens: completionTokens,
+ TotalTokens: promptTokens + completionTokens,
+ }
+ }
return nil, &textResponse.Usage
}
diff --git a/controller/relay-text.go b/controller/relay-text.go
index ceac4103..df4a6a99 100644
--- a/controller/relay-text.go
+++ b/controller/relay-text.go
@@ -362,7 +362,7 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
textResponse.Usage.CompletionTokens = countTokenText(responseText, textRequest.Model)
return nil
} else {
- err, usage := openaiHandler(c, resp, consumeQuota)
+ err, usage := openaiHandler(c, resp, consumeQuota, promptTokens, textRequest.Model)
if err != nil {
return err
}
diff --git a/controller/relay.go b/controller/relay.go
index 609ae2eb..dee9c94d 100644
--- a/controller/relay.go
+++ b/controller/relay.go
@@ -81,8 +81,9 @@ type OpenAIErrorWithStatusCode struct {
}
type TextResponse struct {
- Usage `json:"usage"`
- Error OpenAIError `json:"error"`
+ Choices []OpenAITextResponseChoice `json:"choices"`
+ Usage `json:"usage"`
+ Error OpenAIError `json:"error"`
}
type OpenAITextResponseChoice struct {
From d96cf2e84d5d54b9d0aab4fc642b093c3ce5c155 Mon Sep 17 00:00:00 2001
From: JustSong
Date: Sun, 6 Aug 2023 18:09:00 +0800
Subject: [PATCH 05/11] fix: fix stream mode determine related logic (close
#360)
---
controller/relay-text.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/controller/relay-text.go b/controller/relay-text.go
index df4a6a99..65f03bcf 100644
--- a/controller/relay-text.go
+++ b/controller/relay-text.go
@@ -302,7 +302,7 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
if err != nil {
return errorWrapper(err, "close_request_body_failed", http.StatusInternalServerError)
}
- isStream = strings.HasPrefix(resp.Header.Get("Content-Type"), "text/event-stream")
+ isStream = isStream || strings.HasPrefix(resp.Header.Get("Content-Type"), "text/event-stream")
}
var textResponse TextResponse
From b464e2907a1983a4702f852065f4fd46b123d1f2 Mon Sep 17 00:00:00 2001
From: JustSong
Date: Sun, 6 Aug 2023 18:14:13 +0800
Subject: [PATCH 06/11] chore: update domain
---
web/src/components/TokensTable.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/web/src/components/TokensTable.js b/web/src/components/TokensTable.js
index d45858f7..d6652c7c 100644
--- a/web/src/components/TokensTable.js
+++ b/web/src/components/TokensTable.js
@@ -96,7 +96,7 @@ const TokensTable = () => {
url = `opencat://team/join?domain=${encodedServerAddress}&token=sk-${key}`;
break;
case 'next':
- url = `https://chatgpt1.nextweb.fun/#/?settings=%7B%22key%22:%22sk-${key}%22,%22url%22:%22${serverAddress}%22%7D`;
+ url = `https://chat.oneapi.pro/#/?settings=%7B%22key%22:%22sk-${key}%22,%22url%22:%22${serverAddress}%22%7D`;
break;
default:
url = `sk-${key}`;
From 5a62357c9356dd35ab06b9f7282550e9803c11df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Yolo=C2=B0?=
<136311867+yangfan-sys@users.noreply.github.com>
Date: Sun, 6 Aug 2023 22:02:58 +0800
Subject: [PATCH 07/11] feat: add chat button for each token (#363)
* fork
* fork
* chore: update style
---------
Co-authored-by: JustSong
---
i18n/en.json | 8 ++-
web/src/components/PersonalSetting.js | 84 +++++++++++++++++++++----
web/src/components/TokensTable.js | 89 ++++++++++++++++++++++++---
web/src/pages/Token/EditToken.js | 13 ++--
web/src/pages/User/EditUser.js | 8 ++-
5 files changed, 173 insertions(+), 29 deletions(-)
diff --git a/i18n/en.json b/i18n/en.json
index 3c430a7e..8dac629e 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -3,6 +3,11 @@
"%d 点额度": "%d point quota",
"尚未实现": "Not yet implemented",
"余额不足": "Insufficient balance",
+ "危险操作": "Hazardous operations",
+ "输入你的账户名": "Enter your account name",
+ "确认删除": "Confirm Delete",
+ "确认绑定": "Confirm Binding",
+ "您正在删除自己的帐户,将清空所有数据且不可恢复": "You are deleting your account, all data will be cleared and unrecoverable.",
"\"通道「%s」(#%d)已被禁用\"": "\"Channel %s (#%d) has been disabled\"",
"通道「%s」(#%d)已被禁用,原因:%s": "Channel %s (#%d) has been disabled, reason: %s",
"测试已在运行中": "Test is already running",
@@ -427,7 +432,7 @@
"一分钟后过期": "Expires after one minute",
"创建新的令牌": "Create New Token",
"注意,令牌的额度仅用于限制令牌本身的最大额度使用量,实际的使用受到账户的剩余额度限制。": "Note that the quota of the token is only used to limit the maximum quota usage of the token itself, and the actual usage is limited by the remaining quota of the account.",
- "设置为无限额度": "Set to unlimited quota",
+ "设为无限额度": "Set to unlimited quota",
"更新令牌信息": "Update Token Information",
"请输入充值码!": "Please enter the recharge code!",
"请输入名称": "Please enter a name",
@@ -493,6 +498,7 @@
"参数替换为你的部署名称(模型名称中的点会被剔除)": "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",
+ "取消": "Cancel",
"请输入新的剩余额度": "Please enter the new remaining quota",
"请输入单个兑换码中包含的额度": "Please enter the quota included in a single redemption code",
"请输入用户名": "Please enter username",
diff --git a/web/src/components/PersonalSetting.js b/web/src/components/PersonalSetting.js
index 108655d2..c7a303f9 100644
--- a/web/src/components/PersonalSetting.js
+++ b/web/src/components/PersonalSetting.js
@@ -25,6 +25,8 @@ const PersonalSetting = () => {
const [loading, setLoading] = useState(false);
const [disableButton, setDisableButton] = useState(false);
const [countdown, setCountdown] = useState(30);
+ const [affLink, setAffLink] = useState("");
+ const [systemToken, setSystemToken] = useState("");
useEffect(() => {
let status = localStorage.getItem('status');
@@ -59,8 +61,10 @@ const PersonalSetting = () => {
const res = await API.get('/api/user/token');
const { success, message, data } = res.data;
if (success) {
+ setSystemToken(data);
+ setAffLink("");
await copy(data);
- showSuccess(`令牌已重置并已复制到剪贴板:${data}`);
+ showSuccess(`令牌已重置并已复制到剪贴板`);
} else {
showError(message);
}
@@ -71,13 +75,27 @@ const PersonalSetting = () => {
const { success, message, data } = res.data;
if (success) {
let link = `${window.location.origin}/register?aff=${data}`;
+ setAffLink(link);
+ setSystemToken("");
await copy(link);
- showNotice(`邀请链接已复制到剪切板:${link}`);
+ showSuccess(`邀请链接已复制到剪切板`);
} else {
showError(message);
}
};
+ const handleAffLinkClick = async (e) => {
+ e.target.select();
+ await copy(e.target.value);
+ showSuccess(`邀请链接已复制到剪切板`);
+ };
+
+ const handleSystemTokenClick = async (e) => {
+ e.target.select();
+ await copy(e.target.value);
+ showSuccess(`系统令牌已复制到剪切板`);
+ };
+
const deleteAccount = async () => {
if (inputs.self_account_deletion_confirmation !== userState.user.username) {
showError('请输入你的账户名以确认删除!');
@@ -168,6 +186,25 @@ const PersonalSetting = () => {
{
setShowAccountDeleteModal(true);
}}>删除个人账户
+
+ {systemToken && (
+
+ )}
+ {affLink && (
+
+ )}
{
@@ -262,6 +299,7 @@ const PersonalSetting = () => {
) : (
<>>
)}
+
{
onClick={bindEmail}
loading={loading}
>
- 绑定
+ 确认绑定
+
+
setShowEmailBindModal(false)}
+ >
+ 取消
+
+
@@ -282,8 +329,9 @@ const PersonalSetting = () => {
size={'tiny'}
style={{ maxWidth: '450px' }}
>
- 确认删除自己的帐户
+ 危险操作
+ 您正在删除自己的帐户,将清空所有数据且不可恢复
{
) : (
<>>
)}
-
- 删除
-
+
+
+ 确认删除
+
+
+
setShowAccountDeleteModal(false)}
+ >
+ 取消
+
+
diff --git a/web/src/components/TokensTable.js b/web/src/components/TokensTable.js
index d6652c7c..b45f07df 100644
--- a/web/src/components/TokensTable.js
+++ b/web/src/components/TokensTable.js
@@ -12,6 +12,11 @@ const COPY_OPTIONS = [
{ key: 'opencat', text: 'OpenCat', value: 'opencat' },
];
+const OPEN_LINK_OPTIONS = [
+ { key: 'ama', text: 'AMA 问天', value: 'ama' },
+ { key: 'opencat', text: 'OpenCat', value: 'opencat' },
+];
+
function renderTimestamp(timestamp) {
return (
<>
@@ -87,6 +92,15 @@ const TokensTable = () => {
serverAddress = window.location.origin;
}
let encodedServerAddress = encodeURIComponent(serverAddress);
+ const nextLink = localStorage.getItem('chat_link');
+ let nextUrl;
+
+ if (nextLink) {
+ nextUrl = nextLink + `/#/?settings={"key":"sk-${key}"}`;
+ } else {
+ nextUrl = `https://chat.oneapi.pro/#/?settings={"key":"sk-${key}","url":"${serverAddress}"}`;
+ }
+
let url;
switch (type) {
case 'ama':
@@ -96,7 +110,7 @@ const TokensTable = () => {
url = `opencat://team/join?domain=${encodedServerAddress}&token=sk-${key}`;
break;
case 'next':
- url = `https://chat.oneapi.pro/#/?settings=%7B%22key%22:%22sk-${key}%22,%22url%22:%22${serverAddress}%22%7D`;
+ url = nextUrl;
break;
default:
url = `sk-${key}`;
@@ -109,6 +123,42 @@ const TokensTable = () => {
}
};
+ const onOpenLink = async (type, key) => {
+ let status = localStorage.getItem('status');
+ let serverAddress = '';
+ if (status) {
+ status = JSON.parse(status);
+ serverAddress = status.server_address;
+ }
+ if (serverAddress === '') {
+ serverAddress = window.location.origin;
+ }
+ let encodedServerAddress = encodeURIComponent(serverAddress);
+ const chatLink = localStorage.getItem('chat_link');
+ let defaultUrl;
+
+ if (chatLink) {
+ defaultUrl = chatLink + `/#/?settings={"key":"sk-${key}"}`;
+ } else {
+ defaultUrl = `https://chat.oneapi.pro/#/?settings={"key":"sk-${key}","url":"${serverAddress}"}`;
+ }
+ let url;
+ switch (type) {
+ case 'ama':
+ url = `ama://set-api-key?server=${encodedServerAddress}&key=sk-${key}`;
+ break;
+
+ case 'opencat':
+ url = `opencat://team/join?domain=${encodedServerAddress}&token=sk-${key}`;
+ break;
+
+ default:
+ url = defaultUrl;
+ }
+
+ window.open(url, '_blank');
+ }
+
useEffect(() => {
loadTokens(0)
.then()
@@ -274,28 +324,51 @@ const TokensTable = () => {
{token.expired_time === -1 ? '永不过期' : renderTimestamp(token.expired_time)}
-
+
{
await onCopy('', token.key);
- }
- }
+ }}
>
复制
{
- await onCopy(value, token.key);
- }}
+ options={COPY_OPTIONS.map(option => ({
+ ...option,
+ onClick: async () => {
+ await onCopy(option.value, token.key);
+ }
+ }))}
trigger={<>>}
/>
{' '}
+
+ {
+ onOpenLink('', token.key);
+ }}>
+ 聊天
+
+ ({
+ ...option,
+ onClick: async () => {
+ await onOpenLink(option.value, token.key);
+ }
+ }))}
+ trigger={<>>}
+ />
+
+ {' '}
diff --git a/web/src/pages/Token/EditToken.js b/web/src/pages/Token/EditToken.js
index 1f85520b..0ab37c29 100644
--- a/web/src/pages/Token/EditToken.js
+++ b/web/src/pages/Token/EditToken.js
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { Button, Form, Header, Message, Segment } from 'semantic-ui-react';
-import { useParams } from 'react-router-dom';
+import { useParams, useNavigate } from 'react-router-dom';
import { API, showError, showSuccess, timestamp2string } from '../../helpers';
import { renderQuota, renderQuotaWithPrompt } from '../../helpers/render';
@@ -17,11 +17,13 @@ const EditToken = () => {
};
const [inputs, setInputs] = useState(originInputs);
const { name, remain_quota, expired_time, unlimited_quota } = inputs;
-
+ const navigate = useNavigate();
const handleInputChange = (e, { name, value }) => {
setInputs((inputs) => ({ ...inputs, [name]: value }));
};
-
+ const handleCancel = () => {
+ navigate("/token");
+ }
const setExpiredTime = (month, day, hour, minute) => {
let now = new Date();
let timestamp = now.getTime() / 1000;
@@ -150,8 +152,9 @@ const EditToken = () => {
{
setUnlimitedQuota();
- }}>{unlimited_quota ? '取消无限额度' : '设置为无限额度'}
- 提交
+ }}>{unlimited_quota ? '取消无限额度' : '设为无限额度'}
+ 提交
+ 取消
>
diff --git a/web/src/pages/User/EditUser.js b/web/src/pages/User/EditUser.js
index b1c77945..e8f96027 100644
--- a/web/src/pages/User/EditUser.js
+++ b/web/src/pages/User/EditUser.js
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { Button, Form, Header, Segment } from 'semantic-ui-react';
-import { useParams } from 'react-router-dom';
+import { useParams, useNavigate } from 'react-router-dom';
import { API, showError, showSuccess } from '../../helpers';
import { renderQuota, renderQuotaWithPrompt } from '../../helpers/render';
@@ -36,7 +36,10 @@ const EditUser = () => {
showError(error.message);
}
};
-
+ const navigate = useNavigate();
+ const handleCancel = () => {
+ navigate("/setting");
+ }
const loadUser = async () => {
let res = undefined;
if (userId) {
@@ -176,6 +179,7 @@ const EditUser = () => {
readOnly
/>
+ 取消
提交
From 7422b0d051992af08118fde81bf2257da01cc5b3 Mon Sep 17 00:00:00 2001
From: JustSong
Date: Sun, 6 Aug 2023 22:07:31 +0800
Subject: [PATCH 08/11] chore: update prompt
---
web/src/pages/Channel/EditChannel.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/web/src/pages/Channel/EditChannel.js b/web/src/pages/Channel/EditChannel.js
index 6974315e..4cfec018 100644
--- a/web/src/pages/Channel/EditChannel.js
+++ b/web/src/pages/Channel/EditChannel.js
@@ -371,9 +371,9 @@ const EditChannel = () => {
inputs.type !== 3 && inputs.type !== 8 && (
Date: Sun, 6 Aug 2023 22:09:05 +0800
Subject: [PATCH 09/11] chore: update i18n
---
i18n/en.json | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/i18n/en.json b/i18n/en.json
index 8dac629e..f53aad4c 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -516,5 +516,7 @@
"请输入渠道对应的鉴权密钥": "Please enter the authentication key corresponding to the channel",
"注意,": "Note that, ",
",图片演示。": "related image demo.",
- "令牌创建成功,请在列表页面点击复制获取令牌!": "Token created successfully, please click copy on the list page to get the token!"
+ "令牌创建成功,请在列表页面点击复制获取令牌!": "Token created successfully, please click copy on the list page to get the token!",
+ "代理": "Proxy",
+ "此项可选,用于通过代理站来进行 API 调用,请输入代理站地址,格式为:https://domain.com": "This is optional, used to make API calls through the proxy site, please enter the proxy site address, the format is: https://domain.com"
}
From 463b0b3c5176b2c468847cfee7a1dd0a6c4bfe03 Mon Sep 17 00:00:00 2001
From: JustSong
Date: Sun, 6 Aug 2023 22:28:07 +0800
Subject: [PATCH 10/11] fix: no need to check turnstile when process deletion
---
router/api-router.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/router/api-router.go b/router/api-router.go
index 383133fa..cc330d7e 100644
--- a/router/api-router.go
+++ b/router/api-router.go
@@ -36,7 +36,7 @@ func SetApiRouter(router *gin.Engine) {
{
selfRoute.GET("/self", controller.GetSelf)
selfRoute.PUT("/self", controller.UpdateSelf)
- selfRoute.DELETE("/self", middleware.TurnstileCheck(), controller.DeleteSelf)
+ selfRoute.DELETE("/self", controller.DeleteSelf)
selfRoute.GET("/token", controller.GenerateAccessToken)
selfRoute.GET("/aff", controller.GetAffCode)
selfRoute.POST("/topup", controller.TopUp)
From 9c436921d13181fae8abe7ba70df664f75e7d8a0 Mon Sep 17 00:00:00 2001
From: JustSong
Date: Sun, 6 Aug 2023 23:18:05 +0800
Subject: [PATCH 11/11] docs: update README
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index fcabd2c5..ad90bb15 100644
--- a/README.md
+++ b/README.md
@@ -104,7 +104,7 @@ _✨ 通过标准的 OpenAI API 格式访问所有的大模型,开箱即用
如果上面的镜像无法拉取,可以尝试使用 GitHub 的 Docker 镜像,将上面的 `justsong/one-api` 替换为 `ghcr.io/songquanpeng/one-api` 即可。
-如果你的并发量较大,推荐设置 `SQL_DSN`,详见下面[环境变量](#环境变量)一节。
+如果你的并发量较大,**务必**设置 `SQL_DSN`,详见下面[环境变量](#环境变量)一节。
更新命令:`docker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower -cR`
@@ -213,7 +213,7 @@ docker run --name chatgpt-web -d -p 3002:3002 -e OPENAI_API_BASE_URL=https://ope
> Sealos 的服务器在国外,不需要额外处理网络问题,支持高并发 & 动态伸缩。
-点击以下按钮一键部署:
+点击以下按钮一键部署(部署后访问出现 404 请等待 3~5 分钟):
[](https://cloud.sealos.io/?openapp=system-fastdeploy?templateName=one-api)