Files
qiweimanager-master/config/config_manager.go
yuanzhipeng 1517be2a25 feat(auto-reply): 接入万川平台模型配置 + 各模型独立网关回退
万川平台对接
- 新增 wanchuan_proxy.go:WanchuanLogin/WanchuanGetModel 代理登录与按 code 拉取模型,
  日志对 password/token/apiKey 打码(含 encryptedConfig 二次解析)
- 新增 PlatformConfig(baseUrl/username/password)及 Get/SavePlatformConfig 持久化
- 前端万川卡片:登录→拉取 chat/vision/embedding/rerank/voice→回填 form 并保存→必要时重建向量索引

各模型独立网关(url+key),留空回退聊天网关
- RetrievalConfig 新增 embeddingBaseUrl/embeddingApiKey、rerankBaseUrl/rerankApiKey
- embeddingRequestConfig/rerankRequestConfig:优先独立网关,未配置回退 AI.BaseURL/APIKey
- vision/audio 同模式:非 DashScope 网关下视觉/语音模型留空时不再锁死或强写 DashScope,
  运行期由 fallbackString(VisionModel, Model) 动态复用聊天模型

陈旧向量空间防护
- loadEmbeddingIndex 检测磁盘索引与当前 embedding 模型/维度不一致时清空向量、回退关键词检索,
  并提示重建(embeddingIndexStaleReason,兼容旧版无模型名索引)

UI 状态修复
- 登录拉模型期间统一置全局 busy,禁用闸门收敛为 busy(与刷新联系人等按钮同范式),
  platformBusy 仅保留用于按钮「处理中…」文案,杜绝并发读写 form 与反向可点洞

其他
- 删除遗留 helper/auto_reply_ai.go.bak
- 补充 config/helper 单元测试(视觉回退分支、陈旧索引判定)
2026-06-26 10:17:02 +08:00

187 lines
4.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package config
import (
"encoding/json"
"os"
"path/filepath"
"time"
"qiweimanager/logger"
)
var (
// 全局配置管理器实例
globalConfigManager *ConfigManager
// 全局配置实例
globalConfig *Config
)
// ConfigManager 配置管理器,负责加载和保存配置
type ConfigManager struct {
configFilePath string
logger *logger.Logger
}
// NewConfigManager 创建配置管理器实例
func NewConfigManager(appName string, logger *logger.Logger) (*ConfigManager, error) {
// 获取可执行文件路径
exePath, err := os.Executable()
if err != nil {
// 如果无法获取可执行文件路径,使用当前工作目录作为备选
configDir, err := os.Getwd()
if err != nil {
return nil, err
}
// 创建配置目录
appConfigDir := filepath.Join(configDir, "config")
if err := os.MkdirAll(appConfigDir, 0755); err != nil {
return nil, err
}
// 构建配置文件完整路径
configFilePath := filepath.Join(appConfigDir, "config.json")
return &ConfigManager{
configFilePath: configFilePath,
logger: logger,
},
nil
}
// 获取可执行文件所在目录
exeDir := filepath.Dir(exePath)
// 创建应用程序配置目录位于可执行文件同级的config目录
appConfigDir := filepath.Join(exeDir, "config")
if err := os.MkdirAll(appConfigDir, 0755); err != nil {
return nil, err
}
// 构建配置文件完整路径
configFilePath := filepath.Join(appConfigDir, "config.json")
return &ConfigManager{
configFilePath: configFilePath,
logger: logger,
}, nil
}
// LoadConfig 从文件加载配置
func (cm *ConfigManager) LoadConfig() (*Config, error) {
// 检查配置文件是否存在
if _, err := os.Stat(cm.configFilePath); os.IsNotExist(err) {
cm.logger.Info("配置文件不存在,使用默认配置: %s", cm.configFilePath)
// 返回默认配置
return NewDefaultConfig(), nil
}
// 读取配置文件内容
configData, err := os.ReadFile(cm.configFilePath)
if err != nil {
cm.logger.Error("读取配置文件失败: %v", err)
return nil, err
}
// 解析配置文件
config := &Config{}
if err := json.Unmarshal(configData, config); err != nil {
cm.logger.Error("解析配置文件失败: %v", err)
// 解析失败时返回默认配置
return NewDefaultConfig(), nil
}
config.ApplyDefaults()
cm.logger.Info("配置文件加载成功: %s", cm.configFilePath)
return config, nil
}
// SaveConfig 将配置保存到文件
func (cm *ConfigManager) SaveConfig(config *Config) error {
config.ApplyDefaults()
// 更新最后修改时间
config.LastUpdated = time.Now().Unix()
// 将配置转换为JSON
configData, err := json.MarshalIndent(config, "", " ")
if err != nil {
cm.logger.Error("序列化配置失败: %v", err)
return err
}
// 写入配置文件
if err := os.WriteFile(cm.configFilePath, configData, 0644); err != nil {
cm.logger.Error("写入配置文件失败: %v", err)
return err
}
cm.logger.Info("配置文件保存成功: %s", cm.configFilePath)
return nil
}
// InitGlobalConfig 初始化全局配置
func InitGlobalConfig(appName string, logger *logger.Logger) error {
var err error
globalConfigManager, err = NewConfigManager(appName, logger)
if err != nil {
return err
}
// 加载配置
globalConfig, err = globalConfigManager.LoadConfig()
return err
}
// GetGlobalConfig 获取全局配置实例
func GetGlobalConfig() *Config {
return globalConfig
}
// SaveGlobalConfig 保存全局配置
func SaveGlobalConfig() error {
if globalConfigManager != nil && globalConfig != nil {
return globalConfigManager.SaveConfig(globalConfig)
}
return nil
}
// UpdateCallbackConfig 更新回调配置
func UpdateCallbackConfig(callbackConfig CallbackConfig) error {
if globalConfig != nil {
globalConfig.CallbackConfig = callbackConfig
return SaveGlobalConfig()
}
return nil
}
// UpdateAutoReplyConfig updates automatic customer-service settings.
func UpdateAutoReplyConfig(autoReplyConfig AutoReplyConfig) error {
if globalConfig != nil {
globalConfig.AutoReplyConfig = autoReplyConfig
globalConfig.ApplyDefaults()
return SaveGlobalConfig()
}
return nil
}
// UpdatePlatformConfig updates Wanchuan platform configuration.
func UpdatePlatformConfig(platformConfig PlatformConfig) error {
if globalConfig != nil {
globalConfig.PlatformConfig = platformConfig
return SaveGlobalConfig()
}
return nil
}
// ReloadGlobalConfig reloads config.json from disk.
func ReloadGlobalConfig() (*Config, error) {
if globalConfigManager == nil {
return nil, nil
}
cfg, err := globalConfigManager.LoadConfig()
if err != nil {
return nil, err
}
cfg.ApplyDefaults()
globalConfig = cfg
return globalConfig, nil
}