mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-19 11:58:38 +00:00
feat(monitor_setting): implement automatic channel testing configuration
This commit is contained in:
@@ -20,6 +20,7 @@ import (
|
|||||||
relayconstant "one-api/relay/constant"
|
relayconstant "one-api/relay/constant"
|
||||||
"one-api/relay/helper"
|
"one-api/relay/helper"
|
||||||
"one-api/service"
|
"one-api/service"
|
||||||
|
"one-api/setting/operation_setting"
|
||||||
"one-api/types"
|
"one-api/types"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -477,15 +478,26 @@ func TestAllChannels(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func AutomaticallyTestChannels(frequency int) {
|
var autoTestChannelsOnce sync.Once
|
||||||
if frequency <= 0 {
|
|
||||||
common.SysLog("CHANNEL_TEST_FREQUENCY is not set or invalid, skipping automatic channel test")
|
func AutomaticallyTestChannels() {
|
||||||
return
|
autoTestChannelsOnce.Do(func() {
|
||||||
}
|
for {
|
||||||
for {
|
if !operation_setting.GetMonitorSetting().AutoTestChannelEnabled {
|
||||||
time.Sleep(time.Duration(frequency) * time.Minute)
|
time.Sleep(10 * time.Minute)
|
||||||
common.SysLog("testing all channels")
|
continue
|
||||||
_ = testAllChannels(false)
|
}
|
||||||
common.SysLog("channel test finished")
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
10
main.go
10
main.go
@@ -94,13 +94,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
go controller.AutomaticallyUpdateChannels(frequency)
|
go controller.AutomaticallyUpdateChannels(frequency)
|
||||||
}
|
}
|
||||||
if os.Getenv("CHANNEL_TEST_FREQUENCY") != "" {
|
|
||||||
frequency, err := strconv.Atoi(os.Getenv("CHANNEL_TEST_FREQUENCY"))
|
go controller.AutomaticallyTestChannels()
|
||||||
if err != nil {
|
|
||||||
common.FatalLog("failed to parse CHANNEL_TEST_FREQUENCY: " + err.Error())
|
|
||||||
}
|
|
||||||
go controller.AutomaticallyTestChannels(frequency)
|
|
||||||
}
|
|
||||||
if common.IsMasterNode && constant.UpdateTask {
|
if common.IsMasterNode && constant.UpdateTask {
|
||||||
gopool.Go(func() {
|
gopool.Go(func() {
|
||||||
controller.UpdateMidjourneyTaskBulk()
|
controller.UpdateMidjourneyTaskBulk()
|
||||||
|
|||||||
@@ -2,12 +2,10 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
_ "image/gif"
|
|
||||||
_ "image/jpeg"
|
|
||||||
_ "image/png"
|
|
||||||
"one-api/constant"
|
"one-api/constant"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetFullRequestURL(baseURL string, requestURL string, channelType int) string {
|
func GetFullRequestURL(baseURL string, requestURL string, channelType int) string {
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
_ "image/gif"
|
||||||
|
_ "image/jpeg"
|
||||||
|
_ "image/png"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"one-api/common"
|
"one-api/common"
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
_ "image/gif"
|
||||||
|
_ "image/jpeg"
|
||||||
|
_ "image/png"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"one-api/common"
|
"one-api/common"
|
||||||
@@ -357,33 +360,6 @@ func CountRequestToken(c *gin.Context, meta *types.TokenCountMeta, info *relayco
|
|||||||
return tkm, nil
|
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) {
|
func CountTokenClaudeRequest(request dto.ClaudeRequest, model string) (int, error) {
|
||||||
tkm := 0
|
tkm := 0
|
||||||
|
|
||||||
@@ -543,56 +519,6 @@ func CountTokenRealtime(info *relaycommon.RelayInfo, request dto.RealtimeEvent,
|
|||||||
return textToken, audioToken, nil
|
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 {
|
func CountTokenInput(input any, model string) int {
|
||||||
switch v := input.(type) {
|
switch v := input.(type) {
|
||||||
case string:
|
case string:
|
||||||
|
|||||||
34
setting/operation_setting/monitor_setting.go
Normal file
34
setting/operation_setting/monitor_setting.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -68,6 +68,8 @@ const OperationSetting = () => {
|
|||||||
AutomaticDisableChannelEnabled: false,
|
AutomaticDisableChannelEnabled: false,
|
||||||
AutomaticEnableChannelEnabled: false,
|
AutomaticEnableChannelEnabled: false,
|
||||||
AutomaticDisableKeywords: '',
|
AutomaticDisableKeywords: '',
|
||||||
|
'monitor_setting.auto_test_channel_enabled': false,
|
||||||
|
'monitor_setting.auto_test_channel_minutes': 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
let [loading, setLoading] = useState(false);
|
let [loading, setLoading] = useState(false);
|
||||||
@@ -78,10 +80,7 @@ const OperationSetting = () => {
|
|||||||
if (success) {
|
if (success) {
|
||||||
let newInputs = {};
|
let newInputs = {};
|
||||||
data.forEach((item) => {
|
data.forEach((item) => {
|
||||||
if (
|
if (typeof inputs[item.key] === 'boolean') {
|
||||||
item.key.endsWith('Enabled') ||
|
|
||||||
['DefaultCollapseSidebar'].includes(item.key)
|
|
||||||
) {
|
|
||||||
newInputs[item.key] = toBoolean(item.value);
|
newInputs[item.key] = toBoolean(item.value);
|
||||||
} else {
|
} else {
|
||||||
newInputs[item.key] = item.value;
|
newInputs[item.key] = item.value;
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ export default function SettingsMonitoring(props) {
|
|||||||
AutomaticDisableChannelEnabled: false,
|
AutomaticDisableChannelEnabled: false,
|
||||||
AutomaticEnableChannelEnabled: false,
|
AutomaticEnableChannelEnabled: false,
|
||||||
AutomaticDisableKeywords: '',
|
AutomaticDisableKeywords: '',
|
||||||
|
'monitor_setting.auto_test_channel_enabled': false,
|
||||||
|
'monitor_setting.auto_test_channel_minutes': 10,
|
||||||
});
|
});
|
||||||
const refForm = useRef();
|
const refForm = useRef();
|
||||||
const [inputsRow, setInputsRow] = useState(inputs);
|
const [inputsRow, setInputsRow] = useState(inputs);
|
||||||
@@ -98,6 +100,40 @@ export default function SettingsMonitoring(props) {
|
|||||||
style={{ marginBottom: 15 }}
|
style={{ marginBottom: 15 }}
|
||||||
>
|
>
|
||||||
<Form.Section text={t('监控设置')}>
|
<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}>
|
<Row gutter={16}>
|
||||||
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
|
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
|
||||||
<Form.InputNumber
|
<Form.InputNumber
|
||||||
|
|||||||
Reference in New Issue
Block a user