#E:\AI_System\main.py
import os
import sys
import traceback
import threading
import time
import logging
from pathlib import Path
from core.config import config
from core.command_listener import start_command_listener
from agent.model_manager import ModelManager
from agent.cognitive_architecture import CognitiveSystem
from agent.environment_interface import EnvironmentInterface
def setup_logging():
"""配置系统日志记录"""
log_dir = Path(config.get("LOG_DIR", "logs"))
log_dir.mkdir(parents=True, exist_ok=True)
log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
log_level = config.get("ENVIRONMENT.LOG_LEVEL", "INFO").upper()
logging.basicConfig(
level=getattr(logging, log_level),
format=log_format,
handlers=[
logging.FileHandler(log_dir / "ai_system.log", encoding='utf-8'),
logging.StreamHandler()
]
)
logger = logging.getLogger("Main")
logger.info("日志系统初始化完成 (级别: %s)", log_level)
return logger
def main():
"""主函数"""
logger = setup_logging()
logger.info("=" * 50)
logger.info("🚀 启动AI系统 - 核心认知模式")
logger.info("=" * 50)
logger.info("系统配置摘要:")
logger.info(f"项目根目录: {config.get('DIRECTORIES.PROJECT_ROOT', '未设置')}")
logger.info(f"默认模型路径: {config.get('MODEL_PATHS.TEXT_BASE', '未设置')}")
logger.info(f"日志级别: {config.get('ENVIRONMENT.LOG_LEVEL', 'INFO')}")
# 初始化模型管理器
try:
model_manager = ModelManager(
model_registry=config.get("MODEL_PATHS", {}),
cache_dir=config.get("MODEL_CACHE_DIR", "model_cache"),
use_gpu=config.get("ENVIRONMENT.USE_GPU", True)
)
logger.info("✅ 模型管理器初始化完成")
# 修复模型加载逻辑 - 确保正确加载模型
base_model_key = "TEXT_BASE"
base_model_path = config.get("MODEL_PATHS", {}).get(base_model_key)
if base_model_path and model_manager.load_model(base_model_key):
logger.info(f"✅ 基础模型已加载: {base_model_path}")
else:
logger.warning(f"⚠️ 基础模型加载失败: {base_model_key}")
except Exception as e:
logger.error("❌ 模型管理器初始化失败: %s", str(e))
logger.error(traceback.format_exc())
return
# 初始化认知系统接口
try:
cognitive_system = CognitiveSystem(
name=config.get("AGENT_NAME", "小蓝"),
model_manager=model_manager,
config=config.get("COGNITIVE_CONFIG", {})
)
logger.info("✅ 认知系统初始化完成 - 名称: %s", cognitive_system.name)
except Exception as e:
logger.error("❌ 认知系统初始化失败: %s", str(e))
logger.error(traceback.format_exc())
return
# 初始化环境接口
try:
environment_interface = EnvironmentInterface(
name="环境接口",
cognitive_system=cognitive_system,
config={
"max_workers": config.get("MAX_WORKERS", 4),
"response_timeout": config.get("AGENT_RESPONSE_TIMEOUT", 30.0),
"log_level": config.get("ENVIRONMENT.LOG_LEVEL", "INFO")
}
)
logger.info("✅ 环境接口初始化完成")
except Exception as e:
logger.error("❌ 环境接口初始化失败: %s", str(e))
logger.error(traceback.format_exc())
return
# 创建关闭处理函数
def shutdown_handler():
"""系统关闭处理函数"""
logger.info("🛑 收到关闭命令,开始关闭系统...")
# 先停止命令监听器
if 'command_listener' in locals() and command_listener.running:
command_listener.stop()
# 然后停止环境接口
environment_interface.stop()
logger.info("✅ 系统已完全关闭")
sys.exit(0)
# 自定义命令处理器 - 统一处理所有命令
def command_handler(command: str) -> dict:
"""处理用户命令 - 返回字典格式响应"""
try:
logger.info(f"🔄 处理命令: {command}")
# 命令路由
cmd_lower = command.lower().strip()
# 1. 系统命令处理
if cmd_lower in ["exit", "quit"]:
return {
"status": "success",
"message": "接收到退出命令,正在关闭系统...",
"action": "shutdown"
}
# 2. 其他命令转发给认知系统
logger.info("转发命令给认知系统: %s", command)
response = cognitive_system.process_command(command)
# 格式化输出响应
return {
"status": "success",
"content": response
}
except Exception as e:
logger.error(f"❌ 命令处理错误: {str(e)}", exc_info=True)
return {
"status": "error",
"error": f"处理命令时出错: {str(e)}",
"command": command
}
# 启动命令监听器 - 作为唯一的输入来源
try:
command_listener = start_command_listener(
command_handler=command_handler,
shutdown_handler=shutdown_handler
)
logger.info("✅ 命令监听器已启动")
except Exception as e:
logger.error("❌ 命令监听器启动失败: %s", str(e))
logger.error(traceback.format_exc())
return
logger.info("🌟 系统准备就绪! 输入命令控制模式 (输入 'help' 查看可用命令)")
# 主循环:处理命令监听器的输出(修复卡死问题)
try:
heartbeat_interval = 5 # 心跳间隔(秒)
last_heartbeat = time.time()
while True:
# 短暂休眠以避免CPU占用过高
time.sleep(0.1)
# 添加心跳日志避免卡死
current_time = time.time()
if current_time - last_heartbeat > heartbeat_interval:
logger.debug("💗 系统心跳检测 - 运行中...")
last_heartbeat = current_time
# 检查是否收到退出信号
if not command_listener.running:
logger.info("🛑 命令监听器已停止")
break
except KeyboardInterrupt:
logger.info("🛑 收到中断信号,关闭系统...")
shutdown_handler()
except Exception as e:
logger.error("❌ 主循环发生未预期错误: %s", str(e))
logger.error(traceback.format_exc())
shutdown_handler()
if __name__ == "__main__":
main()
# E:\AI_System\core\config.py
import os
import sys
import json
import re
import logging
from pathlib import Path
from dotenv import load_dotenv
from prettytable import PrettyTable
# 设置日志
logger = logging.getLogger('CoreConfig')
logger.setLevel(logging.INFO)
# 确保有基本日志处理器
if not logger.handlers:
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
class CoreConfig:
"""核心配置系统 - 增强版:支持变量解析和环境继承"""
_instance = None
_config = {}
@classmethod
def get_instance(cls):
"""获取单例实例"""
if cls._instance is None:
cls._instance = cls()
return cls._instance
def __init__(self):
"""初始化配置系统"""
# 设置基础目录
self.base_dir = Path(__file__).resolve().parent.parent
self.env_prefix = "AI_SYSTEM"
# 敏感字段列表(在日志和输出中掩码)
self.sensitive_fields = ["DB_PASSWORD", "SECRET_KEY", "API_KEY", "ACCESS_TOKEN"]
# 路径类型配置键
self.path_keys = [
"LOG_DIR", "CONFIG_DIR", "MODEL_CACHE_DIR", "MODEL_BASE_PATH",
"WEB_UI_DIR", "AGENT_DIR", "CORE_DIR", "MODELS_DIR", "LOGS_DIR",
"TEXT_BASE", "TEXT_CHAT", "MULTIMODAL", "IMAGE_GEN", "YI_VL", "STABLE_DIFFUSION"
]
# 加载配置
self._load_config()
logger.info("✅ 配置系统初始化完成")
# === 变量解析功能增强 ===
VARIABLE_PATTERN = re.compile(r'\$\{([^}]+)\}')
def _resolve_variables(self, data=None, depth=0):
"""递归解析配置中的变量引用,防止无限递归"""
MAX_DEPTH = 5
if depth > MAX_DEPTH:
logger.warning("⚠️ 变量解析达到最大深度限制,可能存在循环引用")
return data
if data is None:
data = self._config
if isinstance(data, dict):
for key, value in data.items():
if isinstance(value, str):
data[key] = self._replace_vars(value, depth + 1)
elif isinstance(value, (dict, list)):
self._resolve_variables(value, depth + 1)
elif isinstance(data, list):
for i, item in enumerate(data):
if isinstance(item, str):
data[i] = self._replace_vars(item, depth + 1)
elif isinstance(item, (dict, list)):
self._resolve_variables(item, depth + 1)
return data
def _replace_vars(self, value: str, depth: int) -> str:
"""替换单个字符串中的变量引用(增强版)"""
def replace_match(match):
var_expression = match.group(1).strip()
# 处理默认值语法:${VAR|default}
if '|' in var_expression:
var_name, default_val = var_expression.split('|', 1)
var_name = var_name.strip()
default_val = default_val.strip()
else:
var_name = var_expression
default_val = None
# 处理环境变量语法:ENV:VAR
if var_name.startswith('ENV:'):
env_var = var_name[4:]
return os.environ.get(env_var, default_val or '')
# 处理配置变量
try:
return str(self.get(var_name, default_val))
except KeyError:
return default_val or ''
return self.VARIABLE_PATTERN.sub(replace_match, value)
# === 分页打印功能增强 ===
def print_long_text(self, text, max_line_length=120, lines_per_page=20):
"""分页打印长文本(支持宽屏自适应)"""
lines = text.split('\n')
page = 1
total_pages = (len(lines) + lines_per_page - 1) // lines_per_page
# 获取终端宽度
try:
columns = os.get_terminal_size().columns
max_line_length = min(max_line_length, columns - 1)
except OSError:
pass # 无法获取终端宽度,使用默认值
for i, line in enumerate(lines):
# 长行自动换行
wrapped_lines = []
while len(line) > max_line_length:
# 查找最后一个空格位置进行优雅换行
space_pos = line.rfind(' ', 0, max_line_length)
if space_pos == -1:
space_pos = max_line_length
wrapped_lines.append(line[:space_pos])
line = line[space_pos + 1:]
wrapped_lines.append(line)
for wrapped_line in wrapped_lines:
print(wrapped_line)
# 分页控制
if (i + 1) % lines_per_page == 0 and (i + 1) < len(lines):
input(f"\n--- 第 {page}/{total_pages} 页 (按Enter继续) ---")
page += 1
print(f"\n--- 结束 (共 {page} 页) ---")
# === 路径验证增强 ===
def _validate_paths(self):
"""验证并创建缺失的关键路径(增强错误处理)"""
# 1. 验证目录路径
dir_paths = [
self.get("LOG_DIR"),
self.get("CONFIG_DIR"),
self.get("MODEL_CACHE_DIR"),
self.get("MODEL_BASE_PATH"),
self.get("WEB_UI_DIR"),
self.get("AGENT_DIR"),
self.get("DIRECTORIES.PROJECT_ROOT")
]
for path in dir_paths:
if path:
try:
resolved_path = Path(path)
if not resolved_path.exists():
resolved_path.mkdir(parents=True, exist_ok=True)
logger.info(f"📁 创建缺失目录: {resolved_path}")
except Exception as e:
logger.error(f"❌ 创建目录失败: {path} - {str(e)}")
# 2. 验证模型路径
model_paths = self.get("MODEL_PATHS", {})
for model_type, path in model_paths.items():
if path:
try:
resolved_path = Path(path)
if not resolved_path.exists():
resolved_path.mkdir(parents=True, exist_ok=True)
logger.info(f"📁 创建缺失模型路径: {resolved_path}")
except Exception as e:
logger.error(f"❌ 创建模型路径失败: {path} - {str(e)}")
# === 配置加载顺序优化 ===
def _load_config(self):
"""加载所有配置(优化加载顺序)"""
try:
# 1. 设置默认值
self._set_defaults()
# 2. 初始环境变量加载(仅用于确定环境)
self._load_environment(initial=True)
# 3. 加载配置文件(根据环境)
self._load_config_files()
# 4. 完整环境变量加载(覆盖配置文件)
self._load_environment()
# 5. 解析变量引用
self._resolve_variables()
logger.info("🔄 完成配置变量解析")
# 6. 验证关键路径
self._validate_paths()
# 7. 验证模型路径
self.validate_model_paths()
except Exception as e:
logger.critical(f"🔥 配置加载失败: {str(e)}", exc_info=True)
raise RuntimeError(f"配置系统初始化失败: {str(e)}") from e
# === 环境变量加载优化 ===
def _load_environment(self, initial=False):
"""加载环境变量(支持初始加载)"""
# 初始加载时只加载基本环境变量
if initial:
# 加载.env文件
env_file = self.base_dir / '.env'
if env_file.exists():
try:
load_dotenv(dotenv_path=str(env_file), override=True)
logger.info(f"🌐 从 {env_file} 加载环境变量")
except Exception as e:
logger.error(f"❌ 加载环境变量失败: {str(e)}")
return
# 完整环境变量加载
for key, value in os.environ.items():
# 检查是否以环境前缀开头
if key.startswith(self.env_prefix + "_"):
# 去掉前缀
config_key = key[len(self.env_prefix) + 1:]
# 处理嵌套结构
if "__" in config_key:
config_key = config_key.replace("__", ".")
elif "_" in config_key and config_key.count("_") > 1:
parts = config_key.split("_")
config_key = ".".join(parts[:-1]) + "." + parts[-1]
# 处理特殊值
if isinstance(value, str):
if value.lower() in ['true', 'false']:
value = value.lower() == 'true'
elif value.isdigit():
value = int(value)
elif value.replace('.', '', 1).isdigit() and value.count('.') < 2:
try:
value = float(value)
except ValueError:
pass # 保持字符串
# 设置配置值
self._set_nested_config(config_key, value)
self._log_sensitive_value(key, value)
elif key in self._config: # 处理非前缀的顶级配置
# 处理特殊值
if value.lower() in ['true', 'false']:
value = value.lower() == 'true'
elif value.isdigit():
value = int(value)
elif value.replace('.', '', 1).isdigit() and value.count('.') < 2:
try:
value = float(value)
except ValueError:
pass # 保持字符串
self._config[key] = value
logger.info(f"🔄 环境变量覆盖: {key}={self._mask_sensitive_value(key, value)}")
# 路径自动修正
self._auto_correct_paths()
def _auto_correct_paths(self):
"""自动修正所有路径配置"""
for key_path in self.list_config_keys():
value = self.get(key_path)
if value and isinstance(value, str):
if any(path_key in key_path for path_key in self.path_keys):
corrected = value.replace('\\', '/').rstrip('/')
if corrected != value:
self._set_nested_config(key_path, corrected)
logger.info(f"🔄 自动修正路径: {key_path}={self._mask_sensitive_value(key_path, corrected)}")
# === 配置访问增强 ===
def list_config_keys(self, prefix="", separator="."):
"""递归列出所有配置键"""
keys = []
def explore(data, current_path):
if isinstance(data, dict):
for key, value in data.items():
new_path = f"{current_path}{separator}{key}" if current_path else key
if isinstance(value, dict):
explore(value, new_path)
else:
keys.append(new_path)
explore(self._config, prefix)
return keys
def get(self, key_path, default=None, sep="."):
"""获取配置值(支持点分路径)"""
keys = key_path.split(sep)
value = self._config
for key in keys:
key = key.upper()
if isinstance(value, dict) and key in value:
value = value[key]
else:
return default
return value
def __getattr__(self, name):
"""允许通过属性方式访问配置项"""
if name in self._config:
return self._config[name]
# 尝试访问嵌套配置
if '.' in name:
return self.get(name)
# 提供一些常用配置的默认值
if name == "DEFAULT_MODEL":
return self.get("MODEL_PATHS.TEXT_BASE", "")
# 记录警告而不是直接抛出异常
logger.warning(f"访问未定义的配置项: {name}")
return None
# === 配置持久化 ===
def save_config(self, filename="local.json"):
"""保存当前配置到文件"""
config_dir = Path(self.get("CONFIG_DIR", self.base_dir / "config"))
config_dir.mkdir(parents=True, exist_ok=True)
config_file = config_dir / filename
try:
with open(config_file, 'w', encoding='utf-8') as f:
json.dump(self._config, f, indent=2, ensure_ascii=False)
logger.info(f"💾 配置已保存到 {config_file}")
return True
except Exception as e:
logger.error(f"❌ 保存配置失败: {str(e)}")
return False
# === 默认配置 ===
def _set_defaults(self):
"""设置默认配置值(简化版)"""
defaults = {
"LOG_DIR": str(self.base_dir / "logs"),
"CONFIG_DIR": str(self.base_dir / "config"),
"MODEL_CACHE_DIR": str(self.base_dir / "model_cache"),
"AGENT_NAME": "小蓝",
"MODEL_BASE_PATH": "E:/AI_Models",
"MODEL_PATHS": {
"TEXT_BASE": "E:/AI_Models/Qwen2-7B",
"TEXT_CHAT": "E:/AI_Models/deepseek-7b-chat",
"MULTIMODAL": "E:/AI_Models/deepseek-vl2",
},
"NETWORK": {
"HOST": "0.0.0.0",
"FLASK_PORT": 8000,
},
"DIRECTORIES": {
"PROJECT_ROOT": str(self.base_dir)
}
}
self._config = defaults
logger.debug("设置默认配置值")
# === 测试工具 ===
def generate_sample_env(self):
"""生成示例环境文件"""
content = [
"# AI_SYSTEM 环境变量配置",
"# 注意:变量名使用双下划线表示嵌套路径",
"",
f"# 系统设置",
f"{self.env_prefix}_AGENT_NAME=小蓝助手",
f"{self.env_prefix}_MAX_WORKERS=8",
"",
f"# 数据库设置",
f"{self.env_prefix}_DATABASE__DB_HOST=db.example.com",
f"{self.env_prefix}_DATABASE__DB_PORT=5432",
"",
f"# 路径设置",
f"{self.env_prefix}_MODEL_BASE_PATH=/opt/models",
f"{self.env_prefix}_MODEL_PATHS__TEXT_BASE=/opt/models/qwen"
]
return "\n".join(content)
# === 其他方法保持不变 ===
# [其余方法如_load_config_files, _merge_config, validate_model_paths等保持不变]
# 为节省空间,这里省略重复代码,实际实现中应保留完整
# 创建全局配置实例
config = CoreConfig.get_instance()
# 测试代码
if __name__ == "__main__":
# 设置详细日志
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
print("=" * 50)
print("配置系统增强版测试")
print("=" * 50)
# 获取配置实例
config = CoreConfig.get_instance()
# 测试变量解析
config._config["TEST"] = {
"PATH": "/home/${USER}",
"DB_URL": "jdbc:postgresql://${DATABASE.DB_HOST}:${DATABASE.DB_PORT}/${DATABASE.DB_NAME}",
"DEFAULT": "${NOT_EXIST|default_value}"
}
config._resolve_variables()
print("\n变量解析测试结果:")
print(f"PATH: {config.TEST['PATH']}")
print(f"DB_URL: {config.TEST['DB_URL']}")
print(f"DEFAULT: {config.TEST['DEFAULT']}")
# 测试分页打印
long_text = "这是一个测试长文本\n" + "\n".join([f"行 {i}: 这是测试内容" * 20 for i in range(1, 51)])
print("\n分页打印测试(按Enter翻页):")
config.print_long_text(long_text, lines_per_page=5)
# 生成示例环境文件
print("\n示例环境文件内容:")
print(config.generate_sample_env())
print("\n测试完成!")
最新发布