From b60887c71d460cf6c41f4f6f5210cbb8f9f8114d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sun, 21 Jun 2026 20:41:24 +0200 Subject: [PATCH] Added ollama as AI provider Unlike the LMStudio one it also features an API key and proper model auto suggestion --- composer.json | 1 + composer.lock | 88 +++++++++++++++++++++- config/packages/ai_ollama_platform.yaml | 5 ++ docs/usage/ai.md | 7 ++ src/Services/AI/AIPlatforms.php | 3 + src/Settings/AISettings/AISettings.php | 3 + src/Settings/AISettings/OllamaSettings.php | 58 ++++++++++++++ symfony.lock | 12 +++ translations/messages.en.xlf | 18 +++++ 9 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 config/packages/ai_ollama_platform.yaml create mode 100644 src/Settings/AISettings/OllamaSettings.php diff --git a/composer.json b/composer.json index d624ea8e..10c9b702 100644 --- a/composer.json +++ b/composer.json @@ -59,6 +59,7 @@ "spatie/db-dumper": "^3.3.1", "symfony/ai-bundle": "^0.10.0", "symfony/ai-lm-studio-platform": "^v0.10.0", + "symfony/ai-ollama-platform": "^0.10.0", "symfony/ai-open-router-platform": "^0.10.0", "symfony/apache-pack": "^1.0", "symfony/asset": "7.4.*", diff --git a/composer.lock b/composer.lock index 5738fb88..ca50c2c6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ec87cdf341410bbd499a9debb5c862ab", + "content-hash": "6a79fa73091c2e15bce035c85c2d61ed", "packages": [ { "name": "amphp/amp", @@ -11061,6 +11061,92 @@ ], "time": "2026-06-15T22:48:31+00:00" }, + { + "name": "symfony/ai-ollama-platform", + "version": "v0.10.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ai-ollama-platform.git", + "reference": "1542f19b78362cafc034c219f5bc9a5a239a0ffb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ai-ollama-platform/zipball/1542f19b78362cafc034c219f5bc9a5a239a0ffb", + "reference": "1542f19b78362cafc034c219f5bc9a5a239a0ffb", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/ai-platform": "^0.10", + "symfony/http-client": "^7.3|^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^11.5.53" + }, + "type": "symfony-ai-platform", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ai", + "name": "symfony/ai" + } + }, + "autoload": { + "psr-4": { + "Symfony\\AI\\Platform\\Bridge\\Ollama\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christopher Hertel", + "email": "mail@christopher-hertel.de" + }, + { + "name": "Oskar Stark", + "email": "oskarstark@googlemail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Ollama platform bridge for Symfony AI", + "keywords": [ + "Bridge", + "ai", + "local", + "ollama", + "platform" + ], + "support": { + "source": "https://github.com/symfony/ai-ollama-platform/tree/v0.10.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-15T22:48:31+00:00" + }, { "name": "symfony/ai-open-router-platform", "version": "v0.10.0", diff --git a/config/packages/ai_ollama_platform.yaml b/config/packages/ai_ollama_platform.yaml new file mode 100644 index 00000000..df551d4a --- /dev/null +++ b/config/packages/ai_ollama_platform.yaml @@ -0,0 +1,5 @@ +ai: + platform: + ollama: + endpoint: '%env(string:settings:ai_ollama:endpoint)%' + api_key: '%env(string:settings:ai_ollama:apiKey)%' diff --git a/docs/usage/ai.md b/docs/usage/ai.md index 3a1fb419..30f6c628 100644 --- a/docs/usage/ai.md +++ b/docs/usage/ai.md @@ -25,3 +25,10 @@ You need to supply an API key for OpenRouter to use it as an AI platform in Part [LMStudio](https://lmstudio.ai/) is a local LLM hosting solution that allows you to run LLMs on your own hardware. You can use LMStudio to host your own LLM and connect it to Part-DB for AI features. Currently only LMStudio without any authentication is supported. Supply your LMStudio instance URL (including the port) to use it as an AI platform in Part-DB. +You have to set a model by hand, as suggestions currently do not work yet. Ensure the context length is suitable for your application. + +### Ollama + +[Ollama](https://ollama.com/) is another local LLM hosting solution that allows you to run LLMs on your own hardware. You can use Ollama to host your own LLM and connect it to Part-DB for AI features. +Supply your Ollama instance URL (including the port) and an optional API key for authentication to use it as an AI platform in Part-DB. The model selector should give you suggestions about available models. +Ensure the context length is suitable for your application. diff --git a/src/Services/AI/AIPlatforms.php b/src/Services/AI/AIPlatforms.php index 2f4d6317..318819a2 100644 --- a/src/Services/AI/AIPlatforms.php +++ b/src/Services/AI/AIPlatforms.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace App\Services\AI; use App\Settings\AISettings\LMStudioSettings; +use App\Settings\AISettings\OllamaSettings; use App\Settings\AISettings\OpenRouterSettings; use Symfony\Contracts\Translation\TranslatableInterface; use Symfony\Contracts\Translation\TranslatorInterface; @@ -32,6 +33,7 @@ enum AIPlatforms: string implements TranslatableInterface { case OPENROUTER = 'openrouter'; case LMSTUDIO = 'lmstudio'; + case OLLAMA = 'ollama'; /** * Returns the name attribute of the service tag for this platform, which is used to register the platform in the AIPlatformRegistry @@ -52,6 +54,7 @@ enum AIPlatforms: string implements TranslatableInterface return match ($this) { self::LMSTUDIO => LMStudioSettings::class, self::OPENROUTER => OpenRouterSettings::class, + self::OLLAMA => OllamaSettings::class, }; } diff --git a/src/Settings/AISettings/AISettings.php b/src/Settings/AISettings/AISettings.php index 732eb597..9f145c7f 100644 --- a/src/Settings/AISettings/AISettings.php +++ b/src/Settings/AISettings/AISettings.php @@ -40,4 +40,7 @@ class AISettings #[EmbeddedSettings] public ?LMStudioSettings $lmstudio = null; + + #[EmbeddedSettings] + public ?OllamaSettings $ollama = null; } diff --git a/src/Settings/AISettings/OllamaSettings.php b/src/Settings/AISettings/OllamaSettings.php new file mode 100644 index 00000000..dd17d5e2 --- /dev/null +++ b/src/Settings/AISettings/OllamaSettings.php @@ -0,0 +1,58 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Settings\AISettings; + +use App\Form\Type\APIKeyType; +use App\Services\AI\AIPlatformSettingsInterface; +use App\Settings\SettingsIcon; +use Jbtronics\SettingsBundle\Metadata\EnvVarMode; +use Jbtronics\SettingsBundle\Settings\Settings; +use Jbtronics\SettingsBundle\Settings\SettingsParameter; +use Jbtronics\SettingsBundle\Settings\SettingsTrait; +use Symfony\Component\Form\Extension\Core\Type\UrlType; +use Symfony\Component\Translation\StaticMessage; +use Symfony\Component\Translation\TranslatableMessage as TM; + +#[Settings(name: 'ai_ollama', label: new TM("settings.ai.ollama"))] +#[SettingsIcon("fa-robot")] +class OllamaSettings implements AIPlatformSettingsInterface +{ + use SettingsTrait; + + #[SettingsParameter(label: new TM("settings.ai.ollama.endpoint"), + formType: UrlType::class, + formOptions: ["attr" => ["placeholder" => new StaticMessage("http://localhost:11434")]], + envVar: "AI_OLLAMA_ENDPOINT", envVarMode: EnvVarMode::OVERWRITE)] + public ?string $endpoint = null; + + #[SettingsParameter(label: new TM("settings.ai.ollama.apiKey"), + formType: APIKeyType::class, + envVar: "AI_OLLAMA_API_KEY", envVarMode: EnvVarMode::OVERWRITE)] + public ?string $apiKey = null; + + public function isAIPlatformEnabled(): bool + { + return $this->endpoint !== null && $this->endpoint !== ""; + } +} diff --git a/symfony.lock b/symfony.lock index f8f88675..94af6e6a 100644 --- a/symfony.lock +++ b/symfony.lock @@ -411,6 +411,18 @@ "config/packages/ai_lm_studio_platform.yaml" ] }, + "symfony/ai-ollama-platform": { + "version": "0.10", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "0.1", + "ref": "2f0ac0a8bc59c4e46b47a962a3ad7fe8104457d6" + }, + "files": [ + "config/packages/ai_ollama_platform.yaml" + ] + }, "symfony/ai-open-router-platform": { "version": "0.8", "recipe": { diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index fe219869..af33ee97 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -13619,6 +13619,24 @@ Buerklin-API Authentication server: Host URL + + + settings.ai.ollama + Ollama + + + + + settings.ai.ollama.endpoint + Endpoint URL + + + + + settings.ai.ollama.apiKey + API Key + + browser_plugin.recent_pages.title