Spaces:
Runtime error
Runtime error
""" | |
DigiPal Configuration Management | |
Handles environment-specific configuration for deployment | |
""" | |
import os | |
from typing import Optional, Dict, Any | |
from dataclasses import dataclass | |
from pathlib import Path | |
import logging | |
class DatabaseConfig: | |
"""Database configuration settings""" | |
path: str = "digipal.db" | |
backup_dir: str = "assets/backups" | |
backup_interval_hours: int = 24 | |
max_backups: int = 10 | |
class AIModelConfig: | |
"""AI model configuration settings""" | |
qwen_model: str = "Qwen/Qwen3-0.6B" | |
kyutai_model: str = "kyutai/stt-2.6b-en-trfs" | |
flux_model: str = "black-forest-labs/FLUX.1-dev" | |
device: str = "auto" | |
torch_dtype: str = "auto" | |
enable_quantization: bool = True | |
max_memory_gb: Optional[int] = None | |
class GradioConfig: | |
"""Gradio interface configuration""" | |
server_name: str = "0.0.0.0" | |
server_port: int = 7860 | |
share: bool = False | |
debug: bool = False | |
auth: Optional[tuple] = None | |
ssl_keyfile: Optional[str] = None | |
ssl_certfile: Optional[str] = None | |
class MCPConfig: | |
"""MCP server configuration""" | |
enabled: bool = True | |
host: str = "localhost" | |
port: int = 8080 | |
max_connections: int = 100 | |
timeout_seconds: int = 30 | |
class LoggingConfig: | |
"""Logging configuration""" | |
level: str = "INFO" | |
format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" | |
file_path: Optional[str] = "logs/digipal.log" | |
max_file_size_mb: int = 10 | |
backup_count: int = 5 | |
enable_structured_logging: bool = True | |
class SecurityConfig: | |
"""Security configuration""" | |
secret_key: Optional[str] = None | |
session_timeout_hours: int = 24 | |
max_login_attempts: int = 5 | |
rate_limit_per_minute: int = 60 | |
enable_cors: bool = True | |
allowed_origins: list = None | |
class PerformanceConfig: | |
"""Performance optimization settings""" | |
cache_size_mb: int = 512 | |
background_update_interval: int = 60 | |
max_concurrent_users: int = 100 | |
enable_model_caching: bool = True | |
image_cache_max_age_days: int = 30 | |
class DigiPalConfig: | |
"""Main configuration class for DigiPal application""" | |
def __init__(self, env: str = None): | |
self.env = env or os.getenv("DIGIPAL_ENV", "development") | |
self.load_config() | |
def load_config(self): | |
"""Load configuration based on environment""" | |
# Base configuration | |
self.database = DatabaseConfig() | |
self.ai_models = AIModelConfig() | |
self.gradio = GradioConfig() | |
self.mcp = MCPConfig() | |
self.logging = LoggingConfig() | |
self.security = SecurityConfig() | |
self.performance = PerformanceConfig() | |
# Environment-specific overrides | |
if self.env == "production": | |
self._load_production_config() | |
elif self.env == "testing": | |
self._load_testing_config() | |
elif self.env == "development": | |
self._load_development_config() | |
# Load from environment variables | |
self._load_from_env() | |
# Validate configuration | |
self._validate_config() | |
def _load_production_config(self): | |
"""Production environment configuration""" | |
# Use /tmp for HuggingFace Spaces (writable temporary storage) | |
import tempfile | |
import os | |
# Create temp directory for this session | |
temp_dir = os.path.join(tempfile.gettempdir(), "digipal_session") | |
os.makedirs(temp_dir, exist_ok=True) | |
self.database.path = os.path.join(temp_dir, "digipal.db") | |
self.database.backup_dir = os.path.join(temp_dir, "backups") | |
self.gradio.debug = False | |
self.gradio.share = False | |
self.logging.level = "INFO" | |
self.logging.file_path = os.path.join(temp_dir, "digipal.log") | |
self.security.session_timeout_hours = 12 | |
self.security.rate_limit_per_minute = 30 | |
self.performance.cache_size_mb = 1024 | |
self.performance.max_concurrent_users = 500 | |
def _load_testing_config(self): | |
"""Testing environment configuration""" | |
self.database.path = "test_digipal.db" | |
self.database.backup_dir = "test_assets/backups" | |
self.gradio.debug = True | |
self.gradio.server_port = 7861 | |
self.logging.level = "DEBUG" | |
self.logging.file_path = None # Console only | |
self.ai_models.enable_quantization = False | |
self.performance.cache_size_mb = 128 | |
def _load_development_config(self): | |
"""Development environment configuration""" | |
self.gradio.debug = True | |
self.gradio.share = False | |
self.logging.level = "DEBUG" | |
self.logging.file_path = "logs/digipal_dev.log" | |
self.security.rate_limit_per_minute = 120 | |
self.performance.cache_size_mb = 256 | |
def _load_from_env(self): | |
"""Load configuration from environment variables""" | |
# Database | |
if os.getenv("DIGIPAL_DB_PATH"): | |
self.database.path = os.getenv("DIGIPAL_DB_PATH") | |
# Gradio | |
if os.getenv("GRADIO_SERVER_NAME"): | |
self.gradio.server_name = os.getenv("GRADIO_SERVER_NAME") | |
if os.getenv("GRADIO_SERVER_PORT"): | |
self.gradio.server_port = int(os.getenv("GRADIO_SERVER_PORT")) | |
if os.getenv("GRADIO_SHARE"): | |
self.gradio.share = os.getenv("GRADIO_SHARE").lower() == "true" | |
# Logging | |
if os.getenv("DIGIPAL_LOG_LEVEL"): | |
self.logging.level = os.getenv("DIGIPAL_LOG_LEVEL") | |
if os.getenv("DIGIPAL_LOG_FILE"): | |
self.logging.file_path = os.getenv("DIGIPAL_LOG_FILE") | |
# Security | |
if os.getenv("DIGIPAL_SECRET_KEY"): | |
self.security.secret_key = os.getenv("DIGIPAL_SECRET_KEY") | |
# AI Models | |
if os.getenv("QWEN_MODEL"): | |
self.ai_models.qwen_model = os.getenv("QWEN_MODEL") | |
if os.getenv("KYUTAI_MODEL"): | |
self.ai_models.kyutai_model = os.getenv("KYUTAI_MODEL") | |
if os.getenv("FLUX_MODEL"): | |
self.ai_models.flux_model = os.getenv("FLUX_MODEL") | |
def _validate_config(self): | |
"""Validate configuration settings""" | |
# Ensure required directories exist (only if writable) | |
try: | |
Path(self.database.backup_dir).mkdir(parents=True, exist_ok=True) | |
except (PermissionError, OSError) as e: | |
# In HuggingFace Spaces, directories may be created automatically | |
# or may not be writable during initialization | |
logging.warning(f"Could not create backup directory {self.database.backup_dir}: {e}") | |
if self.logging.file_path: | |
try: | |
Path(self.logging.file_path).parent.mkdir(parents=True, exist_ok=True) | |
except (PermissionError, OSError) as e: | |
logging.warning(f"Could not create log directory {Path(self.logging.file_path).parent}: {e}") | |
# Validate port ranges | |
if not (1024 <= self.gradio.server_port <= 65535): | |
raise ValueError(f"Invalid Gradio port: {self.gradio.server_port}") | |
if not (1024 <= self.mcp.port <= 65535): | |
raise ValueError(f"Invalid MCP port: {self.mcp.port}") | |
# Validate memory settings | |
if self.performance.cache_size_mb < 64: | |
logging.warning("Cache size is very low, performance may be affected") | |
def get_database_url(self) -> str: | |
"""Get database connection URL""" | |
return f"sqlite:///{self.database.path}" | |
def get_log_config(self) -> Dict[str, Any]: | |
"""Get logging configuration dictionary""" | |
config = { | |
"version": 1, | |
"disable_existing_loggers": False, | |
"formatters": { | |
"standard": { | |
"format": self.logging.format | |
}, | |
"structured": { | |
"()": "structlog.stdlib.ProcessorFormatter", | |
"processor": "structlog.dev.ConsoleRenderer", | |
} if self.logging.enable_structured_logging else { | |
"format": self.logging.format | |
} | |
}, | |
"handlers": { | |
"console": { | |
"class": "logging.StreamHandler", | |
"level": self.logging.level, | |
"formatter": "structured" if self.logging.enable_structured_logging else "standard", | |
"stream": "ext://sys.stdout" | |
} | |
}, | |
"loggers": { | |
"digipal": { | |
"level": self.logging.level, | |
"handlers": ["console"], | |
"propagate": False | |
} | |
}, | |
"root": { | |
"level": self.logging.level, | |
"handlers": ["console"] | |
} | |
} | |
# Add file handler if specified | |
if self.logging.file_path: | |
config["handlers"]["file"] = { | |
"class": "logging.handlers.RotatingFileHandler", | |
"level": self.logging.level, | |
"formatter": "standard", | |
"filename": self.logging.file_path, | |
"maxBytes": self.logging.max_file_size_mb * 1024 * 1024, | |
"backupCount": self.logging.backup_count | |
} | |
config["loggers"]["digipal"]["handlers"].append("file") | |
config["root"]["handlers"].append("file") | |
return config | |
def to_dict(self) -> Dict[str, Any]: | |
"""Convert configuration to dictionary""" | |
return { | |
"env": self.env, | |
"database": self.database.__dict__, | |
"ai_models": self.ai_models.__dict__, | |
"gradio": self.gradio.__dict__, | |
"mcp": self.mcp.__dict__, | |
"logging": self.logging.__dict__, | |
"security": self.security.__dict__, | |
"performance": self.performance.__dict__ | |
} | |
# Global configuration instance | |
config = DigiPalConfig() | |
def get_config() -> DigiPalConfig: | |
"""Get the global configuration instance""" | |
return config | |
def reload_config(env: str = None): | |
"""Reload configuration with optional environment override""" | |
global config | |
config = DigiPalConfig(env) | |
return config |