Skip to content

Commit 65f3f3f

Browse files
committed
Refactor ModelCatalog to injectable service with platform-specific catalogs
- Remove ->value from Capability enum references to use enum instances directly - Convert ModelCatalog to injectable service that can be extended with user models - Remove AbstractModelCatalog and implement ModelCatalogInterface directly - Add platform-specific ModelCatalog services (ai.model_catalog.openai) - Add all GPT and Embeddings models to OpenAI ModelCatalog with proper capabilities - Inject ModelCatalog into OpenAI PlatformFactory with fallback support - Add comprehensive test coverage for OpenAI ModelCatalog - Create example demonstrating custom model addition with audio transcription - Move model catalog configuration from compiler pass to bundle initialization - Remove getCapabilities method and pass name+capabilities to model constructor - Add fallback for all capabilities when none provided in configuration - Ensure default empty model catalogs exist for all platforms
1 parent dc4222b commit 65f3f3f

File tree

12 files changed

+578
-228
lines changed

12 files changed

+578
-228
lines changed

MODELS_CONFIG_EXAMPLE.yaml

Lines changed: 0 additions & 55 deletions
This file was deleted.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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+
use Symfony\AI\Platform\Bridge\OpenAi\Gpt;
13+
use Symfony\AI\Platform\Bridge\OpenAi\ModelCatalog;
14+
use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory;
15+
use Symfony\AI\Platform\Capability;
16+
use Symfony\AI\Platform\Message\Content\Audio;
17+
use Symfony\AI\Platform\Message\Message;
18+
use Symfony\AI\Platform\Message\MessageBag;
19+
20+
require_once dirname(__DIR__).'/bootstrap.php';
21+
22+
$modelCatalog = new ModelCatalog([
23+
'gpt-4o-mini-transcribe' => [
24+
'class' => Gpt::class,
25+
'capabilities' => [
26+
Capability::INPUT_AUDIO,
27+
Capability::INPUT_TEXT,
28+
Capability::OUTPUT_TEXT,
29+
],
30+
],
31+
]);
32+
33+
// Create platform with the custom model catalog
34+
$platform = PlatformFactory::create(
35+
env('OPENAI_API_KEY'),
36+
http_client(),
37+
catalog: $modelCatalog
38+
);
39+
40+
// Use the transcription model
41+
$transcribeModel = $modelCatalog->getModel('gpt-4o-mini-transcribe');
42+
43+
$messages = new MessageBag(
44+
Message::ofUser(
45+
'Please transcribe this audio file.',
46+
Audio::fromFile(dirname(__DIR__, 2).'/fixtures/audio.mp3'),
47+
),
48+
);
49+
50+
$result = $platform->invoke($transcribeModel, $messages, [
51+
'max_tokens' => 300,
52+
]);
53+
54+
echo $result->getResult()->getContent()."\n\n";

src/ai-bundle/config/options.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@
168168
->end()
169169
->end()
170170
->end()
171-
->arrayNode('models')
171+
->arrayNode('model')
172172
->useAttributeAsKey('platform')
173173
->arrayPrototype()
174174
->useAttributeAsKey('model_name')

src/ai-bundle/config/services.php

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@
4141
use Symfony\AI\Platform\Contract;
4242
use Symfony\AI\Platform\Contract\JsonSchema\DescriptionParser;
4343
use Symfony\AI\Platform\Contract\JsonSchema\Factory as SchemaFactory;
44-
use Symfony\AI\Platform\ModelCatalog;
45-
use Symfony\AI\Platform\ModelCatalogInterface;
4644
use Symfony\AI\Store\Command\DropStoreCommand;
4745
use Symfony\AI\Store\Command\IndexCommand;
4846
use Symfony\AI\Store\Command\SetupStoreCommand;
@@ -176,12 +174,5 @@
176174
tagged_locator('ai.indexer', 'name'),
177175
])
178176
->tag('console.command')
179-
180-
// model catalog
181-
->set('ai.model_catalog', ModelCatalog::class)
182-
->args([
183-
[], // models array will be set by compiler pass
184-
])
185-
->alias(ModelCatalogInterface::class, 'ai.model_catalog')
186177
;
187178
};

src/ai-bundle/src/AiBundle.php

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
use Symfony\AI\Agent\Toolbox\Tool\Agent as AgentTool;
2828
use Symfony\AI\Agent\Toolbox\ToolFactory\ChainFactory;
2929
use Symfony\AI\Agent\Toolbox\ToolFactory\MemoryToolFactory;
30-
use Symfony\AI\AiBundle\DependencyInjection\ModelCatalogCompilerPass;
3130
use Symfony\AI\AiBundle\DependencyInjection\ProcessorCompilerPass;
3231
use Symfony\AI\AiBundle\Exception\InvalidArgumentException;
3332
use Symfony\AI\AiBundle\Profiler\TraceablePlatform;
@@ -48,7 +47,9 @@
4847
use Symfony\AI\Platform\Bridge\VertexAi\PlatformFactory as VertexAiPlatformFactory;
4948
use Symfony\AI\Platform\Bridge\Voyage\PlatformFactory as VoyagePlatformFactory;
5049
use Symfony\AI\Platform\Exception\RuntimeException;
50+
use Symfony\AI\Platform\Capability;
5151
use Symfony\AI\Platform\Model;
52+
use Symfony\AI\Platform\ModelCatalog;
5253
use Symfony\AI\Platform\ModelClientInterface;
5354
use Symfony\AI\Platform\Platform;
5455
use Symfony\AI\Platform\PlatformInterface;
@@ -99,7 +100,6 @@ public function build(ContainerBuilder $container): void
99100
parent::build($container);
100101

101102
$container->addCompilerPass(new ProcessorCompilerPass());
102-
$container->addCompilerPass(new ModelCatalogCompilerPass());
103103
}
104104

105105
public function configure(DefinitionConfigurator $definition): void // @phpstan-ignore-line generics.notSubtype
@@ -132,12 +132,13 @@ public function loadExtension(array $config, ContainerConfigurator $container, C
132132
}
133133
}
134134

135-
foreach ($config['models'] ?? [] as $platformName => $models) {
136-
foreach ($models as $modelName => $model) {
137-
$this->processModelConfig($modelName, $model, $platformName, $builder);
138-
}
135+
foreach ($config['model'] ?? [] as $platformName => $models) {
136+
$this->processModelCatalogConfig($platformName, $models, $builder);
139137
}
140138

139+
// Ensure default empty model catalogs exist for all platforms
140+
$this->ensureDefaultModelCatalogs($builder);
141+
141142
foreach ($config['agent'] as $agentName => $agent) {
142143
$this->processAgentConfig($agentName, $agent, $builder);
143144
}
@@ -350,6 +351,7 @@ private function processPlatformConfig(string $type, array $platform, ContainerB
350351
new Reference($platform['http_client'], ContainerInterface::NULL_ON_INVALID_REFERENCE),
351352
new Reference('ai.platform.contract.openai'),
352353
$platform['region'] ?? null,
354+
new Reference('ai.model_catalog.openai', ContainerInterface::NULL_ON_INVALID_REFERENCE),
353355
])
354356
->addTag('ai.platform');
355357

@@ -1162,20 +1164,58 @@ private function processIndexerConfig(int|string $name, array $config, Container
11621164
}
11631165

11641166
/**
1165-
* @param array<string, mixed> $config
1167+
* @param array<string, mixed> $models
11661168
*/
1167-
private function processModelConfig(string $modelName, array $config, string $platformName, ContainerBuilder $container): void
1169+
private function processModelCatalogConfig(string $platformName, array $models, ContainerBuilder $container): void
11681170
{
1169-
$platformServiceId = 'ai.platform.'.$platformName;
1170-
1171-
$modelDefinition = new Definition($config['class']);
1172-
$modelDefinition->addTag('ai.model.catalog', [
1173-
'name' => $modelName,
1174-
'class' => $config['class'],
1175-
'platform' => $platformServiceId,
1176-
'capabilities' => $config['capabilities'],
1177-
]);
1171+
$modelDefinitions = [];
1172+
1173+
foreach ($models as $modelName => $modelConfig) {
1174+
$capabilities = $modelConfig['capabilities'] ?? [];
1175+
1176+
// If no capabilities provided, add all capabilities from Capability enum
1177+
if (empty($capabilities)) {
1178+
$capabilityEnums = Capability::cases();
1179+
} else {
1180+
// Convert string capabilities to Capability enums
1181+
if (is_string($capabilities)) {
1182+
$capabilities = explode(',', $capabilities);
1183+
}
1184+
1185+
$capabilityEnums = [];
1186+
foreach ($capabilities as $capability) {
1187+
$capability = trim($capability);
1188+
if ($capability !== '') {
1189+
$capabilityEnums[] = Capability::from($capability);
1190+
}
1191+
}
1192+
}
1193+
1194+
$modelDefinitions[$modelName] = [
1195+
'class' => $modelConfig['class'],
1196+
'platform' => $platformName,
1197+
'capabilities' => $capabilityEnums,
1198+
];
1199+
}
1200+
1201+
// Create platform-specific model catalog service
1202+
$catalogServiceId = 'ai.model_catalog.' . $platformName;
1203+
$catalogDefinition = new Definition(ModelCatalog::class, [$modelDefinitions]);
1204+
$container->setDefinition($catalogServiceId, $catalogDefinition);
1205+
}
11781206

1179-
$container->setDefinition('ai.model.catalog.'.$modelName, $modelDefinition);
1207+
private function ensureDefaultModelCatalogs(ContainerBuilder $container): void
1208+
{
1209+
$defaultPlatforms = ['openai', 'anthropic', 'gemini', 'azure', 'mistral', 'ollama', 'perplexity'];
1210+
1211+
foreach ($defaultPlatforms as $platform) {
1212+
$catalogServiceId = 'ai.model_catalog.' . $platform;
1213+
1214+
// Only create if it doesn't already exist
1215+
if (!$container->hasDefinition($catalogServiceId)) {
1216+
$catalogDefinition = new Definition(ModelCatalog::class, [[]]);
1217+
$container->setDefinition($catalogServiceId, $catalogDefinition);
1218+
}
1219+
}
11801220
}
11811221
}

src/ai-bundle/src/DependencyInjection/ModelCatalogCompilerPass.php

Lines changed: 0 additions & 43 deletions
This file was deleted.

0 commit comments

Comments
 (0)