schmupu / ioBroker.asterisk

Asterisk VoIP Adapter
MIT License
18 stars 9 forks source link

Google TextToSpeech API #25

Open Coalado opened 3 years ago

Coalado commented 3 years ago

Since several days/weeks, the adapter does not work any more.

I tracked the issue down to "The Google TTS API returns a "Forbidden"". It seems like the adapter is blocked because the same request works in the browser.

However, I updated the transcode.js to use the official Google API. (You need a google API key, but you have ~1.000.000 free characters)

Here is my code. Maybe somebody can implement this, a config option for the google API incl. Key, and re-implement the language/Voice options (which are hardcoded right now). Optionally: Build a Text->Mp3 cache to avoid sensing the same texts over and over...

To test the code:

  1. Enable the Google TextToSpeech API and create an API Key
  2. replace the textToMp3Stream function in transcode.js:
  3. 
    
    textToMp3Stream(text, language, volume) {
    
    return new Promise((resolve, reject) => {
        if (text.length === 0) {
            reject(new Error(`File Length ${text}, ${language}, ${volume}, 0`));
        }
        if (text.length > 200) {
            reject(new Error(`File Length ${text}, ${language}, ${volume}, greater than 200`));
        }
    
        const API_KEY = <YOUR API KEY>;
        const options = {
            host: 'texttospeech.googleapis.com',
            port: 443,
            path: "/v1/text:synthesize?key=" + API_KEY,
            method: 'POST',
            headers: {
                'Content-Type': 'application/json; charset=utf-8'
            }
        };
        let postdata = JSON.stringify({
            'input': {
                'text': text
            },
            'voice': {
                'languageCode': 'de-DE',
                'name': 'en-DE-Wavenet-F',
                'ssmlGender': 'MALE'
            },
            'audioConfig': {
                'audioEncoding': 'MP3'
            }
        });
        const req = https.request(options, (res) => {
            let json = "";
            res.on('data', chunk => {
                json += chunk;
            });
            res.on('end', () => {
    
                if (json.length < 100) {
                    reject(new Error(`Cannot get file: received file is too short ${text}, ${language}, ${volume}, 0`));
                }
                if (json.toString().indexOf('audioContent') < 0) {
                    reject(new Error(`Failed to get AudioContent: ` + json));
                }
                const buff = Buffer.from(JSON.parse(json).audioContent, 'base64');
    
                resolve({
                    text: text,
                    sounddata: buff.toString("binary")
                });
    
            });
        });
        req.on('error', error => {
            console.error(error)
        })
        req.write(postdata);
        req.end();
    
    });

}

Coalado commented 3 years ago

To create an API Key:

  1. Go to https://console.developers.google.com/
  2. Choose or create a project
  3. If the APIs & services page isn't already open, open the left side menu and select APIs & services.
  4. Enable the Text To Speech API
  5. On the left, choose Credentials.
  6. Click Create credentials and then select API key.
stefanoklett commented 3 years ago

or, be google free: https://forum.iobroker.net/topic/45177/asterisk-bringt-error-while-dialing-2-error

I prefer this solution, addictions hurt ;-) regards Stefano

PLCHome commented 3 years ago

This will not work:

$ wget "https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=hallo%20du&tl=de&total=1&idx=0&textlen=10"
--2021-07-16 22:49:43--  https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=hallo%20du&tl=de&total=1&idx=0&textlen=10
Auflösen des Hostnamens translate.google.com (translate.google.com)… 142.250.185.238, 2a00:1450:4005:80b::200e
Verbindungsaufbau zu translate.google.com (translate.google.com)|142.250.185.238|:443 … verbunden.
HTTP-Anforderung gesendet, auf Antwort wird gewartet … 403 Forbidden
2021-07-16 22:49:44 FEHLER 403: Forbidden.

This will work:

$ wget --user-agent='Mozilla/5.0 (Windows NT 6.3; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0' "https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=hallo%20du&tl=de&total=1&idx=0&textlen=10" --2021-07-16 22:51:58--  https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=hallo%20du&tl=de&total=1&idx=0&textlen=10
Auflösen des Hostnamens translate.google.com (translate.google.com)… 142.250.184.206, 2a00:1450:4001:802::200e
Verbindungsaufbau zu translate.google.com (translate.google.com)|142.250.184.206|:443 … verbunden.
HTTP-Anforderung gesendet, auf Antwort wird gewartet … 200 OK
Länge: nicht spezifiziert [audio/mpeg]
Wird in »translate_tts?ie=UTF-8&client=tw-ob&q=hallo du&tl=de&total=1&idx=0&textlen=10« gespeichert.

translate_tts?ie=UTF-8&client=tw-ob&q=hallo du&tl=de&total=     [ <=>                                                                                                                                     ]   5,16K  --.-KB/s    in 0s

2021-07-16 22:51:58 (10,8 MB/s) - »translate_tts?ie=UTF-8&client=tw-ob&q=hallo du&tl=de&total=1&idx=0&textlen=10« gespeichert [5280]

So we can change in lib/transcode.js line 100 - 105

      // https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D0%B8%D1%82%D1%8C%207&tl=ru&total=1&idx=0&textlen=10
      const options = {
        host: 'translate.google.com',
        //port: 443,
        path: '/translate_tts?ie=UTF-8&client=tw-ob&q=' + encodeURI(text) + '&tl=' + language + '&total=1&idx=0&textlen=' + text.length //
      };

to

      // https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D0%B8%D1%82%D1%8C%207&tl=ru&total=1&idx=0&textlen=10
      const options = {
        host: 'translate.google.com',
        //port: 443,
        path: '/translate_tts?ie=UTF-8&client=tw-ob&q=' + encodeURI(text) + '&tl=' + language + '&total=1&idx=0&textlen=' + text.length, //
        headers: {'user-agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0'}
      };

The API will only talk to firefox