diff --git a/README.md b/README.md index f400765f..62aaa114 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,18 @@ foreach($stream as $response){ ### `Audio` Resource +#### `speech` + +Generates audio from the input text. + +```php +$client->audio()->speech([ + 'model' => 'tts-1', + 'input' => 'The quick brown fox jumped over the lazy dog.', + 'voice' => 'alloy', +]); // audio file content as string +``` + #### `transcribe` Transcribes audio into the input language. diff --git a/src/Contracts/Resources/AudioContract.php b/src/Contracts/Resources/AudioContract.php index f462a8a2..6cdf6b6a 100644 --- a/src/Contracts/Resources/AudioContract.php +++ b/src/Contracts/Resources/AudioContract.php @@ -7,6 +7,15 @@ interface AudioContract { + /** + * Generates audio from the input text. + * + * @see https://platform.openai.com/docs/api-reference/audio/createSpeech + * + * @param array $parameters + */ + public function speech(array $parameters): string; + /** * Transcribes audio into the input language. * diff --git a/src/Resources/Audio.php b/src/Resources/Audio.php index 391220ba..73d5fd15 100644 --- a/src/Resources/Audio.php +++ b/src/Resources/Audio.php @@ -14,6 +14,20 @@ final class Audio implements AudioContract { use Concerns\Transportable; + /** + * Generates audio from the input text. + * + * @see https://platform.openai.com/docs/api-reference/audio/createSpeech + * + * @param array $parameters + */ + public function speech(array $parameters): string + { + $payload = Payload::create('audio/speech', $parameters); + + return $this->transporter->requestContent($payload); + } + /** * Transcribes audio into the input language. * diff --git a/src/Testing/Resources/AudioTestResource.php b/src/Testing/Resources/AudioTestResource.php index 16f4d0ea..29a91fea 100644 --- a/src/Testing/Resources/AudioTestResource.php +++ b/src/Testing/Resources/AudioTestResource.php @@ -17,6 +17,11 @@ protected function resource(): string return Audio::class; } + public function speech(array $parameters): string + { + return $this->record(__FUNCTION__, $parameters); + } + public function transcribe(array $parameters): TranscriptionResponse { return $this->record(__FUNCTION__, $parameters); diff --git a/tests/Fixtures/Audio.php b/tests/Fixtures/Audio.php index b0800ce3..607bcc0c 100644 --- a/tests/Fixtures/Audio.php +++ b/tests/Fixtures/Audio.php @@ -153,3 +153,8 @@ function audioFileResource() { return fopen(__DIR__.'/audio.mp3', 'r'); } + +function audioFileContent(): string +{ + return file_get_contents(__DIR__.'/audio.mp3'); +} diff --git a/tests/Resources/Audio.php b/tests/Resources/Audio.php index 3a57b1a1..dd482c19 100644 --- a/tests/Resources/Audio.php +++ b/tests/Resources/Audio.php @@ -191,3 +191,21 @@ expect($result->meta()) ->toBeInstanceOf(MetaInformation::class); }); + +test('text to speech', function () { + $client = mockContentClient('POST', 'audio/speech', [ + 'model' => 'tts-1', + 'input' => 'Hello, how are you?', + 'voice' => 'alloy', + ], audioFileContent()); + + $result = $client->audio()->speech([ + 'model' => 'tts-1', + 'input' => 'Hello, how are you?', + 'voice' => 'alloy', + ]); + + expect($result) + ->toBeString() + ->toBe(audioFileContent()); +}); diff --git a/tests/Testing/Resources/AudioTestResource.php b/tests/Testing/Resources/AudioTestResource.php index 01591cb8..f1f57532 100644 --- a/tests/Testing/Resources/AudioTestResource.php +++ b/tests/Testing/Resources/AudioTestResource.php @@ -5,6 +5,27 @@ use OpenAI\Responses\Audio\TranslationResponse; use OpenAI\Testing\ClientFake; +it('records a speech request', function () { + $fake = new ClientFake([ + 'fake-mp3-content', + ]); + + $fake->audio()->speech([ + 'model' => 'tts-1', + 'input' => 'Hello, how are you?', + 'voice' => 'alloy', + ]); + + $fake->assertSent(Audio::class, function ($method, $parameters) { + return $method === 'speech' && + $parameters === [ + 'model' => 'tts-1', + 'input' => 'Hello, how are you?', + 'voice' => 'alloy', + ]; + }); +}); + it('records an audio transcription request', function () { $fake = new ClientFake([ TranscriptionResponse::fake(),