models __str__(self)和__unicode__(self)

本文介绍了Python中__str__和__unicode__方法的用途及区别,包括它们如何在Python 2和Python 3中工作,特别是在Django框架和Flask应用中的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Python __str__(self)和__unicode__(self)

官方文档:https://docs.python.org/2.7/reference/datamodel.html?highlight=__mro__

python3中使用

object.__str__(self)

Called by the str() built-in function and by the print statement to compute the “informal” string representation of an object. This differs from __repr__() in that it does not have to be a valid Python expression: a more convenient or concise representation may be used instead. The return value must be a string object.

【译文】通过内嵌方法str()调用,并通过print语句计算对象的“非正式”字符串表示。这跟__repr__()的区别在于,它不需要是一个合法的Python表达式:可以用一种更便捷或简明的表现方式。返回类型必须是一个string对象。

 

python2中使用

object.__unicode__(self)

Called to implement unicode() built-in; should return a Unicode object. When this method is not defined, string conversion is attempted, and the result of string conversion is converted to Unicode using the system default encoding.

【译文】实现unicode()内嵌函数;应该返回Unicode对象。当没有定义这个方法时,取而代之的是string转换,转换的结果是用系统默认编码转化为Unicode。

 

============以下内容翻译自这里==============

__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。Django在许多地方使用str(obj)(或者相关方法,unicode(obj)——见下文),比如说在Django管理站点加载一个对象时显示它的值或者作为对象的显示值插入模板中。因此,我们应该总是返回一个友好的,用户可读的字符串作为对象的__str__。尽管这不是必须的,但还是建议这么做。例如:

复制代码

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)

    def __str__(self):
        # Note use of django.utils.encoding.smart_str() here because
        # first_name and last_name will be unicode strings.
        return smart_str('%s %s' % (self.first_name, self.last_name)

__unicode__

复制代码

__unicode__()方法是在一个对象上调用unicode()时被调用的。因为Django的数据库后端会返回Unicode字符串给model属性,所以我们通常会给自己的model写一个__unicode__()方法。前面的例子也可以更简单地写成:

复制代码

class Person(models.Model):  
     first_name = models.CharField(max_length=50)  
     last_name = models.CharField(max_length=50)  
  
     def __unicode__(self):  
         return u'%s %s' % (self.first_name, self.last_name)

复制代码

如果定义了__unicode__()方法但是没有定义__str__()方法,Django会自动提供一个__str__()方法调用__unicode__()方法,然后把结果转换为UTF-8编码的字符串对象。在实际开发中,建议:只定义__unicode__()方法,需要的话让Django来处理字符串对象的转换。

============翻译结束==========================

在Flask里,定义一个Article类的数据模型相应的写法可以写成:

复制代码

class Article(db.Document):
    Title = db.StringField(max_length=255, required=True)
    SegTitle = db.StringField(max_length=255)
    Url = db.StringField(max_length=255, required=True)
    Id = db.StringField(max_length=255, required=True)
    Summary = db.StringField(max_length=255)
    Content = db.StringField()
    SegContent = db.StringField()
    Tags = db.ListField(db.EmbeddedDocumentField(Tag))
    StrTags = db.ListField(db.StringField(max_length=30))
    LabeledTags = db.ListField(db.StringField(max_length=30))
    CrawledDate = db.DateTimeField()
    PostDate = db.StringField()
    Source = db.StringField()
    OriginalSource = db.StringField()

    @property
    def post_type(self):
        return self.__class__.__name__

    def __unicode__(self):
        return self.Title

    meta = {
        'allow_inheritance': False
    }

 

转载:https://www.cnblogs.com/urwlcm/p/4316536.html

# E:\AI_System\core\config.py import os import yaml from pathlib import Path from typing import Any, Dict, Optional, Union import logging from .exceptions import ConfigError class ConfigManager: """配置管理系统,支持环境变量、配置文件默认值""" def __init__(self, base_dir: str, env_prefix: str = "AI_SYSTEM_"): """ 初始化配置管理器 Args: base_dir: 基础目录路径 env_prefix: 环境变量前缀 """ self.base_dir = Path(base_dir) self.env_prefix = env_prefix self.config = {} self.logger = logging.getLogger("ConfigManager") # 创建必要目录 self._create_necessary_dirs() # 加载配置 self._load_config() def _create_necessary_dirs(self): """创建系统必需的目录结构""" required_dirs = [ self.base_dir / "data", self.base_dir / "logs", self.base_dir / "config", self.base_dir / "models", self.base_dir / "cache" ] for dir_path in required_dirs: dir_path.mkdir(parents=True, exist_ok=True) self.logger.info(f"确保目录存在: {dir_path}") def _load_config(self): """加载配置 - 优先级:环境变量 > 配置文件 > 默认值""" # 1. 加载默认配置 self.config = self._get_default_config() # 2. 加载配置文件 config_path = self.base_dir / "config" / "system_config.yaml" if config_path.exists(): try: with open(config_path, 'r', encoding='utf-8') as f: file_config = yaml.safe_load(f) or {} self._merge_config(file_config) self.logger.info(f"从文件加载配置: {config_path}") except Exception as e: self.logger.error(f"配置文件解析错误: {str(e)}") raise ConfigError(f"配置文件解析错误: {str(e)}") else: self.logger.warning(f"配置文件不存在: {config_path}") # 3. 加载环境变量 self._load_env_vars() # 4. 验证必需配置项 self._validate_required_config() def _get_default_config(self) -> Dict[str, Any]: """获取默认配置""" return { # 系统核心配置 "SYSTEM_NAME": "AI_System", "LOG_LEVEL": "INFO", "LOG_DIR": str(self.base_dir / "logs"), # 线程进程配置 "MAX_WORKERS": max(1, os.cpu_count() * 2), # 默认CPU核心数*2 "MAX_THREADS_PER_WORKER": 10, # 网络配置 "API_HOST": "0.0.0.0", "API_PORT": 5000, "API_TIMEOUT": 30, # 资源限制 "MEMORY_LIMIT_MB": 4096, "CPU_LIMIT_PERCENT": 80, # 智能体配置 "AGENT_TYPE": "autonomous", "AGENT_UPDATE_INTERVAL": 60, # 秒 "AGENT_MAX_TASKS": 100, # 数据库配置 "DB_PATH": str(self.base_dir / "data" / "system.db"), "DB_BACKUP_INTERVAL": 3600, # 秒 # 调试配置 "DEBUG_MODE": False, "PROFILE_PERFORMANCE": False } def _merge_config(self, new_config: Dict[str, Any]): """合并配置(递归更新字典)""" def merge_dict(base: Dict, update: Dict): for key, value in update.items(): if isinstance(value, dict) and key in base and isinstance(base[key], dict): merge_dict(base[key], value) else: base[key] = value merge_dict(self.config, new_config) def _load_env_vars(self): """从环境变量加载配置""" for key, value in self.config.items(): env_key = f"{self.env_prefix}{key}" env_value = os.environ.get(env_key) if env_value is not None: # 尝试转换类型 if isinstance(value, bool): self.config[key] = env_value.lower() in ('true', '1', 'yes') elif isinstance(value, int): try: self.config[key] = int(env_value) except ValueError: self.logger.warning(f"环境变量 {env_key} 无法转换为整数: {env_value}") elif isinstance(value, float): try: self.config[key] = float(env_value) except ValueError: self.logger.warning(f"环境变量 {env_key} 无法转换为浮点数: {env_value}") else: self.config[key] = env_value self.logger.info(f"从环境变量加载: {key}={self.config[key]}") def _validate_required_config(self): """验证必需配置项是否存在""" required_keys = [ "MAX_WORKERS", "API_HOST", "API_PORT", "DB_PATH", "LOG_DIR", "LOG_LEVEL" ] missing_keys = [key for key in required_keys if key not in self.config] if missing_keys: error_msg = f"缺少必需配置项: {', '.join(missing_keys)}" self.logger.error(error_msg) raise ConfigError(error_msg) def get(self, key: str, default: Optional[Any] = None) -> Any: """获取配置值""" return self.config.get(key, default) def __getattr__(self, key: str) -> Any: """通过属性访问配置""" if key in self.config: return self.config[key] raise AttributeError(f"配置项 '{key}' 不存在") def __getitem__(self, key: str) -> Any: """通过索引访问配置""" if key in self.config: return self.config[key] raise KeyError(f"配置项 '{key}' 不存在") def __contains__(self, key: str) -> bool: """检查配置项是否存在""" return key in self.config def save_config(self, file_path: Optional[Union[str, Path]] = None): """保存当前配置到文件""" if file_path is None: file_path = self.base_dir / "config" / "system_config.yaml" file_path = Path(file_path) file_path.parent.mkdir(parents=True, exist_ok=True) try: with open(file_path, 'w', encoding='utf-8') as f: yaml.safe_dump(self.config, f, sort_keys=False, allow_unicode=True) self.logger.info(f"配置已保存到: {file_path}") return True except Exception as e: self.logger.error(f"保存配置失败: {str(e)}") return False def reload(self): """重新加载配置""" self.logger.info("重新加载配置...") self._load_config() self.logger.info("配置重新加载完成") def print_config(self, show_all: bool = False): """打印当前配置(安全地隐藏敏感信息)""" sensitive_keys = ["API_KEY", "DB_PASSWORD", "SECRET_KEY"] print("\n当前系统配置:") for key, value in self.config.items(): if key in sensitive_keys and not show_all: print(f"{key}: {'*' * 8}") else: print(f"{key}: {value}") print() # 全局配置实例 _system_config = None def get_config(base_dir: Optional[str] = None, env_prefix: str = "AI_SYSTEM_") -> ConfigManager: """获取全局配置实例(单例模式)""" global _system_config if _system_config is None: if base_dir is None: # 尝试从环境变量获取基础目录 base_dir = os.environ.get(f"{env_prefix}BASE_DIR", os.getcwd()) _system_config = ConfigManager(base_dir=base_dir, env_prefix=env_prefix) return _system_config # 示例使用 if __name__ == "__main__": # 初始化配置 config = get_config(base_dir=os.getcwd()) # 访问配置 print("API端口:", config.API_PORT) print("最大工作线程数:", config.MAX_WORKERS) # 打印配置 config.print_config() # 保存配置 config.save_config() # 测试代码 def test_config_system(): # 设置测试环境变量 os.environ["AI_SYSTEM_API_PORT"] = "8080" os.environ["AI_SYSTEM_DEBUG_MODE"] = "true" # 创建临时目录 import tempfile with tempfile.TemporaryDirectory() as tmpdir: # 创建配置文件 config_path = Path(tmpdir) / "config" / "system_config.yaml" config_path.parent.mkdir(parents=True, exist_ok=True) with open(config_path, 'w') as f: f.write("MAX_WORKERS: 16\nLOG_LEVEL: DEBUG") # 初始化配置 config = ConfigManager(base_dir=tmpdir, env_prefix="AI_SYSTEM_") # 验证配置 assert config.API_PORT == 8080 # 来自环境变量 assert config.MAX_WORKERS == 16 # 来自配置文件 assert config.DEBUG_MODE is True # 环境变量转换 assert config.LOG_LEVEL == "DEBUG" # 来自配置文件 # 测试默认值 assert config.MEMORY_LIMIT_MB == 4096 # 默认值 print("所有测试通过!") if __name__ == "__main__": test_config_system() # E:\AI_System\core\config.py import os import yaml from pathlib import Path from typing import Any, Dict, Optional, Union import logging from .exceptions import ConfigError class ConfigManager: """配置管理系统,支持环境变量、配置文件默认值""" def __init__(self, base_dir: str, env_prefix: str = "AI_SYSTEM_"): """ 初始化配置管理器 Args: base_dir: 基础目录路径 env_prefix: 环境变量前缀 """ self.base_dir = Path(base_dir) self.env_prefix = env_prefix self.config = {} self.logger = logging.getLogger("ConfigManager") # 创建必要目录 self._create_necessary_dirs() # 加载配置 self._load_config() def _create_necessary_dirs(self): """创建系统必需的目录结构""" required_dirs = [ self.base_dir / "data", self.base_dir / "logs", self.base_dir / "config", self.base_dir / "models", self.base_dir / "cache" ] for dir_path in required_dirs: dir_path.mkdir(parents=True, exist_ok=True) self.logger.info(f"确保目录存在: {dir_path}") def _load_config(self): """加载配置 - 优先级:环境变量 > 配置文件 > 默认值""" # 1. 加载默认配置 self.config = self._get_default_config() # 2. 加载配置文件 config_path = self.base_dir / "config" / "system_config.yaml" if config_path.exists(): try: with open(config_path, 'r', encoding='utf-8') as f: file_config = yaml.safe_load(f) or {} self._merge_config(file_config) self.logger.info(f"从文件加载配置: {config_path}") except Exception as e: self.logger.error(f"配置文件解析错误: {str(e)}") raise ConfigError(f"配置文件解析错误: {str(e)}") else: self.logger.warning(f"配置文件不存在: {config_path}") # 3. 加载环境变量 self._load_env_vars() # 4. 验证必需配置项 self._validate_required_config() def _get_default_config(self) -> Dict[str, Any]: """获取默认配置""" return { # 系统核心配置 "SYSTEM_NAME": "AI_System", "LOG_LEVEL": "INFO", "LOG_DIR": str(self.base_dir / "logs"), # 线程进程配置 "MAX_WORKERS": max(1, os.cpu_count() * 2), # 默认CPU核心数*2 "MAX_THREADS_PER_WORKER": 10, # 网络配置 "API_HOST": "0.0.0.0", "API_PORT": 5000, "API_TIMEOUT": 30, # 资源限制 "MEMORY_LIMIT_MB": 4096, "CPU_LIMIT_PERCENT": 80, # 智能体配置 "AGENT_TYPE": "autonomous", "AGENT_UPDATE_INTERVAL": 60, # 秒 "AGENT_MAX_TASKS": 100, # 数据库配置 "DB_PATH": str(self.base_dir / "data" / "system.db"), "DB_BACKUP_INTERVAL": 3600, # 秒 # 调试配置 "DEBUG_MODE": False, "PROFILE_PERFORMANCE": False } def _merge_config(self, new_config: Dict[str, Any]): """合并配置(递归更新字典)""" def merge_dict(base: Dict, update: Dict): for key, value in update.items(): if isinstance(value, dict) and key in base and isinstance(base[key], dict): merge_dict(base[key], value) else: base[key] = value merge_dict(self.config, new_config) def _load_env_vars(self): """从环境变量加载配置""" for key, value in self.config.items(): env_key = f"{self.env_prefix}{key}" env_value = os.environ.get(env_key) if env_value is not None: # 尝试转换类型 if isinstance(value, bool): self.config[key] = env_value.lower() in ('true', '1', 'yes') elif isinstance(value, int): try: self.config[key] = int(env_value) except ValueError: self.logger.warning(f"环境变量 {env_key} 无法转换为整数: {env_value}") elif isinstance(value, float): try: self.config[key] = float(env_value) except ValueError: self.logger.warning(f"环境变量 {env_key} 无法转换为浮点数: {env_value}") else: self.config[key] = env_value self.logger.info(f"从环境变量加载: {key}={self.config[key]}") def _validate_required_config(self): """验证必需配置项是否存在""" required_keys = [ "MAX_WORKERS", "API_HOST", "API_PORT", "DB_PATH", "LOG_DIR", "LOG_LEVEL" ] missing_keys = [key for key in required_keys if key not in self.config] if missing_keys: error_msg = f"缺少必需配置项: {', '.join(missing_keys)}" self.logger.error(error_msg) raise ConfigError(error_msg) def get(self, key: str, default: Optional[Any] = None) -> Any: """获取配置值""" return self.config.get(key, default) def __getattr__(self, key: str) -> Any: """通过属性访问配置""" if key in self.config: return self.config[key] raise AttributeError(f"配置项 '{key}' 不存在") def __getitem__(self, key: str) -> Any: """通过索引访问配置""" if key in self.config: return self.config[key] raise KeyError(f"配置项 '{key}' 不存在") def __contains__(self, key: str) -> bool: """检查配置项是否存在""" return key in self.config def save_config(self, file_path: Optional[Union[str, Path]] = None): """保存当前配置到文件""" if file_path is None: file_path = self.base_dir / "config" / "system_config.yaml" file_path = Path(file_path) file_path.parent.mkdir(parents=True, exist_ok=True) try: with open(file_path, 'w', encoding='utf-8') as f: yaml.safe_dump(self.config, f, sort_keys=False, allow_unicode=True) self.logger.info(f"配置已保存到: {file_path}") return True except Exception as e: self.logger.error(f"保存配置失败: {str(e)}") return False def reload(self): """重新加载配置""" self.logger.info("重新加载配置...") self._load_config() self.logger.info("配置重新加载完成") def print_config(self, show_all: bool = False): """打印当前配置(安全地隐藏敏感信息)""" sensitive_keys = ["API_KEY", "DB_PASSWORD", "SECRET_KEY"] print("\n当前系统配置:") for key, value in self.config.items(): if key in sensitive_keys and not show_all: print(f"{key}: {'*' * 8}") else: print(f"{key}: {value}") print() # 全局配置实例 _system_config = None def get_config(base_dir: Optional[str] = None, env_prefix: str = "AI_SYSTEM_") -> ConfigManager: """获取全局配置实例(单例模式)""" global _system_config if _system_config is None: if base_dir is None: # 尝试从环境变量获取基础目录 base_dir = os.environ.get(f"{env_prefix}BASE_DIR", os.getcwd()) _system_config = ConfigManager(base_dir=base_dir, env_prefix=env_prefix) return _system_config # 示例使用 if __name__ == "__main__": # 初始化配置 config = get_config(base_dir=os.getcwd()) # 访问配置 print("API端口:", config.API_PORT) print("最大工作线程数:", config.MAX_WORKERS) # 打印配置 config.print_config() # 保存配置 config.save_config() # 测试代码 def test_config_system(): # 设置测试环境变量 os.environ["AI_SYSTEM_API_PORT"] = "8080" os.environ["AI_SYSTEM_DEBUG_MODE"] = "true" # 创建临时目录 import tempfile with tempfile.TemporaryDirectory() as tmpdir: # 创建配置文件 config_path = Path(tmpdir) / "config" / "system_config.yaml" config_path.parent.mkdir(parents=True, exist_ok=True) with open(config_path, 'w') as f: f.write("MAX_WORKERS: 16\nLOG_LEVEL: DEBUG") # 初始化配置 config = ConfigManager(base_dir=tmpdir, env_prefix="AI_SYSTEM_") # 验证配置 assert config.API_PORT == 8080 # 来自环境变量 assert config.MAX_WORKERS == 16 # 来自配置文件 assert config.DEBUG_MODE is True # 环境变量转换 assert config.LOG_LEVEL == "DEBUG" # 来自配置文件 # 测试默认值 assert config.MEMORY_LIMIT_MB == 4096 # 默认值 print("所有测试通过!") if __name__ == "__main__": test_config_system() Microsoft Windows [版本 10.0.22631.2861] (c) Microsoft Corporation。保留所有权利。 C:\Users\Administrator>cd /d E:\AI_System\web_ui E:\AI_System\web_ui>python server.py Traceback (most recent call last): File "E:\AI_System\web_ui\server.py", line 49, in <module> from core.config import CoreConfig as SystemConfig File "E:\AI_System\core\__init__.py", line 5, in <module> from .config import CoreConfig File "E:\AI_System\core\config.py", line 7, in <module> from .exceptions import ConfigError ImportError: cannot import name 'ConfigError' from 'core.exceptions' (E:\AI_System\core\exceptions.py) E:\AI_System\web_ui>
最新发布
08-13
# E:\AI_System\core\config.py import os import json import logging from pathlib import Path from typing import Dict, Any, Optional, Union import hashlib import sys class CoreConfig: """核心配置管理器 - Windows兼容版""" def __init__(self, config_path: Union[str, Path] = None, env_prefix: str = "", default_config: Dict = None): # 确定基础目录 - 修复AttributeError self.BASE_DIR = self._determine_base_dir() # 初始化参数 self.config_path = Path(config_path) if config_path else None self.env_prefix = env_prefix self.default_config = default_config or {} self._config = { 'BASE_DIR': str(self.BASE_DIR), # 确保BASE_DIR在配置中 'LOG_DIR': str(self.BASE_DIR / "logs"), 'CONFIG_DIR': str(self.BASE_DIR / "config"), 'CACHE_DIR': str(self.BASE_DIR / "cache"), 'DATA_DIR': str(self.BASE_DIR / "data"), 'MODEL_DIR': str(self.BASE_DIR / "models"), } self._last_hash = None # 设置安全的日志器 - 避免Unicode错误 self.logger = self._create_safe_logger() # 初始化配置 self._initialize() def _determine_base_dir(self) -> Path: """确定基础目录""" # 1. 尝试从环境变量获取 base_dir_env = os.getenv(f"{self.env_prefix}BASE_DIR") if base_dir_env: return Path(base_dir_env).resolve() # 2. 尝试基于当前文件位置计算 try: return Path(__file__).parent.parent.resolve() except NameError: # 在交互式环境中运行时 return Path.cwd().resolve() # 3. 默认使用当前工作目录 return Path.cwd().resolve() def _create_safe_logger(self) -> logging.Logger: """创建安全的日志器(Windows兼容)""" logger = logging.getLogger('CoreConfig') logger.setLevel(logging.INFO) # 创建安全的控制台处理器 class SafeConsoleHandler(logging.StreamHandler): def emit(self, record): try: msg = self.format(record) # 替换或移除Windows不支持的Unicode字符 safe_msg = msg.encode('utf-8', errors='replace').decode('utf-8') stream = self.stream stream.write(safe_msg + self.terminator) self.flush() except Exception: self.handleError(record) console_handler = SafeConsoleHandler() console_handler.setFormatter(logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' )) logger.addHandler(console_handler) return logger def _initialize(self): """初始化配置""" self.logger.info("初始化配置管理器 | 环境前缀: %s | 基础目录: %s", self.env_prefix, self.BASE_DIR) # 加载环境变量 self._load_environment() # 加载配置文件 if self.config_path and self.config_path.exists(): self._load_config_file() elif self.config_path: self.logger.warning("配置文件不存在: %s", self.config_path) # 合并默认配置 self._merge_defaults() # 创建必要目录 self._create_directories() self.logger.info("配置加载完成 | 条目数: %d", len(self._config)) def _load_environment(self): """加载环境变量""" self.logger.info("加载环境变量...") # 加载系统环境变量 for key, value in os.environ.items(): if key.startswith(self.env_prefix): config_key = key[len(self.env_prefix):].lower() self._config[config_key] = value def _load_config_file(self): """加载配置文件""" file_type = self.config_path.suffix.lower() self.logger.info("加载配置文件: %s (类型: %s)", self.config_path, file_type[1:]) try: if file_type == '.json': with open(self.config_path, 'r', encoding='utf-8') as f: config_data = json.load(f) elif file_type in ('.yaml', '.yml'): import yaml with open(self.config_path, 'r', encoding='utf-8') as f: config_data = yaml.safe_load(f) elif file_type == '.ini': import configparser parser = configparser.ConfigParser() parser.read(self.config_path, encoding='utf-8') config_data = {} for section in parser.sections(): config_data[section] = dict(parser.items(section)) else: raise ValueError(f"不支持的配置文件类型: {file_type}") # 合并配置 self._deep_merge(self._config, config_data) self._last_hash = self._calculate_hash() except Exception as e: self.logger.error("加载配置文件失败: %s", str(e)) def _merge_defaults(self): """合并默认配置""" self.logger.info("合并默认配置...") self._deep_merge(self._config, self.default_config) def _deep_merge(self, target: Dict, source: Dict): """深度合并字典""" for key, value in source.items(): if (key in target and isinstance(target[key], dict) and isinstance(value, dict)): self._deep_merge(target[key], value) else: target[key] = value def _calculate_hash(self) -> str: """计算配置哈希值""" return hashlib.md5(json.dumps(self._config, sort_keys=True).encode()).hexdigest() def _create_directories(self): """创建配置中指定的目录""" dir_keys = ['log_dir', 'cache_dir', 'model_dir', 'data_dir'] for key in dir_keys: path = self.get_path(key) if not path.exists(): path.mkdir(parents=True, exist_ok=True) self.logger.info("创建目录: %s", path) def get(self, key: str, default: Any = None) -> Any: """安全获取配置值""" keys = key.split('.') current = self._config for k in keys: if isinstance(current, dict) and k in current: current = current[k] else: return default return current def get_path(self, key: str, default: Optional[Union[str, Path]] = None) -> Path: """获取路径配置项""" path_str = self.get(key, default) if path_str is None: return self.BASE_DIR / "default" # 安全回退 path = Path(path_str) if not path.is_absolute(): return self.BASE_DIR / path return path def __getattr__(self, name: str) -> Any: """支持点操作符访问配置项""" if name in self._config: return self._config[name] # 支持嵌套属性访问 parts = name.split('.') current = self._config for part in parts: if part in current: current = current[part] else: raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'") return current # E:\AI_System\web_ui\server.py import sys import os import time import logging import json import traceback import threading import platform import psutil import datetime from pathlib import Path from functools import wraps from concurrent.futures import ThreadPoolExecutor from logging.handlers import RotatingFileHandler # ========== 安全工具函数 ========== def safe_path(path_str: str) -> Path: """安全处理路径字符串,确保跨平台兼容性""" try: path = Path(path_str) if not path.is_absolute(): # 如果路径是相对的,基于项目根目录解析 base_dir = Path(__file__).parent.parent.resolve() return (base_dir / path).resolve() return path.resolve() except Exception as e: logging.error(f"路径解析错误: {path_str} - {str(e)}") return Path.cwd().resolve() class SafeConsoleHandler(logging.StreamHandler): """Windows安全的控制台日志处理器""" def emit(self, record): try: msg = self.format(record) # 安全处理Unicode字符 safe_msg = msg.encode('utf-8', errors='replace').decode('utf-8') stream = self.stream stream.write(safe_msg + self.terminator) self.flush() except Exception: self.handleError(record) # ========== 配置系统初始化 ========== # 添加核心模块路径 sys.path.insert(0, str(Path(__file__).parent.parent)) # 导入核心配置 from core.config import CoreConfig as SystemConfig # 全局配置实例 system_config = SystemConfig() # ========== 安全日志系统 ========== def setup_logger() -> logging.Logger: """配置并返回安全的日志系统""" logger = logging.getLogger('WebServer') # 清除所有现有处理器 for handler in logger.handlers[:]: logger.removeHandler(handler) # 安全获取配置项 debug_mode = system_config.get('DEBUG', False) log_level = logging.DEBUG if debug_mode else logging.INFO log_file = system_config.get('logging.file', 'logs/web_server.log') max_log_size = system_config.get('logging.max_size', 10) # MB backup_count = system_config.get('logging.backup_count', 5) # 设置日志级别 logger.setLevel(log_level) # 创建安全的控制台处理器 console_handler = SafeConsoleHandler() console_handler.setLevel(log_level) # 创建安全的文件处理器 try: # 确保日志目录存在 log_path = safe_path(log_file) log_path.parent.mkdir(parents=True, exist_ok=True) file_handler = RotatingFileHandler( filename=str(log_path), maxBytes=max_log_size * 1024 * 1024, backupCount=backup_count, encoding='utf-8' ) file_handler.setLevel(logging.DEBUG) except Exception as e: logging.error(f"无法创建文件日志处理器: {str(e)}") file_handler = logging.NullHandler() # 创建安全的格式化器 formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(process)d - %(thread)d - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) # 应用格式化器 console_handler.setFormatter(formatter) file_handler.setFormatter(formatter) # 添加处理器 logger.addHandler(console_handler) logger.addHandler(file_handler) # 设置根日志器 root_logger = logging.getLogger() root_logger.setLevel(log_level) for handler in root_logger.handlers[:]: root_logger.removeHandler(handler) root_logger.addHandler(console_handler) root_logger.addHandler(file_handler) # 配置第三方库日志器 third_party_loggers = ['werkzeug', 'engineio', 'socketio', 'urllib3'] for log_name in third_party_loggers: lib_logger = logging.getLogger(log_name) lib_logger.setLevel(logging.WARNING) lib_logger.propagate = False lib_logger.addHandler(file_handler) # 安全记录日志系统初始化完成 logger.info("日志系统初始化完成") logger.info("日志级别: %s", 'DEBUG' if debug_mode else 'INFO') logger.info("日志文件: %s", log_file) return logger # 初始化日志系统 logger = setup_logger() # ========== Flask应用初始化 ========== from flask import Flask, render_template, request, jsonify, send_from_directory, current_app # 安全获取模板静态文件路径 template_dir = safe_path(system_config.get('template_dir', Path(__file__).parent / 'templates')) static_dir = safe_path(system_config.get('static_dir', Path(__file__).parent / 'static')) app = Flask( __name__, template_folder=str(template_dir), static_folder=str(static_dir), static_url_path='/static' ) # 设置Flask调试模式 app.debug = system_config.get('DEBUG', False) app.secret_key = system_config.get('SECRET_KEY', 'default_secret_key') # ========== 环境管理器 ========== class EnvironmentManager: """跨平台兼容的环境管理器""" def __init__(self): self.state = { 'temperature': 22.5, 'humidity': 45.0, 'light_level': 75, 'objects': [], 'last_updated': datetime.datetime.now().isoformat() } self.healthy = True self.lock = threading.Lock() self.running = False self.update_thread = None self.observers = [] logger.info("环境管理器初始化成功") def start(self): """启动环境状态更新线程""" if self.running: return self.running = True self.update_thread = threading.Thread(target=self._update_loop, daemon=True) self.update_thread.start() logger.info("环境管理器已启动") def stop(self): """停止环境管理器""" self.running = False if self.update_thread and self.update_thread.is_alive(): self.update_thread.join(timeout=5) logger.info("环境管理器已停止") def register_observer(self, callback): """注册状态变更观察者""" self.observers.append(callback) logger.debug("注册环境状态观察者: %s", callback.__name__) def _notify_observers(self): """通知所有观察者状态变更""" for observer in self.observers: try: observer(self.state) except Exception as e: logger.error("通知环境观察者失败: %s", str(e)) def _update_loop(self): """环境状态更新循环""" while self.running: try: with self.lock: # 模拟环境变化 self.state['temperature'] = round(20 + 5 * (time.time() % 10) / 10, 1) self.state['humidity'] = round(40 + 10 * (time.time() % 10) / 10, 1) self.state['light_level'] = round(70 + 10 * (time.time() % 10) / 10, 1) self.state['last_updated'] = datetime.datetime.now().isoformat() # 通知观察者 self._notify_observers() except Exception as e: logger.error("环境更新失败: %s", str(e)) time.sleep(1.0) def get_state(self): """获取当前环境状态""" with self.lock: return self.state.copy() def execute_action(self, action, params): """执行环境动作""" logger.info("执行环境动作: %s 参数: %s", action, params) try: if action == "adjust_temperature": return self._adjust_temperature(params) elif action == "adjust_light": return self._adjust_light(params) elif action == "add_object": return self._add_object(params) elif action == "remove_object": return self._remove_object(params) else: logger.warning("未知环境动作: %s", action) return False except Exception as e: logger.error("执行环境动作失败: %s", str(e)) return False def _adjust_temperature(self, params): """调整温度""" value = params.get('value') if value is None: logger.warning("缺少温度值参数") return False try: value = float(value) except ValueError: logger.warning("无效的温度值: %s", value) return False if 10 <= value <= 40: with self.lock: self.state['temperature'] = value return True logger.warning("温度值超出范围 (10-40): %s", value) return False def _adjust_light(self, params): """调整光照强度""" level = params.get('level') if level is None: logger.warning("缺少光照强度参数") return False try: level = float(level) except ValueError: logger.warning("无效的光照强度: %s", level) return False if 0 <= level <= 100: with self.lock: self.state['light_level'] = level return True logger.warning("光照强度超出范围 (0-100): %s", level) return False def _add_object(self, params): """添加环境对象""" obj_name = params.get('name') if not obj_name: logger.warning("缺少对象名称") return False obj_type = params.get('type', 'object') position = params.get('position', 'unknown') # 检查是否已存在 with self.lock: for obj in self.state['objects']: if obj['name'] == obj_name: logger.warning("对象已存在: %s", obj_name) return False # 添加新对象 self.state['objects'].append({ 'name': obj_name, 'type': obj_type, 'position': position, 'added_at': datetime.datetime.now().isoformat() }) return True def _remove_object(self, params): """移除环境对象""" obj_name = params.get('name') if not obj_name: logger.warning("缺少对象名称") return False # 查找并移除对象 with self.lock: for i, obj in enumerate(self.state['objects']): if obj['name'] == obj_name: del self.state['objects'][i] return True logger.warning("未找到对象: %s", obj_name) return False def is_healthy(self): """检查环境健康状态""" # 简单检查:确保所有值在合理范围内 with self.lock: temp = self.state['temperature'] light = self.state['light_level'] if temp < 10 or temp > 40: logger.warning("温度超出健康范围: %s℃", temp) return False if light < 0 or light > 100: logger.warning("光照强度超出健康范围: %s%%", light) return False return self.healthy and self.running # ========== 系统初始化器 ========== class SystemInitializer: """健壮的系统初始化器""" def __init__(self): self.start_time = time.time() self.components = { 'ai_core': None, 'hardware_manager': None, 'life_scheduler': None, 'ai_agent': None, 'environment_manager': None } # 安全获取基础目录 try: self.base_dir = safe_path(system_config.get('BASE_DIR', Path(__file__).parent.parent)) logger.info("系统初始化器创建, 基础目录: %s", self.base_dir) except Exception as e: self.base_dir = Path.cwd().resolve() logger.error("获取基础目录失败, 使用当前目录: %s | 错误: %s", self.base_dir, str(e)) def initialize_system_paths(self): """安全初始化系统路径""" try: # 添加项目根目录到 sys.path if str(self.base_dir) not in sys.path: sys.path.insert(0, str(self.base_dir)) logger.info("项目根目录: %s", self.base_dir) # 添加子目录 sub_dirs = ['agent', 'core', 'utils', 'config', 'cognitive_arch', 'environment'] for sub_dir in sub_dirs: full_path = self.base_dir / sub_dir if full_path.exists() and full_path.is_dir(): if str(full_path) not in sys.path: sys.path.insert(0, str(full_path)) logger.info("添加路径: %s", full_path) else: logger.warning("目录不存在: %s - 已跳过", full_path) except Exception as e: logger.error("系统路径初始化失败: %s", str(e)) def initialize_environment_manager(self): """初始化环境管理器""" try: self.components['environment_manager'] = EnvironmentManager() self.components['environment_manager'].start() logger.info("环境管理器初始化成功") return self.components['environment_manager'] except Exception as e: logger.error("环境管理器初始化失败: %s", str(e)) logger.error(traceback.format_exc()) logger.warning("环境交互功能将不可用") return None def initialize_ai_core(self): """初始化AI核心""" logger.info("AI核心初始化") # 简化实现 self.components['ai_core'] = type('AICore', (), { 'status': 'running', 'get_state': lambda: { "status": "running", "model": system_config.get('DEFAULT_MODEL', 'gpt-3.5-turbo'), "last_update": datetime.datetime.now().isoformat() } })() return self.components['ai_core'] def initialize_hardware_manager(self): """初始化硬件管理器""" logger.info("硬件管理器初始化") # 简化实现 self.components['hardware_manager'] = type('HardwareManager', (), { 'get_status': lambda: { "cpu_usage": psutil.cpu_percent(), "memory_usage": psutil.virtual_memory().percent, "gpu_usage": 0, "disk_usage": psutil.disk_usage('/').percent, "timestamp": datetime.datetime.now().isoformat() } })() return self.components['hardware_manager'] def initialize_life_scheduler(self): """初始化生活调度器""" logger.info("生活调度器初始化") # 简化实现 self.components['life_scheduler'] = type('LifeScheduler', (), { 'get_status': lambda: { "current_activity": "thinking", "next_activity": "learning", "energy": 85, "last_update": datetime.datetime.now().isoformat() } })() return self.components['life_scheduler'] def initialize_ai_agent(self): """初始化AI智能体""" logger.info("开始初始化AI智能体") try: # 动态导入智能体模块 from agent.autonomous_agent import AutonomousAgent # 创建智能体实例 self.components['ai_agent'] = AutonomousAgent() # 将环境管理器传递给智能体(如果存在) if self.components['environment_manager']: # 检查智能体是否有设置环境的方法 if hasattr(self.components['ai_agent'], 'set_environment'): self.components['ai_agent'].set_environment( self.components['environment_manager'] ) logger.info("已将环境管理器连接到智能体") else: logger.warning("智能体没有set_environment方法,无法连接环境管理器") # 启动智能体后台任务 if hasattr(self.components['ai_agent'], 'start'): self.components['ai_agent'].start() logger.info("智能体后台任务已启动") else: logger.warning("智能体没有start方法,无法启动后台任务") logger.info("AI智能体初始化完成") return True except ImportError: logger.warning("无法导入AutonomousAgent,使用模拟智能体") self._create_mock_agent() return False except Exception as e: logger.error("AI智能体初始化失败: %s", str(e)) logger.error(traceback.format_exc()) self._create_mock_agent() return False def _create_mock_agent(self): """创建模拟智能体""" logger.warning("使用模拟智能体作为回退方案") self.components['ai_agent'] = type('MockAgent', (), { 'process_input': lambda self, input, user_id: f"智能体初始化失败,使用模拟模式: 收到消息 '{input}'" })() def start_evolution_monitor(self): """启动进化监视器""" logger.info("进化监视器启动") # 简化实现 def monitor(): while True: logger.debug("进化监视器运行中...") time.sleep(60) threading.Thread(target=monitor, daemon=True).start() def initialize_all(self): """初始化所有系统组件""" logger.info("=" * 50) logger.info("开始初始化AI系统") logger.info("=" * 50) self.initialize_system_paths() self.initialize_ai_core() self.initialize_hardware_manager() self.initialize_life_scheduler() self.initialize_ai_agent() self.initialize_environment_manager() self.start_evolution_monitor() logger.info("所有系统组件初始化完成") return self.components # ========== WebSocket处理 ========== def setup_websocket_handlers(socketio, env_manager): if not socketio or not env_manager: return @socketio.on('connect') def handle_connect(): logger.info('客户端已连接') socketio.emit('system_status', {'status': 'ready'}) # 注册环境状态观察者 env_manager.register_observer(lambda state: socketio.emit('environment_update', state)) @socketio.on('disconnect') def handle_disconnect(): logger.info('客户端已断开连接') @socketio.on('user_message') def handle_user_message(data): user_id = data.get('user_id', 'guest') message = data.get('message', '') logger.info("收到来自 %s 的消息: %s", user_id, message) # 使用线程池处理消息 def process_message(): try: components = current_app.config['SYSTEM_COMPONENTS'] if components['ai_agent']: return components['ai_agent'].process_input(message, user_id) else: return f"已收到您的消息: {message}" except Exception as e: logger.error("消息处理失败: %s", str(e)) return "处理消息时出错" future = ThreadPoolExecutor().submit(process_message) try: response = future.result(timeout=10) socketio.emit('agent_response', { 'user_id': user_id, 'response': response }) except TimeoutError: socketio.emit('agent_response', { 'user_id': user_id, 'response': "处理超时,请重试" }) # ========== 路由注册 ========== def register_routes(app): @app.route('/') def home(): """根路由显示欢迎页面""" current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") return render_template('index.html', current_time=current_time, host=request.host, version="1.0") # 环境路由 @app.route('/environment') def environment_view(): return render_template('environment_view.html') @app.route('/api/environment/state', methods=['GET']) def get_environment_state(): env_manager = app.config['SYSTEM_COMPONENTS'].get('environment_manager') if not env_manager: return jsonify({"success": False, "error": "环境管理器未初始化"}), 503 try: state = env_manager.get_state() return jsonify(state) except Exception as e: app.logger.error("获取环境状态失败: %s", traceback.format_exc()) return jsonify({"success": False, "error": str(e)}), 500 @app.route('/api/environment/action', methods=['POST']) def execute_environment_action(): env_manager = app.config['SYSTEM_COMPONENTS'].get('environment_manager') if not env_manager: return jsonify({"success": False, "error": "环境管理器未初始化"}), 503 try: data = request.json action = data.get('action') params = data.get('params', {}) if not action: return jsonify({"success": False, "error": "缺少动作参数"}), 400 success = env_manager.execute_action(action, params) return jsonify({"success": success, "action": action}) except Exception as e: app.logger.error("执行环境动作失败: %s", traceback.format_exc()) return jsonify({"success": False, "error": str(e)}), 500 # 静态文件路由 @app.route('/static/<path:filename>') def static_files(filename): return send_from_directory(app.static_folder, filename) # 健康检查路由 @app.route('/health') def health_check(): components = app.config['SYSTEM_COMPONENTS'] status = { "ai_core": components['ai_core'] is not None, "hardware_manager": components['hardware_manager'] is not None, "life_scheduler": components['life_scheduler'] is not None, "ai_agent": components['ai_agent'] is not None, "environment_manager": components['environment_manager'] and components['environment_manager'].is_healthy(), "timestamp": datetime.datetime.now().isoformat() } return jsonify(status) # 系统状态路由 @app.route('/status') def status(): components = app.config['SYSTEM_COMPONENTS'] system_info = { "uptime": time.time() - app.config['START_TIME'], "ai_core_status": components['ai_core'].get_state() if components['ai_core'] else "uninitialized", "hardware_status": components['hardware_manager'].get_status() if components[ 'hardware_manager'] else "uninitialized", "life_scheduler_status": components['life_scheduler'].get_status() if components[ 'life_scheduler'] else "uninitialized", "environment_status": components['environment_manager'].get_state() if components[ 'environment_manager'] else "uninitialized", "platform": platform.platform(), "python_version": sys.version, "memory_usage": psutil.virtual_memory().percent, "cpu_usage": psutil.cpu_percent(), "thread_count": threading.active_count(), "process_id": os.getpid(), "timestamp": datetime.datetime.now().isoformat() } return jsonify(system_info) # ========== 错误处理 ========== def register_error_handlers(app): @app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404 @app.errorhandler(500) def internal_server_error(e): return render_template('500.html'), 500 @app.errorhandler(Exception) def handle_general_exception(e): logger.error("未处理异常: %s", str(e)) logger.error(traceback.format_exc()) return render_template('error.html', error=str(e)), 500 # ========== Web应用工厂 ========== def create_app(): # 创建Flask应用 try: template_dir = safe_path(system_config.get('template_dir', Path(__file__).parent / 'templates')) static_dir = safe_path(system_config.get('static_dir', Path(__file__).parent / 'static')) except Exception as e: logger.error("路径配置错误: %s", str(e)) template_dir = Path(__file__).parent / 'templates' static_dir = Path(__file__).parent / 'static' app = Flask( __name__, template_folder=str(template_dir), static_folder=str(static_dir), static_url_path='/static' ) app.secret_key = system_config.get('SECRET_KEY', 'default_secret_key') # 初始化系统组件 try: system_initializer = SystemInitializer() components = system_initializer.initialize_all() app.config['SYSTEM_COMPONENTS'] = components app.config['START_TIME'] = system_initializer.start_time except Exception as e: logger.error("系统初始化失败: %s", str(e)) app.config['SYSTEM_COMPONENTS'] = {} app.config['START_TIME'] = time.time() # 配置SocketIO socketio = None try: from flask_socketio import SocketIO socketio = SocketIO( app, async_mode=system_config.get('ASYNC_MODE', 'threading'), logger=logger.getEffectiveLevel() <= logging.DEBUG, engineio_logger=logger.getEffectiveLevel() <= logging.DEBUG ) env_manager = app.config['SYSTEM_COMPONENTS'].get('environment_manager') if env_manager: setup_websocket_handlers(socketio, env_manager) app.config['SOCKETIO'] = socketio except ImportError: logger.error("未安装flask-socketio,WebSocket功能不可用") except Exception as e: logger.error("SocketIO初始化失败: %s", str(e)) # 注册路由错误处理 register_routes(app) register_error_handlers(app) return app, socketio # ========== 主程序入口 ========== if __name__ == '__main__': try: app, socketio = create_app() # 服务器配置 host = system_config.get('server.host', '0.0.0.0') port = system_config.get('server.port', 5000) env = os.environ.get('ENV', 'development') # 启动服务器 if env == 'production': # 生产环境使用Waitress服务器 from waitress import serve logger.info("生产服务器启动: http://%s:%s", host, port) serve(app, host=host, port=port, threads=8) else: # 开发环境使用内置服务器 logger.info("开发服务器启动: http://%s:%s", host, port) if socketio: socketio.run( app, host=host, port=port, debug=system_config.get('DEBUG', False), use_reloader=False ) else: app.run( host=host, port=port, debug=system_config.get('DEBUG', False), use_reloader=False ) except Exception as e: logger.critical("服务器启动失败: %s", str(e)) logger.critical(traceback.format_exc()) Microsoft Windows [版本 10.0.22631.2861] (c) Microsoft Corporation。保留所有权利。 C:\Users\Administrator>cd /d E:\AI_System\web_ui E:\AI_System\web_ui>python server.py Traceback (most recent call last): File "E:\AI_System\web_ui\server.py", line 53, in <module> from core.config import CoreConfig as SystemConfig File "E:\AI_System\core\__init__.py", line 12, in <module> system_config = CoreConfig( File "E:\AI_System\core\config.py", line 19, in __init__ self.BASE_DIR = self._determine_base_dir() File "E:\AI_System\core\config.py", line 44, in _determine_base_dir base_dir_env = os.getenv(f"{self.env_prefix}BASE_DIR") File "E:\AI_System\core\config.py", line 199, in __getattr__ if name in self._config: File "E:\AI_System\core\config.py", line 199, in __getattr__ if name in self._config: File "E:\AI_System\core\config.py", line 199, in __getattr__ if name in self._config: [Previous line repeated 982 more times] RecursionError: maximum recursion depth exceeded E:\AI_System\web_ui>
08-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值