Skip to content

Commit dbd8dfe

Browse files
committed
ref
1 parent e496475 commit dbd8dfe

File tree

4 files changed

+64
-65
lines changed

4 files changed

+64
-65
lines changed

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,6 @@ final class ElevenLabs extends Model
3131
public const SCRIBE_V1 = 'scribe_v1';
3232
public const SCRIBE_V1_EXPERIMENTAL = 'scribe_v1_experimental';
3333

34-
/**
35-
* @param array{
36-
* voice: string,
37-
* } $options
38-
*/
3934
public function __construct(
4035
string $name = self::ELEVEN_MULTILINGUAL_V2,
4136
array $options = [],

src/platform/src/Bridge/ElevenLabs/ElevenLabsClient.php

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,18 @@ public function supports(Model $model): bool
3737

3838
public function request(Model $model, array|string $payload, array $options = []): RawResultInterface
3939
{
40+
if (!\is_array($payload)) {
41+
throw new InvalidArgumentException(\sprintf('The payload must be an array, received "%s".', get_debug_type($payload)));
42+
}
43+
4044
if (\in_array($model->getName(), [ElevenLabs::SCRIBE_V1, ElevenLabs::SCRIBE_V1_EXPERIMENTAL], true)) {
4145
return $this->doSpeechToTextRequest($model, $payload, $options);
4246
}
4347

4448
$capabilities = $this->retrieveCapabilities($model);
4549

46-
if ([] === $capabilities) {
47-
throw new InvalidArgumentException('The model information could not be retrieved from the ElevenLabs API. Your model might not be supported. Try to use another one.');
50+
if (!$capabilities['can_do_text_to_speech']) {
51+
throw new InvalidArgumentException(\sprintf('The model "%s" does not support text-to-speech.', $model->getName()));
4852
}
4953

5054
return $this->doTextToSpeechRequest($model, $payload, $options);
@@ -56,10 +60,6 @@ public function request(Model $model, array|string $payload, array $options = []
5660
*/
5761
private function doSpeechToTextRequest(Model $model, array|string $payload, array $options): RawHttpResult
5862
{
59-
if (!\is_array($payload)) {
60-
throw new InvalidArgumentException(\sprintf('The payload must be an array, received "%s".', get_debug_type($payload)));
61-
}
62-
6363
return new RawHttpResult($this->httpClient->request('POST', \sprintf('%s/speech-to-text', $this->hostUrl), [
6464
'headers' => [
6565
'xi-api-key' => $this->apiKey,
@@ -78,11 +78,7 @@ private function doSpeechToTextRequest(Model $model, array|string $payload, arra
7878
private function doTextToSpeechRequest(Model $model, array|string $payload, array $options): RawHttpResult
7979
{
8080
if (!\array_key_exists('voice', $model->getOptions())) {
81-
throw new InvalidArgumentException('The model option is required.');
82-
}
83-
84-
if (!\is_array($payload)) {
85-
throw new InvalidArgumentException(\sprintf('The payload must be an array, received "%s".', get_debug_type($payload)));
81+
throw new InvalidArgumentException('The voice option is required.');
8682
}
8783

8884
if (!\array_key_exists('text', $payload)) {
@@ -102,6 +98,9 @@ private function doTextToSpeechRequest(Model $model, array|string $payload, arra
10298
]));
10399
}
104100

101+
/**
102+
* @return array<string, mixed>
103+
*/
105104
private function retrieveCapabilities(Model $model): array
106105
{
107106
$capabilityResponse = $this->httpClient->request('GET', \sprintf('%s/models', $this->hostUrl), [
@@ -114,6 +113,10 @@ private function retrieveCapabilities(Model $model): array
114113

115114
$currentModelConfiguration = array_filter($models, static fn (array $information): bool => $information['model_id'] === $model->getName());
116115

116+
if ([] === $currentModelConfiguration) {
117+
throw new InvalidArgumentException('The model information could not be retrieved from the ElevenLabs API. Your model might not be supported. Try to use another one.');
118+
}
119+
117120
return reset($currentModelConfiguration);
118121
}
119122
}

src/platform/tests/Bridge/ElevenLabs/ElevenLabsClientTest.php

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\AI\Platform\Tests\Bridge\ElevenLabs;
1313

1414
use PHPUnit\Framework\Attributes\CoversClass;
15+
use PHPUnit\Framework\Attributes\Group;
1516
use PHPUnit\Framework\Attributes\UsesClass;
1617
use PHPUnit\Framework\TestCase;
1718
use Symfony\AI\Platform\Bridge\ElevenLabs\ElevenLabs;
@@ -21,6 +22,8 @@
2122
use Symfony\AI\Platform\Message\Content\Audio;
2223
use Symfony\AI\Platform\Model;
2324
use Symfony\Component\HttpClient\MockHttpClient;
25+
use Symfony\Component\HttpClient\Response\JsonMockResponse;
26+
use Symfony\Component\HttpClient\Response\MockResponse;
2427

2528
#[CoversClass(ElevenLabsClient::class)]
2629
#[UsesClass(ElevenLabs::class)]
@@ -43,18 +46,27 @@ public function testSupportsModel()
4346

4447
public function testClientCannotPerformWithInvalidModel()
4548
{
49+
$mockHttpClient = new MockHttpClient([
50+
new JsonMockResponse([
51+
[
52+
'model_id' => 'bar',
53+
'can_do_text_to_speech' => false,
54+
],
55+
]),
56+
new JsonMockResponse([]),
57+
]);
4658
$normalizer = new AudioNormalizer();
4759

4860
$client = new ElevenLabsClient(
49-
new MockHttpClient(),
61+
$mockHttpClient,
5062
'my-api-key',
5163
'https://api.elevenlabs.io/v1',
5264
);
5365

5466
$payload = $normalizer->normalize(Audio::fromFile(\dirname(__DIR__, 5).'/fixtures/audio.mp3'));
5567

5668
$this->expectException(InvalidArgumentException::class);
57-
$this->expectExceptionMessage('The model option is required.');
69+
$this->expectExceptionMessage('The model information could not be retrieved from the ElevenLabs API. Your model might not be supported. Try to use another one.');
5870
$this->expectExceptionCode(0);
5971
$client->request(new ElevenLabs('foo'), $payload);
6072
}
@@ -70,14 +82,16 @@ public function testClientCannotPerformSpeechToTextRequestWithInvalidPayload()
7082
$this->expectException(InvalidArgumentException::class);
7183
$this->expectExceptionMessage('The payload must be an array, received "string".');
7284
$this->expectExceptionCode(0);
73-
$client->request(new ElevenLabs(ElevenLabs::SPEECH_TO_TEXT, options: [
74-
'model' => 'bar',
75-
]), 'foo');
85+
$client->request(new ElevenLabs(ElevenLabs::ELEVEN_MULTILINGUAL_V2), 'foo');
7686
}
7787

7888
public function testClientCanPerformSpeechToTextRequest()
7989
{
80-
$httpClient = new MockHttpClient();
90+
$httpClient = new MockHttpClient([
91+
new JsonMockResponse([
92+
'text' => 'foo',
93+
]),
94+
]);
8195
$normalizer = new AudioNormalizer();
8296

8397
$client = new ElevenLabsClient(
@@ -88,49 +102,25 @@ public function testClientCanPerformSpeechToTextRequest()
88102

89103
$payload = $normalizer->normalize(Audio::fromFile(\dirname(__DIR__, 5).'/fixtures/audio.mp3'));
90104

91-
$client->request(new ElevenLabs(ElevenLabs::SPEECH_TO_TEXT, options: [
92-
'model' => 'bar',
93-
]), $payload);
105+
$client->request(new ElevenLabs(ElevenLabs::SCRIBE_V1), $payload);
94106

95107
$this->assertSame(1, $httpClient->getRequestsCount());
96108
}
97109

98-
public function testClientCannotPerformTextToSpeechRequestWithoutModel()
99-
{
100-
$client = new ElevenLabsClient(
101-
new MockHttpClient(),
102-
'https://api.elevenlabs.io/v1',
103-
'my-api-key',
104-
);
105-
106-
$this->expectException(InvalidArgumentException::class);
107-
$this->expectExceptionMessage('The model option is required.');
108-
$this->expectExceptionCode(0);
109-
$client->request(new ElevenLabs(), []);
110-
}
111-
112-
public function testClientCannotPerformTextToSpeechRequestWithInvalidPayload()
113-
{
114-
$client = new ElevenLabsClient(
115-
new MockHttpClient(),
116-
'https://api.elevenlabs.io/v1',
117-
'my-api-key',
118-
);
119-
120-
$this->expectException(InvalidArgumentException::class);
121-
$this->expectExceptionMessage('The payload must be an array, received "string".');
122-
$this->expectExceptionCode(0);
123-
$client->request(new ElevenLabs(options: [
124-
'model' => 'bar',
125-
]), 'foo');
126-
}
127-
128110
public function testClientCannotPerformTextToSpeechRequestWithoutValidPayload()
129111
{
130-
$normalizer = new AudioNormalizer();
112+
$mockHttpClient = new MockHttpClient([
113+
new JsonMockResponse([
114+
[
115+
'model_id' => ElevenLabs::ELEVEN_MULTILINGUAL_V2,
116+
'can_do_text_to_speech' => true,
117+
],
118+
]),
119+
new JsonMockResponse([]),
120+
]);
131121

132122
$client = new ElevenLabsClient(
133-
new MockHttpClient(),
123+
$mockHttpClient,
134124
'https://api.elevenlabs.io/v1',
135125
'my-api-key',
136126
);
@@ -139,13 +129,24 @@ public function testClientCannotPerformTextToSpeechRequestWithoutValidPayload()
139129
$this->expectExceptionMessage('The payload must contain a "text" key');
140130
$this->expectExceptionCode(0);
141131
$client->request(new ElevenLabs(options: [
142-
'model' => 'bar',
132+
'voice' => 'Dslrhjl3ZpzrctukrQSN',
143133
]), []);
144134
}
145135

136+
#[Group('foo')]
146137
public function testClientCanPerformTextToSpeechRequest()
147138
{
148-
$httpClient = new MockHttpClient();
139+
$payload = Audio::fromFile(\dirname(__DIR__, 5).'/fixtures/audio.mp3');
140+
141+
$httpClient = new MockHttpClient([
142+
new JsonMockResponse([
143+
[
144+
'model_id' => ElevenLabs::ELEVEN_MULTILINGUAL_V2,
145+
'can_do_text_to_speech' => true,
146+
],
147+
]),
148+
new MockResponse($payload->asBinary()),
149+
]);
149150

150151
$client = new ElevenLabsClient(
151152
$httpClient,
@@ -154,11 +155,11 @@ public function testClientCanPerformTextToSpeechRequest()
154155
);
155156

156157
$client->request(new ElevenLabs(options: [
157-
'model' => 'bar',
158+
'voice' => 'Dslrhjl3ZpzrctukrQSN',
158159
]), [
159160
'text' => 'foo',
160161
]);
161162

162-
$this->assertSame(1, $httpClient->getRequestsCount());
163+
$this->assertSame(2, $httpClient->getRequestsCount());
163164
}
164165
}

src/platform/tests/Bridge/ElevenLabs/ElevenLabsConverterTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@
1717
use Symfony\AI\Platform\Bridge\ElevenLabs\ElevenLabs;
1818
use Symfony\AI\Platform\Bridge\ElevenLabs\ElevenLabsResultConverter;
1919
use Symfony\AI\Platform\Model;
20-
use Symfony\AI\Platform\Result\AudioResult;
20+
use Symfony\AI\Platform\Result\BinaryResult;
2121
use Symfony\AI\Platform\Result\InMemoryRawResult;
2222
use Symfony\AI\Platform\Result\TextResult;
2323

2424
#[CoversClass(ElevenLabsResultConverter::class)]
2525
#[UsesClass(ElevenLabs::class)]
2626
#[UsesClass(Model::class)]
2727
#[UsesClass(TextResult::class)]
28-
#[UsesClass(AudioResult::class)]
28+
#[UsesClass(BinaryResult::class)]
2929
#[UsesClass(InMemoryRawResult::class)]
3030
final class ElevenLabsConverterTest extends TestCase
3131
{
@@ -72,7 +72,7 @@ public function getContent(): string
7272

7373
$result = $converter->convert($rawResult);
7474

75-
$this->assertInstanceOf(AudioResult::class, $result);
76-
$this->assertSame('audio/mpeg', $result->getMimeType());
75+
$this->assertInstanceOf(BinaryResult::class, $result);
76+
$this->assertSame('audio/mpeg', $result->mimeType);
7777
}
7878
}

0 commit comments

Comments
 (0)