feat: Refactor model configuration management with new config system

- Introduce a new configuration management approach for model-specific settings
- Update Gemini settings to use the new config system with more flexible management
- Add support for dynamic configuration updates in option handling
- Modify Claude and Vertex adaptors to use new configuration methods
- Enhance web interface to support namespaced configuration keys
This commit is contained in:
1808837298@qq.com
2025-02-27 20:49:34 +08:00
parent 06a78f9042
commit 929668bead
7 changed files with 93 additions and 88 deletions

View File

@@ -3,7 +3,7 @@ package model
import ( import (
"one-api/common" "one-api/common"
"one-api/setting" "one-api/setting"
"one-api/setting/model_setting" "one-api/setting/config"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -24,6 +24,8 @@ func AllOption() ([]*Option, error) {
func InitOptionMap() { func InitOptionMap() {
common.OptionMapRWMutex.Lock() common.OptionMapRWMutex.Lock()
common.OptionMap = make(map[string]string) common.OptionMap = make(map[string]string)
// 添加原有的系统配置
common.OptionMap["FileUploadPermission"] = strconv.Itoa(common.FileUploadPermission) common.OptionMap["FileUploadPermission"] = strconv.Itoa(common.FileUploadPermission)
common.OptionMap["FileDownloadPermission"] = strconv.Itoa(common.FileDownloadPermission) common.OptionMap["FileDownloadPermission"] = strconv.Itoa(common.FileDownloadPermission)
common.OptionMap["ImageUploadPermission"] = strconv.Itoa(common.ImageUploadPermission) common.OptionMap["ImageUploadPermission"] = strconv.Itoa(common.ImageUploadPermission)
@@ -111,13 +113,16 @@ func InitOptionMap() {
common.OptionMap["DemoSiteEnabled"] = strconv.FormatBool(setting.DemoSiteEnabled) common.OptionMap["DemoSiteEnabled"] = strconv.FormatBool(setting.DemoSiteEnabled)
common.OptionMap["ModelRequestRateLimitEnabled"] = strconv.FormatBool(setting.ModelRequestRateLimitEnabled) common.OptionMap["ModelRequestRateLimitEnabled"] = strconv.FormatBool(setting.ModelRequestRateLimitEnabled)
common.OptionMap["CheckSensitiveOnPromptEnabled"] = strconv.FormatBool(setting.CheckSensitiveOnPromptEnabled) common.OptionMap["CheckSensitiveOnPromptEnabled"] = strconv.FormatBool(setting.CheckSensitiveOnPromptEnabled)
//common.OptionMap["CheckSensitiveOnCompletionEnabled"] = strconv.FormatBool(constant.CheckSensitiveOnCompletionEnabled)
common.OptionMap["StopOnSensitiveEnabled"] = strconv.FormatBool(setting.StopOnSensitiveEnabled) common.OptionMap["StopOnSensitiveEnabled"] = strconv.FormatBool(setting.StopOnSensitiveEnabled)
common.OptionMap["SensitiveWords"] = setting.SensitiveWordsToString() common.OptionMap["SensitiveWords"] = setting.SensitiveWordsToString()
common.OptionMap["StreamCacheQueueLength"] = strconv.Itoa(setting.StreamCacheQueueLength) common.OptionMap["StreamCacheQueueLength"] = strconv.Itoa(setting.StreamCacheQueueLength)
common.OptionMap["AutomaticDisableKeywords"] = setting.AutomaticDisableKeywordsToString() common.OptionMap["AutomaticDisableKeywords"] = setting.AutomaticDisableKeywordsToString()
common.OptionMap["GeminiSafetySettings"] = model_setting.GeminiSafetySettingsJsonString()
common.OptionMap["GeminiVersionSettings"] = model_setting.GeminiVersionSettingsJsonString() // 自动添加所有注册的模型配置
modelConfigs := config.GlobalConfig.ExportAllConfigs()
for k, v := range modelConfigs {
common.OptionMap[k] = v
}
common.OptionMapRWMutex.Unlock() common.OptionMapRWMutex.Unlock()
loadOptionsFromDatabase() loadOptionsFromDatabase()
@@ -161,6 +166,13 @@ func updateOptionMap(key string, value string) (err error) {
common.OptionMapRWMutex.Lock() common.OptionMapRWMutex.Lock()
defer common.OptionMapRWMutex.Unlock() defer common.OptionMapRWMutex.Unlock()
common.OptionMap[key] = value common.OptionMap[key] = value
// 检查是否是模型配置 - 使用更规范的方式处理
if handleConfigUpdate(key, value) {
return nil // 已由配置系统处理
}
// 处理传统配置项...
if strings.HasSuffix(key, "Permission") { if strings.HasSuffix(key, "Permission") {
intValue, _ := strconv.Atoi(value) intValue, _ := strconv.Atoi(value)
switch key { switch key {
@@ -235,9 +247,6 @@ func updateOptionMap(key string, value string) (err error) {
setting.CheckSensitiveOnPromptEnabled = boolValue setting.CheckSensitiveOnPromptEnabled = boolValue
case "ModelRequestRateLimitEnabled": case "ModelRequestRateLimitEnabled":
setting.ModelRequestRateLimitEnabled = boolValue setting.ModelRequestRateLimitEnabled = boolValue
//case "CheckSensitiveOnCompletionEnabled":
// constant.CheckSensitiveOnCompletionEnabled = boolValue
case "StopOnSensitiveEnabled": case "StopOnSensitiveEnabled":
setting.StopOnSensitiveEnabled = boolValue setting.StopOnSensitiveEnabled = boolValue
case "SMTPSSLEnabled": case "SMTPSSLEnabled":
@@ -354,12 +363,33 @@ func updateOptionMap(key string, value string) (err error) {
setting.SensitiveWordsFromString(value) setting.SensitiveWordsFromString(value)
case "AutomaticDisableKeywords": case "AutomaticDisableKeywords":
setting.AutomaticDisableKeywordsFromString(value) setting.AutomaticDisableKeywordsFromString(value)
case "GeminiSafetySettings":
model_setting.GeminiSafetySettingFromJsonString(value)
case "GeminiVersionSettings":
model_setting.GeminiVersionSettingFromJsonString(value)
case "StreamCacheQueueLength": case "StreamCacheQueueLength":
setting.StreamCacheQueueLength, _ = strconv.Atoi(value) setting.StreamCacheQueueLength, _ = strconv.Atoi(value)
} }
return err return err
} }
// handleConfigUpdate 处理分层配置更新,返回是否已处理
func handleConfigUpdate(key, value string) bool {
parts := strings.SplitN(key, ".", 2)
if len(parts) != 2 {
return false // 不是分层配置
}
configName := parts[0]
configKey := parts[1]
// 获取配置对象
cfg := config.GlobalConfig.Get(configName)
if cfg == nil {
return false // 未注册的配置
}
// 更新配置
configMap := map[string]string{
configKey: value,
}
config.UpdateConfigFromMap(cfg, configMap)
return true // 已处理
}

View File

@@ -8,6 +8,7 @@ import (
"one-api/dto" "one-api/dto"
"one-api/relay/channel/claude" "one-api/relay/channel/claude"
relaycommon "one-api/relay/common" relaycommon "one-api/relay/common"
"one-api/setting/model_setting"
) )
const ( const (
@@ -38,6 +39,7 @@ func (a *Adaptor) GetRequestURL(info *relaycommon.RelayInfo) (string, error) {
} }
func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Header, info *relaycommon.RelayInfo) error { func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Header, info *relaycommon.RelayInfo) error {
model_setting.GetClaudeSettings().WriteHeaders(req)
return nil return nil
} }

View File

@@ -9,6 +9,7 @@ import (
"one-api/dto" "one-api/dto"
"one-api/relay/channel" "one-api/relay/channel"
relaycommon "one-api/relay/common" relaycommon "one-api/relay/common"
"one-api/setting/model_setting"
"strings" "strings"
) )
@@ -55,6 +56,7 @@ func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Header, info *rel
anthropicVersion = "2023-06-01" anthropicVersion = "2023-06-01"
} }
req.Set("anthropic-version", anthropicVersion) req.Set("anthropic-version", anthropicVersion)
model_setting.GetClaudeSettings().WriteHeaders(req)
return nil return nil
} }

View File

@@ -10,6 +10,7 @@ import (
"one-api/dto" "one-api/dto"
relaycommon "one-api/relay/common" relaycommon "one-api/relay/common"
"one-api/service" "one-api/service"
"one-api/setting/model_setting"
"strings" "strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -93,9 +94,10 @@ func RequestOpenAI2ClaudeMessage(textRequest dto.GeneralOpenAIRequest) (*ClaudeR
Tools: claudeTools, Tools: claudeTools,
} }
if strings.HasSuffix(textRequest.Model, "-thinking") { if model_setting.GetClaudeSettings().ThinkingAdapterEnabled &&
strings.HasSuffix(textRequest.Model, "-thinking") {
if claudeRequest.MaxTokens == 0 { if claudeRequest.MaxTokens == 0 {
claudeRequest.MaxTokens = 8192 claudeRequest.MaxTokens = uint(model_setting.GetClaudeSettings().ThinkingAdapterMaxTokens)
} }
// 因为BudgetTokens 必须大于1024 // 因为BudgetTokens 必须大于1024
@@ -106,7 +108,7 @@ func RequestOpenAI2ClaudeMessage(textRequest dto.GeneralOpenAIRequest) (*ClaudeR
// BudgetTokens 为 max_tokens 的 80% // BudgetTokens 为 max_tokens 的 80%
claudeRequest.Thinking = &Thinking{ claudeRequest.Thinking = &Thinking{
Type: "enabled", Type: "enabled",
BudgetTokens: int(float64(claudeRequest.MaxTokens) * 0.8), BudgetTokens: int(float64(claudeRequest.MaxTokens) * model_setting.GetClaudeSettings().ThinkingAdapterBudgetTokensPercentage),
} }
// TODO: 临时处理 // TODO: 临时处理
// https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#important-considerations-when-using-extended-thinking // https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#important-considerations-when-using-extended-thinking

View File

@@ -28,6 +28,7 @@ var claudeModelMap = map[string]string{
"claude-3-opus-20240229": "claude-3-opus@20240229", "claude-3-opus-20240229": "claude-3-opus@20240229",
"claude-3-haiku-20240307": "claude-3-haiku@20240307", "claude-3-haiku-20240307": "claude-3-haiku@20240307",
"claude-3-5-sonnet-20240620": "claude-3-5-sonnet@20240620", "claude-3-5-sonnet-20240620": "claude-3-5-sonnet@20240620",
"claude-3-7-sonnet-20250219": "claude-3-7-sonnet@20250219",
} }
const anthropicVersion = "vertex-2023-10-16" const anthropicVersion = "vertex-2023-10-16"
@@ -156,7 +157,6 @@ func (a *Adaptor) ConvertEmbeddingRequest(c *gin.Context, info *relaycommon.Rela
return nil, errors.New("not implemented") return nil, errors.New("not implemented")
} }
func (a *Adaptor) DoRequest(c *gin.Context, info *relaycommon.RelayInfo, requestBody io.Reader) (any, error) { func (a *Adaptor) DoRequest(c *gin.Context, info *relaycommon.RelayInfo, requestBody io.Reader) (any, error) {
return channel.DoApiRequest(a, c, info, requestBody) return channel.DoApiRequest(a, c, info, requestBody)
} }

View File

@@ -1,83 +1,52 @@
package model_setting package model_setting
import ( import (
"encoding/json" "one-api/setting/config"
"one-api/common"
) )
var geminiSafetySettings = map[string]string{ // GeminiSettings 定义Gemini模型的配置
"default": "OFF", type GeminiSettings struct {
"HARM_CATEGORY_CIVIC_INTEGRITY": "BLOCK_NONE", SafetySettings map[string]string `json:"safety_settings"`
VersionSettings map[string]string `json:"version_settings"`
} }
// 默认配置
var defaultGeminiSettings = GeminiSettings{
SafetySettings: map[string]string{
"default": "OFF",
"HARM_CATEGORY_CIVIC_INTEGRITY": "BLOCK_NONE",
},
VersionSettings: map[string]string{
"default": "v1beta",
"gemini-1.0-pro": "v1",
},
}
// 全局实例
var geminiSettings = defaultGeminiSettings
func init() {
// 注册到全局配置管理器
config.GlobalConfig.Register("gemini", &geminiSettings)
}
// GetGeminiSettings 获取Gemini配置
func GetGeminiSettings() *GeminiSettings {
return &geminiSettings
}
// GetGeminiSafetySetting 获取安全设置
func GetGeminiSafetySetting(key string) string { func GetGeminiSafetySetting(key string) string {
if value, ok := geminiSafetySettings[key]; ok { if value, ok := geminiSettings.SafetySettings[key]; ok {
return value return value
} }
return geminiSafetySettings["default"] return geminiSettings.SafetySettings["default"]
}
func GeminiSafetySettingFromJsonString(jsonString string) {
geminiSafetySettings = map[string]string{}
err := json.Unmarshal([]byte(jsonString), &geminiSafetySettings)
if err != nil {
geminiSafetySettings = map[string]string{
"default": "OFF",
"HARM_CATEGORY_CIVIC_INTEGRITY": "BLOCK_NONE",
}
}
// check must have default
if _, ok := geminiSafetySettings["default"]; !ok {
geminiSafetySettings["default"] = common.GeminiSafetySetting
}
}
func GeminiSafetySettingsJsonString() string {
// check must have default
if _, ok := geminiSafetySettings["default"]; !ok {
geminiSafetySettings["default"] = common.GeminiSafetySetting
}
jsonString, err := json.Marshal(geminiSafetySettings)
if err != nil {
return "{}"
}
return string(jsonString)
}
var geminiVersionSettings = map[string]string{
"default": "v1beta",
"gemini-1.0-pro": "v1",
} }
// GetGeminiVersionSetting 获取版本设置
func GetGeminiVersionSetting(key string) string { func GetGeminiVersionSetting(key string) string {
if value, ok := geminiVersionSettings[key]; ok { if value, ok := geminiSettings.VersionSettings[key]; ok {
return value return value
} }
return geminiVersionSettings["default"] return geminiSettings.VersionSettings["default"]
}
func GeminiVersionSettingFromJsonString(jsonString string) {
geminiVersionSettings = map[string]string{}
err := json.Unmarshal([]byte(jsonString), &geminiVersionSettings)
if err != nil {
geminiVersionSettings = map[string]string{
"default": "v1beta",
}
}
// check must have default
if _, ok := geminiVersionSettings["default"]; !ok {
geminiVersionSettings["default"] = "v1beta"
}
}
func GeminiVersionSettingsJsonString() string {
// check must have default
if _, ok := geminiVersionSettings["default"]; !ok {
geminiVersionSettings["default"] = "v1beta"
}
jsonString, err := json.Marshal(geminiVersionSettings)
if err != nil {
return "{}"
}
return string(jsonString)
} }

View File

@@ -24,8 +24,8 @@ export default function SettingGeminiModel(props) {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [inputs, setInputs] = useState({ const [inputs, setInputs] = useState({
GeminiSafetySettings: '', 'gemini.safety_settings': '',
GeminiVersionSettings: '', 'gemini.version_settings': '',
}); });
const refForm = useRef(); const refForm = useRef();
const [inputsRow, setInputsRow] = useState(inputs); const [inputsRow, setInputsRow] = useState(inputs);
@@ -90,7 +90,7 @@ export default function SettingGeminiModel(props) {
<Form.TextArea <Form.TextArea
label={t('Gemini安全设置')} label={t('Gemini安全设置')}
placeholder={t('为一个 JSON 文本,例如:') + '\n' + JSON.stringify(GEMINI_SETTING_EXAMPLE, null, 2)} placeholder={t('为一个 JSON 文本,例如:') + '\n' + JSON.stringify(GEMINI_SETTING_EXAMPLE, null, 2)}
field={'GeminiSafetySettings'} field={'gemini.safety_settings'}
extraText={t('default为默认设置可单独设置每个分类的安全等级')} extraText={t('default为默认设置可单独设置每个分类的安全等级')}
autosize={{ minRows: 6, maxRows: 12 }} autosize={{ minRows: 6, maxRows: 12 }}
trigger='blur' trigger='blur'
@@ -101,7 +101,7 @@ export default function SettingGeminiModel(props) {
message: t('不是合法的 JSON 字符串') message: t('不是合法的 JSON 字符串')
} }
]} ]}
onChange={(value) => setInputs({ ...inputs, GeminiSafetySettings: value })} onChange={(value) => setInputs({ ...inputs, 'gemini.safety_settings': value })}
/> />
</Col> </Col>
</Row> </Row>
@@ -110,7 +110,7 @@ export default function SettingGeminiModel(props) {
<Form.TextArea <Form.TextArea
label={t('Gemini版本设置')} label={t('Gemini版本设置')}
placeholder={t('为一个 JSON 文本,例如:') + '\n' + JSON.stringify(GEMINI_VERSION_EXAMPLE, null, 2)} placeholder={t('为一个 JSON 文本,例如:') + '\n' + JSON.stringify(GEMINI_VERSION_EXAMPLE, null, 2)}
field={'GeminiVersionSettings'} field={'gemini.version_settings'}
extraText={t('default为默认设置可单独设置每个模型的版本')} extraText={t('default为默认设置可单独设置每个模型的版本')}
autosize={{ minRows: 6, maxRows: 12 }} autosize={{ minRows: 6, maxRows: 12 }}
trigger='blur' trigger='blur'
@@ -121,7 +121,7 @@ export default function SettingGeminiModel(props) {
message: t('不是合法的 JSON 字符串') message: t('不是合法的 JSON 字符串')
} }
]} ]}
onChange={(value) => setInputs({ ...inputs, GeminiVersionSettings: value })} onChange={(value) => setInputs({ ...inputs, 'gemini.version_settings': value })}
/> />
</Col> </Col>
</Row> </Row>