Codelint-MCP / src /config.py
OsamaAliMid's picture
Add CodeLint MCP Premium Edition application
ec37394
"""
πŸ† 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()