Skip to content

Commit b319521

Browse files
committed
ref
1 parent a812ecc commit b319521

File tree

8 files changed

+148
-8
lines changed

8 files changed

+148
-8
lines changed

examples/speech/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Speech Examples
2+
3+
Speech is mainly used to transform text to audio and vice versa, it can also be used to create an audio to audio pipeline.
4+
5+
To run the examples, you can use additional tools like (mpg123)[https://www.mpg123.de/]:
6+
7+
```bash
8+
php speech/agent-eleven-labs-speech-tts.php | mpg123 -
9+
php speech/agent-eleven-labs-speech-sts.php | mpg123 -
10+
```
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\Agent\Agent;
13+
use Symfony\AI\Platform\Bridge\ElevenLabs\ElevenLabsSpeechListener;
14+
use Symfony\AI\Platform\Bridge\ElevenLabs\ElevenLabsSpeechProvider;
15+
use Symfony\AI\Platform\Bridge\ElevenLabs\PlatformFactory;
16+
use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory as OpenAiPlatformFactory;
17+
use Symfony\AI\Platform\Message\Content\Audio;
18+
use Symfony\AI\Platform\Message\Message;
19+
use Symfony\AI\Platform\Message\MessageBag;
20+
use Symfony\AI\Platform\Speech\SpeechConfiguration;
21+
use Symfony\AI\Platform\Speech\SpeechProviderListener;
22+
use Symfony\Component\EventDispatcher\EventDispatcher;
23+
24+
require_once dirname(__DIR__).'/bootstrap.php';
25+
26+
$eventDispatcher = new EventDispatcher();
27+
$eventDispatcher->addSubscriber(new SpeechProviderListener([
28+
new ElevenLabsSpeechProvider(PlatformFactory::create(
29+
apiKey: env('ELEVEN_LABS_API_KEY'),
30+
httpClient: http_client(),
31+
speechConfiguration: new SpeechConfiguration(
32+
ttsModel: 'eleven_multilingual_v2',
33+
ttsVoice: 'Dslrhjl3ZpzrctukrQSN', // Brad (https://elevenlabs.io/app/voice-library?voiceId=Dslrhjl3ZpzrctukrQSN)
34+
sttModel: 'eleven_multilingual_v2'
35+
)),
36+
),
37+
], [
38+
new ElevenLabsSpeechListener(PlatformFactory::create(
39+
apiKey: env('ELEVEN_LABS_API_KEY'),
40+
httpClient: http_client(),
41+
speechConfiguration: new SpeechConfiguration(
42+
sttModel: 'scribe_v1'
43+
)),
44+
),
45+
]));
46+
47+
$platform = OpenAiPlatformFactory::create(env('OPENAI_API_KEY'), httpClient: http_client(), eventDispatcher: $eventDispatcher);
48+
49+
$agent = new Agent($platform, 'gpt-4o');
50+
$answer = $agent->call(new MessageBag(
51+
Message::ofUser(Audio::fromFile(dirname(__DIR__, 2).'/fixtures/audio.mp3'))
52+
));
53+
54+
echo $answer->getSpeech()->asBinary();
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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\Agent\Agent;
13+
use Symfony\AI\Platform\Bridge\ElevenLabs\ElevenLabsSpeechListener;
14+
use Symfony\AI\Platform\Bridge\ElevenLabs\PlatformFactory;
15+
use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory as OpenAiPlatformFactory;
16+
use Symfony\AI\Platform\Message\Content\Audio;
17+
use Symfony\AI\Platform\Message\Message;
18+
use Symfony\AI\Platform\Message\MessageBag;
19+
use Symfony\AI\Platform\Speech\SpeechConfiguration;
20+
use Symfony\AI\Platform\Speech\SpeechProviderListener;
21+
use Symfony\Component\EventDispatcher\EventDispatcher;
22+
23+
require_once dirname(__DIR__).'/bootstrap.php';
24+
25+
$eventDispatcher = new EventDispatcher();
26+
$eventDispatcher->addSubscriber(new SpeechProviderListener([], [
27+
new ElevenLabsSpeechListener(PlatformFactory::create(
28+
apiKey: env('ELEVEN_LABS_API_KEY'),
29+
httpClient: http_client(),
30+
speechConfiguration: new SpeechConfiguration(
31+
sttModel: 'scribe_v1'
32+
)),
33+
),
34+
]));
35+
36+
$platform = OpenAiPlatformFactory::create(env('OPENAI_API_KEY'), httpClient: http_client(), eventDispatcher: $eventDispatcher);
37+
38+
$agent = new Agent($platform, 'gpt-4o');
39+
$answer = $agent->call(new MessageBag(
40+
Message::ofUser(Audio::fromFile(dirname(__DIR__, 2).'/fixtures/audio.mp3'))
41+
));
42+
43+
echo $answer->getContent();

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727
apiKey: env('ELEVEN_LABS_API_KEY'),
2828
httpClient: http_client(),
2929
speechConfiguration: new SpeechConfiguration(
30-
'eleven_multilingual_v2',
31-
'Dslrhjl3ZpzrctukrQSN', // Brad (https://elevenlabs.io/app/voice-library?voiceId=Dslrhjl3ZpzrctukrQSN)
32-
'eleven_multilingual_v2'
30+
ttsModel: 'eleven_multilingual_v2',
31+
ttsVoice: 'Dslrhjl3ZpzrctukrQSN', // Brad (https://elevenlabs.io/app/voice-library?voiceId=Dslrhjl3ZpzrctukrQSN)
32+
sttModel: 'eleven_multilingual_v2'
3333
)),
3434
),
3535
], []));

src/platform/src/Bridge/ElevenLabs/ElevenLabsSpeechListener.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,30 @@
1212
namespace Symfony\AI\Platform\Bridge\ElevenLabs;
1313

1414
use Symfony\AI\Platform\Capability;
15+
use Symfony\AI\Platform\Message\Content\Text;
16+
use Symfony\AI\Platform\Message\MessageBag;
1517
use Symfony\AI\Platform\Platform;
1618
use Symfony\AI\Platform\Speech\SpeechListenerInterface;
1719

20+
/**
21+
* @author Guillaume Loulier <[email protected]>
22+
*/
1823
final class ElevenLabsSpeechListener implements SpeechListenerInterface
1924
{
2025
public function __construct(
2126
private readonly Platform $platform,
2227
) {
2328
}
2429

25-
public function listen(object|array|string $input, array $options): string
30+
public function listen(object|array|string $input, array $options): Text
2631
{
2732
$speechConfiguration = $this->platform->getSpeechConfiguration();
2833

34+
$input = ($input instanceof MessageBag && $input->containsAudio()) ? $input->getUserMessage()->getAudioContent() : $input;
35+
2936
$result = $this->platform->invoke($speechConfiguration->sttModel, $input, $options);
3037

31-
return $result->asText();
38+
return new Text($result->asText());
3239
}
3340

3441
public function support(object|array|string $input, array $options): bool

src/platform/src/Message/UserMessage.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\AI\Platform\Message;
1313

14+
use Symfony\AI\Platform\Exception\RuntimeException;
1415
use Symfony\AI\Platform\Message\Content\Audio;
1516
use Symfony\AI\Platform\Message\Content\ContentInterface;
1617
use Symfony\AI\Platform\Message\Content\Image;
@@ -71,6 +72,19 @@ public function hasAudioContent(): bool
7172
return false;
7273
}
7374

75+
public function getAudioContent(): ?Audio
76+
{
77+
foreach ($this->content as $content) {
78+
if (!$content instanceof Audio) {
79+
continue;
80+
}
81+
82+
return $content;
83+
}
84+
85+
throw new RuntimeException('No Audio content found.');
86+
}
87+
7488
public function hasImageContent(): bool
7589
{
7690
foreach ($this->content as $content) {

src/platform/src/Speech/SpeechListenerInterface.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111

1212
namespace Symfony\AI\Platform\Speech;
1313

14+
use Symfony\AI\Platform\Message\Content\Text;
15+
1416
/**
1517
* @author Guillaume Loulier <[email protected]>
1618
*/
1719
interface SpeechListenerInterface
1820
{
19-
public function listen(array|string|object $input, array $options): string;
21+
public function listen(array|string|object $input, array $options): Text;
2022

2123
public function support(array|string|object $input, array $options): bool;
2224
}

src/platform/src/Speech/SpeechProviderListener.php

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

1414
use Symfony\AI\Platform\Event\InvocationEvent;
1515
use Symfony\AI\Platform\Event\ResultEvent;
16+
use Symfony\AI\Platform\Message\Message;
17+
use Symfony\AI\Platform\Message\MessageBag;
1618
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
1719

1820
/**
@@ -33,7 +35,7 @@ public function __construct(
3335
public static function getSubscribedEvents(): array
3436
{
3537
return [
36-
InvocationEvent::class => 'onInvocation',
38+
InvocationEvent::class => ['onInvocation', 255],
3739
ResultEvent::class => 'onResult',
3840
];
3941
}
@@ -48,7 +50,15 @@ public function onInvocation(InvocationEvent $event): void
4850
continue;
4951
}
5052

51-
$event->setInput($speechListener->listen($input, $options));
53+
$overriddenInput = $speechListener->listen($input, $options);
54+
55+
if (!$input instanceof MessageBag) {
56+
$event->setInput($overriddenInput);
57+
}
58+
59+
$event->setInput(new MessageBag(
60+
Message::ofUser($overriddenInput),
61+
));
5262
}
5363
}
5464

0 commit comments

Comments
 (0)