systemConfig = $systemConfig; } /** * Get a provider instance. */ public function provider(?string $identifier = null): AiProviderInterface { $identifier = $identifier ?: $this->systemConfig->get('ai_provider', 'gpt'); if (isset($this->providers[$identifier])) { return $this->providers[$identifier]; } $config = $this->getProviderConfig($identifier); $instance = match ($identifier) { 'gpt' => new GptProvider($config), 'gemini' => new GeminiProvider($config), 'claude' => new ClaudeProvider($config), 'deepseek' => new OpenAiCompatibleProvider('deepseek', 'https://api.deepseek.com/chat/completions', $config), 'grok' => new OpenAiCompatibleProvider('grok', 'https://api.x.ai/v1/chat/completions', $config), 'mistral' => new OpenAiCompatibleProvider('mistral', 'https://api.mistral.ai/v1/chat/completions', $config), 'openrouter' => new OpenAiCompatibleProvider('openrouter', 'https://openrouter.ai/api/v1/chat/completions', $config), 'ollama' => new OllamaProvider($config), default => throw new \Exception("Unsupported AI provider: {$identifier}"), }; return $this->providers[$identifier] = $instance; } /** * Get configuration for a specific provider from system settings. */ protected function getProviderConfig(string $identifier): array { return [ 'key' => $this->systemConfig->get("ai_{$identifier}_key"), 'base_url' => $this->systemConfig->get("ai_{$identifier}_base_url"), 'default_model' => $this->systemConfig->get('ai_default_model'), 'instruction' => $this->systemConfig->get('ai_system_instruction'), 'temperature' => $this->systemConfig->get('ai_temperature', 0.7), 'max_tokens' => $this->systemConfig->get('ai_max_tokens', 2000), ]; } /** * Static method to get supported models for each provider. */ public static function getSupportedModels(): array { return [ 'gpt' => [ ['id' => 'gpt-4o', 'name' => 'GPT-4o (Newest)'], ['id' => 'gpt-4-turbo', 'name' => 'GPT-4 Turbo'], ['id' => 'gpt-3.5-turbo', 'name' => 'GPT-3.5 Turbo'], ], 'gemini' => [ ['id' => 'gemini-1.5-pro', 'name' => 'Gemini 1.5 Pro'], ['id' => 'gemini-1.5-flash', 'name' => 'Gemini 1.5 Flash'], ['id' => 'gemini-1.0-pro', 'name' => 'Gemini 1.0 Pro'], ], 'claude' => [ ['id' => 'claude-3-5-sonnet-20240620', 'name' => 'Claude 3.5 Sonnet'], ['id' => 'claude-3-opus-20240229', 'name' => 'Claude 3 Opus'], ['id' => 'claude-3-sonnet-20240229', 'name' => 'Claude 3 Sonnet'], ['id' => 'claude-3-haiku-20240307', 'name' => 'Claude 3 Haiku'], ], 'deepseek' => [ ['id' => 'deepseek-chat', 'name' => 'DeepSeek Chat'], ['id' => 'deepseek-coder', 'name' => 'DeepSeek Coder'], ], 'grok' => [ ['id' => 'grok-1', 'name' => 'Grok-1'], ], 'mistral' => [ ['id' => 'mistral-large-latest', 'name' => 'Mistral Large'], ['id' => 'mistral-medium-latest', 'name' => 'Mistral Medium'], ['id' => 'mistral-small-latest', 'name' => 'Mistral Small'], ], 'openrouter' => [ ['id' => 'google/gemini-pro-1.5', 'name' => 'Gemini Pro 1.5'], ['id' => 'anthropic/claude-3.5-sonnet', 'name' => 'Claude 3.5 Sonnet'], ['id' => 'meta-llama/llama-3-70b-instruct', 'name' => 'Llama 3 70B'], ], 'ollama' => [ ['id' => 'llama3', 'name' => 'Llama 3'], ['id' => 'mistral', 'name' => 'Mistral'], ['id' => 'phi3', 'name' => 'Phi-3'], ], ]; } }