From 18bf07b19f18ba059931330cfdb346bafb13c741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sun, 26 Apr 2026 01:10:00 +0200 Subject: [PATCH] Added an AI platform selector for settings --- src/Form/Settings/AiPlatformChoiceType.php | 54 +++++++++++++++++++ src/Services/AI/AIPlatforms.php | 11 +++- .../Providers/AIInfoExtractor.php | 10 ++-- .../AIExtractorSettings.php | 7 ++- 4 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 src/Form/Settings/AiPlatformChoiceType.php diff --git a/src/Form/Settings/AiPlatformChoiceType.php b/src/Form/Settings/AiPlatformChoiceType.php new file mode 100644 index 00000000..b28f217d --- /dev/null +++ b/src/Form/Settings/AiPlatformChoiceType.php @@ -0,0 +1,54 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\Settings; + +use App\Services\AI\AIPlatformRegistry; +use App\Services\AI\AIPlatforms; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\EnumType; +use Symfony\Component\OptionsResolver\OptionsResolver; + +final class AiPlatformChoiceType extends AbstractType +{ + public function __construct(private readonly AIPlatformRegistry $platformRegistry) + { + } + + public function getParent(): ?string + { + return EnumType::class; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $choices = array_map(static fn(string $val) => AIPlatforms::from($val), array_keys($this->platformRegistry->getEnabledPlatforms())); + + $resolver->setDefaults([ + 'class' => AIPlatforms::class, + 'choices' => $choices, + 'required' => false, + ]); + } +} diff --git a/src/Services/AI/AIPlatforms.php b/src/Services/AI/AIPlatforms.php index 9a1480e4..ec772cf3 100644 --- a/src/Services/AI/AIPlatforms.php +++ b/src/Services/AI/AIPlatforms.php @@ -25,8 +25,10 @@ namespace App\Services\AI; use App\Settings\AISettings\LMStudioSettings; use App\Settings\AISettings\OpenRouterSettings; +use Symfony\Contracts\Translation\TranslatableInterface; +use Symfony\Contracts\Translation\TranslatorInterface; -enum AIPlatforms: string +enum AIPlatforms: string implements TranslatableInterface { case OPENROUTER = 'openrouter'; case LMSTUDIO = 'lmstudio'; @@ -54,4 +56,11 @@ enum AIPlatforms: string default => throw new \InvalidArgumentException(sprintf('No settings class defined for AI platform "%s".', $this->name)), }; } + + public function trans(TranslatorInterface $translator, ?string $locale = null): string + { + $key = 'settings.ai.' . $this->value; + + return $translator->trans($key, locale: $locale); + } } diff --git a/src/Services/InfoProviderSystem/Providers/AIInfoExtractor.php b/src/Services/InfoProviderSystem/Providers/AIInfoExtractor.php index 973987de..d5be0267 100644 --- a/src/Services/InfoProviderSystem/Providers/AIInfoExtractor.php +++ b/src/Services/InfoProviderSystem/Providers/AIInfoExtractor.php @@ -26,14 +26,11 @@ namespace App\Services\InfoProviderSystem\Providers; use App\Exceptions\ProviderIDNotSupportedException; use App\Services\AI\AIPlatformRegistry; -use App\Services\AI\AIPlatforms; use App\Services\InfoProviderSystem\DTOJsonSchemaConverter; use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; use App\Settings\InfoProviderSystem\AIExtractorSettings; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; -use Symfony\AI\Platform\PlatformInterface; -use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Contracts\HttpClient\HttpClientInterface; final class AIInfoExtractor implements InfoProviderInterface @@ -76,8 +73,7 @@ final class AIInfoExtractor implements InfoProviderInterface public function isActive(): bool { - return true; - //return !empty($this->settings->apiKey) && $this->settings->enabled; + return $this->settings->platform !== null && $this->settings->model !== ''; } public function searchByKeyword(string $keyword): array @@ -172,10 +168,10 @@ final class AIInfoExtractor implements InfoProviderInterface ); try { - $aiPlatform = $this->AIPlatformRegistry->getPlatform(AIPlatforms::OPENROUTER); + $aiPlatform = $this->AIPlatformRegistry->getPlatform($this->settings->platform ?? throw new \RuntimeException('No AI platform selected') ); //'openai/gpt-5-mini' - $result = $aiPlatform->invoke('openrouter/auto', $input, [ + $result = $aiPlatform->invoke($this->settings->model, $input, [ 'response_format' => [ 'type' => 'json_schema', 'json_schema' => $this->jsonSchemaConverter->getJSONSchema(), diff --git a/src/Settings/InfoProviderSystem/AIExtractorSettings.php b/src/Settings/InfoProviderSystem/AIExtractorSettings.php index c78ca96e..69b02637 100644 --- a/src/Settings/InfoProviderSystem/AIExtractorSettings.php +++ b/src/Settings/InfoProviderSystem/AIExtractorSettings.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace App\Settings\InfoProviderSystem; +use App\Form\Settings\AiPlatformChoiceType; +use App\Services\AI\AIPlatforms; use App\Settings\SettingsIcon; use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Settings\Settings; @@ -36,10 +38,11 @@ class AIExtractorSettings { use SettingsTrait; - #[SettingsParameter(label: new TM("settings.ips.ai_extractor.api_key"), description: new TM("settings.ips.ai_extractor.api_key.description"), + #[SettingsParameter(label: new TM("settings.ips.ai_extractor.ai_platform"), description: new TM("settings.ips.ai_extractor.ai_platform.help"), + formType: AiPlatformChoiceType::class, envVar: "string:PROVIDER_AI_EXTRACTOR_API_KEY", envVarMode: EnvVarMode::OVERWRITE )] - public ?string $apiKey = null; + public ?AIPlatforms $platform = null; #[SettingsParameter(label: new TM("settings.ips.ai_extractor.model"), description: new TM("settings.ips.ai_extractor.model.description"), envVar: "string:PROVIDER_AI_EXTRACTOR_MODEL", envVarMode: EnvVarMode::OVERWRITE