Skip to content

Commit 2c573eb

Browse files
committed
feat(voice): Voice package
1 parent 024fcca commit 2c573eb

File tree

16 files changed

+233
-26
lines changed

16 files changed

+233
-26
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Symfony AI consists of several lower and higher level **components** and the res
1717
* **[Agent](src/agent/README.md)**: Framework for building AI agents that can interact with users and perform tasks.
1818
* **[Chat](src/chat/README.md)**: An unified interface to send messages to agents and store long-term context.
1919
* **[Store](src/store/README.md)**: Data storage abstraction with indexing and retrieval for AI applications.
20+
* **[Voice](src/voice/README.md)**: An unified interface to provide TTS / STT / STS for agents and more.
2021
* **Bundles**
2122
* **[AI Bundle](src/ai-bundle/README.md)**: Symfony integration for AI Platform, Store and Agent components.
2223
* **[MCP Bundle](src/mcp-bundle/README.md)**: Symfony integration for official MCP SDK, allowing them to act as MCP servers or clients.

docs/components/voice.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Symfony AI - Voice Component
2+
============================

src/agent/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"phpstan/phpdoc-parser": "^2.1",
2626
"psr/log": "^3.0",
2727
"symfony/ai-platform": "@dev",
28+
"symfony/ai-voice": "@dev",
2829
"symfony/clock": "^7.3|^8.0",
2930
"symfony/http-client": "^7.3|^8.0",
3031
"symfony/property-access": "^7.3|^8.0",

src/agent/src/Agent.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\AI\Platform\Message\MessageBag;
1818
use Symfony\AI\Platform\PlatformInterface;
1919
use Symfony\AI\Platform\Result\ResultInterface;
20+
use Symfony\AI\Voice\VoiceProviderInterface;
2021

2122
/**
2223
* @author Christopher Hertel <[email protected]>

src/ai-bundle/config/options.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,18 @@
774774
->end()
775775
->end()
776776
->end()
777+
->arrayNode('voice')
778+
->children()
779+
->arrayNode('eleven_labs')
780+
->useAttributeAsKey('name')
781+
->arrayPrototype()
782+
->children()
783+
->stringNode('model')->cannotBeEmpty()->end()
784+
->end()
785+
->end()
786+
->end()
787+
->end()
788+
->end()
777789
->arrayNode('vectorizer')
778790
->info('Vectorizers for converting strings to Vector objects and transforming TextDocument arrays to VectorDocument arrays')
779791
->useAttributeAsKey('name')

src/ai-bundle/src/AiBundle.php

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@
8484
use Symfony\AI\Store\Indexer;
8585
use Symfony\AI\Store\IndexerInterface;
8686
use Symfony\AI\Store\StoreInterface;
87+
use Symfony\AI\Voice\Bridge\ElevenLabs\VoiceProvider as ElevenLabsVoiceProvider;
88+
use Symfony\AI\Voice\VoiceProviderInterface;
8789
use Symfony\Component\Clock\ClockInterface;
8890
use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
8991
use Symfony\Component\DependencyInjection\Attribute\Target;
@@ -184,6 +186,10 @@ public function loadExtension(array $config, ContainerConfigurator $container, C
184186
$builder->removeDefinition('ai.command.drop_message_store');
185187
}
186188

189+
foreach ($config['voice'] as $voiceProvider => $provider) {
190+
$this->processVoiceProviderConfig($voiceProvider, $provider, $builder);
191+
}
192+
187193
foreach ($config['vectorizer'] ?? [] as $vectorizerName => $vectorizer) {
188194
$this->processVectorizerConfig($vectorizerName, $vectorizer, $builder);
189195
}
@@ -754,8 +760,9 @@ private function processAgentConfig(string $name, array $config, ContainerBuilde
754760
$agentDefinition
755761
->setArgument(2, []) // placeholder until ProcessorCompilerPass process.
756762
->setArgument(3, []) // placeholder until ProcessorCompilerPass process.
757-
->setArgument(4, $name)
758-
->setArgument(5, new Reference('logger', ContainerInterface::IGNORE_ON_INVALID_REFERENCE))
763+
->setArgument(4, []) // placeholder until VoiceProviderCompilerPass process.
764+
->setArgument(5, $name)
765+
->setArgument(6, new Reference('logger', ContainerInterface::IGNORE_ON_INVALID_REFERENCE))
759766
;
760767

761768
$container->setDefinition($agentId, $agentDefinition);
@@ -1396,6 +1403,30 @@ private function processMessageStoreConfig(string $type, array $messageStores, C
13961403
}
13971404
}
13981405

1406+
/**
1407+
* @param array<string, mixed> $providers
1408+
*/
1409+
private function processVoiceProviderConfig(string $name, array $providers, ContainerBuilder $container): void
1410+
{
1411+
if ('eleven_labs' === $name) {
1412+
foreach ($providers as $type => $config) {
1413+
$definition = new Definition(ElevenLabsVoiceProvider::class);
1414+
$definition
1415+
->setLazy(true)
1416+
->setArguments([
1417+
new Reference('ai.platform.eleven_labs'),
1418+
$config['model'],
1419+
])
1420+
->addTag('proxy', ['interface' => VoiceProviderInterface::class])
1421+
->addTag('ai.voice.provider');
1422+
1423+
$container->setDefinition('ai.voice.eleven_labs.'.$name, $definition);
1424+
$container->registerAliasForArgument('ai.voice.'.$type.'.'.$name, VoiceProviderInterface::class, $name);
1425+
$container->registerAliasForArgument('ai.voice.'.$type.'.'.$name, VoiceProviderInterface::class, $type.'_'.$name);
1426+
}
1427+
}
1428+
}
1429+
13991430
/**
14001431
* @param array<string, mixed> $config
14011432
*/
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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\AiBundle\DependencyInjection;
13+
14+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
17+
/**
18+
* @author Guillaume Loulier <[email protected]>
19+
*/
20+
final class VoiceProviderCompilerPass implements CompilerPassInterface
21+
{
22+
public function process(ContainerBuilder $container): void
23+
{
24+
$voiceProviders = $container->findTaggedServiceIds('ai.voice.provider');
25+
}
26+
}

src/voice/.gitattributes

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/.github export-ignore
2+
/tests export-ignore
3+
.gitattributes export-ignore
4+
.gitignore export-ignore
5+
phpstan.dist.neon export-ignore
6+
phpunit.xml.dist export-ignore
7+
CLAUDE.md export-ignore
8+
AGENTS.md export-ignore

src/voice/LICENSE

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2025-present Fabien Potencier
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is furnished
8+
to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

src/voice/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Symfony AI - Voice Component
2+
3+
The Voice component provides a low-level abstraction for Text-To-Speech / Speech-To-Text / Speech-To-Speech features.
4+
5+
**This Component is experimental**.
6+
[Experimental features](https://symfony.com/doc/current/contributing/code/experimental.html)
7+
are not covered by Symfony's
8+
[Backward Compatibility Promise](https://symfony.com/doc/current/contributing/code/bc.html).
9+
10+
## Installation
11+
12+
```bash
13+
composer require symfony/ai-voice
14+
```
15+
16+
**This repository is a READ-ONLY sub-tree split**. See
17+
https://github.com/symfony/ai to create issues or submit pull requests.
18+
19+
## Resources
20+
21+
- [Documentation](../../docs/index.rst)
22+
- [Report issues](https://github.com/symfony/ai/issues) and
23+
[send Pull Requests](https://github.com/symfony/ai/pulls)
24+
in the [main Symfony AI repository](https://github.com/symfony/ai)

0 commit comments

Comments
 (0)