""" 🏆 Premium AI Provider Configuration System Supports: OpenAI GPT-5, Google Gemini 3, Claude Sonnet 4.5, and 6 Free OpenRouter Models """ import os from pathlib import Path from typing import Optional, Dict from enum import Enum from dataclasses import dataclass from dotenv import load_dotenv import logging logger = logging.getLogger(__name__) # Load environment variables load_dotenv() class AIProvider(str, Enum): """Supported AI providers""" # ⭐ Premium Providers (Require API Keys) OPENAI = "openai" GOOGLE_GEMINI = "google" ANTHROPIC = "anthropic" # 🆓 Free OpenRouter Models GROK = "grok" KAT_CODER = "kat-coder" QWEN_CODER = "qwen-coder" LONGCAT = "longcat" GPT_OSS = "gpt-oss" KIMI = "kimi" @dataclass class ModelConfig: """Configuration for an AI model""" name: str display_name: str provider: AIProvider model_id: str is_premium: bool badge: str requires_api_key: bool # 🎯 Available Models Configuration AVAILABLE_MODELS: Dict[str, ModelConfig] = { # ⭐ Premium Models "gpt-5": ModelConfig( name="gpt-5", display_name="⭐ GPT-5 (OpenAI)", provider=AIProvider.OPENAI, model_id="gpt-5", is_premium=True, badge="⭐ PRO", requires_api_key=True ), "gemini-3": ModelConfig( name="gemini-3", display_name="⭐ Gemini 3 (Google)", provider=AIProvider.GOOGLE_GEMINI, model_id="gemini-3.0-pro", is_premium=True, badge="⭐ PRO", requires_api_key=True ), "claude-sonnet": ModelConfig( name="claude-sonnet", display_name="⭐ Claude Sonnet 4.5 (Anthropic)", provider=AIProvider.ANTHROPIC, model_id="claude-sonnet-4.5", is_premium=True, badge="⭐ PRO", requires_api_key=True ), # 🆓 Free OpenRouter Models "grok-4.1": ModelConfig( name="grok-4.1", display_name="🆓 Grok 4.1 Fast", provider=AIProvider.GROK, model_id="x-ai/grok-4.1-fast:free", is_premium=False, badge="🆓 FREE", requires_api_key=False ), "kat-coder": ModelConfig( name="kat-coder", display_name="🆓 KAT-Coder-Pro V1", provider=AIProvider.KAT_CODER, model_id="kwaipilot/kat-coder-pro:free", is_premium=False, badge="🆓 FREE", requires_api_key=False ), "qwen-coder": ModelConfig( name="qwen-coder", display_name="🆓 Qwen3 Coder", provider=AIProvider.QWEN_CODER, model_id="qwen/qwen3-coder:free", is_premium=False, badge="🆓 FREE", requires_api_key=False ), "longcat": ModelConfig( name="longcat", display_name="🆓 LongCat Flash Chat", provider=AIProvider.LONGCAT, model_id="meituan/longcat-flash-chat:free", is_premium=False, badge="🆓 FREE", requires_api_key=False ), "gpt-oss": ModelConfig( name="gpt-oss", display_name="🆓 GPT-OSS 20B", provider=AIProvider.GPT_OSS, model_id="openai/gpt-oss-20b:free", is_premium=False, badge="🆓 FREE", requires_api_key=False ), "kimi": ModelConfig( name="kimi", display_name="🆓 Kimi K2", provider=AIProvider.KIMI, model_id="moonshotai/kimi-k2:free", is_premium=False, badge="🆓 FREE", requires_api_key=False ), } class Config: """🏆 Premium Application Configuration""" # API Keys GOOGLE_API_KEY: str = os.getenv("GOOGLE_API_KEY", "") OPENAI_API_KEY: str = os.getenv("OPENAI_API_KEY", "") ANTHROPIC_API_KEY: str = os.getenv("ANTHROPIC_API_KEY", "") OPENROUTER_API_KEY: str = os.getenv( "OPENROUTER_API_KEY", "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" ) # Default model DEFAULT_MODEL: str = os.getenv("DEFAULT_MODEL", "grok-4.1") # AI settings MAX_TOKENS: int = int(os.getenv("MAX_TOKENS", "4096")) TEMPERATURE: float = float(os.getenv("TEMPERATURE", "0.7")) # Server settings LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO") # Cache settings CACHE_MAX_SIZE: int = int(os.getenv("CACHE_MAX_SIZE", "1000")) # Rate limiting RATE_LIMIT_PER_MINUTE: int = int(os.getenv("RATE_LIMIT_PER_MINUTE", "60")) # Project paths PROJECT_ROOT: Path = Path(__file__).parent.parent RESOURCES_DIR: Path = PROJECT_ROOT / "src" / "resources" / "static" @classmethod def get_model_config(cls, model_name: str) -> Optional[ModelConfig]: """Get configuration for a specific model""" return AVAILABLE_MODELS.get(model_name) @classmethod def get_available_models(cls) -> Dict[str, ModelConfig]: """Get all available models""" return AVAILABLE_MODELS @classmethod def get_dropdown_options(cls) -> list: """Get formatted options for UI dropdown""" options = [] # Premium models first for model_id, config in AVAILABLE_MODELS.items(): if config.is_premium: options.append(config.display_name) # Then free models for model_id, config in AVAILABLE_MODELS.items(): if not config.is_premium: options.append(config.display_name) return options @classmethod def get_model_by_display_name(cls, display_name: str) -> Optional[str]: """Get model key from display name""" for model_id, config in AVAILABLE_MODELS.items(): if config.display_name == display_name: return model_id return None @classmethod def validate_api_key(cls, model_name: str, api_key: Optional[str] = None) -> bool: """Validate if required API key is available""" model_config = cls.get_model_config(model_name) if not model_config: return False # Free OpenRouter models don't need user API key if not model_config.requires_api_key: return True # Premium models need specific API keys if model_config.provider == AIProvider.OPENAI: return bool(api_key or cls.OPENAI_API_KEY) elif model_config.provider == AIProvider.GOOGLE_GEMINI: return bool(api_key or cls.GOOGLE_API_KEY) elif model_config.provider == AIProvider.ANTHROPIC: return bool(api_key or cls.ANTHROPIC_API_KEY) return False @classmethod def validate(cls) -> bool: """Validate configuration""" # At least OpenRouter should work return bool(cls.OPENROUTER_API_KEY) @classmethod def get_config_file(cls, path: Optional[str] = None) -> Optional[Path]: """Get configuration file path""" if path: return Path(path) # Check for .codelintrc.json in current directory config_path = Path.cwd() / ".codelintrc.json" if config_path.exists(): return config_path return None # Validate configuration on import Config.validate()