Explorar o código

feat: 添加成功时自动启用通道功能, close #27

CaIon %!s(int64=2) %!d(string=hai) anos
pai
achega
5c8f8b4901

+ 1 - 0
common/constants.go

@@ -87,6 +87,7 @@ var QuotaForInviter = 0
 var QuotaForInvitee = 0
 var QuotaForInvitee = 0
 var ChannelDisableThreshold = 5.0
 var ChannelDisableThreshold = 5.0
 var AutomaticDisableChannelEnabled = false
 var AutomaticDisableChannelEnabled = false
+var AutomaticEnableChannelEnabled = false
 var QuotaRemindThreshold = 1000
 var QuotaRemindThreshold = 1000
 var PreConsumedQuota = 500
 var PreConsumedQuota = 500
 
 

+ 22 - 7
controller/channel-test.go

@@ -78,6 +78,9 @@ func testChannel(channel *model.Channel, request ChatRequest) (err error, openai
 		return err, nil
 		return err, nil
 	}
 	}
 	if response.Usage.CompletionTokens == 0 {
 	if response.Usage.CompletionTokens == 0 {
+		if response.Error.Message == "" {
+			response.Error.Message = "补全 tokens 非预期返回 0"
+		}
 		return errors.New(fmt.Sprintf("type %s, code %v, message %s", response.Error.Type, response.Error.Code, response.Error.Message)), &response.Error
 		return errors.New(fmt.Sprintf("type %s, code %v, message %s", response.Error.Type, response.Error.Code, response.Error.Message)), &response.Error
 	}
 	}
 	return nil, nil
 	return nil, nil
@@ -146,12 +149,23 @@ var testAllChannelsRunning bool = false
 
 
 // disable & notify
 // disable & notify
 func disableChannel(channelId int, channelName string, reason string) {
 func disableChannel(channelId int, channelName string, reason string) {
-	if common.RootUserEmail == "" {
-		common.RootUserEmail = model.GetRootUserEmail()
-	}
 	model.UpdateChannelStatusById(channelId, common.ChannelStatusAutoDisabled)
 	model.UpdateChannelStatusById(channelId, common.ChannelStatusAutoDisabled)
 	subject := fmt.Sprintf("通道「%s」(#%d)已被禁用", channelName, channelId)
 	subject := fmt.Sprintf("通道「%s」(#%d)已被禁用", channelName, channelId)
 	content := fmt.Sprintf("通道「%s」(#%d)已被禁用,原因:%s", channelName, channelId, reason)
 	content := fmt.Sprintf("通道「%s」(#%d)已被禁用,原因:%s", channelName, channelId, reason)
+	notifyRootUser(subject, content)
+}
+
+func enableChannel(channelId int, channelName string) {
+	model.UpdateChannelStatusById(channelId, common.ChannelStatusEnabled)
+	subject := fmt.Sprintf("通道「%s」(#%d)已被启用", channelName, channelId)
+	content := fmt.Sprintf("通道「%s」(#%d)已被启用", channelName, channelId)
+	notifyRootUser(subject, content)
+}
+
+func notifyRootUser(subject string, content string) {
+	if common.RootUserEmail == "" {
+		common.RootUserEmail = model.GetRootUserEmail()
+	}
 	err := common.SendEmail(subject, common.RootUserEmail, content)
 	err := common.SendEmail(subject, common.RootUserEmail, content)
 	if err != nil {
 	if err != nil {
 		common.SysError(fmt.Sprintf("failed to send email: %s", err.Error()))
 		common.SysError(fmt.Sprintf("failed to send email: %s", err.Error()))
@@ -180,9 +194,7 @@ func testAllChannels(notify bool) error {
 	}
 	}
 	go func() {
 	go func() {
 		for _, channel := range channels {
 		for _, channel := range channels {
-			if channel.Status != common.ChannelStatusEnabled {
-				continue
-			}
+			isChannelEnabled := channel.Status == common.ChannelStatusEnabled
 			tik := time.Now()
 			tik := time.Now()
 			err, openaiErr := testChannel(channel, *testRequest)
 			err, openaiErr := testChannel(channel, *testRequest)
 			tok := time.Now()
 			tok := time.Now()
@@ -201,9 +213,12 @@ func testAllChannels(notify bool) error {
 			if channel.AutoBan != nil && *channel.AutoBan == 0 {
 			if channel.AutoBan != nil && *channel.AutoBan == 0 {
 				ban = false
 				ban = false
 			}
 			}
-			if shouldDisableChannel(openaiErr, -1) && ban {
+			if isChannelEnabled && shouldDisableChannel(openaiErr, -1) && ban {
 				disableChannel(channel.Id, channel.Name, err.Error())
 				disableChannel(channel.Id, channel.Name, err.Error())
 			}
 			}
+			if !isChannelEnabled && shouldEnableChannel(err, openaiErr) {
+				enableChannel(channel.Id, channel.Name)
+			}
 			channel.UpdateResponseTime(milliseconds)
 			channel.UpdateResponseTime(milliseconds)
 			time.Sleep(common.RequestInterval)
 			time.Sleep(common.RequestInterval)
 		}
 		}

+ 13 - 0
controller/relay-utils.go

@@ -258,6 +258,19 @@ func shouldDisableChannel(err *OpenAIError, statusCode int) bool {
 	return false
 	return false
 }
 }
 
 
+func shouldEnableChannel(err error, openAIErr *OpenAIError) bool {
+	if !common.AutomaticEnableChannelEnabled {
+		return false
+	}
+	if err != nil {
+		return false
+	}
+	if openAIErr != nil {
+		return false
+	}
+	return true
+}
+
 func setEventStreamHeaders(c *gin.Context) {
 func setEventStreamHeaders(c *gin.Context) {
 	c.Writer.Header().Set("Content-Type", "text/event-stream")
 	c.Writer.Header().Set("Content-Type", "text/event-stream")
 	c.Writer.Header().Set("Cache-Control", "no-cache")
 	c.Writer.Header().Set("Cache-Control", "no-cache")

+ 3 - 0
model/option.go

@@ -34,6 +34,7 @@ func InitOptionMap() {
 	common.OptionMap["TurnstileCheckEnabled"] = strconv.FormatBool(common.TurnstileCheckEnabled)
 	common.OptionMap["TurnstileCheckEnabled"] = strconv.FormatBool(common.TurnstileCheckEnabled)
 	common.OptionMap["RegisterEnabled"] = strconv.FormatBool(common.RegisterEnabled)
 	common.OptionMap["RegisterEnabled"] = strconv.FormatBool(common.RegisterEnabled)
 	common.OptionMap["AutomaticDisableChannelEnabled"] = strconv.FormatBool(common.AutomaticDisableChannelEnabled)
 	common.OptionMap["AutomaticDisableChannelEnabled"] = strconv.FormatBool(common.AutomaticDisableChannelEnabled)
+	common.OptionMap["AutomaticEnableChannelEnabled"] = strconv.FormatBool(common.AutomaticEnableChannelEnabled)
 	common.OptionMap["LogConsumeEnabled"] = strconv.FormatBool(common.LogConsumeEnabled)
 	common.OptionMap["LogConsumeEnabled"] = strconv.FormatBool(common.LogConsumeEnabled)
 	common.OptionMap["DisplayInCurrencyEnabled"] = strconv.FormatBool(common.DisplayInCurrencyEnabled)
 	common.OptionMap["DisplayInCurrencyEnabled"] = strconv.FormatBool(common.DisplayInCurrencyEnabled)
 	common.OptionMap["DisplayTokenStatEnabled"] = strconv.FormatBool(common.DisplayTokenStatEnabled)
 	common.OptionMap["DisplayTokenStatEnabled"] = strconv.FormatBool(common.DisplayTokenStatEnabled)
@@ -158,6 +159,8 @@ func updateOptionMap(key string, value string) (err error) {
 			common.EmailDomainRestrictionEnabled = boolValue
 			common.EmailDomainRestrictionEnabled = boolValue
 		case "AutomaticDisableChannelEnabled":
 		case "AutomaticDisableChannelEnabled":
 			common.AutomaticDisableChannelEnabled = boolValue
 			common.AutomaticDisableChannelEnabled = boolValue
+		case "AutomaticEnableChannelEnabled":
+			common.AutomaticEnableChannelEnabled = boolValue
 		case "LogConsumeEnabled":
 		case "LogConsumeEnabled":
 			common.LogConsumeEnabled = boolValue
 			common.LogConsumeEnabled = boolValue
 		case "DisplayInCurrencyEnabled":
 		case "DisplayInCurrencyEnabled":

+ 2 - 2
web/src/components/ChannelsTable.js

@@ -478,7 +478,7 @@ const ChannelsTable = () => {
         const res = await API.get(`/api/channel/test`);
         const res = await API.get(`/api/channel/test`);
         const {success, message} = res.data;
         const {success, message} = res.data;
         if (success) {
         if (success) {
-            showInfo('已成功开始测试所有已启用通道,请刷新页面查看结果。');
+            showInfo('已成功开始测试所有通道,请刷新页面查看结果。');
         } else {
         } else {
             showError(message);
             showError(message);
         }
         }
@@ -702,7 +702,7 @@ const ChannelsTable = () => {
                         onConfirm={testAllChannels}
                         onConfirm={testAllChannels}
                         position={isMobile()?'top':'top'}
                         position={isMobile()?'top':'top'}
                     >
                     >
-                        <Button theme='light' type='warning' style={{marginRight: 8}}>测试所有已启用通道</Button>
+                        <Button theme='light' type='warning' style={{marginRight: 8}}>测试所有通道</Button>
                     </Popconfirm>
                     </Popconfirm>
                     <Popconfirm
                     <Popconfirm
                         title="确定?"
                         title="确定?"

+ 7 - 0
web/src/components/OperationSetting.js

@@ -18,6 +18,7 @@ const OperationSetting = () => {
         ChatLink2: '', // 添加的新状态变量
         ChatLink2: '', // 添加的新状态变量
         QuotaPerUnit: 0,
         QuotaPerUnit: 0,
         AutomaticDisableChannelEnabled: '',
         AutomaticDisableChannelEnabled: '',
+        AutomaticEnableChannelEnabled: '',
         ChannelDisableThreshold: 0,
         ChannelDisableThreshold: 0,
         LogConsumeEnabled: '',
         LogConsumeEnabled: '',
         DisplayInCurrencyEnabled: '',
         DisplayInCurrencyEnabled: '',
@@ -332,6 +333,12 @@ const OperationSetting = () => {
                             name='AutomaticDisableChannelEnabled'
                             name='AutomaticDisableChannelEnabled'
                             onChange={handleInputChange}
                             onChange={handleInputChange}
                         />
                         />
+                        <Form.Checkbox
+                            checked={inputs.AutomaticEnableChannelEnabled === 'true'}
+                            label='成功时自动启用通道'
+                            name='AutomaticEnableChannelEnabled'
+                            onChange={handleInputChange}
+                        />
                     </Form.Group>
                     </Form.Group>
                     <Form.Button onClick={() => {
                     <Form.Button onClick={() => {
                         submitConfig('monitor').then();
                         submitConfig('monitor').then();