File size: 5,344 Bytes
b30d305
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
"""
环境变量配置管理器
统一管理所有环境变量配置
"""
import os
from typing import Optional, Union, List
from pathlib import Path

class EnvConfig:
    """环境变量配置管理器"""
    
    def __init__(self):
        self._load_env_file()
    
    def _load_env_file(self):
        """加载.env文件"""
        env_file = Path(".env")
        if env_file.exists():
            with open(env_file, 'r', encoding='utf-8') as f:
                for line in f:
                    line = line.strip()
                    if line and not line.startswith('#') and '=' in line:
                        key, value = line.split('=', 1)
                        key = key.strip()
                        value = value.strip()
                        # 移除引号
                        if value.startswith('"') and value.endswith('"'):
                            value = value[1:-1]
                        elif value.startswith("'") and value.endswith("'"):
                            value = value[1:-1]
                        os.environ[key] = value
    
    def get_str(self, key: str, default: str = "") -> str:
        """获取字符串配置"""
        return os.getenv(key, default)
    
    def get_int(self, key: str, default: int = 0) -> int:
        """获取整数配置"""
        try:
            return int(os.getenv(key, str(default)))
        except ValueError:
            return default
    
    def get_float(self, key: str, default: float = 0.0) -> float:
        """获取浮点数配置"""
        try:
            return float(os.getenv(key, str(default)))
        except ValueError:
            return default
    
    def get_bool(self, key: str, default: bool = False) -> bool:
        """获取布尔配置"""
        value = os.getenv(key, str(default)).lower()
        return value in ('true', '1', 'yes', 'on')
    
    def get_list(self, key: str, default: List[str] = None, separator: str = ",") -> List[str]:
        """获取列表配置"""
        if default is None:
            default = []
        value = os.getenv(key, "")
        if not value:
            return default
        return [item.strip() for item in value.split(separator) if item.strip()]
    
    # ================================
    # 管理员认证配置
    # ================================
    
    @property
    def admin_password(self) -> str:
        """管理员密码"""
        return self.get_str("ADMIN_PASSWORD", "admin123")
    

    
    # ================================
    # Web服务器配置
    # ================================

    @property
    def web_port(self) -> int:
        """Web服务器端口"""
        return self.get_int("WEB_PORT", 3000)
    
    # ================================
    # AI服务商配置
    # ================================
    
    @property
    def anthropic_max_tokens(self) -> int:
        """Anthropic最大token数"""
        return self.get_int("ANTHROPIC_MAX_TOKENS", 4096)
    

    
    # ================================
    # 数据库配置
    # ================================

    @property
    def database_path(self) -> str:
        """数据库文件路径"""
        return self.get_str("DATABASE_PATH", "data/channels.db")

    # ================================
    # 日志配置
    # ================================

    @property
    def log_level(self) -> str:
        """日志级别"""
        return self.get_str("LOG_LEVEL", "WARNING")

    @property
    def debug_mode(self) -> bool:
        """是否启用调试模式"""
        return self.get_bool("DEBUG_MODE", False)

    @property
    def log_file(self) -> str:
        """日志文件路径"""
        return self.get_str("LOG_FILE", "logs/app.log")

    @property
    def log_max_days(self) -> int:
        """日志文件保留天数"""
        return self.get_int("LOG_MAX_DAYS", 1)

    
    def validate_config(self) -> List[str]:
        """验证配置,返回错误列表"""
        errors = []

        # 验证必需配置
        if not self.admin_password:
            errors.append("ADMIN_PASSWORD cannot be empty")

        # 验证数据库路径
        db_dir = Path(self.database_path).parent
        if not db_dir.exists():
            try:
                db_dir.mkdir(parents=True, exist_ok=True)
            except Exception as e:
                errors.append(f"Cannot create database directory {db_dir}: {e}")

        # 验证端口范围
        if not (1 <= self.web_port <= 65535):
            errors.append(f"WEB_PORT must be between 1 and 65535, got {self.web_port}")

        # 验证Anthropic最大token数
        if self.anthropic_max_tokens <= 0:
            errors.append(f"ANTHROPIC_MAX_TOKENS must be positive, got {self.anthropic_max_tokens}")

        # 验证日志配置
        if self.log_max_days <= 0:
            errors.append(f"LOG_MAX_DAYS must be positive, got {self.log_max_days}")

        # 验证日志文件路径
        if self.log_file:
            log_dir = Path(self.log_file).parent
            if not log_dir.exists():
                try:
                    log_dir.mkdir(parents=True, exist_ok=True)
                except Exception as e:
                    errors.append(f"Cannot create log directory {log_dir}: {e}")

        return errors


# 全局配置实例
env_config = EnvConfig()