also looking at this
meemalabs/laravel-text-to-speech
Added support for speech marks.
#26
7 files
+125
-19
| @@ -53,6 +53,10 @@ $path = TextToSpeech::language('ja-JP') | ||
| 53 | 53 | // use the SSML text type in the convert() method. |
| 54 | 54 | $path = TextToSpeech::ssml() |
| 55 | 55 | ->convert('<speak>Hi There <break /> This is SSML syntax</speak'); |
| 56 | ||
| 57 | // using speech marks. | |
| 58 | $output = TextToSpeech::speechMarks(['sentence', 'word', 'viseme', 'ssml']) | |
| 59 | ->convert('This is a test'); // This will return an array. | |
| 56 | 60 | ``` |
| 57 | 61 | |
| 58 | 62 | ## Installation |
| @@ -159,7 +163,7 @@ return [ | ||
| 159 | 163 | 'polly' => [ |
| 160 | 164 | /** |
| 161 | 165 | * Voice ID to use for the synthesis. |
| 162 | * You may use any of the following: | |
| 166 | * You may use any of the following:. | |
| 163 | 167 | * |
| 164 | 168 | * Aditi, Amy, Astrid, Bianca, Brian, Camila, Carla, Carmen, Celine, |
| 165 | 169 | * Chantal, Conchita, Cristiano, Dora, Emma, Enrique, Ewa, Filiz, |
| @@ -171,6 +175,14 @@ return [ | ||
| 171 | 175 | */ |
| 172 | 176 | 'voice_id' => env('AWS_VOICE_ID', 'Amy'), |
| 173 | 177 | |
| 178 | /** | |
| 179 | * You can request any or all of the speech mark types, but leave it empty if you don't use speech marks. | |
| 180 | * You may add any of the following:. | |
| 181 | * | |
| 182 | * sentence, word, viseme, ssml | |
| 183 | */ | |
| 184 | 'speech_marks' => [], | |
| 185 | ||
| 174 | 186 | /** |
| 175 | 187 | * IAM Credentials from AWS. |
| 176 | 188 | */ |
| @@ -28,7 +28,8 @@ | ||
| 28 | 28 | "php": "^7.3|^7.4|^8.0", |
| 29 | 29 | "aws/aws-sdk-php": "^3.178", |
| 30 | 30 | "guzzlehttp/guzzle": "^6.0|^7.0", |
| 31 | "illuminate/support": "5.*|^6.0|^7.0|^8.0" | |
| 31 | "illuminate/support": "5.*|^6.0|^7.0|^8.0", | |
| 32 | "ext-json": "*" | |
| 32 | 33 | }, |
| 33 | 34 | "require-dev": { |
| 34 | 35 | "orchestra/testbench": "^4.0|^5.0|^6.0", |
| @@ -82,6 +82,14 @@ return [ | ||
| 82 | 82 | */ |
| 83 | 83 | 'voice_id' => env('AWS_VOICE_ID', 'Amy'), |
| 84 | 84 | |
| 85 | /** | |
| 86 | * You can request any or all of the speech mark types, but leave it empty if you don't use speech marks. | |
| 87 | * You may add any of the following:. | |
| 88 | * | |
| 89 | * sentence, word, viseme, ssml | |
| 90 | */ | |
| 91 | 'speech_marks' => [], | |
| 92 | ||
| 85 | 93 | /** |
| 86 | 94 | * IAM Credentials from AWS. |
| 87 | 95 | */ |
| @@ -6,6 +6,7 @@ use Aws\Polly\PollyClient; | ||
| 6 | 6 | use Aws\Result; |
| 7 | 7 | use Cion\TextToSpeech\Contracts\Converter; |
| 8 | 8 | use Cion\TextToSpeech\Traits\HasLanguage; |
| 9 | use Cion\TextToSpeech\Traits\HasSpeechMarks; | |
| 9 | 10 | use Cion\TextToSpeech\Traits\Sourceable; |
| 10 | 11 | use Cion\TextToSpeech\Traits\SSMLable; |
| 11 | 12 | use Cion\TextToSpeech\Traits\Storable; |
| @@ -13,7 +14,7 @@ use Illuminate\Support\Arr; | ||
| 13 | 14 | |
| 14 | 15 | class PollyConverter implements Converter |
| 15 | 16 | { |
| 16 | use Storable, Sourceable, HasLanguage, SSMLable; | |
| 17 | use Storable, Sourceable, HasLanguage, SSMLable, HasSpeechMarks; | |
| 17 | 18 | |
| 18 | 19 | /** |
| 19 | 20 | * Client instance of Polly. |
| @@ -47,7 +48,7 @@ class PollyConverter implements Converter | ||
| 47 | 48 | * |
| 48 | 49 | * @param string $data |
| 49 | 50 | * @param array $options |
| 50 | * @return string | |
| 51 | * @return string|array | |
| 51 | 52 | */ |
| 52 | 53 | public function convert(string $data, array $options = null) |
| 53 | 54 | { |
| @@ -59,6 +60,10 @@ class PollyConverter implements Converter | ||
| 59 | 60 | |
| 60 | 61 | $result = $this->synthesizeSpeech($text, $options); |
| 61 | 62 | |
| 63 | if ($this->hasSpeechMarks()) { | |
| 64 | return $this->formatToArray($this->getResultContent($result)); | |
| 65 | } | |
| 66 | ||
| 62 | 67 | if ($result instanceof Result) { |
| 63 | 68 | // Store audio file to disk |
| 64 | 69 | return $this->store( |
| @@ -82,26 +87,28 @@ class PollyConverter implements Converter | ||
| 82 | 87 | */ |
| 83 | 88 | protected function synthesizeSpeech($text, array $options = null) |
| 84 | 89 | { |
| 90 | $speechMarks = $this->getSpeechMarks(); | |
| 91 | ||
| 92 | $arguments = [ | |
| 93 | 'LanguageCode' => $this->getLanguage(), | |
| 94 | 'VoiceId' => $this->voice($options), | |
| 95 | 'OutputFormat' => $this->format($options), | |
| 96 | 'TextType' => $this->textType(), | |
| 97 | 'SpeechMarkTypes' => $speechMarks, | |
| 98 | ]; | |
| 99 | ||
| 85 | 100 | if (is_string($text)) { |
| 86 | return $this->client->synthesizeSpeech([ | |
| 87 | 'LanguageCode' => $this->getLanguage(), | |
| 88 | 'VoiceId' => $this->voice($options), | |
| 89 | 'OutputFormat' => $this->format($options), | |
| 90 | 'TextType' => $this->textType(), | |
| 91 | 'Text' => $text, | |
| 92 | ]); | |
| 101 | return $this->client->synthesizeSpeech(array_merge($arguments, [ | |
| 102 | 'Text' => $text, | |
| 103 | ])); | |
| 93 | 104 | } |
| 94 | 105 | |
| 95 | 106 | $results = []; |
| 96 | 107 | |
| 97 | 108 | foreach ($text as $textItem) { |
| 98 | $result = $this->client->synthesizeSpeech([ | |
| 99 | 'LanguageCode' => $this->getLanguage(), | |
| 100 | 'VoiceId' => $this->voice($options), | |
| 101 | 'OutputFormat' => $this->format($options), | |
| 102 | 'TextType' => $this->textType(), | |
| 103 | 'Text' => $textItem, | |
| 104 | ]); | |
| 109 | $result = $this->client->synthesizeSpeech(array_merge($arguments, [ | |
| 110 | 'Text' => $textItem, | |
| 111 | ])); | |
| 105 | 112 | |
| 106 | 113 | array_push($results, $result); |
| 107 | 114 | } |
| @@ -190,11 +197,27 @@ class PollyConverter implements Converter | ||
| 190 | 197 | */ |
| 191 | 198 | protected function format($options) |
| 192 | 199 | { |
| 200 | if ($this->hasSpeechMarks()) { | |
| 201 | return 'json'; | |
| 202 | } | |
| 203 | ||
| 193 | 204 | $default = config('tts.output_format', 'mp3'); |
| 194 | 205 | |
| 195 | 206 | return Arr::get($options, 'format', $default); |
| 196 | 207 | } |
| 197 | 208 | |
| 209 | /** | |
| 210 | * Get the speech marks. | |
| 211 | * | |
| 212 | * @return array | |
| 213 | */ | |
| 214 | protected function getSpeechMarks() | |
| 215 | { | |
| 216 | $default = config('tts.services.polly.speech_marks', []); | |
| 217 | ||
| 218 | return ! empty($this->speechMarks) ? $this->speechMarks : $default; | |
| 219 | } | |
| 220 | ||
| 198 | 221 | /** |
| 199 | 222 | * Get the content of the result from AWS Polly. |
| 200 | 223 | * |
| @@ -205,4 +228,31 @@ class PollyConverter implements Converter | ||
| 205 | 228 | { |
| 206 | 229 | return $result->get('AudioStream')->getContents(); |
| 207 | 230 | } |
| 231 | ||
| 232 | /** | |
| 233 | * Determines if speech marks are set. | |
| 234 | * | |
| 235 | * @return bool | |
| 236 | */ | |
| 237 | protected function hasSpeechMarks() | |
| 238 | { | |
| 239 | return ! empty($this->getSpeechMarks()); | |
| 240 | } | |
| 241 | ||
| 242 | /** | |
| 243 | * Format the given json string into an array. | |
| 244 | * | |
| 245 | * @param string $json | |
| 246 | * @return array | |
| 247 | */ | |
| 248 | protected function formatToArray($json) | |
| 249 | { | |
| 250 | $jsons = explode(PHP_EOL, $json); | |
| 251 | ||
| 252 | array_pop($jsons); | |
| 253 | ||
| 254 | return collect($jsons)->map(function ($json) { | |
| 255 | return json_decode($json, true); | |
| 256 | })->toArray(); | |
| 257 | } | |
| 208 | 258 | } |
| @@ -5,12 +5,13 @@ namespace Cion\TextToSpeech\Facades; | ||
| 5 | 5 | use Illuminate\Support\Facades\Facade; |
| 6 | 6 | |
| 7 | 7 | /** |
| 8 | * @method static void convert($data, array $options) | |
| 8 | * @method static string|array convert($data, array $options) | |
| 9 | 9 | * @method static \Cion\TextToSpeech\Contracts\Converter saveTo(string $path) |
| 10 | 10 | * @method static \Cion\TextToSpeech\Contracts\Converter disk(string $disk) |
| 11 | 11 | * @method static \Cion\TextToSpeech\Contracts\Converter source(string $source) |
| 12 | 12 | * @method static \Cion\TextToSpeech\Contracts\Converter language(string $language) |
| 13 | 13 | * @method static \Cion\TextToSpeech\Contracts\Converter ssml() |
| 14 | * @method static \Cion\TextToSpeech\Contracts\Converter speechMarks(array $speechMarks) | |
| 14 | 15 | */ |
| 15 | 16 | class TextToSpeech extends Facade |
| 16 | 17 | { |
| @@ -0,0 +1,24 @@ | ||
| 1 | <?php | |
| 2 | ||
| 3 | namespace Cion\TextToSpeech\Traits; | |
| 4 | ||
| 5 | trait HasSpeechMarks | |
| 6 | { | |
| 7 | /** | |
| 8 | * @var array | |
| 9 | */ | |
| 10 | protected $speechMarks = []; | |
| 11 | ||
| 12 | /** | |
| 13 | * Sets the speech mark types. | |
| 14 | * | |
| 15 | * @param array $speechMarks | |
| 16 | * @return $this | |
| 17 | */ | |
| 18 | public function speechMarks(array $speechMarks) | |
| 19 | { | |
| 20 | $this->speechMarks = $speechMarks; | |
| 21 | ||
| 22 | return $this; | |
| 23 | } | |
| 24 | } | |
| @@ -97,4 +97,14 @@ class PollyConverterTest extends TextToSpeechTestCase | ||
| 97 | 97 | |
| 98 | 98 | Storage::assertExists($path); |
| 99 | 99 | } |
| 100 | ||
| 101 | /** @test */ | |
| 102 | public function it_should_return_an_array_when_speech_marks_are_set() | |
| 103 | { | |
| 104 | $converter = new PollyConverter($this->client); | |
| 105 | ||
| 106 | $result = $converter->speechMarks(['sentence'])->convert('test'); | |
| 107 | ||
| 108 | $this->assertIsArray($result); | |
| 109 | } | |
| 100 | 110 | } |