mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-30 12:01:46 +00:00
✨ feat(architecture): Core+Plugin
This commit is contained in:
161
config/plugin_config.go
Normal file
161
config/plugin_config.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
"github.com/QuantumNous/new-api/core/interfaces"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// PluginConfig 插件配置结构
|
||||
type PluginConfig struct {
|
||||
Channels map[string]interfaces.ChannelConfig `yaml:"channels"`
|
||||
Middlewares []interfaces.MiddlewareConfig `yaml:"middlewares"`
|
||||
Hooks HooksConfig `yaml:"hooks"`
|
||||
}
|
||||
|
||||
// HooksConfig Hook配置
|
||||
type HooksConfig struct {
|
||||
Relay []interfaces.HookConfig `yaml:"relay"`
|
||||
}
|
||||
|
||||
var (
|
||||
// 全局配置实例
|
||||
globalPluginConfig *PluginConfig
|
||||
)
|
||||
|
||||
// LoadPluginConfig 加载插件配置
|
||||
func LoadPluginConfig(configPath string) (*PluginConfig, error) {
|
||||
// 如果没有指定配置文件路径,使用默认路径
|
||||
if configPath == "" {
|
||||
configPath = "config/plugins.yaml"
|
||||
}
|
||||
|
||||
// 检查文件是否存在
|
||||
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
||||
common.SysLog(fmt.Sprintf("Plugin config file not found: %s, using default configuration", configPath))
|
||||
return getDefaultConfig(), nil
|
||||
}
|
||||
|
||||
// 读取配置文件
|
||||
data, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read plugin config: %w", err)
|
||||
}
|
||||
|
||||
// 解析YAML
|
||||
var config PluginConfig
|
||||
if err := yaml.Unmarshal(data, &config); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse plugin config: %w", err)
|
||||
}
|
||||
|
||||
// 环境变量替换
|
||||
expandEnvVars(&config)
|
||||
|
||||
common.SysLog(fmt.Sprintf("Loaded plugin config from: %s", configPath))
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// getDefaultConfig 返回默认配置
|
||||
func getDefaultConfig() *PluginConfig {
|
||||
return &PluginConfig{
|
||||
Channels: make(map[string]interfaces.ChannelConfig),
|
||||
Middlewares: make([]interfaces.MiddlewareConfig, 0),
|
||||
Hooks: HooksConfig{
|
||||
Relay: make([]interfaces.HookConfig, 0),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// expandEnvVars 展开环境变量
|
||||
func expandEnvVars(config *PluginConfig) {
|
||||
// 展开Hook配置中的环境变量
|
||||
for i := range config.Hooks.Relay {
|
||||
for key, value := range config.Hooks.Relay[i].Config {
|
||||
if strValue, ok := value.(string); ok {
|
||||
config.Hooks.Relay[i].Config[key] = os.ExpandEnv(strValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 展开Middleware配置中的环境变量
|
||||
for i := range config.Middlewares {
|
||||
for key, value := range config.Middlewares[i].Config {
|
||||
if strValue, ok := value.(string); ok {
|
||||
config.Middlewares[i].Config[key] = os.ExpandEnv(strValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetGlobalPluginConfig 获取全局配置
|
||||
func GetGlobalPluginConfig() *PluginConfig {
|
||||
if globalPluginConfig == nil {
|
||||
configPath := os.Getenv("PLUGIN_CONFIG_PATH")
|
||||
if configPath == "" {
|
||||
configPath = "config/plugins.yaml"
|
||||
}
|
||||
|
||||
config, err := LoadPluginConfig(configPath)
|
||||
if err != nil {
|
||||
common.SysError(fmt.Sprintf("Failed to load plugin config: %v", err))
|
||||
config = getDefaultConfig()
|
||||
}
|
||||
|
||||
globalPluginConfig = config
|
||||
}
|
||||
|
||||
return globalPluginConfig
|
||||
}
|
||||
|
||||
// SavePluginConfig 保存插件配置
|
||||
func SavePluginConfig(config *PluginConfig, configPath string) error {
|
||||
if configPath == "" {
|
||||
configPath = "config/plugins.yaml"
|
||||
}
|
||||
|
||||
// 确保目录存在
|
||||
dir := filepath.Dir(configPath)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create config directory: %w", err)
|
||||
}
|
||||
|
||||
// 序列化为YAML
|
||||
data, err := yaml.Marshal(config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal config: %w", err)
|
||||
}
|
||||
|
||||
// 写入文件
|
||||
if err := ioutil.WriteFile(configPath, data, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write config file: %w", err)
|
||||
}
|
||||
|
||||
common.SysLog(fmt.Sprintf("Saved plugin config to: %s", configPath))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReloadPluginConfig 重新加载配置
|
||||
func ReloadPluginConfig() error {
|
||||
configPath := os.Getenv("PLUGIN_CONFIG_PATH")
|
||||
if configPath == "" {
|
||||
configPath = "config/plugins.yaml"
|
||||
}
|
||||
|
||||
config, err := LoadPluginConfig(configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
globalPluginConfig = config
|
||||
common.SysLog("Plugin config reloaded")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
52
config/plugins.yaml
Normal file
52
config/plugins.yaml
Normal file
@@ -0,0 +1,52 @@
|
||||
# New-API 插件配置
|
||||
# 此文件用于配置所有插件的启用状态和参数
|
||||
|
||||
# Channel插件配置
|
||||
channels:
|
||||
openai:
|
||||
enabled: true
|
||||
priority: 100
|
||||
|
||||
claude:
|
||||
enabled: true
|
||||
priority: 90
|
||||
|
||||
gemini:
|
||||
enabled: true
|
||||
priority: 85
|
||||
|
||||
# Middleware插件配置
|
||||
middlewares:
|
||||
- name: auth
|
||||
enabled: true
|
||||
priority: 100
|
||||
|
||||
- name: ratelimit
|
||||
enabled: true
|
||||
priority: 90
|
||||
config:
|
||||
default_rate: 60
|
||||
|
||||
# Hook插件配置
|
||||
hooks:
|
||||
# Relay层Hook
|
||||
relay:
|
||||
# 联网搜索插件
|
||||
- name: web_search
|
||||
enabled: false # 默认禁用,需要配置API key后启用
|
||||
priority: 50
|
||||
config:
|
||||
provider: google
|
||||
api_key: ${WEB_SEARCH_API_KEY} # 从环境变量读取
|
||||
|
||||
# 内容过滤插件
|
||||
- name: content_filter
|
||||
enabled: false # 默认禁用,需要配置后启用
|
||||
priority: 100 # 高优先级,最后执行
|
||||
config:
|
||||
filter_nsfw: true
|
||||
filter_political: false
|
||||
sensitive_words:
|
||||
- "敏感词1"
|
||||
- "敏感词2"
|
||||
|
||||
Reference in New Issue
Block a user