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
1bbabda0
authored
Sep 03, 2025
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(monitor_setting): implement automatic channel testing configuration
parent
22b724ca
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
107 additions
and
103 deletions
+107
-103
controller/channel-test.go
+23
-11
main.go
+3
-7
relay/common/relay_utils.go
+2
-4
service/file_decoder.go
+3
-0
service/token_counter.go
+3
-77
setting/operation_setting/monitor_setting.go
+34
-0
web/src/components/settings/OperationSetting.jsx
+3
-4
web/src/pages/Setting/Operation/SettingsMonitoring.jsx
+36
-0
No files found.
controller/channel-test.go
View file @
1bbabda0
...
...
@@ -20,6 +20,7 @@ import (
relayconstant
"one-api/relay/constant"
"one-api/relay/helper"
"one-api/service"
"one-api/setting/operation_setting"
"one-api/types"
"strconv"
"strings"
...
...
@@ -477,15 +478,26 @@ func TestAllChannels(c *gin.Context) {
return
}
func
AutomaticallyTestChannels
(
frequency
int
)
{
if
frequency
<=
0
{
common
.
SysLog
(
"CHANNEL_TEST_FREQUENCY is not set or invalid, skipping automatic channel test"
)
return
}
for
{
time
.
Sleep
(
time
.
Duration
(
frequency
)
*
time
.
Minute
)
common
.
SysLog
(
"testing all channels"
)
_
=
testAllChannels
(
false
)
common
.
SysLog
(
"channel test finished"
)
}
var
autoTestChannelsOnce
sync
.
Once
func
AutomaticallyTestChannels
()
{
autoTestChannelsOnce
.
Do
(
func
()
{
for
{
if
!
operation_setting
.
GetMonitorSetting
()
.
AutoTestChannelEnabled
{
time
.
Sleep
(
10
*
time
.
Minute
)
continue
}
frequency
:=
operation_setting
.
GetMonitorSetting
()
.
AutoTestChannelMinutes
common
.
SysLog
(
fmt
.
Sprintf
(
"automatically test channels with interval %d minutes"
,
frequency
))
for
{
time
.
Sleep
(
time
.
Duration
(
frequency
)
*
time
.
Minute
)
common
.
SysLog
(
"automatically testing all channels"
)
_
=
testAllChannels
(
false
)
common
.
SysLog
(
"automatically channel test finished"
)
if
!
operation_setting
.
GetMonitorSetting
()
.
AutoTestChannelEnabled
{
break
}
}
}
})
}
main.go
View file @
1bbabda0
...
...
@@ -94,13 +94,9 @@ func main() {
}
go
controller
.
AutomaticallyUpdateChannels
(
frequency
)
}
if
os
.
Getenv
(
"CHANNEL_TEST_FREQUENCY"
)
!=
""
{
frequency
,
err
:=
strconv
.
Atoi
(
os
.
Getenv
(
"CHANNEL_TEST_FREQUENCY"
))
if
err
!=
nil
{
common
.
FatalLog
(
"failed to parse CHANNEL_TEST_FREQUENCY: "
+
err
.
Error
())
}
go
controller
.
AutomaticallyTestChannels
(
frequency
)
}
go
controller
.
AutomaticallyTestChannels
()
if
common
.
IsMasterNode
&&
constant
.
UpdateTask
{
gopool
.
Go
(
func
()
{
controller
.
UpdateMidjourneyTaskBulk
()
...
...
relay/common/relay_utils.go
View file @
1bbabda0
...
...
@@ -2,12 +2,10 @@ package common
import
(
"fmt"
"github.com/gin-gonic/gin"
_
"image/gif"
_
"image/jpeg"
_
"image/png"
"one-api/constant"
"strings"
"github.com/gin-gonic/gin"
)
func
GetFullRequestURL
(
baseURL
string
,
requestURL
string
,
channelType
int
)
string
{
...
...
service/file_decoder.go
View file @
1bbabda0
...
...
@@ -5,6 +5,9 @@ import (
"encoding/base64"
"fmt"
"image"
_
"image/gif"
_
"image/jpeg"
_
"image/png"
"io"
"net/http"
"one-api/common"
...
...
service/token_counter.go
View file @
1bbabda0
...
...
@@ -5,6 +5,9 @@ import (
"errors"
"fmt"
"image"
_
"image/gif"
_
"image/jpeg"
_
"image/png"
"log"
"math"
"one-api/common"
...
...
@@ -357,33 +360,6 @@ func CountRequestToken(c *gin.Context, meta *types.TokenCountMeta, info *relayco
return
tkm
,
nil
}
//func CountTokenChatRequest(info *relaycommon.RelayInfo, request dto.GeneralOpenAIRequest) (int, error) {
// tkm := 0
// msgTokens, err := CountTokenMessages(info, request.Messages, request.Model, request.Stream)
// if err != nil {
// return 0, err
// }
// tkm += msgTokens
// if request.Tools != nil {
// openaiTools := request.Tools
// countStr := ""
// for _, tool := range openaiTools {
// countStr = tool.Function.Name
// if tool.Function.Description != "" {
// countStr += tool.Function.Description
// }
// if tool.Function.Parameters != nil {
// countStr += fmt.Sprintf("%v", tool.Function.Parameters)
// }
// }
// toolTokens := CountTokenInput(countStr, request.Model)
// tkm += 8
// tkm += toolTokens
// }
//
// return tkm, nil
//}
func
CountTokenClaudeRequest
(
request
dto
.
ClaudeRequest
,
model
string
)
(
int
,
error
)
{
tkm
:=
0
...
...
@@ -543,56 +519,6 @@ func CountTokenRealtime(info *relaycommon.RelayInfo, request dto.RealtimeEvent,
return
textToken
,
audioToken
,
nil
}
//func CountTokenMessages(info *relaycommon.RelayInfo, messages []dto.Message, model string, stream bool) (int, error) {
// //recover when panic
// tokenEncoder := getTokenEncoder(model)
// // Reference:
// // https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb
// // https://github.com/pkoukk/tiktoken-go/issues/6
// //
// // Every message follows <|start|>{role/name}\n{content}<|end|>\n
// var tokensPerMessage int
// var tokensPerName int
//
// tokensPerMessage = 3
// tokensPerName = 1
//
// tokenNum := 0
// for _, message := range messages {
// tokenNum += tokensPerMessage
// tokenNum += getTokenNum(tokenEncoder, message.Role)
// if message.Content != nil {
// if message.Name != nil {
// tokenNum += tokensPerName
// tokenNum += getTokenNum(tokenEncoder, *message.Name)
// }
// arrayContent := message.ParseContent()
// for _, m := range arrayContent {
// if m.Type == dto.ContentTypeImageURL {
// imageUrl := m.GetImageMedia()
// imageTokenNum, err := getImageToken(info, imageUrl, model, stream)
// if err != nil {
// return 0, err
// }
// tokenNum += imageTokenNum
// log.Printf("image token num: %d", imageTokenNum)
// } else if m.Type == dto.ContentTypeInputAudio {
// // TODO: 音频token数量计算
// tokenNum += 100
// } else if m.Type == dto.ContentTypeFile {
// tokenNum += 5000
// } else if m.Type == dto.ContentTypeVideoUrl {
// tokenNum += 5000
// } else {
// tokenNum += getTokenNum(tokenEncoder, m.Text)
// }
// }
// }
// }
// tokenNum += 3 // Every reply is primed with <|start|>assistant<|message|>
// return tokenNum, nil
//}
func
CountTokenInput
(
input
any
,
model
string
)
int
{
switch
v
:=
input
.
(
type
)
{
case
string
:
...
...
setting/operation_setting/monitor_setting.go
0 → 100644
View file @
1bbabda0
package
operation_setting
import
(
"one-api/setting/config"
"os"
"strconv"
)
type
MonitorSetting
struct
{
AutoTestChannelEnabled
bool
`json:"auto_test_channel_enabled"`
AutoTestChannelMinutes
int
`json:"auto_test_channel_minutes"`
}
// 默认配置
var
monitorSetting
=
MonitorSetting
{
AutoTestChannelEnabled
:
false
,
AutoTestChannelMinutes
:
10
,
}
func
init
()
{
// 注册到全局配置管理器
config
.
GlobalConfig
.
Register
(
"monitor_setting"
,
&
monitorSetting
)
}
func
GetMonitorSetting
()
*
MonitorSetting
{
if
os
.
Getenv
(
"CHANNEL_TEST_FREQUENCY"
)
!=
""
{
frequency
,
err
:=
strconv
.
Atoi
(
os
.
Getenv
(
"CHANNEL_TEST_FREQUENCY"
))
if
err
==
nil
&&
frequency
>
0
{
monitorSetting
.
AutoTestChannelEnabled
=
true
monitorSetting
.
AutoTestChannelMinutes
=
frequency
}
}
return
&
monitorSetting
}
web/src/components/settings/OperationSetting.jsx
View file @
1bbabda0
...
...
@@ -68,6 +68,8 @@ const OperationSetting = () => {
AutomaticDisableChannelEnabled
:
false
,
AutomaticEnableChannelEnabled
:
false
,
AutomaticDisableKeywords
:
''
,
'monitor_setting.auto_test_channel_enabled'
:
false
,
'monitor_setting.auto_test_channel_minutes'
:
10
,
});
let
[
loading
,
setLoading
]
=
useState
(
false
);
...
...
@@ -78,10 +80,7 @@ const OperationSetting = () => {
if
(
success
)
{
let
newInputs
=
{};
data
.
forEach
((
item
)
=>
{
if
(
item
.
key
.
endsWith
(
'Enabled'
)
||
[
'DefaultCollapseSidebar'
].
includes
(
item
.
key
)
)
{
if
(
typeof
inputs
[
item
.
key
]
===
'boolean'
)
{
newInputs
[
item
.
key
]
=
toBoolean
(
item
.
value
);
}
else
{
newInputs
[
item
.
key
]
=
item
.
value
;
...
...
web/src/pages/Setting/Operation/SettingsMonitoring.jsx
View file @
1bbabda0
...
...
@@ -38,6 +38,8 @@ export default function SettingsMonitoring(props) {
AutomaticDisableChannelEnabled
:
false
,
AutomaticEnableChannelEnabled
:
false
,
AutomaticDisableKeywords
:
''
,
'monitor_setting.auto_test_channel_enabled'
:
false
,
'monitor_setting.auto_test_channel_minutes'
:
10
,
});
const
refForm
=
useRef
();
const
[
inputsRow
,
setInputsRow
]
=
useState
(
inputs
);
...
...
@@ -100,6 +102,40 @@ export default function SettingsMonitoring(props) {
<
Form
.
Section
text=
{
t
(
'监控设置'
)
}
>
<
Row
gutter=
{
16
}
>
<
Col
xs=
{
24
}
sm=
{
12
}
md=
{
8
}
lg=
{
8
}
xl=
{
8
}
>
<
Form
.
Switch
field=
{
'monitor_setting.auto_test_channel_enabled'
}
label=
{
t
(
'定时测试所有通道'
)
}
size=
'default'
checkedText=
'|'
uncheckedText=
'〇'
onChange=
{
(
value
)
=>
setInputs
({
...
inputs
,
'monitor_setting.auto_test_channel_enabled'
:
value
,
})
}
/>
</
Col
>
<
Col
xs=
{
24
}
sm=
{
12
}
md=
{
8
}
lg=
{
8
}
xl=
{
8
}
>
<
Form
.
InputNumber
label=
{
t
(
'自动测试所有通道间隔时间'
)
}
step=
{
1
}
min=
{
1
}
suffix=
{
t
(
'分钟'
)
}
extraText=
{
t
(
'每隔多少分钟测试一次所有通道'
)
}
placeholder=
{
''
}
field=
{
'monitor_setting.auto_test_channel_minutes'
}
onChange=
{
(
value
)
=>
setInputs
({
...
inputs
,
'monitor_setting.auto_test_channel_minutes'
:
parseInt
(
value
),
})
}
/>
</
Col
>
</
Row
>
<
Row
gutter=
{
16
}
>
<
Col
xs=
{
24
}
sm=
{
12
}
md=
{
8
}
lg=
{
8
}
xl=
{
8
}
>
<
Form
.
InputNumber
label=
{
t
(
'测试所有渠道的最长响应时间'
)
}
step=
{
1
}
...
...
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