WB_Analyzer / config.py
bakyt92's picture
update of api connection
e7c4b2b
"""
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()