From 1aa713ed7170dc2967ef5ac1c50f641ad35967c8 Mon Sep 17 00:00:00 2001 From: Christopher Hertel Date: Sun, 9 Nov 2025 23:40:08 +0100 Subject: [PATCH] Add Hugging Face as Platform to Bundle config --- src/ai-bundle/config/options.php | 10 +++++++ src/ai-bundle/config/services.php | 3 +++ src/ai-bundle/src/AiBundle.php | 22 +++++++++++++++ .../templates/data_collector.html.twig | 2 +- .../Contract/HuggingFaceContract.php | 27 +++++++++++++++++++ .../Bridge/HuggingFace/PlatformFactory.php | 12 ++++----- 6 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 src/platform/src/Bridge/HuggingFace/Contract/HuggingFaceContract.php diff --git a/src/ai-bundle/config/options.php b/src/ai-bundle/config/options.php index d35fb1902..5f8c653c4 100644 --- a/src/ai-bundle/config/options.php +++ b/src/ai-bundle/config/options.php @@ -83,6 +83,16 @@ ->end() ->end() ->end() + ->arrayNode('huggingface') + ->children() + ->stringNode('api_key')->isRequired()->end() + ->stringNode('provider')->defaultValue('hf-inference')->end() + ->stringNode('http_client') + ->defaultValue('http_client') + ->info('Service ID of the HTTP client to use') + ->end() + ->end() + ->end() ->arrayNode('vertexai') ->children() ->stringNode('location')->isRequired()->end() diff --git a/src/ai-bundle/config/services.php b/src/ai-bundle/config/services.php index 33783bcf2..fb3a56c15 100644 --- a/src/ai-bundle/config/services.php +++ b/src/ai-bundle/config/services.php @@ -36,6 +36,7 @@ use Symfony\AI\Platform\Bridge\Gemini\Contract\GeminiContract; use Symfony\AI\Platform\Bridge\Gemini\ModelCatalog as GeminiModelCatalog; use Symfony\AI\Platform\Bridge\Gemini\TokenOutputProcessor as GeminiTokenOutputProcessor; +use Symfony\AI\Platform\Bridge\HuggingFace\Contract\HuggingFaceContract; use Symfony\AI\Platform\Bridge\HuggingFace\ModelCatalog as HuggingFaceModelCatalog; use Symfony\AI\Platform\Bridge\LmStudio\ModelCatalog as LmStudioModelCatalog; use Symfony\AI\Platform\Bridge\Meta\ModelCatalog as MetaModelCatalog; @@ -76,6 +77,8 @@ ->factory([AnthropicContract::class, 'create']) ->set('ai.platform.contract.gemini', Contract::class) ->factory([GeminiContract::class, 'create']) + ->set('ai.platform.contract.huggingface', Contract::class) + ->factory([HuggingFaceContract::class, 'create']) ->set('ai.platform.contract.vertexai.gemini', Contract::class) ->factory([VertexAiGeminiContract::class, 'create']) ->set('ai.platform.contract.ollama', Contract::class) diff --git a/src/ai-bundle/src/AiBundle.php b/src/ai-bundle/src/AiBundle.php index 75c1f6b37..2290a5dad 100644 --- a/src/ai-bundle/src/AiBundle.php +++ b/src/ai-bundle/src/AiBundle.php @@ -51,6 +51,7 @@ use Symfony\AI\Platform\Bridge\DockerModelRunner\PlatformFactory as DockerModelRunnerPlatformFactory; use Symfony\AI\Platform\Bridge\ElevenLabs\PlatformFactory as ElevenLabsPlatformFactory; use Symfony\AI\Platform\Bridge\Gemini\PlatformFactory as GeminiPlatformFactory; +use Symfony\AI\Platform\Bridge\HuggingFace\PlatformFactory as HuggingFacePlatformFactory; use Symfony\AI\Platform\Bridge\LmStudio\PlatformFactory as LmStudioPlatformFactory; use Symfony\AI\Platform\Bridge\Mistral\PlatformFactory as MistralPlatformFactory; use Symfony\AI\Platform\Bridge\Ollama\PlatformFactory as OllamaPlatformFactory; @@ -397,6 +398,27 @@ private function processPlatformConfig(string $type, array $platform, ContainerB return; } + if ('huggingface' === $type) { + $platformId = 'ai.platform.huggingface'; + $definition = (new Definition(Platform::class)) + ->setFactory(HuggingFacePlatformFactory::class.'::create') + ->setLazy(true) + ->addTag('proxy', ['interface' => PlatformInterface::class]) + ->setArguments([ + $platform['api_key'], + $platform['provider'], + new Reference($platform['http_client'], ContainerInterface::NULL_ON_INVALID_REFERENCE), + new Reference('ai.platform.model_catalog.huggingface'), + new Reference('ai.platform.contract.huggingface'), + new Reference('event_dispatcher'), + ]) + ->addTag('ai.platform', ['name' => 'huggingface']); + + $container->setDefinition($platformId, $definition); + + return; + } + if ('vertexai' === $type && isset($platform['location'], $platform['project_id'])) { if (!class_exists(ApplicationDefaultCredentials::class)) { throw new RuntimeException('For using the Vertex AI platform, google/auth package is required. Try running "composer require google/auth".'); diff --git a/src/ai-bundle/templates/data_collector.html.twig b/src/ai-bundle/templates/data_collector.html.twig index 117bb6d76..cfcd72645 100644 --- a/src/ai-bundle/templates/data_collector.html.twig +++ b/src/ai-bundle/templates/data_collector.html.twig @@ -166,7 +166,7 @@ {% endfor %} {% else %} - {{ call.result }} + {{ dump(call.result) }} {% endif %} {% if call.metadata|length > 0 %}
diff --git a/src/platform/src/Bridge/HuggingFace/Contract/HuggingFaceContract.php b/src/platform/src/Bridge/HuggingFace/Contract/HuggingFaceContract.php new file mode 100644 index 000000000..b496e2eeb --- /dev/null +++ b/src/platform/src/Bridge/HuggingFace/Contract/HuggingFaceContract.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\AI\Platform\Bridge\HuggingFace\Contract; + +use Symfony\AI\Platform\Contract; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; + +final class HuggingFaceContract extends Contract +{ + public static function create(NormalizerInterface ...$normalizer): Contract + { + return parent::create( + new FileNormalizer(), + new MessageBagNormalizer(), + ...$normalizer, + ); + } +} diff --git a/src/platform/src/Bridge/HuggingFace/PlatformFactory.php b/src/platform/src/Bridge/HuggingFace/PlatformFactory.php index e9303416e..52c2b0aad 100644 --- a/src/platform/src/Bridge/HuggingFace/PlatformFactory.php +++ b/src/platform/src/Bridge/HuggingFace/PlatformFactory.php @@ -12,9 +12,9 @@ namespace Symfony\AI\Platform\Bridge\HuggingFace; use Psr\EventDispatcher\EventDispatcherInterface; -use Symfony\AI\Platform\Bridge\HuggingFace\Contract\FileNormalizer; -use Symfony\AI\Platform\Bridge\HuggingFace\Contract\MessageBagNormalizer; +use Symfony\AI\Platform\Bridge\HuggingFace\Contract\HuggingFaceContract; use Symfony\AI\Platform\Contract; +use Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface; use Symfony\AI\Platform\Platform; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -28,6 +28,7 @@ public static function create( #[\SensitiveParameter] string $apiKey, string $provider = Provider::HF_INFERENCE, ?HttpClientInterface $httpClient = null, + ModelCatalogInterface $modelCatalog = new ModelCatalog(), ?Contract $contract = null, ?EventDispatcherInterface $eventDispatcher = null, ): Platform { @@ -36,11 +37,8 @@ public static function create( return new Platform( [new ModelClient($httpClient, $provider, $apiKey)], [new ResultConverter()], - new ModelCatalog(), - $contract ?? Contract::create( - new FileNormalizer(), - new MessageBagNormalizer(), - ), + $modelCatalog, + $contract ?? HuggingFaceContract::create(), $eventDispatcher, ); }