Skip to content

Commit e239ecc

Browse files
committed
bug #49 fix: consistent Whisper task option for OpenAI and Azure bridges (#350) (Copilot)
This PR was merged into the main branch. Discussion ---------- fix: consistent Whisper task option for OpenAI and Azure bridges (#350) | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | Docs? | no | Issues | | License | MIT Cherry picking php-llm/llm-chain#350 Commits ------- 5d66c61 fix: consistent Whisper task option for OpenAI and Azure bridges (#350)
2 parents 1527a44 + 5d66c61 commit e239ecc

File tree

5 files changed

+240
-2
lines changed

5 files changed

+240
-2
lines changed

src/platform/src/Bridge/Azure/OpenAI/WhisperModelClient.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\AI\Platform\Bridge\Azure\OpenAI;
1313

1414
use Symfony\AI\Platform\Bridge\OpenAI\Whisper;
15+
use Symfony\AI\Platform\Bridge\OpenAI\Whisper\Task;
1516
use Symfony\AI\Platform\Model;
1617
use Symfony\AI\Platform\ModelClientInterface;
1718
use Symfony\Component\HttpClient\EventSourceHttpClient;
@@ -48,7 +49,11 @@ public function supports(Model $model): bool
4849

4950
public function request(Model $model, array|string $payload, array $options = []): ResponseInterface
5051
{
51-
$url = \sprintf('https://%s/openai/deployments/%s/audio/translations', $this->baseUrl, $this->deployment);
52+
$task = $options['task'] ?? Task::TRANSCRIPTION;
53+
$endpoint = Task::TRANSCRIPTION === $task ? 'transcriptions' : 'translations';
54+
$url = \sprintf('https://%s/openai/deployments/%s/audio/%s', $this->baseUrl, $this->deployment, $endpoint);
55+
56+
unset($options['task']);
5257

5358
return $this->httpClient->request('POST', $url, [
5459
'headers' => [

src/platform/src/Bridge/OpenAI/Whisper/ModelClient.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ public function supports(Model $model): bool
3838

3939
public function request(Model $model, array|string $payload, array $options = []): ResponseInterface
4040
{
41-
return $this->httpClient->request('POST', 'https://api.openai.com/v1/audio/transcriptions', [
41+
$task = $options['task'] ?? Task::TRANSCRIPTION;
42+
$endpoint = Task::TRANSCRIPTION === $task ? 'transcriptions' : 'translations';
43+
unset($options['task']);
44+
45+
return $this->httpClient->request('POST', \sprintf('https://api.openai.com/v1/audio/%s', $endpoint), [
4246
'auth_bearer' => $this->apiKey,
4347
'headers' => ['Content-Type' => 'multipart/form-data'],
4448
'body' => array_merge($options, $payload, ['model' => $model->getName()]),
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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\Platform\Bridge\OpenAI\Whisper;
13+
14+
/**
15+
* @author Christopher Hertel <[email protected]>
16+
*/
17+
interface Task
18+
{
19+
public const TRANSCRIPTION = 'transcription';
20+
public const TRANSLATION = 'translation';
21+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
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\Platform\Tests\Bridge\Azure\OpenAI;
13+
14+
use PHPUnit\Framework\Attributes\CoversClass;
15+
use PHPUnit\Framework\Attributes\Small;
16+
use PHPUnit\Framework\Attributes\Test;
17+
use PHPUnit\Framework\TestCase;
18+
use Symfony\AI\Platform\Bridge\Azure\OpenAI\WhisperModelClient;
19+
use Symfony\AI\Platform\Bridge\OpenAI\Whisper;
20+
use Symfony\AI\Platform\Bridge\OpenAI\Whisper\Task;
21+
use Symfony\Component\HttpClient\MockHttpClient;
22+
use Symfony\Component\HttpClient\Response\MockResponse;
23+
24+
#[CoversClass(WhisperModelClient::class)]
25+
#[Small]
26+
final class WhisperModelClientTest extends TestCase
27+
{
28+
#[Test]
29+
public function itSupportsWhisperModel(): void
30+
{
31+
$client = new WhisperModelClient(
32+
new MockHttpClient(),
33+
'test.openai.azure.com',
34+
'whisper-deployment',
35+
'2023-12-01-preview',
36+
'test-key'
37+
);
38+
$model = new Whisper();
39+
40+
self::assertTrue($client->supports($model));
41+
}
42+
43+
#[Test]
44+
public function itUsesTranscriptionEndpointByDefault(): void
45+
{
46+
$httpClient = new MockHttpClient([
47+
function ($method, $url): MockResponse {
48+
self::assertSame('POST', $method);
49+
self::assertSame('https://test.azure.com/openai/deployments/whspr/audio/transcriptions?api-version=2023-12', $url);
50+
51+
return new MockResponse('{"text": "Hello World"}');
52+
},
53+
]);
54+
55+
$client = new WhisperModelClient($httpClient, 'test.azure.com', 'whspr', '2023-12', 'test-key');
56+
$model = new Whisper();
57+
$payload = ['file' => 'audio-data'];
58+
59+
$client->request($model, $payload);
60+
61+
self::assertSame(1, $httpClient->getRequestsCount());
62+
}
63+
64+
#[Test]
65+
public function itUsesTranscriptionEndpointWhenTaskIsSpecified(): void
66+
{
67+
$httpClient = new MockHttpClient([
68+
function ($method, $url): MockResponse {
69+
self::assertSame('POST', $method);
70+
self::assertSame('https://test.azure.com/openai/deployments/whspr/audio/transcriptions?api-version=2023-12', $url);
71+
72+
return new MockResponse('{"text": "Hello World"}');
73+
},
74+
]);
75+
76+
$client = new WhisperModelClient($httpClient, 'test.azure.com', 'whspr', '2023-12', 'test-key');
77+
$model = new Whisper();
78+
$payload = ['file' => 'audio-data'];
79+
$options = ['task' => Task::TRANSCRIPTION];
80+
81+
$client->request($model, $payload, $options);
82+
83+
self::assertSame(1, $httpClient->getRequestsCount());
84+
}
85+
86+
#[Test]
87+
public function itUsesTranslationEndpointWhenTaskIsSpecified(): void
88+
{
89+
$httpClient = new MockHttpClient([
90+
function ($method, $url): MockResponse {
91+
self::assertSame('POST', $method);
92+
self::assertSame('https://test.azure.com/openai/deployments/whspr/audio/translations?api-version=2023-12', $url);
93+
94+
return new MockResponse('{"text": "Hello World"}');
95+
},
96+
]);
97+
98+
$client = new WhisperModelClient($httpClient, 'test.azure.com', 'whspr', '2023-12', 'test-key');
99+
$model = new Whisper();
100+
$payload = ['file' => 'audio-data'];
101+
$options = ['task' => Task::TRANSLATION];
102+
103+
$client->request($model, $payload, $options);
104+
105+
self::assertSame(1, $httpClient->getRequestsCount());
106+
}
107+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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\Platform\Tests\Bridge\OpenAI\Whisper;
13+
14+
use PHPUnit\Framework\Attributes\CoversClass;
15+
use PHPUnit\Framework\Attributes\Small;
16+
use PHPUnit\Framework\Attributes\Test;
17+
use PHPUnit\Framework\TestCase;
18+
use Symfony\AI\Platform\Bridge\OpenAI\Whisper;
19+
use Symfony\AI\Platform\Bridge\OpenAI\Whisper\ModelClient;
20+
use Symfony\AI\Platform\Bridge\OpenAI\Whisper\Task;
21+
use Symfony\Component\HttpClient\MockHttpClient;
22+
use Symfony\Component\HttpClient\Response\MockResponse;
23+
24+
#[CoversClass(ModelClient::class)]
25+
#[Small]
26+
final class ModelClientTest extends TestCase
27+
{
28+
#[Test]
29+
public function itSupportsWhisperModel(): void
30+
{
31+
$client = new ModelClient(new MockHttpClient(), 'test-key');
32+
$model = new Whisper();
33+
34+
self::assertTrue($client->supports($model));
35+
}
36+
37+
#[Test]
38+
public function itUsesTranscriptionEndpointByDefault(): void
39+
{
40+
$httpClient = new MockHttpClient([
41+
function ($method, $url): MockResponse {
42+
self::assertSame('POST', $method);
43+
self::assertSame('https://api.openai.com/v1/audio/transcriptions', $url);
44+
45+
return new MockResponse('{"text": "Hello World"}');
46+
},
47+
]);
48+
49+
$client = new ModelClient($httpClient, 'test-key');
50+
$model = new Whisper();
51+
$payload = ['file' => 'audio-data'];
52+
53+
$client->request($model, $payload);
54+
55+
self::assertSame(1, $httpClient->getRequestsCount());
56+
}
57+
58+
#[Test]
59+
public function itUsesTranscriptionEndpointWhenTaskIsSpecified(): void
60+
{
61+
$httpClient = new MockHttpClient([
62+
function ($method, $url): MockResponse {
63+
self::assertSame('POST', $method);
64+
self::assertSame('https://api.openai.com/v1/audio/transcriptions', $url);
65+
66+
return new MockResponse('{"text": "Hello World"}');
67+
},
68+
]);
69+
70+
$client = new ModelClient($httpClient, 'test-key');
71+
$model = new Whisper();
72+
$payload = ['file' => 'audio-data'];
73+
$options = ['task' => Task::TRANSCRIPTION];
74+
75+
$client->request($model, $payload, $options);
76+
77+
self::assertSame(1, $httpClient->getRequestsCount());
78+
}
79+
80+
#[Test]
81+
public function itUsesTranslationEndpointWhenTaskIsSpecified(): void
82+
{
83+
$httpClient = new MockHttpClient([
84+
function ($method, $url): MockResponse {
85+
self::assertSame('POST', $method);
86+
self::assertSame('https://api.openai.com/v1/audio/translations', $url);
87+
88+
return new MockResponse('{"text": "Hello World"}');
89+
},
90+
]);
91+
92+
$client = new ModelClient($httpClient, 'test-key');
93+
$model = new Whisper();
94+
$payload = ['file' => 'audio-data'];
95+
$options = ['task' => Task::TRANSLATION];
96+
97+
$client->request($model, $payload, $options);
98+
99+
self::assertSame(1, $httpClient->getRequestsCount());
100+
}
101+
}

0 commit comments

Comments
 (0)