Spaces:
Sleeping
Sleeping
| import os | |
| from dataclasses import dataclass, field | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| class Config: | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: Telegram | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| BOT_TOKEN: str = os.getenv("BOT_TOKEN", "") | |
| OWNER_ID: int = int(os.getenv("OWNER_ID", "0") or "0") | |
| WEBHOOK_PATH: str = "/webhook" | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: Database (Neon PostgreSQL) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| DATABASE_URL: str = os.getenv("DATABASE_URL", "") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: AI β Primary Model (GLM via NVIDIA) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| NVIDIA_API_KEY: str = os.getenv("NVIDIA_API_KEY", "") | |
| NVIDIA_BASE_URL: str = "https://integrate.api.nvidia.com/v1" | |
| PRIMARY_MODEL: str = os.getenv("MODEL_NAME", "z-ai/glm-5.1") | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: AI β Fallback Model | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| FALLBACK_MODEL: str = os.getenv("FALLBACK_MODEL", "") | |
| FALLBACK_ENABLED: bool = os.getenv("FALLBACK_ENABLED", "false").lower() == "true" | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: AI Parameters β Optimized for GLM-5.1 | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # GLM-4.5 ΡΠ΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°ΡΠΈΠΈ ΡΠ΅ΡΠ΅Π· NVIDIA NIM: | |
| # - temperature: 0.3β0.8 (Π½ΠΈΠΆΠ΅ = ΡΠΎΡΠ½Π΅Π΅, Π²ΡΡΠ΅ = ΠΊΡΠ΅Π°ΡΠΈΠ²Π½Π΅Π΅) | |
| # - top_p: 0.7β0.95 | |
| # - max_tokens: Π·Π°Π²ΠΈΡΠΈΡ ΠΎΡ Π·Π°Π΄Π°ΡΠΈ, 4096β8192 Π΄Π»Ρ Π΄Π»ΠΈΠ½Π½ΡΡ ΠΎΡΠ²Π΅ΡΠΎΠ² | |
| GLM_TEMPERATURE: float = float(os.getenv("GLM_TEMPERATURE", "0.7")) | |
| GLM_TOP_P: float = float(os.getenv("GLM_TOP_P", "0.9")) | |
| GLM_FREQUENCY_PENALTY: float = float(os.getenv("GLM_FREQUENCY_PENALTY", "0.1")) | |
| GLM_PRESENCE_PENALTY: float = float(os.getenv("GLM_PRESENCE_PENALTY", "0.05")) | |
| GLM_MAX_TOKENS: int = int(os.getenv("GLM_MAX_TOKENS", "4096")) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: Timeouts β Granular for NVIDIA NIM | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # NVIDIA NIM ΠΌΠΎΠΆΠ΅Ρ ΠΎΡΠ²Π΅ΡΠ°ΡΡ 2β3 ΠΌΠΈΠ½ΡΡΡ Π½Π° ΡΠ»ΠΎΠΆΠ½ΡΠ΅ Π·Π°ΠΏΡΠΎΡΡ. | |
| # connect: Π²ΡΠ΅ΠΌΡ ΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΈΡ TCP-ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ | |
| # read: Π²ΡΠ΅ΠΌΡ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΡ ΠΏΠ΅ΡΠ²ΠΎΠ³ΠΎ Π±Π°ΠΉΡΠ° ΠΎΡΠ²Π΅ΡΠ° | |
| # write: Π²ΡΠ΅ΠΌΡ Π½Π° ΠΎΡΠΏΡΠ°Π²ΠΊΡ Π·Π°ΠΏΡΠΎΡΠ° | |
| TIMEOUT_CONNECT: float = float(os.getenv("TIMEOUT_CONNECT", "10.0")) | |
| TIMEOUT_READ: float = float(os.getenv("TIMEOUT_READ", "180.0")) # 3 ΠΌΠΈΠ½ΡΡΡ | |
| TIMEOUT_WRITE: float = float(os.getenv("TIMEOUT_WRITE", "10.0")) | |
| TIMEOUT_POOL: float = float(os.getenv("TIMEOUT_POOL", "5.0")) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: Retry Configuration | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| MAX_RETRIES: int = int(os.getenv("MAX_RETRIES", "3")) | |
| RETRY_BASE_DELAY: float = float(os.getenv("RETRY_BASE_DELAY", "2.0")) | |
| RETRY_MAX_DELAY: float = float(os.getenv("RETRY_MAX_DELAY", "60.0")) | |
| RETRY_EXPONENTIAL_BASE: float = float(os.getenv("RETRY_EXPONENTIAL_BASE", "2.0")) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: Streaming | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| STREAMING_ENABLED: bool = os.getenv("STREAMING_ENABLED", "true").lower() == "true" | |
| STREAMING_CHUNK_SIZE: int = int(os.getenv("STREAMING_CHUNK_SIZE", "100")) | |
| STREAMING_UPDATE_INTERVAL: float = float(os.getenv("STREAMING_UPDATE_INTERVAL", "1.5")) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: History & Memory | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| MAX_HISTORY: int = int(os.getenv("MAX_HISTORY", "20")) # ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠΉ Π² ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ΅ | |
| MAX_CONTEXT_TOKENS: int = int(os.getenv("MAX_CONTEXT_TOKENS", "6000")) # ΠΏΡΠΈΠΌΠ΅ΡΠ½ΠΎ ΡΠΎΠΊΠ΅Π½ΠΎΠ² | |
| SUMMARIZE_THRESHOLD: int = int(os.getenv("SUMMARIZE_THRESHOLD", "30")) | |
| SUMMARY_MAX_TOKENS: int = int(os.getenv("SUMMARY_MAX_TOKENS", "512")) | |
| KEEP_RECENT_MESSAGES: int = int(os.getenv("KEEP_RECENT_MESSAGES", "10")) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: Telegram Limits | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| MAX_MESSAGE_LENGTH: int = 4096 | |
| TYPING_ACTION_INTERVAL: float = 4.5 # Telegram typing action expires after ~5s | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: Rate Limiting | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| RATE_LIMIT_ENABLED: bool = os.getenv("RATE_LIMIT_ENABLED", "true").lower() == "true" | |
| RATE_LIMIT_REQUESTS_PER_MINUTE: int = int(os.getenv("RATE_LIMIT_REQUESTS_PER_MINUTE", "10")) | |
| RATE_LIMIT_BURST: int = int(os.getenv("RATE_LIMIT_BURST", "3")) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: Cache | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| CACHE_ENABLED: bool = os.getenv("CACHE_ENABLED", "true").lower() == "true" | |
| CACHE_TTL_SECONDS: int = int(os.getenv("CACHE_TTL_SECONDS", "300")) # 5 ΠΌΠΈΠ½ΡΡ | |
| CACHE_MAX_SIZE: int = int(os.getenv("CACHE_MAX_SIZE", "1000")) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BLOCK: Monitoring | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO") | |
| METRICS_ENABLED: bool = os.getenv("METRICS_ENABLED", "true").lower() == "true" | |
| def __post_init__(self) -> None: | |
| if self.DATABASE_URL.startswith("postgres://"): | |
| self.DATABASE_URL = self.DATABASE_URL.replace( | |
| "postgres://", "postgresql://", 1 | |
| ) | |
| def validate(self) -> None: | |
| required = [ | |
| ("BOT_TOKEN", self.BOT_TOKEN), | |
| ("OWNER_ID", self.OWNER_ID), | |
| ("DATABASE_URL", self.DATABASE_URL), | |
| ("NVIDIA_API_KEY", self.NVIDIA_API_KEY), | |
| ] | |
| for name, value in required: | |
| if not value: | |
| raise ValueError(f"{name} is required") | |
| config = Config() | |
| config.validate() | |