""" Configuration management for Hugging Face Spaces deployment Handles environment variables and application settings """ import os from typing import Dict, Any from dotenv import load_dotenv # Load environment variables from .env file if it exists (for local development) load_dotenv() class Config: """Application configuration management""" def __init__(self): # No automatic environment variable loading - tokens come from Gradio interface only self.wildberries_api_token = None # Official Wildberries API URLs based on documentation self.wildberries_base_url = "https://statistics-api.wildberries.ru" self.wildberries_content_url = "https://content-api.wildberries.ru" self.wildberries_analytics_url = "https://seller-analytics-api.wildberries.ru" self.wildberries_common_url = "https://common-api.wildberries.ru" self.wildberries_marketplace_url = "https://marketplace-api.wildberries.ru" self.wildberries_supplies_url = "https://supplies-api.wildberries.ru" # Rate limiting settings (based on official documentation) # Statistics API: Maximum of 300 requests per minute self.rate_limit_requests = 300 # requests per minute self.rate_limit_window = 60 # seconds # Request timeout settings self.request_timeout = 30 # seconds self.max_retries = 3 self.retry_backoff_factor = 2 # Application settings self.demo_mode = True # Always start in demo mode, users provide tokens via UI self.debug_mode = os.getenv("DEBUG", "false").lower() == "true" # Hugging Face Spaces specific settings self.hf_space_id = os.getenv("SPACE_ID") self.hf_space_author = os.getenv("SPACE_AUTHOR_NAME") # Gradio settings self.gradio_analytics = os.getenv("GRADIO_ANALYTICS_ENABLED", "false").lower() == "true" self.gradio_theme = os.getenv("GRADIO_THEME", "soft") def get_api_headers(self, api_token: str = None) -> Dict[str, str]: """Get headers for Wildberries API requests""" headers = { "Content-Type": "application/json", "User-Agent": "Wildberries-Analytics-Dashboard/1.0" } if api_token: headers["Authorization"] = f"Bearer {api_token}" return headers def get_rate_limit_config(self) -> Dict[str, Any]: """Get rate limiting configuration""" return { "requests_per_minute": self.rate_limit_requests, "window_seconds": self.rate_limit_window, "backoff_factor": self.retry_backoff_factor } def is_configured(self, api_token: str = None) -> bool: """Check if the application is properly configured with API token""" return api_token is not None and len(api_token.strip()) > 0 def get_endpoints(self) -> Dict[str, str]: """Get API endpoint configurations based on working API calls""" return { # Statistics API endpoints - Correct sales endpoint "sales": f"{self.wildberries_base_url}/api/v1/supplier/sales", "orders": f"{self.wildberries_base_url}/api/v5/supplier/reportDetailByPeriod", "stocks": f"{self.wildberries_base_url}/api/v1/supplier/stocks", "incomes": f"{self.wildberries_base_url}/api/v5/supplier/reportDetailByPeriod", "reportDetailByPeriod": f"{self.wildberries_base_url}/api/v5/supplier/reportDetailByPeriod", # Analytics API endpoints "analytics": f"{self.wildberries_analytics_url}/api/v2/nm-report/detail", # Content API endpoints "content": f"{self.wildberries_content_url}/content/v1/cards/cursor/list", # Common API endpoints "news": f"{self.wildberries_common_url}/api/communications/v2/news", "seller_info": f"{self.wildberries_common_url}/api/v1/seller-info", # Connection check endpoints for each service "ping_statistics": f"{self.wildberries_base_url}/ping", "ping_content": f"{self.wildberries_content_url}/ping", "ping_analytics": f"{self.wildberries_analytics_url}/ping", "ping_common": f"{self.wildberries_common_url}/ping", "ping_marketplace": f"{self.wildberries_marketplace_url}/ping", "ping_supplies": f"{self.wildberries_supplies_url}/ping" } def validate_token(self, token: str) -> bool: """Validate the format of a Wildberries API token (JWT format)""" if not token: return False # Wildberries tokens are JWT format based on official documentation try: # Check if it looks like a JWT (three parts separated by dots) parts = token.split('.') if len(parts) != 3: return False # Check minimum length (JWT tokens are typically longer) if len(token) < 50: return False return True except Exception: return False def get_demo_settings(self) -> Dict[str, Any]: """Get settings for demo mode""" return { "demo_products_count": 15, "demo_sales_days": 30, "demo_revenue_range": (10000, 500000), # rubles "demo_stock_range": (0, 1000), "demo_categories": [ "Одежда", "Обувь", "Аксессуары", "Красота", "Дом и сад", "Спорт", "Электроника", "Книги" ] } def __repr__(self) -> str: """String representation of configuration""" return f""" Wildberries Analytics Dashboard Configuration: - Demo Mode: {self.demo_mode} - Debug Mode: {self.debug_mode} - API Configured: {self.is_configured()} - Rate Limit: {self.rate_limit_requests}/min - HF Space: {self.hf_space_author}/{self.hf_space_id if self.hf_space_id else 'local'} """ # Global configuration instance _config = None def get_config() -> Config: """Get the global configuration instance""" global _config if _config is None: _config = Config() return _config def reload_config() -> Config: """Reload configuration (useful for testing)""" global _config _config = Config() return _config # Environment validation for Hugging Face Spaces def validate_hf_environment(): """Validate that we're running in a proper HF Spaces environment""" config = get_config() issues = [] if not config.wildberries_api_token: issues.append("WILDBERRIES_API_TOKEN not set - running in demo mode") if config.wildberries_api_token and not config.validate_token(config.wildberries_api_token): issues.append("WILDBERRIES_API_TOKEN appears to be invalid format") return issues # Export commonly used configurations DEFAULT_CONFIG = get_config() API_ENDPOINTS = DEFAULT_CONFIG.get_endpoints() RATE_LIMIT_CONFIG = DEFAULT_CONFIG.get_rate_limit_config() DEMO_SETTINGS = DEFAULT_CONFIG.get_demo_settings()