Skip to content

Commit 437c9fb

Browse files
committed
ref
1 parent b319521 commit 437c9fb

18 files changed

+217
-18
lines changed

docs/components/platform.rst

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,8 +501,58 @@ This allows fast and isolated testing of AI-powered features without relying on
501501

502502
This requires `cURL` and the `ext-curl` extension to be installed.
503503

504-
Adding Voice
505-
~~~~~~~~~~~~
504+
Speech support
505+
~~~~~~~~~~~~~~
506+
507+
Using speech to send messages / receive answers as audio is a common use case when integrating agents and/or chats.
508+
509+
Speech support can be enable using ``Symfony\AI\Platform\Speech\SpeechProviderListener``::
510+
511+
use Symfony\AI\Agent\Agent;
512+
use Symfony\AI\Platform\Bridge\ElevenLabs\ElevenLabsSpeechProvider;
513+
use Symfony\AI\Platform\Bridge\ElevenLabs\PlatformFactory;
514+
use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory as OpenAiPlatformFactory;
515+
use Symfony\AI\Platform\Message\Message;
516+
use Symfony\AI\Platform\Message\MessageBag;
517+
use Symfony\AI\Platform\Speech\SpeechConfiguration;
518+
use Symfony\AI\Platform\Speech\SpeechProviderListener;
519+
use Symfony\Component\EventDispatcher\EventDispatcher;
520+
521+
$eventDispatcher = new EventDispatcher();
522+
$eventDispatcher->addSubscriber(new SpeechProviderListener([
523+
new ElevenLabsSpeechProvider(PlatformFactory::create(
524+
apiKey: $elevenLabsApiKey,
525+
httpClient: http_client(),
526+
speechConfiguration: new SpeechConfiguration(
527+
ttsModel: 'eleven_multilingual_v2',
528+
ttsVoice: 'Dslrhjl3ZpzrctukrQSN', // Brad (https://elevenlabs.io/app/voice-library?voiceId=Dslrhjl3ZpzrctukrQSN)
529+
sttModel: 'eleven_multilingual_v2'
530+
)),
531+
),
532+
], []));
533+
534+
$platform = OpenAiPlatformFactory::create($openAiApiKey, httpClient: HttpClient::create(), eventDispatcher: $eventDispatcher);
535+
536+
$agent = new Agent($platform, 'gpt-4o');
537+
$answer = $agent->call(new MessageBag(
538+
Message::ofUser('Tina has one brother and one sister. How many sisters do Tina\'s siblings have?'),
539+
));
540+
541+
echo $answer->getSpeech('eleven_labs')->asBinary();
542+
543+
When using the bundle, the configuration allows to configure models and voices::
544+
545+
ai:
546+
platform:
547+
eleven_labs:
548+
api_key: '%env(ELEVEN_LABS_API_KEY)%'
549+
550+
speech:
551+
eleven_labs:
552+
tts_model: 'eleven_multilingual_v2'
553+
tts_voice: '%env(ELEVEN_LABS_VOICE_IDENTIFIER)%'
554+
tts_extra_options:
555+
foo: bar
506556

507557
Code Examples
508558
~~~~~~~~~~~~~

examples/speech/agent-eleven-labs-speech-tts.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@
4141
Message::ofUser('Tina has one brother and one sister. How many sisters do Tina\'s siblings have?'),
4242
));
4343

44-
echo $answer->getSpeech()->asBinary();
44+
echo $answer->getSpeech('eleven_labs')?->asBinary();

src/ai-bundle/config/services.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
use Symfony\AI\Platform\Contract\JsonSchema\DescriptionParser;
6464
use Symfony\AI\Platform\Contract\JsonSchema\Factory as SchemaFactory;
6565
use Symfony\AI\Platform\Serializer\StructuredOutputSerializer;
66+
use Symfony\AI\Platform\Speech\SpeechProviderListener;
6667
use Symfony\AI\Platform\StructuredOutput\PlatformSubscriber;
6768
use Symfony\AI\Platform\StructuredOutput\ResponseFormatFactory;
6869
use Symfony\AI\Platform\StructuredOutput\ResponseFormatFactoryInterface;
@@ -235,5 +236,13 @@
235236
tagged_locator('ai.message_store', 'name'),
236237
])
237238
->tag('console.command')
239+
240+
// listeners
241+
->set('ai.speech_provider.listener', SpeechProviderListener::class)
242+
->args([
243+
tagged_locator('ai.speech_provider', 'name'),
244+
tagged_locator('ai.speech_listener', 'name'),
245+
])
246+
->tag('kernel.event_subscriber')
238247
;
239248
};

src/platform/src/Bridge/ElevenLabs/ElevenLabsSpeechProvider.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function generate(DeferredResult $result, array $options): Speech
3939
...$options,
4040
]);
4141

42-
return new Speech($payload, $speechResult);
42+
return new Speech($payload, $speechResult, 'eleven_labs');
4343
}
4444

4545
public function support(DeferredResult $result, array $options): bool

src/platform/src/CachedPlatform.php

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

1414
use Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface;
1515
use Symfony\AI\Platform\Result\DeferredResult;
16+
use Symfony\AI\Platform\Speech\SpeechConfiguration;
1617
use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
1718
use Symfony\Contracts\Cache\CacheInterface;
1819
use Symfony\Contracts\Cache\ItemInterface;
@@ -66,4 +67,9 @@ public function getModelCatalog(): ModelCatalogInterface
6667
{
6768
return $this->platform->getModelCatalog();
6869
}
70+
71+
public function getSpeechConfiguration(): ?SpeechConfiguration
72+
{
73+
return $this->platform->getSpeechConfiguration();
74+
}
6975
}

src/platform/src/Message/UserMessage.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public function hasAudioContent(): bool
7272
return false;
7373
}
7474

75-
public function getAudioContent(): ?Audio
75+
public function getAudioContent(): Audio
7676
{
7777
foreach ($this->content as $content) {
7878
if (!$content instanceof Audio) {

src/platform/src/Result/BaseResult.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespace Symfony\AI\Platform\Result;
1313

1414
use Symfony\AI\Platform\Metadata\MetadataAwareTrait;
15-
use Symfony\AI\Platform\Speech\SpeechAwareTrait;
15+
use Symfony\AI\Platform\Speech\SpeechBagAwareTrait;
1616

1717
/**
1818
* Base result of converted result classes.
@@ -23,5 +23,5 @@ abstract class BaseResult implements ResultInterface
2323
{
2424
use MetadataAwareTrait;
2525
use RawResultAwareTrait;
26-
use SpeechAwareTrait;
26+
use SpeechBagAwareTrait;
2727
}

src/platform/src/Result/DeferredResult.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use Symfony\AI\Platform\Exception\UnexpectedResultTypeException;
1616
use Symfony\AI\Platform\Metadata\MetadataAwareTrait;
1717
use Symfony\AI\Platform\ResultConverterInterface;
18-
use Symfony\AI\Platform\Speech\SpeechAwareTrait;
18+
use Symfony\AI\Platform\Speech\SpeechBagAwareTrait;
1919
use Symfony\AI\Platform\Vector\Vector;
2020

2121
/**
@@ -24,7 +24,7 @@
2424
final class DeferredResult
2525
{
2626
use MetadataAwareTrait;
27-
use SpeechAwareTrait;
27+
use SpeechBagAwareTrait;
2828

2929
private bool $isConverted = false;
3030
private ResultInterface $convertedResult;
@@ -56,7 +56,10 @@ public function getResult(): ResultInterface
5656
}
5757

5858
$this->convertedResult->getMetadata()->set($this->getMetadata()->all());
59-
$this->convertedResult->setSpeech($this->getSpeech());
59+
60+
foreach ($this->speechBag as $speech) {
61+
$this->convertedResult->addSpeech($speech);
62+
}
6063

6164
return $this->convertedResult;
6265
}

src/platform/src/Result/ResultInterface.php

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

1414
use Symfony\AI\Platform\Metadata\Metadata;
1515
use Symfony\AI\Platform\Result\Exception\RawResultAlreadySetException;
16+
use Symfony\AI\Platform\Speech\Speech;
1617

1718
/**
1819
* @author Christopher Hertel <[email protected]>
@@ -33,4 +34,8 @@ public function getRawResult(): ?RawResultInterface;
3334
* @throws RawResultAlreadySetException if the result is tried to be set more than once
3435
*/
3536
public function setRawResult(RawResultInterface $rawResult): void;
37+
38+
public function addSpeech(Speech $speech): void;
39+
40+
public function getSpeech(string $identifier): ?Speech;
3641
}

src/platform/src/Speech/Speech.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,19 @@
1818
*/
1919
final class Speech
2020
{
21+
/**
22+
* @param string|array<mixed, mixed> $payload
23+
*/
2124
public function __construct(
2225
private readonly string|array $payload,
2326
private readonly DeferredResult $result,
27+
private readonly string $identifier,
2428
) {
2529
}
2630

31+
/**
32+
* @return string|array<mixed, mixed>
33+
*/
2734
public function getPayload(): string|array
2835
{
2936
return $this->payload;
@@ -33,4 +40,9 @@ public function asBinary(): string
3340
{
3441
return $this->result->asBinary();
3542
}
43+
44+
public function getIdentifier(): string
45+
{
46+
return $this->identifier;
47+
}
3648
}

0 commit comments

Comments
 (0)