TTS Engine Custom - Amazon Polly - 24 languages

WORKING SUMMARY:

  1. Run these commands in shell:
cd /opt/
git clone https://github.com/awslabs/aws-nodejs-sample
cd aws-nodejs-sample
npm install
npm install optimist
npm install child_process

2a) Create file in directory /opt/aws-nodejs-sample/

vim script.js

// Load the SDK
var argv = require('optimist').argv;
const AWS = require('aws-sdk')
const Fs = require('fs')
var child_process = require('child_process');
// Create an Polly client
const Polly = new AWS.Polly({
accessKeyId: "accessKeyId here",
secretAccessKey: "secretAccesKey here",
signatureVersion: 'v4',
region: 'us-east-1'

})

let params = {
'Text': argv.text,
// 'Text': 'Tatiana',
'OutputFormat': 'mp3',
'SampleRate': '8000',
'VoiceId': 'Amy'
}

Polly.synthesizeSpeech(params, (err, data) => {
if (err) {
console.log(err.code)
} else if (data) {
if (data.AudioStream instanceof Buffer) {
Fs.writeFile(argv.mp3, data.AudioStream, function(err) {
if (err) {
return console.log(err)
}
console.log("The file was saved!")
var output = child_process.execSync('lame --decode ' + argv.mp3 + ' ' + '-b 8000' + ' ' + argv.wav + '.wav');

        })
    }
}
})

2b) You can change the voice, by going to google and typing “Amazon Polly Available Voices”. Sorry but new users cant post links here.

Then copy the Name/ID you want and replace ‘Amy’ in the ‘VoiceId’ line above with that ID.
Also, DO NOT FORGET to obtain and enter your AWS ‘accessKeyId’ and ‘secretAccessKey’ in the lines marked bold above!

3a) Modify /var/lib/asterisk/agi-bin/propolys-tts.agi to change the following lines:

vim /var/lib/asterisk/agi-bin/propolys-tts.agi

FROM

    default;
            $format = array(
                    **"ext" => "sln",**
                    "rate" => "8000"
            );
    break;

TO

    default;
            $format = array(
                    **"ext" => "wav",**
                    "rate" => "8000"
            );
    break;

3b) Continue modifying the same file to add the following lines to switch ($engine) { before the default case.

            case 'aws-polly':
                    exec($enginebin." /opt/aws-nodejs-sample/script.js --mp3=/var/lib/asterisk/sounds/tts/$engine-tts-$hash.mp3 --text='$text' --wav=/var/lib/asterisk/sounds/tts/$engine-tts-$hash");
                    break;

3c) IMPORTANT NOTE: Any time you apply an updated configuration in the GUI it will replace all of these steps in #3 and you will have to re-enter these changes to restore the TTS engine.

  1. Go to Settings >> Text to Speech Engines, then click + Add TTS Engine

Engine Name: Custom, then type ‘aws-polly’ without quotes.
Engine Path: /usr/bin/node

  1. Create TTS from Applications >> Text to Speech using the aws-polly engine.
    DO NOT Apply Config when you create your TTS entries, it will remove all the work in Step #3 above and you will have to re-enter it again.

You now have a fully customizable AWS/Polly TTS

And a HUGE THANK YOU to jersonjunior for all his help in getting this up and running. I came across this post and was a little hesitant, but this is a GREAT solution for TTS in FreePBX.

To make things simpler, when everything is setup, make a copy of /var/lib/asterisk/agi-bin/propolys-tts.agi as /var/lib/asterisk/agi-bin/propolys-tts.bak and then you can simply replace the file when you need to Apply Config.

3 Likes

@theclevercrib I know it was not your intent but you essentially went around our spam filters. Which is violating policy and makes the system think you are a spammer. I made your first account a normal user and changed ownership on your new posts.

2 Likes

Thank you kindly, I was going to contact a sysadmin when I could reply again.

I love the concept and thank you for the huge effort. When i follow the steps I get the following:

/opt/aws-nodejs-sample/script.js: line 1: syntax error near unexpected token (' /opt/aws-nodejs-sample/script.js: line 1: var argv = require(‘optimist’).argv;’

my script.js
var argv = require(‘optimist’).argv;
const AWS = require(‘aws-sdk’)
const Fs = require(‘fs’)
var child_process = require(‘child_process’);
const Polly = new AWS.Polly({
… etc

You need to add this to line 1:
#!/usr/bin/env node

I am trying AWS polly out, but have come to a brick wall.
When I execute the script the wav file is not created.
and no obvious error message.
Is there a way to enable a debug reporting ?

Any help appreciated.

Scripts as above
extract from full log as follows

[2017-10-09 14:08:25] VERBOSE[4758][C-00000092] pbx.c: Executing [1@ext-tts:4] AGI(“SIP/Sip_61731230612-0000008e”, “propolys-tts.agi,“this is a test of aws Polly”,aws-polly,/usr/bin/node”) in new stack
[2017-10-09 14:08:25] VERBOSE[4758][C-00000092] res_agi.c: Launched AGI Script /var/lib/asterisk/agi-bin/propolys-tts.agi
[2017-10-09 14:08:25] VERBOSE[4758][C-00000092] res_agi.c: propolys-tts.agi,“this is a test of aws Polly”,aws-polly,/usr/bin/node: TTS AGI Started
[2017-10-09 14:08:25] VERBOSE[4758][C-00000092] res_agi.c: propolys-tts.agi,“this is a test of aws Polly”,aws-polly,/usr/bin/node: Generated WAV file: /var/lib/asterisk/sounds/tts/aws-polly-tts-df04e889735f84e9670a11fbe67d89b9.wav
[2017-10-09 14:08:25] VERBOSE[4758][C-00000092] res_agi.c: propolys-tts.agi,“this is a test of aws Polly”,aws-polly,/usr/bin/node: TXT file: /var/lib/asterisk/sounds/tts/aws-polly-tts-df04e889735f84e9670a11fbe67d89b9.txt
[2017-10-09 14:08:25] VERBOSE[4758][C-00000092] res_agi.c: propolys-tts.agi,“this is a test of aws Polly”,aws-polly,/usr/bin/node: Text to speech wave file doesnt exist, lets create it.
[2017-10-09 14:08:25] VERBOSE[4758][C-00000092] res_agi.c: propolys-tts.agi,“this is a test of aws Polly”,aws-polly,/usr/bin/node: Executing aws-polly
[2017-10-09 14:08:25] VERBOSE[4758][C-00000092] res_agi.c: propolys-tts.agi,“this is a test of aws Polly”,aws-polly,/usr/bin/node: File was not created!
[2017-10-09 14:08:25] VERBOSE[4758][C-00000092] res_agi.c: propolys-tts.agi,“this is a test of aws Polly”,aws-polly,/usr/bin/node: TTS AGI end
[2017-10-09 14:08:25] VERBOSE[4758][C-00000092] res_agi.c: <SIP/Sip_61731230612-0000008e>AGI Script propolys-tts.agi completed, returning 0

Permissions seem ok too

Belay my last post
Word of warning for others following this thread.
When you cut and paste your AWS access keys do not lose the commas at the end of the line.
:grin:

So this is working if you can follow directions?
Can someone make this easy for the rest of us to implement?

Hello. How could we enable polly for two languages at the same time? so i tried to create 2 scripts for these languages. and i added two cases like that

    case 'aws-polly-en':
            exec($enginebin." /opt/aws-nodejs-sample/script_en.js --mp3=/var/lib/asterisk/sounds/tts/$engine-tts-$hash.mp3 --text='$text' --wav=/var/lib/asterisk/sounds/tts/$engine-tts-$hash");
            break;

    case 'aws-polly-tr':
            exec($enginebin." /opt/aws-nodejs-sample/script_tr.js --mp3=/var/lib/asterisk/sounds/tts/$engine-tts-$hash.mp3 --text='$text' --wav=/var/lib/asterisk/sounds/tts/$engine-tts-$hash");
            break;

However couldn’t add two engines to the TTS Engine. It warns me “/usr/bin/node already used, please use a different Engine Path.”

Any solution?

Try this:

})

let params = {
‘Text’: argv.text,
// ‘Text’: ‘Tatiana’,
‘OutputFormat’: ‘mp3’,
‘SampleRate’: ‘8000’,
‘VoiceId’: ‘Vitoria’
}

To

})

let params = {
‘Text’: argv.text,
// ‘Text’: ‘Tatiana’,
‘OutputFormat’: ‘mp3’,
‘SampleRate’: ‘8000’,
‘VoiceId’:argv.voice
}

what does “argv.voice” actually do? Because i already changed it with a different speaker name in my second script. Do you want me to change it as it seems? If so, how could polly decide which speaker should be spoken?

I am trying to use AWS-Polly but it seems I am doing something wrong or permissions issue somewhere. I followed install and create/modify script.js and propolys-tts to the letter of Jerson Jr/ William Bond. It trys to work because I see in my tts sound folder aws-polly-tts* wav, txt and mp3 files but not the sln file that my CLI says it is trying to play back. Also when I download and play back the mp3 and wav file they are blank. The text file has the text from my text to speech application. I only say it maybe a permissions issue because the files it does create does not have the group write permission like when I use the flite engine.

Disregard, turns out the text to speech app had special characters in it. Everything works when I removed them.

1 Like

I get this error

node script.js --mp3=/var/lib/asterisk/sounds/mp3file --text=‘testando’ --wav=/var/lib/asterisk/sounds/wavfile

/opt/aws-nodejs-sample/script.js:15
let params = {
^^^^^^
SyntaxError: Unexpected identifier
at Module._compile (module.js:439:25)
at Object.Module._extensions…js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:906:3
root@erimat:/opt/aws-nodejs-sample#

node script.js --mp3=/var/lib/asterisk/sounds/test.mp3 --text=‘Hello’ --wav=/var/lib/asterisk/sounds/tts/test");

I know its been said before, but this would be so useful as a module. Thanks @jersonjunior for keeping this alive.

It’s up to jerson if he wants to do this.

1 Like

From experience:

Doing the code is the easy part. Building it into a module is no small undertaking. I found the new object model daunting, and I’m not new to this programming thing. What I did that with the SCCP Manager on the old FreePBX (1.8 and before) was still a LOT of work. All of the new supporting code, packaging, BMO-interfacing, and GUI tricks make it a big effort and time investment for someone that only does this once. Even then, the project ends up in the repository as a “here you go, knock yourself out” piece of software.

Don’t get me wrong, I’d do that work again if I wasn’t working full time and running my own business. Having some teaming from the commercial folks for an “open” module would be really cool. Of course, how does one fund something like that? Sangoma’s people are paid to do this, so asking us to ask them isn’t really appropriate, and if Sangoma asks them to do it for free, there are labor rules about that…

A compromise solution might be to take James’ “basic” hello world starter kit and put together a webinar explaining how the pieces go together for us “wanna-be” module developers. Perhaps a clear path for “promotion” and (of course) the obligatory NDA/Release that Sangoma has all
developers sign might be a good first step.

https://wiki.freepbx.org/display/FOP/FreePBX+Module+Generator

2 Likes

I would like to do this module, but I do not have the ability to perform this task, in the beginning I contacted the Sangoma people but the bureaucracy did not let things flow, anyway I believe that a simple change in the engine module could improve the module to operate with IBM Watson, Microsoft Bing and Amazon Polly. Modify the module so that it can write the entries in /var/lib/asterisk/agi-bin/propolys-tts.agi

Example:

case ‘node’:

                    exec($enginebin." /opt/aws-nodejs-sample/script.js --mp3=/var/lib/asterisk/sounds/tts/$engine-tts-$hash.mp3 --text='$text' --wav=/var/lib/asterisk/sounds/tts/$engine-tts-$hash");
                    break;

The remainder would be borne by the user, would already be a major breakthrough.