Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
53ff1547
authored
Oct 12, 2024
by
1808837298@qq.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 弃用旧的聊天配置
parent
917aa6c0
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
304 additions
and
124 deletions
+304
-124
constant/chat.go
+34
-0
controller/misc.go
+1
-0
model/option.go
+3
-0
web/src/components/OperationSetting.js
+6
-0
web/src/components/TokensTable.js
+105
-122
web/src/helpers/data.js
+1
-0
web/src/pages/Setting/Operation/SettingsChats.js
+148
-0
web/src/pages/Setting/Operation/SettingsGeneral.js
+5
-1
web/src/pages/Token/EditToken.js
+1
-1
No files found.
constant/chat.go
0 → 100644
View file @
53ff1547
package
constant
import
(
"encoding/json"
"one-api/common"
)
var
Chats
=
[]
map
[
string
]
string
{
{
"ChatGPT Next Web 官方示例"
:
"https://app.nextchat.dev/#/?settings={
\"
key
\"
:
\"
{key}
\"
,
\"
url
\"
:
\"
{address}
\"
}"
,
},
{
"Lobe Chat 官方示例"
:
"https://chat-preview.lobehub.com/?settings={
\"
keyVaults
\"
:{
\"
openai
\"
:{
\"
apiKey
\"
:
\"
{key}
\"
,
\"
baseURL
\"
:
\"
{address}/v1
\"
}}}"
,
},
{
"AMA 问天"
:
"ama://set-api-key?server={address}&key={key}"
,
},
{
"OpenCat"
:
"opencat://team/join?domain={address}&token={key}"
,
},
}
func
UpdateChatsByJsonString
(
jsonString
string
)
error
{
return
json
.
Unmarshal
([]
byte
(
jsonString
),
&
Chats
)
}
func
Chats2JsonString
()
string
{
jsonBytes
,
err
:=
json
.
Marshal
(
Chats
)
if
err
!=
nil
{
common
.
SysError
(
"error marshalling chats: "
+
err
.
Error
())
return
"[]"
}
return
string
(
jsonBytes
)
}
controller/misc.go
View file @
53ff1547
...
...
@@ -63,6 +63,7 @@ func GetStatus(c *gin.Context) {
"default_collapse_sidebar"
:
common
.
DefaultCollapseSidebar
,
"enable_online_topup"
:
constant
.
PayAddress
!=
""
&&
constant
.
EpayId
!=
""
&&
constant
.
EpayKey
!=
""
,
"mj_notify_enabled"
:
constant
.
MjNotifyEnabled
,
"chats"
:
constant
.
Chats
,
},
})
return
...
...
model/option.go
View file @
53ff1547
...
...
@@ -69,6 +69,7 @@ func InitOptionMap() {
common
.
OptionMap
[
"Price"
]
=
strconv
.
FormatFloat
(
constant
.
Price
,
'f'
,
-
1
,
64
)
common
.
OptionMap
[
"MinTopUp"
]
=
strconv
.
Itoa
(
constant
.
MinTopUp
)
common
.
OptionMap
[
"TopupGroupRatio"
]
=
common
.
TopupGroupRatio2JSONString
()
common
.
OptionMap
[
"Chats"
]
=
constant
.
Chats2JsonString
()
common
.
OptionMap
[
"GitHubClientId"
]
=
""
common
.
OptionMap
[
"GitHubClientSecret"
]
=
""
common
.
OptionMap
[
"TelegramBotToken"
]
=
""
...
...
@@ -248,6 +249,8 @@ func updateOptionMap(key string, value string) (err error) {
constant
.
WorkerValidKey
=
value
case
"PayAddress"
:
constant
.
PayAddress
=
value
case
"Chats"
:
err
=
constant
.
UpdateChatsByJsonString
(
value
)
case
"CustomCallbackAddress"
:
constant
.
CustomCallbackAddress
=
value
case
"EpayId"
:
...
...
web/src/components/OperationSetting.js
View file @
53ff1547
...
...
@@ -10,6 +10,7 @@ import SettingsCreditLimit from '../pages/Setting/Operation/SettingsCreditLimit.
import
SettingsMagnification
from
'../pages/Setting/Operation/SettingsMagnification.js'
;
import
{
API
,
showError
,
showSuccess
}
from
'../helpers'
;
import
SettingsChats
from
'../pages/Setting/Operation/SettingsChats.js'
;
const
OperationSetting
=
()
=>
{
let
[
inputs
,
setInputs
]
=
useState
({
...
...
@@ -50,6 +51,7 @@ const OperationSetting = () => {
DataExportInterval
:
5
,
DefaultCollapseSidebar
:
false
,
// 默认折叠侧边栏
RetryTimes
:
0
,
Chats
:
"[]"
,
});
let
[
loading
,
setLoading
]
=
useState
(
false
);
...
...
@@ -131,6 +133,10 @@ const OperationSetting = () => {
<
Card
style
=
{{
marginTop
:
'10px'
}}
>
<
SettingsCreditLimit
options
=
{
inputs
}
refresh
=
{
onRefresh
}
/
>
<
/Card
>
{
/* 聊天设置 */
}
<
Card
style
=
{{
marginTop
:
'10px'
}}
>
<
SettingsChats
options
=
{
inputs
}
refresh
=
{
onRefresh
}
/
>
<
/Card
>
{
/* 倍率设置 */
}
<
Card
style
=
{{
marginTop
:
'10px'
}}
>
<
SettingsMagnification
options
=
{
inputs
}
refresh
=
{
onRefresh
}
/
>
...
...
web/src/components/TokensTable.js
View file @
53ff1547
...
...
@@ -24,17 +24,6 @@ import {
import
{
IconTreeTriangleDown
}
from
'@douyinfe/semi-icons'
;
import
EditToken
from
'../pages/Token/EditToken'
;
const
COPY_OPTIONS
=
[
{
key
:
'next'
,
text
:
'ChatGPT Next Web'
,
value
:
'next'
},
{
key
:
'ama'
,
text
:
'ChatGPT Web & Midjourney'
,
value
:
'ama'
},
{
key
:
'opencat'
,
text
:
'OpenCat'
,
value
:
'opencat'
},
];
const
OPEN_LINK_OPTIONS
=
[
{
key
:
'ama'
,
text
:
'ChatGPT Web & Midjourney'
,
value
:
'ama'
},
{
key
:
'opencat'
,
text
:
'OpenCat'
,
value
:
'opencat'
},
];
function
renderTimestamp
(
timestamp
)
{
return
<>
{
timestamp2string
(
timestamp
)}
<
/>
;
}
...
...
@@ -87,27 +76,6 @@ function renderStatus(status, model_limits_enabled = false) {
}
const
TokensTable
=
()
=>
{
const
link_menu
=
[
{
node
:
'item'
,
key
:
'next'
,
name
:
'ChatGPT Next Web'
,
onClick
:
()
=>
{
onOpenLink
(
'next'
);
},
},
{
node
:
'item'
,
key
:
'ama'
,
name
:
'AMA 问天'
,
value
:
'ama'
},
{
node
:
'item'
,
key
:
'next-mj'
,
name
:
'ChatGPT Web & Midjourney'
,
value
:
'next-mj'
,
onClick
:
()
=>
{
onOpenLink
(
'next-mj'
);
},
},
{
node
:
'item'
,
key
:
'opencat'
,
name
:
'OpenCat'
,
value
:
'opencat'
},
];
const
columns
=
[
{
...
...
@@ -174,7 +142,67 @@ const TokensTable = () => {
{
title
:
''
,
dataIndex
:
'operate'
,
render
:
(
text
,
record
,
index
)
=>
(
render
:
(
text
,
record
,
index
)
=>
{
let
chats
=
localStorage
.
getItem
(
'chats'
);
let
chatsArray
=
[]
let
chatLink
=
localStorage
.
getItem
(
'chat_link'
);
let
mjLink
=
localStorage
.
getItem
(
'chat_link2'
);
let
shouldUseCustom
=
true
;
if
(
chatLink
)
{
shouldUseCustom
=
false
;
chatLink
+=
`/#/?settings={"key":"{key}","url":"{address}"}`
;
chatsArray
.
push
({
node
:
'item'
,
key
:
'default'
,
name
:
'ChatGPT Next Web'
,
onClick
:
()
=>
{
onOpenLink
(
'default'
,
chatLink
,
record
);
},
});
}
if
(
mjLink
)
{
shouldUseCustom
=
false
;
mjLink
+=
`/#/?settings={"key":"{key}","url":"{address}"}`
;
chatsArray
.
push
({
node
:
'item'
,
key
:
'mj'
,
name
:
'ChatGPT Next Midjourney'
,
onClick
:
()
=>
{
onOpenLink
(
'mj'
,
mjLink
,
record
);
},
});
}
if
(
shouldUseCustom
)
{
try
{
// console.log(chats);
chats
=
JSON
.
parse
(
chats
);
// check chats is array
if
(
Array
.
isArray
(
chats
))
{
for
(
let
i
=
0
;
i
<
chats
.
length
;
i
++
)
{
let
chat
=
{}
chat
.
node
=
'item'
;
// c is a map
// chat.key = chats[i].name;
// console.log(chats[i])
for
(
let
key
in
chats
[
i
])
{
if
(
chats
[
i
].
hasOwnProperty
(
key
))
{
chat
.
key
=
i
;
chat
.
name
=
key
;
chat
.
onClick
=
()
=>
{
onOpenLink
(
key
,
chats
[
i
][
key
],
record
);
}
}
}
chatsArray
.
push
(
chat
);
}
}
}
catch
(
e
)
{
console
.
log
(
e
);
showError
(
'聊天链接配置错误,请联系管理员'
);
}
}
return
(
<
div
>
<
Popover
content
=
{
'sk-'
+
record
.
key
}
...
...
@@ -203,7 +231,11 @@ const TokensTable = () => {
theme
=
'light'
style
=
{{
color
:
'rgba(var(--semi-teal-7), 1)'
}}
onClick
=
{()
=>
{
onOpenLink
(
'next'
,
record
.
key
);
if
(
chatsArray
.
length
===
0
)
{
showError
(
'请联系管理员配置聊天链接'
);
}
else
{
onOpenLink
(
'default'
,
chats
[
0
][
Object
.
keys
(
chats
[
0
])[
0
]],
record
);
}
}}
>
聊天
...
...
@@ -211,50 +243,7 @@ const TokensTable = () => {
<
Dropdown
trigger
=
'click'
position
=
'bottomRight'
menu
=
{[
{
node
:
'item'
,
key
:
'next'
,
disabled
:
!
localStorage
.
getItem
(
'chat_link'
),
name
:
'ChatGPT Next Web'
,
onClick
:
()
=>
{
onOpenLink
(
'next'
,
record
.
key
);
},
},
{
node
:
'item'
,
key
:
'next-mj'
,
disabled
:
!
localStorage
.
getItem
(
'chat_link2'
),
name
:
'ChatGPT Web & Midjourney'
,
onClick
:
()
=>
{
onOpenLink
(
'next-mj'
,
record
.
key
);
},
},
// {
// node: 'item',
// key: 'lobe',
// name: 'Lobe Chat',
// onClick: () => {
// onOpenLink('lobe', record.key);
// },
// },
{
node
:
'item'
,
key
:
'ama'
,
name
:
'AMA 问天(BotGem)'
,
onClick
:
()
=>
{
onOpenLink
(
'ama'
,
record
.
key
);
},
},
{
node
:
'item'
,
key
:
'opencat'
,
name
:
'OpenCat'
,
onClick
:
()
=>
{
onOpenLink
(
'opencat'
,
record
.
key
);
},
},
]}
menu
=
{
chatsArray
}
>
<
Button
style
=
{{
...
...
@@ -316,7 +305,8 @@ const TokensTable = () => {
编辑
<
/Button
>
<
/div
>
),
);
},
},
];
...
...
@@ -330,8 +320,7 @@ const TokensTable = () => {
const
[
searchKeyword
,
setSearchKeyword
]
=
useState
(
''
);
const
[
searchToken
,
setSearchToken
]
=
useState
(
''
);
const
[
searching
,
setSearching
]
=
useState
(
false
);
const
[
showTopUpModal
,
setShowTopUpModal
]
=
useState
(
false
);
const
[
targetTokenIdx
,
setTargetTokenIdx
]
=
useState
(
0
);
const
[
chats
,
setChats
]
=
useState
([]);
const
[
editingToken
,
setEditingToken
]
=
useState
({
id
:
undefined
,
});
...
...
@@ -376,16 +365,6 @@ const TokensTable = () => {
setLoading
(
false
);
};
const
onPaginationChange
=
(
e
,
{
activePage
})
=>
{
(
async
()
=>
{
if
(
activePage
===
Math
.
ceil
(
tokens
.
length
/
pageSize
)
+
1
)
{
// In this case we have to load more data and then append them.
await
loadTokens
(
activePage
-
1
);
}
setActivePage
(
activePage
);
})();
};
const
refresh
=
async
()
=>
{
await
loadTokens
(
activePage
-
1
);
};
...
...
@@ -402,7 +381,8 @@ const TokensTable = () => {
}
};
const
onOpenLink
=
async
(
type
,
key
)
=>
{
const
onOpenLink
=
async
(
type
,
url
,
record
)
=>
{
// console.log(type, url, key);
let
status
=
localStorage
.
getItem
(
'status'
);
let
serverAddress
=
''
;
if
(
status
)
{
...
...
@@ -413,36 +393,39 @@ const TokensTable = () => {
serverAddress
=
window
.
location
.
origin
;
}
let
encodedServerAddress
=
encodeURIComponent
(
serverAddress
);
const
chatLink
=
localStorage
.
getItem
(
'chat_link'
);
const
mjLink
=
localStorage
.
getItem
(
'chat_link2'
);
let
defaultUrl
;
if
(
chatLink
)
{
defaultUrl
=
chatLink
+
`/#/?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
;
case
'lobe'
:
url
=
`https://chat-preview.lobehub.com/?settings={"keyVaults":{"openai":{"apiKey":"sk-
${
key
}
","baseURL":"
${
encodedServerAddress
}
/v1"}}}`
;
break
;
case
'next-mj'
:
url
=
mjLink
+
`/#/?settings={"key":"sk-
${
key
}
","url":"
${
serverAddress
}
"}`
;
break
;
default
:
if
(
!
chatLink
)
{
showError
(
'管理员未设置聊天链接'
);
return
;
}
url
=
defaultUrl
;
}
url
=
url
.
replace
(
'{address}'
,
encodedServerAddress
);
url
=
url
.
replace
(
'{key}'
,
'sk-'
+
record
.
key
);
// console.log(url);
// const chatLink = localStorage.getItem('chat_link');
// const mjLink = localStorage.getItem('chat_link2');
// let defaultUrl;
//
// if (chatLink) {
// defaultUrl =
// chatLink + `/#/?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;
// case 'lobe':
// url = `https://chat-preview.lobehub.com/?settings={"keyVaults":{"openai":{"apiKey":"sk-${key}","baseURL":"${encodedServerAddress}/v1"}}}`;
// break;
// case 'next-mj':
// url =
// mjLink + `/#/?settings={"key":"sk-${key}","url":"${serverAddress}"}`;
// break;
// default:
// if (!chatLink) {
// showError('管理员未设置聊天链接');
// return;
// }
// url = defaultUrl;
// }
window
.
open
(
url
,
'_blank'
);
};
...
...
web/src/helpers/data.js
View file @
53ff1547
...
...
@@ -8,6 +8,7 @@ export function setStatusData(data) {
localStorage
.
setItem
(
'enable_drawing'
,
data
.
enable_drawing
);
localStorage
.
setItem
(
'enable_task'
,
data
.
enable_task
);
localStorage
.
setItem
(
'enable_data_export'
,
data
.
enable_data_export
);
localStorage
.
setItem
(
'chats'
,
JSON
.
stringify
(
data
.
chats
));
localStorage
.
setItem
(
'data_export_default_time'
,
data
.
data_export_default_time
,
...
...
web/src/pages/Setting/Operation/SettingsChats.js
0 → 100644
View file @
53ff1547
import
React
,
{
useEffect
,
useState
,
useRef
}
from
'react'
;
import
{
Banner
,
Button
,
Col
,
Form
,
Popconfirm
,
Row
,
Space
,
Spin
}
from
'@douyinfe/semi-ui'
;
import
{
compareObjects
,
API
,
showError
,
showSuccess
,
showWarning
,
verifyJSON
,
verifyJSONPromise
}
from
'../../../helpers'
;
export
default
function
SettingsChats
(
props
)
{
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
inputs
,
setInputs
]
=
useState
({
Chats
:
"[]"
,
});
const
refForm
=
useRef
();
const
[
inputsRow
,
setInputsRow
]
=
useState
(
inputs
);
async
function
onSubmit
()
{
try
{
console
.
log
(
'Starting validation...'
);
await
refForm
.
current
.
validate
().
then
(()
=>
{
console
.
log
(
'Validation passed'
);
const
updateArray
=
compareObjects
(
inputs
,
inputsRow
);
if
(
!
updateArray
.
length
)
return
showWarning
(
'你似乎并没有修改什么'
);
const
requestQueue
=
updateArray
.
map
((
item
)
=>
{
let
value
=
''
;
if
(
typeof
inputs
[
item
.
key
]
===
'boolean'
)
{
value
=
String
(
inputs
[
item
.
key
]);
}
else
{
value
=
inputs
[
item
.
key
];
}
return
API
.
put
(
'/api/option/'
,
{
key
:
item
.
key
,
value
});
});
setLoading
(
true
);
Promise
.
all
(
requestQueue
)
.
then
((
res
)
=>
{
if
(
requestQueue
.
length
===
1
)
{
if
(
res
.
includes
(
undefined
))
return
;
}
else
if
(
requestQueue
.
length
>
1
)
{
if
(
res
.
includes
(
undefined
))
return
showError
(
'部分保存失败,请重试'
);
}
showSuccess
(
'保存成功'
);
props
.
refresh
();
})
.
catch
(()
=>
{
showError
(
'保存失败,请重试'
);
})
.
finally
(()
=>
{
setLoading
(
false
);
});
}).
catch
((
error
)
=>
{
console
.
error
(
'Validation failed:'
,
error
);
showError
(
'请检查输入'
);
});
}
catch
(
error
)
{
showError
(
'请检查输入'
);
console
.
error
(
error
);
}
}
async
function
resetModelRatio
()
{
try
{
let
res
=
await
API
.
post
(
`/api/option/rest_model_ratio`
);
// return {success, message}
if
(
res
.
data
.
success
)
{
showSuccess
(
res
.
data
.
message
);
props
.
refresh
();
}
else
{
showError
(
res
.
data
.
message
);
}
}
catch
(
error
)
{
showError
(
error
);
}
}
useEffect
(()
=>
{
const
currentInputs
=
{};
for
(
let
key
in
props
.
options
)
{
if
(
Object
.
keys
(
inputs
).
includes
(
key
))
{
if
(
key
===
'Chats'
)
{
const
obj
=
JSON
.
parse
(
props
.
options
[
key
]);
currentInputs
[
key
]
=
JSON
.
stringify
(
obj
,
null
,
2
);
}
else
{
currentInputs
[
key
]
=
props
.
options
[
key
];
}
}
}
setInputs
(
currentInputs
);
setInputsRow
(
structuredClone
(
currentInputs
));
refForm
.
current
.
setValues
(
currentInputs
);
},
[
props
.
options
]);
return
(
<
Spin
spinning
=
{
loading
}
>
<
Form
values
=
{
inputs
}
getFormApi
=
{(
formAPI
)
=>
(
refForm
.
current
=
formAPI
)}
style
=
{{
marginBottom
:
15
}}
>
<
Form
.
Section
text
=
{
'令牌聊天设置'
}
>
<
Banner
type
=
'warning'
description
=
{
'必须将上方聊天链接全部设置为空,才能使用下方聊天设置功能'
}
/
>
<
Banner
type
=
'info'
description
=
{
'链接中的{key}将自动替换为sk-xxxx,{address}将自动替换为系统设置的服务器地址,末尾不带/和/v1'
}
/
>
<
Form
.
TextArea
label
=
{
'聊天配置'
}
extraText
=
{
''
}
placeholder
=
{
'为一个 JSON 文本'
}
field
=
{
'Chats'
}
autosize
=
{{
minRows
:
6
,
maxRows
:
12
}}
trigger
=
'blur'
stopValidateWithError
rules
=
{[
{
validator
:
(
rule
,
value
)
=>
{
return
verifyJSON
(
value
);
},
message
:
'不是合法的 JSON 字符串'
}
]}
onChange
=
{(
value
)
=>
setInputs
({
...
inputs
,
Chats
:
value
})
}
/
>
<
/Form.Section
>
<
/Form
>
<
Space
>
<
Button
onClick
=
{
onSubmit
}
>
保存聊天设置
<
/Button
>
<
/Space
>
<
/Spin
>
);
}
web/src/pages/Setting/Operation/SettingsGeneral.js
View file @
53ff1547
import
React
,
{
useEffect
,
useState
,
useRef
}
from
'react'
;
import
{
Button
,
Col
,
Form
,
Row
,
Spin
}
from
'@douyinfe/semi-ui'
;
import
{
B
anner
,
B
utton
,
Col
,
Form
,
Row
,
Spin
}
from
'@douyinfe/semi-ui'
;
import
{
compareObjects
,
API
,
...
...
@@ -74,6 +74,10 @@ export default function GeneralSettings(props) {
return
(
<>
<
Spin
spinning
=
{
loading
}
>
<
Banner
type
=
'warning'
description
=
{
'聊天链接功能已经弃用,请使用下方聊天设置功能'
}
/
>
<
Form
values
=
{
inputs
}
getFormApi
=
{(
formAPI
)
=>
(
refForm
.
current
=
formAPI
)}
...
...
web/src/pages/Token/EditToken.js
View file @
53ff1547
...
...
@@ -49,7 +49,7 @@ const EditToken = (props) => {
group
}
=
inputs
;
// const [visible, setVisible] = useState(false);
const
[
models
,
setModels
]
=
useState
(
{}
);
const
[
models
,
setModels
]
=
useState
(
[]
);
const
[
groups
,
setGroups
]
=
useState
([]);
const
navigate
=
useNavigate
();
const
handleInputChange
=
(
name
,
value
)
=>
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment