#!/usr/bin/env python3 """ Deployment Configuration for LinguaCustodia Financial AI API Consolidated deployment settings and utilities. """ import os import logging from typing import Dict, Any, Optional from dotenv import load_dotenv from pydantic import BaseModel, Field # Load environment variables load_dotenv() logger = logging.getLogger(__name__) class DeploymentConfig(BaseModel): """Deployment configuration for different platforms.""" # Platform settings platform: str = Field("huggingface", description="Deployment platform") environment: str = Field("production", description="Environment (production, staging, development)") # Application settings app_name: str = Field("lingua-custodia-api", description="Application name") app_port: int = Field(8000, description="Application port") app_host: str = Field("0.0.0.0", description="Application host") # Model settings default_model: str = Field("llama3.1-8b", description="Default model to use") max_tokens: int = Field(2048, description="Maximum tokens for inference") temperature: float = Field(0.6, description="Temperature for generation") timeout_seconds: int = Field(300, description="Request timeout in seconds") # Logging settings log_level: str = Field("INFO", description="Logging level") log_format: str = Field("json", description="Log format") # Performance settings worker_processes: int = Field(1, description="Number of worker processes") worker_threads: int = Field(4, description="Number of worker threads") max_connections: int = Field(100, description="Maximum connections") # Security settings secret_key: Optional[str] = Field(None, description="Secret key for security") allowed_hosts: str = Field("localhost,127.0.0.1", description="Allowed hosts") class ScalewayConfig(BaseModel): """Scaleway-specific configuration.""" # Authentication access_key: str = Field(..., description="Scaleway access key") secret_key: str = Field(..., description="Scaleway secret key") project_id: str = Field(..., description="Scaleway project ID") organization_id: Optional[str] = Field(None, description="Scaleway organization ID") region: str = Field("fr-par", description="Scaleway region") # Deployment settings namespace_name: str = Field("lingua-custodia", description="Container namespace name") container_name: str = Field("lingua-custodia-api", description="Container name") function_name: str = Field("lingua-custodia-api", description="Function name") # Resource settings memory_limit: int = Field(16384, description="Memory limit in MB (16GB for 8B models)") cpu_limit: int = Field(4000, description="CPU limit in mCPU (4 vCPUs)") min_scale: int = Field(1, description="Minimum scale") max_scale: int = Field(3, description="Maximum scale") timeout: int = Field(600, description="Timeout in seconds (10min for model loading)") # Privacy settings privacy: str = Field("public", description="Privacy setting") http_option: str = Field("enabled", description="HTTP option") class HuggingFaceConfig(BaseModel): """HuggingFace Spaces configuration.""" # Authentication hf_token: str = Field(..., description="HuggingFace token") hf_token_lc: str = Field(..., description="LinguaCustodia token") # Space settings space_name: str = Field("linguacustodia-financial-api", description="Space name") space_type: str = Field("docker", description="Space type") hardware: str = Field("t4-medium", description="Hardware type") # Storage settings persistent_storage: bool = Field(True, description="Enable persistent storage") storage_size: str = Field("150GB", description="Storage size") class KoyebConfig(BaseModel): """Koyeb-specific configuration.""" # Authentication api_token: str = Field(..., description="Koyeb API token") region: str = Field("fra", description="Koyeb region") # Application settings app_name: str = Field("lingua-custodia-inference", description="Application name") service_name: str = Field("lingua-custodia-api", description="Service name") # Instance settings instance_type: str = Field("small", description="Instance type") min_instances: int = Field(1, description="Minimum instances") max_instances: int = Field(3, description="Maximum instances") def get_deployment_config() -> DeploymentConfig: """Get deployment configuration from environment variables.""" return DeploymentConfig( platform=os.getenv("DEPLOYMENT_PLATFORM", "huggingface"), environment=os.getenv("ENVIRONMENT", "production"), app_name=os.getenv("APP_NAME", "lingua-custodia-api"), app_port=int(os.getenv("APP_PORT", 8000)), app_host=os.getenv("APP_HOST", "0.0.0.0"), default_model=os.getenv("DEFAULT_MODEL", "llama3.1-8b"), max_tokens=int(os.getenv("MAX_TOKENS", 2048)), temperature=float(os.getenv("TEMPERATURE", 0.6)), timeout_seconds=int(os.getenv("TIMEOUT_SECONDS", 300)), log_level=os.getenv("LOG_LEVEL", "INFO"), log_format=os.getenv("LOG_FORMAT", "json"), worker_processes=int(os.getenv("WORKER_PROCESSES", 1)), worker_threads=int(os.getenv("WORKER_THREADS", 4)), max_connections=int(os.getenv("MAX_CONNECTIONS", 100)), secret_key=os.getenv("SECRET_KEY"), allowed_hosts=os.getenv("ALLOWED_HOSTS", "localhost,127.0.0.1") ) def get_scaleway_config() -> ScalewayConfig: """Get Scaleway configuration from environment variables.""" return ScalewayConfig( access_key=os.getenv("SCW_ACCESS_KEY", ""), secret_key=os.getenv("SCW_SECRET_KEY", ""), project_id=os.getenv("SCW_DEFAULT_PROJECT_ID", ""), organization_id=os.getenv("SCW_DEFAULT_ORGANIZATION_ID"), region=os.getenv("SCW_REGION", "fr-par"), namespace_name=os.getenv("SCW_NAMESPACE_NAME", "lingua-custodia"), container_name=os.getenv("SCW_CONTAINER_NAME", "lingua-custodia-api"), function_name=os.getenv("SCW_FUNCTION_NAME", "lingua-custodia-api"), memory_limit=int(os.getenv("SCW_MEMORY_LIMIT", 16384)), cpu_limit=int(os.getenv("SCW_CPU_LIMIT", 4000)), min_scale=int(os.getenv("SCW_MIN_SCALE", 1)), max_scale=int(os.getenv("SCW_MAX_SCALE", 3)), timeout=int(os.getenv("SCW_TIMEOUT", 600)), privacy=os.getenv("SCW_PRIVACY", "public"), http_option=os.getenv("SCW_HTTP_OPTION", "enabled") ) def get_huggingface_config() -> HuggingFaceConfig: """Get HuggingFace configuration from environment variables.""" return HuggingFaceConfig( hf_token=os.getenv("HF_TOKEN", ""), hf_token_lc=os.getenv("HF_TOKEN_LC", ""), space_name=os.getenv("HF_SPACE_NAME", "linguacustodia-financial-api"), space_type=os.getenv("HF_SPACE_TYPE", "docker"), hardware=os.getenv("HF_HARDWARE", "t4-medium"), persistent_storage=os.getenv("HF_PERSISTENT_STORAGE", "true").lower() == "true", storage_size=os.getenv("HF_STORAGE_SIZE", "150GB") ) def get_koyeb_config() -> KoyebConfig: """Get Koyeb configuration from environment variables.""" return KoyebConfig( api_token=os.getenv("KOYEB_API_TOKEN", ""), region=os.getenv("KOYEB_REGION", "fra"), app_name=os.getenv("KOYEB_APP_NAME", "lingua-custodia-inference"), service_name=os.getenv("KOYEB_SERVICE_NAME", "lingua-custodia-api"), instance_type=os.getenv("KOYEB_INSTANCE_TYPE", "small"), min_instances=int(os.getenv("KOYEB_MIN_INSTANCES", 1)), max_instances=int(os.getenv("KOYEB_MAX_INSTANCES", 3)) ) def validate_deployment_config(config: DeploymentConfig) -> bool: """Validate deployment configuration.""" try: # Basic validation if not config.app_name: logger.error("App name is required") return False if config.app_port <= 0 or config.app_port > 65535: logger.error("Invalid app port") return False if config.temperature < 0 or config.temperature > 2: logger.error("Temperature must be between 0 and 2") return False if config.max_tokens <= 0: logger.error("Max tokens must be positive") return False logger.info("✅ Deployment configuration is valid") return True except Exception as e: logger.error(f"❌ Configuration validation failed: {e}") return False def get_environment_info() -> Dict[str, Any]: """Get environment information for debugging.""" return { "python_version": os.sys.version, "current_directory": os.getcwd(), "environment_variables": { "APP_NAME": os.getenv("APP_NAME"), "APP_PORT": os.getenv("APP_PORT"), "DEFAULT_MODEL": os.getenv("DEFAULT_MODEL"), "DEPLOYMENT_PLATFORM": os.getenv("DEPLOYMENT_PLATFORM"), "ENVIRONMENT": os.getenv("ENVIRONMENT"), "LOG_LEVEL": os.getenv("LOG_LEVEL") }, "file_system": { "app_files": [f for f in os.listdir('.') if f.startswith('app')], "deployment_files": [f for f in os.listdir('.') if f.startswith('deploy')], "config_files": [f for f in os.listdir('.') if 'config' in f.lower()] } }