Skip to content

Commit 8431479

Browse files
committed
ref(platform): OllamaCatalog
1 parent 33811e8 commit 8431479

File tree

6 files changed

+64
-25
lines changed

6 files changed

+64
-25
lines changed

src/ai-bundle/config/services.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
use Symfony\AI\Platform\Bridge\Mistral\ModelCatalog as MistralModelCatalog;
4747
use Symfony\AI\Platform\Bridge\Mistral\TokenOutputProcessor as MistralTokenOutputProcessor;
4848
use Symfony\AI\Platform\Bridge\Ollama\Contract\OllamaContract;
49-
use Symfony\AI\Platform\Bridge\Ollama\ModelCatalog as OllamaModelCatalog;
5049
use Symfony\AI\Platform\Bridge\OpenAi\Contract\OpenAiContract;
5150
use Symfony\AI\Platform\Bridge\OpenAi\ModelCatalog as OpenAiModelCatalog;
5251
use Symfony\AI\Platform\Bridge\OpenAi\TokenOutputProcessor as OpenAiTokenOutputProcessor;
@@ -67,6 +66,7 @@
6766
use Symfony\AI\Store\Command\DropStoreCommand;
6867
use Symfony\AI\Store\Command\IndexCommand;
6968
use Symfony\AI\Store\Command\SetupStoreCommand;
69+
use Symfony\Component\DependencyInjection\Reference;
7070

7171
return static function (ContainerConfigurator $container): void {
7272
$container->services()
@@ -99,7 +99,6 @@
9999
->set('ai.platform.model_catalog.huggingface', HuggingFaceModelCatalog::class)
100100
->set('ai.platform.model_catalog.lmstudio', LmStudioModelCatalog::class)
101101
->set('ai.platform.model_catalog.mistral', MistralModelCatalog::class)
102-
->set('ai.platform.model_catalog.ollama', OllamaModelCatalog::class)
103102
->set('ai.platform.model_catalog.openai', OpenAiModelCatalog::class)
104103
->set('ai.platform.model_catalog.openrouter', OpenRouterModelCatalog::class)
105104
->set('ai.platform.model_catalog.perplexity', PerplexityModelCatalog::class)

src/ai-bundle/src/AiBundle.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
use Symfony\AI\Platform\Bridge\Gemini\PlatformFactory as GeminiPlatformFactory;
4646
use Symfony\AI\Platform\Bridge\LmStudio\PlatformFactory as LmStudioPlatformFactory;
4747
use Symfony\AI\Platform\Bridge\Mistral\PlatformFactory as MistralPlatformFactory;
48+
use Symfony\AI\Platform\Bridge\Ollama\OllamaCatalog;
4849
use Symfony\AI\Platform\Bridge\Ollama\PlatformFactory as OllamaPlatformFactory;
4950
use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory as OpenAiPlatformFactory;
5051
use Symfony\AI\Platform\Bridge\OpenRouter\PlatformFactory as OpenRouterPlatformFactory;
@@ -442,7 +443,14 @@ private function processPlatformConfig(string $type, array $platform, ContainerB
442443
}
443444

444445
if ('ollama' === $type) {
445-
$platformId = 'ai.platform.ollama';
446+
$catalogDefinition = (new Definition(OllamaCatalog::class))
447+
->setArguments([
448+
$platform['host_url'],
449+
new Reference('http_client'),
450+
]);
451+
452+
$container->setDefinition('ai.platform.model_catalog.ollama', $catalogDefinition);
453+
446454
$definition = (new Definition(Platform::class))
447455
->setFactory(OllamaPlatformFactory::class.'::create')
448456
->setLazy(true)
@@ -455,7 +463,7 @@ private function processPlatformConfig(string $type, array $platform, ContainerB
455463
])
456464
->addTag('ai.platform', ['name' => 'ollama']);
457465

458-
$container->setDefinition($platformId, $definition);
466+
$container->setDefinition('ai.platform.ollama', $definition);
459467

460468
return;
461469
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\AI\Platform\Bridge\Ollama;
13+
14+
use Symfony\AI\Platform\Exception\InvalidArgumentException;
15+
use Symfony\AI\Platform\Model;
16+
use Symfony\AI\Platform\ModelCatalog\DynamicModelCatalog;
17+
use Symfony\Contracts\HttpClient\HttpClientInterface;
18+
19+
final class OllamaCatalog extends DynamicModelCatalog
20+
{
21+
public function __construct(
22+
private readonly string $host,
23+
private readonly HttpClientInterface $httpClient,
24+
) {
25+
parent::__construct();
26+
}
27+
28+
public function getModel(string $modelName): Model
29+
{
30+
$model = parent::getModel($modelName);
31+
32+
$response = $this->httpClient->request('POST', \sprintf('%s/api/show', $this->host), [
33+
'json' => [
34+
'model' => $model->getName(),
35+
],
36+
]);
37+
38+
$payload = $response->toArray();
39+
40+
if ([] === $payload['capabilities'] ?? []) {
41+
throw new InvalidArgumentException('The model information could not be retrieved from the Ollama API. Your Ollama server might be too old. Try upgrade it.');
42+
}
43+
44+
return new Ollama($model->getName(), $payload['capabilities'], $model->getOptions());
45+
}
46+
}

src/platform/src/Bridge/Ollama/OllamaClient.php

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,9 @@ public function supports(Model $model): bool
3535

3636
public function request(Model $model, array|string $payload, array $options = []): RawHttpResult
3737
{
38-
$response = $this->httpClient->request('POST', \sprintf('%s/api/show', $this->hostUrl), [
39-
'json' => [
40-
'model' => $model->getName(),
41-
],
42-
]);
43-
44-
$capabilities = $response->toArray()['capabilities'] ?? null;
45-
46-
if (null === $capabilities) {
47-
throw new InvalidArgumentException('The model information could not be retrieved from the Ollama API. Your Ollama server might be too old. Try upgrade it.');
48-
}
49-
5038
return match (true) {
51-
\in_array('completion', $capabilities, true) => $this->doCompletionRequest($payload, $options),
52-
\in_array('embedding', $capabilities, true) => $this->doEmbeddingsRequest($model, $payload, $options),
39+
\in_array('completion', $model->getCapabilities(), true) => $this->doCompletionRequest($payload, $options),
40+
\in_array('embedding', $model->getCapabilities(), true) => $this->doEmbeddingsRequest($model, $payload, $options),
5341
default => throw new InvalidArgumentException(\sprintf('Unsupported model "%s": "%s".', $model::class, $model->getName())),
5442
};
5543
}

src/platform/src/Bridge/Ollama/PlatformFactory.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
use Symfony\AI\Platform\Bridge\Ollama\Contract\OllamaContract;
1515
use Symfony\AI\Platform\Contract;
16-
use Symfony\AI\Platform\ModelCatalog\DynamicModelCatalog;
1716
use Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface;
1817
use Symfony\AI\Platform\Platform;
1918
use Symfony\Component\HttpClient\EventSourceHttpClient;
@@ -27,15 +26,15 @@ final class PlatformFactory
2726
public static function create(
2827
string $hostUrl = 'http://localhost:11434',
2928
?HttpClientInterface $httpClient = null,
30-
ModelCatalogInterface $modelCatalog = new DynamicModelCatalog(Ollama::class),
29+
?ModelCatalogInterface $modelCatalog = null,
3130
?Contract $contract = null,
3231
): Platform {
3332
$httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient);
3433

3534
return new Platform(
3635
[new OllamaClient($httpClient, $hostUrl)],
3736
[new OllamaResultConverter()],
38-
$modelCatalog,
37+
$modelCatalog ?? new OllamaCatalog($hostUrl, $httpClient),
3938
$contract ?? OllamaContract::create(),
4039
);
4140
}

src/platform/src/ModelCatalog/DynamicModelCatalog.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,15 @@
2525

2626
class DynamicModelCatalog extends AbstractModelCatalog
2727
{
28-
public function __construct(
29-
private readonly ?string $expectedModel = Model::class,
30-
) {
28+
public function __construct()
29+
{
3130
$this->models = [];
3231
}
3332

3433
public function getModel(string $modelName): Model
3534
{
3635
$parsed = self::parseModelName($modelName);
3736

38-
return new $this->expectedModel($parsed['name'], Capability::cases(), $parsed['options']);
37+
return new Model($parsed['name'], Capability::cases(), $parsed['options']);
3938
}
4039
}

0 commit comments

Comments
 (0)