feat: Add automatic channel disabling based on configurable keywords
- Introduce AutomaticDisableKeywords setting to dynamically control channel disabling - Implement AC search for matching error messages against disable keywords - Add frontend UI for configuring automatic disable keywords - Update localization with new keyword-based channel disabling feature - Refactor sensitive word and AC search logic to support multiple keyword lists
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"one-api/common"
|
||||
relaymodel "one-api/dto"
|
||||
"one-api/model"
|
||||
"one-api/setting"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -64,21 +65,10 @@ func ShouldDisableChannel(channelType int, err *relaymodel.OpenAIErrorWithStatus
|
||||
case "forbidden":
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(err.Error.Message, "Your credit balance is too low") { // anthropic
|
||||
return true
|
||||
} else if strings.HasPrefix(err.Error.Message, "This organization has been disabled.") {
|
||||
return true
|
||||
} else if strings.HasPrefix(err.Error.Message, "You exceeded your current quota") {
|
||||
return true
|
||||
} else if strings.HasPrefix(err.Error.Message, "Permission denied") {
|
||||
return true
|
||||
}
|
||||
|
||||
if strings.Contains(err.Error.Message, "The security token included in the request is invalid") { // anthropic
|
||||
return true
|
||||
} else if strings.Contains(err.Error.Message, "Operation not allowed") {
|
||||
return true
|
||||
} else if strings.Contains(err.Error.Message, "Your account is not authorized") {
|
||||
lowerMessage := strings.ToLower(err.Error.Message)
|
||||
search, _ := AcSearch(lowerMessage, setting.AutomaticDisableKeywords, true)
|
||||
if search {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -60,17 +60,7 @@ func SensitiveWordContains(text string) (bool, []string) {
|
||||
return false, nil
|
||||
}
|
||||
checkText := strings.ToLower(text)
|
||||
// 构建一个AC自动机
|
||||
m := InitAc()
|
||||
hits := m.MultiPatternSearch([]rune(checkText), false)
|
||||
if len(hits) > 0 {
|
||||
words := make([]string, 0)
|
||||
for _, hit := range hits {
|
||||
words = append(words, string(hit.Word))
|
||||
}
|
||||
return true, words
|
||||
}
|
||||
return false, nil
|
||||
return AcSearch(checkText, setting.SensitiveWords, false)
|
||||
}
|
||||
|
||||
// SensitiveWordReplace 敏感词替换,返回是否包含敏感词和替换后的文本
|
||||
@@ -79,7 +69,7 @@ func SensitiveWordReplace(text string, returnImmediately bool) (bool, []string,
|
||||
return false, nil, text
|
||||
}
|
||||
checkText := strings.ToLower(text)
|
||||
m := InitAc()
|
||||
m := InitAc(setting.SensitiveWords)
|
||||
hits := m.MultiPatternSearch([]rune(checkText), returnImmediately)
|
||||
if len(hits) > 0 {
|
||||
words := make([]string, 0)
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
goahocorasick "github.com/anknown/ahocorasick"
|
||||
"one-api/setting"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -57,9 +56,9 @@ func RemoveDuplicate(s []string) []string {
|
||||
return result
|
||||
}
|
||||
|
||||
func InitAc() *goahocorasick.Machine {
|
||||
func InitAc(words []string) *goahocorasick.Machine {
|
||||
m := new(goahocorasick.Machine)
|
||||
dict := readRunes()
|
||||
dict := readRunes(words)
|
||||
if err := m.Build(dict); err != nil {
|
||||
fmt.Println(err)
|
||||
return nil
|
||||
@@ -67,10 +66,10 @@ func InitAc() *goahocorasick.Machine {
|
||||
return m
|
||||
}
|
||||
|
||||
func readRunes() [][]rune {
|
||||
func readRunes(words []string) [][]rune {
|
||||
var dict [][]rune
|
||||
|
||||
for _, word := range setting.SensitiveWords {
|
||||
for _, word := range words {
|
||||
word = strings.ToLower(word)
|
||||
l := bytes.TrimSpace([]byte(word))
|
||||
dict = append(dict, bytes.Runes(l))
|
||||
@@ -78,3 +77,25 @@ func readRunes() [][]rune {
|
||||
|
||||
return dict
|
||||
}
|
||||
|
||||
func AcSearch(findText string, dict []string, stopImmediately bool) (bool, []string) {
|
||||
if len(dict) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
if len(findText) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
m := InitAc(dict)
|
||||
if m == nil {
|
||||
return false, nil
|
||||
}
|
||||
hits := m.MultiPatternSearch([]rune(findText), stopImmediately)
|
||||
if len(hits) > 0 {
|
||||
words := make([]string, 0)
|
||||
for _, hit := range hits {
|
||||
words = append(words, string(hit.Word))
|
||||
}
|
||||
return true, words
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user