From 84a3946a104bca8a8b9d49b6d88cc95ee02c2e1b Mon Sep 17 00:00:00 2001 From: Rigel Kent Carbonel Date: Sat, 10 Apr 2021 21:56:46 +0800 Subject: [PATCH 1/5] Added support for speech marks. --- composer.json | 3 +- src/Converters/PollyConverter.php | 68 +++++++++++++++++++++++-------- src/Facades/TextToSpeech.php | 3 +- src/Traits/HasSpeechMarks.php | 26 ++++++++++++ tests/PollyConverterTest.php | 10 +++++ 5 files changed, 92 insertions(+), 18 deletions(-) create mode 100644 src/Traits/HasSpeechMarks.php diff --git a/composer.json b/composer.json index 0ebc26b..daf6af0 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,8 @@ "php": "^7.3|^7.4|^8.0", "aws/aws-sdk-php": "^3.178", "guzzlehttp/guzzle": "^6.0|^7.0", - "illuminate/support": "5.*|^6.0|^7.0|^8.0" + "illuminate/support": "5.*|^6.0|^7.0|^8.0", + "ext-json": "*" }, "require-dev": { "orchestra/testbench": "^4.0|^5.0|^6.0", diff --git a/src/Converters/PollyConverter.php b/src/Converters/PollyConverter.php index 9227d78..bf444d9 100644 --- a/src/Converters/PollyConverter.php +++ b/src/Converters/PollyConverter.php @@ -6,6 +6,7 @@ use Aws\Result; use Cion\TextToSpeech\Contracts\Converter; use Cion\TextToSpeech\Traits\HasLanguage; +use Cion\TextToSpeech\Traits\HasSpeechMarks; use Cion\TextToSpeech\Traits\Sourceable; use Cion\TextToSpeech\Traits\SSMLable; use Cion\TextToSpeech\Traits\Storable; @@ -13,7 +14,7 @@ class PollyConverter implements Converter { - use Storable, Sourceable, HasLanguage, SSMLable; + use Storable, Sourceable, HasLanguage, SSMLable, HasSpeechMarks; /** * Client instance of Polly. @@ -47,7 +48,7 @@ public function getClient(): PollyClient * * @param string $data * @param array $options - * @return string + * @return string|array */ public function convert(string $data, array $options = null) { @@ -59,6 +60,10 @@ public function convert(string $data, array $options = null) $result = $this->synthesizeSpeech($text, $options); + if ($this->hasSpeechMarks()) { + return $this->formatToArray($this->getResultContent($result)); + } + if ($result instanceof Result) { // Store audio file to disk return $this->store( @@ -82,26 +87,26 @@ public function convert(string $data, array $options = null) */ protected function synthesizeSpeech($text, array $options = null) { + $arguments = [ + 'LanguageCode' => $this->getLanguage(), + 'VoiceId' => $this->voice($options), + 'OutputFormat' => $this->format($options), + 'TextType' => $this->textType(), + 'SpeechMarkTypes' => $this->speechMarks, + ]; + if (is_string($text)) { - return $this->client->synthesizeSpeech([ - 'LanguageCode' => $this->getLanguage(), - 'VoiceId' => $this->voice($options), - 'OutputFormat' => $this->format($options), - 'TextType' => $this->textType(), - 'Text' => $text, - ]); + return $this->client->synthesizeSpeech(array_merge($arguments, [ + 'Text' => $text, + ])); } $results = []; foreach ($text as $textItem) { - $result = $this->client->synthesizeSpeech([ - 'LanguageCode' => $this->getLanguage(), - 'VoiceId' => $this->voice($options), - 'OutputFormat' => $this->format($options), - 'TextType' => $this->textType(), - 'Text' => $textItem, - ]); + $result = $this->client->synthesizeSpeech(array_merge($arguments, [ + 'Text' => $textItem, + ])); array_push($results, $result); } @@ -190,6 +195,10 @@ protected function getLanguage() */ protected function format($options) { + if ($this->hasSpeechMarks()) { + return 'json'; + } + $default = config('tts.output_format', 'mp3'); return Arr::get($options, 'format', $default); @@ -205,4 +214,31 @@ protected function getResultContent($result) { return $result->get('AudioStream')->getContents(); } + + /** + * Determines if speech marks are set. + * + * @return bool + */ + protected function hasSpeechMarks() + { + return ! empty($this->speechMarks); + } + + /** + * Format the given json string into an array. + * + * @param string $json + * @return array + */ + protected function formatToArray($json) + { + $jsons = explode(PHP_EOL, $json); + + array_pop($jsons); + + return collect($jsons)->map(function ($json) { + return json_decode($json, true); + })->toArray(); + } } diff --git a/src/Facades/TextToSpeech.php b/src/Facades/TextToSpeech.php index f398928..8b22f45 100644 --- a/src/Facades/TextToSpeech.php +++ b/src/Facades/TextToSpeech.php @@ -5,12 +5,13 @@ use Illuminate\Support\Facades\Facade; /** - * @method static void convert($data, array $options) + * @method static string|array convert($data, array $options) * @method static \Cion\TextToSpeech\Contracts\Converter saveTo(string $path) * @method static \Cion\TextToSpeech\Contracts\Converter disk(string $disk) * @method static \Cion\TextToSpeech\Contracts\Converter source(string $source) * @method static \Cion\TextToSpeech\Contracts\Converter language(string $language) * @method static \Cion\TextToSpeech\Contracts\Converter ssml() + * @method static \Cion\TextToSpeech\Contracts\Converter speechMarks(array $speechMarks) */ class TextToSpeech extends Facade { diff --git a/src/Traits/HasSpeechMarks.php b/src/Traits/HasSpeechMarks.php new file mode 100644 index 0000000..d3b2153 --- /dev/null +++ b/src/Traits/HasSpeechMarks.php @@ -0,0 +1,26 @@ +speechMarks = $speechMarks; + + return $this; + } +} diff --git a/tests/PollyConverterTest.php b/tests/PollyConverterTest.php index 4279825..72b7eac 100644 --- a/tests/PollyConverterTest.php +++ b/tests/PollyConverterTest.php @@ -97,4 +97,14 @@ public function it_should_specify_path_source_and_be_able_to_retrieve_text() Storage::assertExists($path); } + + /** @test */ + public function it_should_return_an_array_when_speech_marks_are_set() + { + $converter = new PollyConverter($this->client); + + $result = $converter->speechMarks(['sentence'])->convert('test'); + + $this->assertIsArray($result); + } } From 93ba68b6bf8d5e48ce644523270ab4a2dc67ed75 Mon Sep 17 00:00:00 2001 From: Rigel Kent Carbonel Date: Sat, 10 Apr 2021 21:57:05 +0800 Subject: [PATCH 2/5] Apply fixes from StyleCI (#25) --- src/Converters/PollyConverter.php | 2 +- src/Traits/HasSpeechMarks.php | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Converters/PollyConverter.php b/src/Converters/PollyConverter.php index bf444d9..b787ea0 100644 --- a/src/Converters/PollyConverter.php +++ b/src/Converters/PollyConverter.php @@ -238,7 +238,7 @@ protected function formatToArray($json) array_pop($jsons); return collect($jsons)->map(function ($json) { - return json_decode($json, true); + return json_decode($json, true); })->toArray(); } } diff --git a/src/Traits/HasSpeechMarks.php b/src/Traits/HasSpeechMarks.php index d3b2153..af68a1e 100644 --- a/src/Traits/HasSpeechMarks.php +++ b/src/Traits/HasSpeechMarks.php @@ -1,9 +1,7 @@ Date: Sat, 10 Apr 2021 22:03:40 +0800 Subject: [PATCH 3/5] docs: update readme for speech marks --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index a3d8cb6..8bd522c 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,10 @@ $path = TextToSpeech::language('ja-JP') // use the SSML text type in the convert() method. $path = TextToSpeech::ssml() ->convert('Hi There This is SSML syntaxconvert('This is a test'); // This will return an array. ``` ## Installation From 5fb6c4e18400ff41d946a8a266f29133ab577bd6 Mon Sep 17 00:00:00 2001 From: Rigel Kent Carbonel Date: Sat, 10 Apr 2021 22:20:58 +0800 Subject: [PATCH 4/5] docs: update readme for the added speech marks config. --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8bd522c..0e2c926 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ return [ 'polly' => [ /** * Voice ID to use for the synthesis. - * You may use any of the following: + * You may use any of the following:. * * Aditi, Amy, Astrid, Bianca, Brian, Camila, Carla, Carmen, Celine, * Chantal, Conchita, Cristiano, Dora, Emma, Enrique, Ewa, Filiz, @@ -175,6 +175,14 @@ return [ */ 'voice_id' => env('AWS_VOICE_ID', 'Amy'), + /** + * You can request any or all of the speech mark types, but leave it empty if you don't use speech marks. + * You may add any of the following:. + * + * sentence, word, viseme, ssml + */ + 'speech_marks' => [], + /** * IAM Credentials from AWS. */ From 9011dda2689420c93e9efdcc06b717aa22168bdf Mon Sep 17 00:00:00 2001 From: Rigel Kent Carbonel Date: Sat, 10 Apr 2021 22:21:18 +0800 Subject: [PATCH 5/5] feat: add speech marks in config --- config/config.php | 8 ++++++++ src/Converters/PollyConverter.php | 18 ++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/config/config.php b/config/config.php index e264a27..12e679d 100644 --- a/config/config.php +++ b/config/config.php @@ -82,6 +82,14 @@ */ 'voice_id' => env('AWS_VOICE_ID', 'Amy'), + /** + * You can request any or all of the speech mark types, but leave it empty if you don't use speech marks. + * You may add any of the following:. + * + * sentence, word, viseme, ssml + */ + 'speech_marks' => [], + /** * IAM Credentials from AWS. */ diff --git a/src/Converters/PollyConverter.php b/src/Converters/PollyConverter.php index b787ea0..8faf49c 100644 --- a/src/Converters/PollyConverter.php +++ b/src/Converters/PollyConverter.php @@ -87,12 +87,14 @@ public function convert(string $data, array $options = null) */ protected function synthesizeSpeech($text, array $options = null) { + $speechMarks = $this->getSpeechMarks(); + $arguments = [ 'LanguageCode' => $this->getLanguage(), 'VoiceId' => $this->voice($options), 'OutputFormat' => $this->format($options), 'TextType' => $this->textType(), - 'SpeechMarkTypes' => $this->speechMarks, + 'SpeechMarkTypes' => $speechMarks, ]; if (is_string($text)) { @@ -204,6 +206,18 @@ protected function format($options) return Arr::get($options, 'format', $default); } + /** + * Get the speech marks. + * + * @return array + */ + protected function getSpeechMarks() + { + $default = config('tts.services.polly.speech_marks', []); + + return ! empty($this->speechMarks) ? $this->speechMarks : $default; + } + /** * Get the content of the result from AWS Polly. * @@ -222,7 +236,7 @@ protected function getResultContent($result) */ protected function hasSpeechMarks() { - return ! empty($this->speechMarks); + return ! empty($this->getSpeechMarks()); } /**