Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
One TTS to rule them all
#!/usr/bin/env bash
# By Psycho
# Shell script to handle different TTS and online / offline connectivity
# This bash script can be set as a custom TTS for snips but also called directly from your skills
# a great way to give more than one personality to your assistant
# Original script: https://gist.github.com/Psychokiller1888/cf10af3220b5cd6d9c92c709c6af92c2
####### COMMON #######
#------------------------------------
# Set your cache path
cache="/home/pi/snipsSuperTTS/cache"
#------------------------------------
# - Install mpg123
# - The cache path is created by the script itself at first run! If you already have the cache directories, make sure to set its owner to "_snips" => sudo chown _snips /home/pi/snipsSuperTTS/cache
# - Edit /etc/snips.toml
# - Set "customtts" as snips-tts provider
# - Add as customtts: command = ["/home/pi/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "google", "%%LANG%%", "US", "Wavenet-C", "FEMALE", "%%TEXT%%", "22050"]
# Change "US" to another language country code, "GB" per exemple for a british voice
# You can customize the "Wavenet-C" to another voice of your choice. https://cloud.google.com/text-to-speech/docs/voices / https://docs.aws.amazon.com/polly/latest/dg/voicelist.html
# Offline voices possibilities are: picotts or mycroft
# Fit "FEMALE" to the voice gender you want. Note this is linked to google voices
# You can change the sample rate, the last argument, to your needs
# Restart snips: systemctl restart snips-*
# If you want a total customized experience, you can easily enable both google and amazon and use a different one depending on what you want. Don't be shy, there's no limit
# Note that not all parameters do something depending on the voice you choose. Those are marked with "--" in the provided examples
####### MycroftAI - Mimic #######
# https://github.com/MycroftAI/mimic
# This one is pretty long to install, but hey, the quality compared to pico is worth it!
# Set the following option to True to use Mycroft instead of pico. Don't forget to set the path too
#
# Example: command = ["/home/pi/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "mycroft", "%%LANG%%", "--", "slt_hts", "--", "%%TEXT%%", "22050"]
#
# Available voices: aew ahw aup awb axb bdl clb eey fem gka jmk ksp ljm rms rxr slt slt_hts
# Or you can use an external voice on http.
#
# sudo apt-get install gcc make pkg-config automake libtool libasound2-dev
# git clone https://github.com/MycroftAI/mimic.git
# cd mimic
# ./dependencies.sh --prefix="/usr/local"
# ./autogen.sh
# ./configure --prefix="/usr/local"
# make
# sudo /sbin/ldconfig
# make check
useMycroft=false
mycroftPath="/home/pi/mimic"
####### GOOGLE #######
# Install Google SDK: https://cloud.google.com/text-to-speech/docs/quickstart-protocol
# Follow point 6. to initialize the sdk after creating your service account
# Get your api key from the console https://console.developers.google.com
# Uncomment the following and set it accordingly:
#
#googleWavenetAPIKey=""
#
# Example: command = ["/home/pi/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "google", "%%LANG%%", "US", "Wavenet-C", "FEMALE", "%%TEXT%%", "22050"]
###### AMAZON #######
# Install Amazon sdk
# curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip"
# unzip awscli-bundle.zip
# ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws
# Uncomment the following lines and set them accordingly:
#
#export AWS_ACCESS_KEY_ID=""
#export AWS_SECRET_ACCESS_KEY=""
#export AWS_DEFAULT_REGION="eu-central-1"
#awscli='/usr/local/bin/aws'
#
# command = ["/home/pi/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "amazon", "%%LANG%%", "US", "Joanna", "--", "%%TEXT%%", "22050"]
#
####################################################################################################
outfile="$1"
service="$2"
lang="$3"
country="$4"
voice="$5"
gender="$6"
text="$7"
sampleRate="$8"
if [ "$service" = "mycroft" ] || [ "$service" = "picotts" ]; then
status="offline"
else
echo -e "GET http://google.com HTTP/1.0\n\n" | nc google.com 80 > /dev/null 2>&1
if [ $? -eq 0 ]; then
status="online"
else
status="offline"
fi
# Alternative for some people having problem pinging google.com. Comment the above and uncomment the following
#wget -q --tries=1 --timeout=1 --spider http://google.com
#if [[ $? -eq 0 ]]; then
# status="online"
#else
# status="offline"
#fi
fi
function picotts() {
case "$lang" in
*en*)
lang="en-US";;
*de*)
lang="de-DE";;
*es*)
lang="es-ES";;
*fr*)
lang="fr-FR";;
*it*)
lang="it-IT";;
*)
lang="en-US";;
esac
text=$(sed 's/<[^>]*>//g' <<< "$text")
pico2wave -w "$outfile" -l "$lang" "$text"
}
function mycroft() {
text=$(sed 's/<[^>]*>//g' <<< "$text")
."$mycroftPath/mimic" -t "$text" -o "$outfile" -voice "$mycroftPath""/voices/cmu_us_""$voice"".flitevox"
}
if [ "$service" = "google" ]; then
cache="$cache/google/"
mkdir -p "$cache"
text=${text//\'/\\\'}
languageCode="$lang"-"$country"
googleVoice="$languageCode"-"$voice"
md5string="$text"_"$googleVoice"_"$sampleRate"_"$lang"
hash="$(echo -n "$md5string" | md5sum | sed 's/ .*$//')"
cachefile="$cache""$hash".wav
downloadFile="/tmp/""$hash"
if [[ -f "$cachefile" ]]; then
cp "$cachefile" "$outfile"
else
if [ "$status" != "online" ]; then
if [[ "$useMycroft" = true ]]; then
mycroft
else
picotts
fi
else
if [ "$text" != *"<speak>"* ]; then
text="<speak>""$text""</speak>"
fi
curl -H "Content-Type: application/json; charset=utf-8" \
--data "{
'input':{
'ssml':'$text'
},
'voice':{
'languageCode':'$languageCode',
'name':'$googleVoice',
'ssmlGender':'$gender'
},
'audioConfig':{
'audioEncoding':'MP3',
'sampleRateHertz':'$sampleRate'
}
}" "https://texttospeech.googleapis.com/v1/text:synthesize?key="$googleWavenetAPIKey > "$downloadFile"
sed -i 's/audioContent//' "$downloadFile" && \
tr -d '\n ":{}' < "$downloadFile" > "$downloadFile".tmp && \
base64 "$downloadFile".tmp --decode > "$downloadFile".mp3
mpg123 --quiet --wav "$cachefile" "$downloadFile".mp3
rm "$downloadFile" && \
rm "$downloadFile".tmp && \
rm "$downloadFile".mp3
cp "$cachefile" "$outfile"
fi
fi
elif [ "$service" = "amazon" ]; then
cache="$cache/amazon/"
mkdir -p "$cache"
amazonVoice=$voice
md5string="$text""_""$amazonVoice"_"$sampleRate"_"$lang"
hash="$(echo -n "$md5string" | md5sum | sed 's/ .*$//')"
cachefile="$cache""$hash".mp3
if [ -f "$cachefile" ]; then
mpg123 -q -w $outfile $cachefile
else
if [ "$status" != "online" ]; then
if [[ "$useMycroft" = true ]]; then
mycroft
else
picotts
fi
else
if [ "$text" != *"<speak>"* ];then
text="<speak>""$text""</speak>"
fi
$awscli polly synthesize-speech \
--output-format mp3 \
--voice-id "$voice" \
--sample-rate "$sampleRate" \
--text-type ssml \
--text "$text" \
"$cachefile"
mpg123 -q -w $outfile $cachefile
fi
fi
elif [ "$service" = "picotts" ]; then
picotts
elif [ "$service" = "mycroft" ]; then
mycroft
else
if [[ "$useMycroft" = true ]]; then
mycroft
else
picotts
fi
fi
@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Nov 15, 2018

This contains a connectivity check, and in case of being offline, falls back to cached file if available and if not goes picotts

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Nov 15, 2018

An exemple, for both google or amazon

Edit snips.toml: sudo nano /etc/snips.tom

[snips-tts]
## Choose one tts provider (defaults to picotts)
# provider = "picotts"
# provider = "makerstts"
provider = "customtts"
## customtts specific configuration (here configured to use picotts using the en-US language)
## available placeholder variables : %%OUTPUT_FILE%%, %%LANG%%, %%TEXT%%
customtts = { command = ["/home/pi/ProjectAlice/shell/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "amazon", "%%LANG%%", "US", "Joanna", "FEMALE", "%%TEXT%%", "22050"] }
#customtts = { command = ["/home/pi/ProjectAlice/shell/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "google", "%%LANG%%", "US", "Wavenet-C", "FEMALE", "%%TEXT%%", "44100"] }

Restart snips: sudo systemctl restart snips-*

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Nov 16, 2018

Update to enable ssml on Google, and to remove any ssml tags when using pico

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Nov 16, 2018

Added Mycroft Mimic TTS support with install instructions. Note that the install is really long, but definitly worth it for an offline TTS to replace the dusty picotts

@wizbowes

This comment has been minimized.

Copy link

@wizbowes wizbowes commented Nov 18, 2018

In your second comment - is that format correct:
customtts = { command = ["/home/pi/ProjectAlice/shell/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "amazon", "%%LANG%%", "US", "Joanna", "FEMALE", "%%TEXT%%", "22050"] }

Shouldn't there be no commas? i.e.

customtts = { command = ["/home/pi/ProjectAlice/shell/snipsSuperTTS.sh" "%%OUTPUT_FILE%%" "amazon" "%%LANG%%" "US" "Joanna" "FEMALE" "%%TEXT%%" "22050"] }

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Nov 20, 2018

No, it's an array, so it takes commas

@binarytested

This comment has been minimized.

Copy link

@binarytested binarytested commented Dec 4, 2018

It seems that if $service = "amazon", $status will always be `"offline". Sorry if I'm missing something.

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Dec 29, 2018

By Toxip: https://forum.snips.ai/t/snipssupertts-on-script-to-rule-them-all/747/16?u=psycho

If you’re building Mycroft mimic on a raspberry device and run out of memory while building like I did, you should increase the swap size in /etc/dphys-swapfile. It’s only 100MB by default and easily runs out.

@danito

This comment has been minimized.

Copy link

@danito danito commented Dec 29, 2018

It seems that if $service = "amazon", $status will always be `"offline". Sorry if I'm missing something.

seems that you have to install snips-asr-google even if you want to use amazon, otherwise it stays offline.
Edit : when running from snips-tts, ps ax | grep -v grep | grep snips-asr-google > /dev/null is false, so it stays offline. I have removed the part and it checks if it can get the google page.

if [ $service == 'mycroft' ] || [ $service == 'picotts' ]; then
    status="offline"
else
    echo -e "GET http://google.com HTTP/1.0\n\n" | nc google.com 80 > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        status="online"
    else
       status="offline"
    fi
fi
@gtrhayrug

This comment has been minimized.

Copy link

@gtrhayrug gtrhayrug commented Jan 1, 2019

Hi Psycho, and happy new year.
I want to install mimic before to use your script.
Even if i change swap size on pi3 (to 500 Mb) and reboot i'm sticken on 9 fails item on make check.
On the last installation step (make check) it reports:

> FAIL: unittests/hrg_test
> FAIL: unittests/regex_test
> FAIL: unittests/string_test
> FAIL: unittests/token_test
> FAIL: unittests/voice_select
> FAIL: unittests/wave_test
> FAIL: unittests/lex_test
> FAIL: unittests/lts_test
> FAIL: unittests/nums_test
> ============================================================================
> Testsuite summary for mimic 1.1.0.9000
> ============================================================================
> # TOTAL: 9
> # PASS:  0
> # SKIP:  0
> # XFAIL: 0
> # FAIL:  9
> # XPASS: 0
> # ERROR: 0
> ============================================================================
> See ./test-suite.log
> Please report to https://github.com/MycroftAI/mimic/issues
> ============================================================================
> Makefile:4695 : la recette pour la cible « test-suite.log » a échouée
> make[3]: *** [test-suite.log] Erreur 1
> make[3] : on quitte le répertoire « /home/boss/mimic »
> Makefile:4801 : la recette pour la cible « check-TESTS » a échouée
> make[2]: *** [check-TESTS] Erreur 2
> make[2] : on quitte le répertoire « /home/boss/mimic »
> Makefile:5095 : la recette pour la cible « check-am » a échouée
> make[1]: *** [check-am] Erreur 2
> make[1] : on quitte le répertoire « /home/boss/mimic »
> Makefile:4581 : la recette pour la cible « check-recursive » a échouée
> make: *** [check-recursive] Erreur `1`
> 

If I want to use only mimic (not google or amazon), do i need to change on sh script:
`

useMycroft=false => true `

and i don't understand how i can:

> # - Set "customtts" as snips-tts provider

in the toml file, i need to add:

> customtts: command = ["/home/boss/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "google", "%%LANG%%", "FR", "mycroft", "FEMALE", "%%TEXT%%", "44100"]

Is it correct ?

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Jan 2, 2019

Re the errors, try to reach microft, those errors are explained on their github

About the command, well, if you want to use "microft" why do you specify "google"?

command = ["/home/pi/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "mycroft", "%%LANG%%", "FR", "slt", "FEMALE", "%%TEXT%%", "22050"]

Note that lang and gender params won't do anything if you force mycroft use

@gtrhayrug

This comment has been minimized.

Copy link

@gtrhayrug gtrhayrug commented Jan 2, 2019

Thanks Psycho.

Sorry i made a mistake. I don't modify the toml, i ask you what do i need to do after make the compilation. But, i dont make the modifications in the toml due to 9 errors...

I will keep a look on their github.

@gtrhayrug

This comment has been minimized.

Copy link

@gtrhayrug gtrhayrug commented Jan 2, 2019

Just one question, to avoid a mistake, where do i need to post this request on mimic github ?
https://github.com/MycroftAI

@gtrhayrug

This comment has been minimized.

Copy link

@gtrhayrug gtrhayrug commented Jan 3, 2019

Hurmf, i did again the installation and it is okay. I have 9 pass with green colors, oh yes !
on the sh script:
useMycroft=true
mycroftPath="/home/boss/mimic"

But i have modified my toml like this:

[snips-tts]
provider = "customtts"
customtts = { command = ["/home/boss/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "mycroft", "%%LANG%%", "FR", "slt", "FEMALE", "%%TEXT%%", "22050"] }

After restarting snips service, when i try to say using jeedom+snips plugin some sentences, i heard the original snips voice...
If i comment the two lines, again. If i made a mistake (volontary) in the toml tts i have no sound...

Why i don't heard mycroft voice ?

EDIT : i have installed snips-tts on my satellite. Do i need to make the installation again on the snips server ?
https://i.imgur.com/yWwEMsm.png

@gtrhayrug

This comment has been minimized.

Copy link

@gtrhayrug gtrhayrug commented Jan 7, 2019

Definitively, i don't understand what i'm doing wrong...

I have configured polly AWS (key_id, secret_access_key and default_region="eu-west-3" after done the installation using the command lines provided in the sh script.

I add this line in the snips.toml server (not satellite !)
customtts = { command = ["/home/boss/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "amazon", "%%LANG%%", "FR", "Celine", "FEMALE", "%%TEXT%%", "22050"] }
No voice on my satellite...

https://i.imgur.com/k1t9RgP.png

I have installed google sdk, configuring API, copy the json file in the script directory, auth etc ...

I add this line (comment the previous) again... no voice !
customtts = { command = ["/home/boss/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "google", "%%LANG%%", "FR", "Wavenet-C", "FEMALE", "%%TEXT%%", "44100"] }

I don't understand what i'm doing wrong...

When i'm removing customtts snips voice works again...

@danito

This comment has been minimized.

Copy link

@danito danito commented Jan 7, 2019

Hi,
Can you run snips-tts -vvv and also tail -f /var/log/syslog to check what errors you get when asking for speech. In my case, when using the script with Amazon, it stayed offline, even with google-asr installed. See my comment above where I deleted the part where it checks for online activities.
https://gist.github.com/Psychokiller1888/cf10af3220b5cd6d9c92c709c6af92c2#gistcomment-2760404
You can also add something like

echo $status $service

after line 132 so it shows in the logs. If it is offline, it will switch back to picoTTS. if you have an error, it will fail. I had a permission problem where the user _snips needed to have access to the script.
If you're using Amazon Polly, then you need to change your customtts =

customtts = { command = ["/home/boss/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "amazon", "%%LANG%%", "FR", "Celine", "FEMALE", "%%TEXT%%", "21200"] }
@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Jan 7, 2019

You shouldn't install it on satellites, Snips sends the audio from main to satellites. So uninstall your tts service on the satellites and make sur this is running on the main

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Jan 7, 2019

@danito You are mixing TTS and ASR. What does google-asr to do with this? I'm using the script daily using both amazon and google and the online check works, I don't know what problems you encounter

@gtrhayrug

This comment has been minimized.

Copy link

@gtrhayrug gtrhayrug commented Jan 7, 2019

Thank you !
I have an error on path:


:37:34.263485] DEBUG:rumqtt::connection            : snips-tts|10602-VM-DEB9-SRVSNIPS-1 Received control message Pingresp
[18:37:35.283497] DEBUG:rumqtt::connection            : snips-tts|10602-VM-DEB9-SRVSNIPS-1 Received message on hermes/audioServer/SATPI-SNIPS2/playFinished
[18:37:35.283521] DEBUG:hermes_mqtt                   : Received a message on MQTT topic '"hermes/audioServer/SATPI-SNIPS2/playFinished"', payload: {"id":"48c57fb6-c2db-4981-9b9e-ec42fddfec43","siteId":"SATPI-SNIPS2"}
[18:37:35.283557] WARN :snips_tts_hermes              : Received a "play finished" message from audio server with an unknown id '48c57fb6-c2db-4981-9b9e-ec42fddfec43'. It could be normal if you have more than one audio server.
[18:37:35.615383] DEBUG:rumqtt::connection            : snips-tts|10602-VM-DEB9-SRVSNIPS-1 Received message on hermes/tts/say
[18:37:35.615412] DEBUG:hermes_mqtt                   : Received a message on MQTT topic '"hermes/tts/say"', payload: {"text":"Entre 17.1 \u00b0 et 19.8 \u00b0 au maximum. Pour une moyenne de 18.47 \u00b0","siteId":"SATPI-SNIPS2","lang":"fr"}
[18:37:35.615491] DEBUG:snips_tts_hermes::custom      : Generating wav bytes for 'Entre 17.1 ° et 19.8 ° au maximum. Pour une moyenne de 18.47 °' using custom tts
[18:37:35.615499] DEBUG:snips_tts_hermes::custom      : Running '"/home/boss/snipsSuperTTS/snipsSuperTTS.sh" "/tmp/.tmpkvQIJ4.wav" "mycroft" "fr" "FR" "slt" "FEMALE" "Entre 17.1 \xc2\xb0 et 19.8 \xc2\xb0 au maximum. Pour une moyenne de 18.47 \xc2\xb0" "22050"'
/home/boss/snipsSuperTTS/snipsSuperTTS.sh: ligne 113: ./home/boss/snipsSuperTTS/mimic: Aucun fichier ou dossier de ce type
[18:37:35.622845] DEBUG:snips_tts_hermes              : Sending wav bytes for 'SayMessage { text: "Entre 17.1 ° et 19.8 ° au maximum. Pour une moyenne de 18.47 °", lang: Some("fr"), id: None, site_id: "SATPI-SNIPS2", session_id: None }' to audio server with id 'f621eac3-fee1-4440-96cc-dabfc2cf4bab'
[18:37:35.622873] DEBUG:hermes_mqtt                   : Publishing as binary on MQTT topic 'hermes/audioServer/SATPI-SNIPS2/playBytes/f621eac3-fee1-4440-96cc-dabfc2cf4bab', with size 0
[18:37:35.622907] DEBUG:rumqtt::connection            : Send: Publish(Publish { dup: false, qos: AtMostOnce, retain: false, topic_name: "hermes/audioServer/SATPI-SNIPS2/playBytes/f621eac3-fee1-4440-96cc-dabfc2cf4bab", pid: None, payload: [] })
[18:37:44.630254] DEBUG:rumqtt::state                 : Expecting pingresp

If i try:
mycroftPath="/home/boss/snipsSuperTTS"

i have:
home/boss/snipsSuperTTS/snipsSuperTTS.sh: ligne 113: ./home/boss/snipsSuperTTS/mimic: Aucun fichier ou dossier de ce type

If i try:
mycroftPath="/home/boss/snipsSuperTTS/mimic"

i have the same error but with
[18:39:52.139420] DEBUG:snips_tts_hermes::custom : Running '"/home/boss/snipsSuperTTS/snipsSuperTTS.sh" "/tmp/.tmp71NZri.wav" "mycroft" "fr" "FR" "slt" "FEMALE" "Entre 17.1 \xc2\xb0 et 19.8 \xc2\xb0 au maximum. Pour une moyenne de 18.47 \xc2\xb0" "22050"'
/home/boss/snipsSuperTTS/snipsSuperTTS.sh: ligne 113: ./home/boss/snipsSuperTTS/mimic/mimic: Aucun fichier ou dossier de ce type

but in this case, i heard mimic in english ! not in french...

customtts = { command = ["/home/boss/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "mycroft", "%%LANG%%", "FR", "slt", "FEMALE", "%%TEXT%%", "22050"] }

mimic executable is in /home/boss/snipsSuperTTS/mimic directory so to launch it
https://i.imgur.com/2pJl8ts.png

i've tried /home/boss/snipsSuperTTS/mimic/mimic/mimic (in case of...) lol ! Again... no working.

@BertBlei

This comment has been minimized.

Copy link

@BertBlei BertBlei commented Jan 7, 2019

@danito You are mixing TTS and ASR. What does google-asr to do with this? I'm using the script daily using both amazon and google and the online check works, I don't know what problems you encounter

Hi Psychokiller1888,
@danito is referring to this part of the online-check:
if ps ax | grep -v grep | grep snips-asr-google > /dev/null

You are apparently checking for snips-asr-google to be running, otherwise you set the status to offline... He commented it out (I commented it out, too) and then the check works also without snips-asr-google installed (Actually I just removed the '-google' and check for snips-asr now...)

The other thing he mentioned saved my day. The Snips Platform (snips-tts) needs access rights to the cache folder and apparently it does not have these out of the box since it is not running under the 'pi' account (where the cache folder lives).
I have done a chmod on the cache folder and then Polly worked like a charm!

Thanks for the great work! And thank you @danito, too! Your comment was extremely helpful!

Regards from Berlin!

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Jan 8, 2019

Oh, that's still the old script, I did not update it on the gist, my bad, sorry, fixing it immediately

@danito

This comment has been minimized.

Copy link

@danito danito commented Jan 8, 2019

Hi,
That explains a lot, thanks for the update.
Might it be worth that you also add the customtts command = [...] example for every service this matters (Amazon), a link back to this gist here and/or the forum entry, so that it's self explaining and we can find back a place to ask for help if needed?

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Jan 24, 2019

I hate gist.... Why don't they add notifications?? @github ffs!

Goods ideas, doing it!

@pablobolomey

This comment has been minimized.

Copy link

@pablobolomey pablobolomey commented Jan 25, 2019

hmmm thisn is doing my head in, I have the script working but can not get the google side working, I have no idea what I'm doing wring

@tbearman

This comment has been minimized.

Copy link

@tbearman tbearman commented Feb 19, 2019

Thanks for this great script. I've only tried it with Mycroft for now, but I did have to add the executable in line 125:

from:
."$mycroftPath" -t "$text" -o "$outfile" -voice "$mycroftPath""/voices/cmu_us_""$voice"".flitevox"

to:
."$mycroftPath/mimic" -t "$text" -o "$outfile" -voice "$mycroftPath""/voices/cmu_us_""$voice"".flitevox"

@a1higgins-oss

This comment has been minimized.

Copy link

@a1higgins-oss a1higgins-oss commented May 6, 2019

@Psychokiller1888
You could also add the account free google-translate tts API call to cover all bases. I created the following bash script for my simple needs, but feel free to integrate it in to your super script. Enjoy.

#!/bin/bash

if [ $1 = "-h" ]
then
  echo "Usage: $0 outfile language text"
  exit 0
fi

cache_dir="/var/cache/google-translate-tts"
tmpfile=$(mktemp /tmp/google-translate-tts.XXXXXXXX)
filename_md5=$(echo -n $3 | md5sum)
filename=$cache_dir"/"${filename_md5%% *}".wav"

echo $tmpfile
echo $filename

if [ ! -d $cache_dir ]
then
  echo $cache_dir" does not exist. Please create with needed permissions."
fi

if [ -s $filename ]
then
  echo "Using cached audio file "$filename
else
  echo "Caching new audio file "$filename
  wget -q -U Mozilla -O $tmpfile "http://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&tl=$2&q=$3"
  mpg123 --quiet --wav $filename $tmpfile
  rm -f $tmpfile
fi

cp $filename $1

@hokascha

This comment has been minimized.

Copy link

@hokascha hokascha commented May 20, 2019

The gcloud auth application-default print-access-token call is teribly slow on my Raspi2B+ and is also intended to be used for debugging only. Would you consider switching to OAuth or other possible auth mechanisms?

@hokascha

This comment has been minimized.

Copy link

@hokascha hokascha commented Jun 5, 2019

To speed up Google TTS, just create an API key in Google cloud console and add "?key=XXX" to the Google URL while removing the Authorization-Header. Way faster than generating access tokens at each call.

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Jun 12, 2019

@hokascha Thx! I updated to use the api key!

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Jun 12, 2019

@a1higgins-oss

Thank you also! Will add it. I have a few others coming also, such as IBM

@adelapole

This comment has been minimized.

Copy link

@adelapole adelapole commented Jun 22, 2019

How would you go about changing Google TTS mp3 to LINEAR16?

'audioEncoding':'mp3', to 'audioEncoding':'LINEAR16',

When I do this the cache file is created but playback is a short 'glitch/chirp' sound.

Google TTS API states that a .wav header is included when requesting LINEAR16.

}" "https://texttospeech.googleapis.com/v1/text:synthesize?key="$googleWavenetAPIKey > "$downloadFile"

            sed -i 's/audioContent//' "$downloadFile" && \
            tr -d '\n ":{}' < "$downloadFile" > "$downloadFile".tmp && \
            base64 "$downloadFile".tmp --decode > "$downloadFile".wav
@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Jun 22, 2019

Is the audio file ok somewhat? I mean, if you open it with audacity per exemple, and change the rates and all, is it a normal sound file?

@adelapole

This comment has been minimized.

Copy link

@adelapole adelapole commented Jun 22, 2019

Is the audio file ok somewhat? I mean, if you open it with audacity per exemple, and change the rates and all, is it a normal sound file?

@Psychokiller1888 Thanks for the reply.
My mistake: I was passing the decoded output through mpg123.
mpg123 --quiet --wav "$cachefile" "$downloadFile".wav

This worked for me for LINEAR16 with aplay.

'audioConfig':{
                'audioEncoding':'LINEAR16',
                'sampleRateHertz':'$sampleRate',
                'effectsProfileId': ['large-home-entertainment-class-device']
              }
            }" "https://texttospeech.googleapis.com/v1/text:synthesize?key="$googleWavenetAPIKey > "$downloadFile"

            sed -i 's/audioContent//' "$downloadFile" && \
            tr -d '\n ":{}' < "$downloadFile" > "$downloadFile".tmp && \
            base64 "$downloadFile".tmp --decode > "$downloadFile"

            aplay "$downloadFile".wav

            cp "$downloadFile" "$cachefile"

            rm "$downloadFile" && \
            rm "$downloadFile".tmp && \
            rm "$downloadFile".wav
            cp "$cachefile" "$outfile"
@Sohn123

This comment has been minimized.

Copy link

@Sohn123 Sohn123 commented Aug 11, 2019

Hey I try to setup snips super tts with Google. And it works if I execute the script from the command line with Google but not if I set it up via /etc/snips.toml. With Mycroft it works perfectly. And I don't have any clue what to do to get it work. Any suggestions?

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Aug 12, 2019

did you edit the script to put your credentials? Check /var/log/syslog for errors returned also

@Sohn123

This comment has been minimized.

Copy link

@Sohn123 Sohn123 commented Aug 12, 2019

Yes I edited it and put my credentials in the scripts. And if I execute the script from the command line it works with Google so the API key is correct. But if I try to call the script from snips it doesn't work with Google but it works with Mycroft so the path and everything should be also correct.

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Aug 12, 2019

So it's most prolly a premission issue. Check your syslog to see if it fails accessing the cache directory

@Sohn123

This comment has been minimized.

Copy link

@Sohn123 Sohn123 commented Aug 12, 2019

I thought I already changed the owner of the cache directory but it seems like I forgot about that... Now it works perfectly! Thanks for the fast help

@LazzaAU

This comment has been minimized.

Copy link

@LazzaAU LazzaAU commented Aug 15, 2019

hi psycho, the first time i installed this a few weeks ago everything worked fine. Now that i've started with a fresh copy of stretch and snips ive tried setting this up again but have the following error when trying to install mimic

pi@snips:~ $ cd mimic
pi@snips:~/mimic $ ./dependencies.sh --prefix="/usr/local"
/usr/bin/pkg-config
Have PCRE2? [no]
--2019-08-16 00:39:41-- ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre2-10.23.zip
=> ‘pcre2-10.23.zip’
Resolving ftp.csx.cam.ac.uk (ftp.csx.cam.ac.uk)... 131.111.8.115
Connecting to ftp.csx.cam.ac.uk (ftp.csx.cam.ac.uk)|131.111.8.115|:21... failed: Connection timed out.
Retrying.

--2019-08-16 00:41:58-- ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre2-10.23.zip
(try: 2) => ‘pcre2-10.23.zip’
Connecting to ftp.csx.cam.ac.uk (ftp.csx.cam.ac.uk)|131.111.8.115|:21... failed: Connection timed out.
Retrying.

been that way for three days now. i also cant ping ftp.csx.cam.ac.uk so assuming the site is down ??
is there a alternative for this part of the install process ?

cheers

@LazzaAU

This comment has been minimized.

Copy link

@LazzaAU LazzaAU commented Aug 16, 2019

FYI.
i edited the wget line in dependencies.sh file to be
wget "https://ftp.pcre.org/pub/pcre/pcre2-10.23.zip"

and that seemed to be a good alternative so far.

PCRE2 installation succeeded

@DanBmh

This comment has been minimized.

Copy link

@DanBmh DanBmh commented Sep 3, 2019

@Psychokiller1888
I created a fork of your skript with some additional functionalities (mainly more wavenet params and translate-tts). Feel free to copy code back to your gist.

@HorizonKane

This comment has been minimized.

Copy link

@HorizonKane HorizonKane commented Sep 27, 2019

Hi,

I have problems to get this running. I installed the AWS cli bundle successfully.

I added this to snips.toml after uncommenting customtts provider:

customtts = { command = ["/home/pi/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "amazon", "%%LANG%%", "DE", "Vicky", "--", "%%TEXT%%", "22050"] }

I created an additional IAM account in AWS, giving it the Polly access profile. The keys I got there I put here:

export AWS_ACCESS_KEY_ID="myID"
export AWS_SECRET_ACCESS_KEY="mykey"
export AWS_DEFAULT_REGION="eu-central-1"
awscli='/usr/local/bin/aws'

When I now give a command to Snips, everything works fine but I hear no voice and sam watch says:

[11:20:28] [AudioServer] was asked to play a wav of 0.0 kB with id 'a5365dfa-27d1-4a91-b383-506beb1c4482' on site default

Of course there is no voice when it is asked to play 0kb ... the question is how I find out why the file did not get created?

@HorizonKane

This comment has been minimized.

Copy link

@HorizonKane HorizonKane commented Sep 27, 2019

I connected to the AWS console and can see that the key was used today...so it must have connected to AWS successfully.

I also ran aws configure and used polly through aws cli which created me a mp3 successfully. But with Snips still no success.

@HorizonKane

This comment has been minimized.

Copy link

@HorizonKane HorizonKane commented Sep 27, 2019

Okay, I found the problem in the syslog. The girls name is Vicki, not Vicky. She doesn't like being called Vicky... :)

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Sep 27, 2019

I think it more a permission problem. You can check the syslog when it tries to answer tail -f /var/log/syslog

@HorizonKane

This comment has been minimized.

Copy link

@HorizonKane HorizonKane commented Sep 27, 2019

Yeah that way I found it I spelled the name of the voice girl wrong. Now it's working :)

Installed mimic first, then realised it can't speak german :/

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Sep 27, 2019

Yeah, it's sad mimic only speaks english

@HorizonKane

This comment has been minimized.

Copy link

@HorizonKane HorizonKane commented Sep 27, 2019

Anyways, thanks for your work! Polly is quite nice. However a local solution that speaks german would be great.

@Andergraw

This comment has been minimized.

Copy link

@Andergraw Andergraw commented Dec 3, 2019

Hi @Psychokiller1888,
thanks for the script, it's been very useful. I have it working with Polly.
But now, I would like to test Mycroft's Mimic as default offline service (instead of pico).
When I follow your instructions (the same as Mycroft's) I get an error. I asked them directly, but do you have any clue what is this related to?
Thanks!
MycroftAI/mimic1#186

@Pittermaennchen

This comment has been minimized.

Copy link

@Pittermaennchen Pittermaennchen commented Mar 1, 2020

Hi @Psychokiller1888,
thank you very much for that awesome script!

Unfortunately, I can`t get it running.

Here is what I did so far:
I installed mpg123 on my Raspberry Pi.
I edited the snips.toml file in /etc/: I uncommented the "provider: customtts" line and the "customtts = { command ..."-line with the command for Google's Wavenet TTS.
I copied the snipsSuperTTS.sh file to /home/pi
In the google console (after I was forced to enter my credit card number -.- ) I activated "Cloud Text-to-Speech API" and then I created an API-Key
Then I edited the snipsSuperTTS file: uncommented the line "googleWavenetAPIKey="MY API-KEY CONSISTING OF A LOT OF LETTERS AND NUMBERS"" and entered the API key I created in the console.cloud.google.
As advised in the Google Paragraph in snipsSuperTTS.sh-file, I installed Google SDK on my RaspberryPi, following the Linux-instructions here in Point 6 (https://cloud.google.com/text-to-speech/docs/quickstart-protocol)
Then, I tried to run the snipsSuperTTS.sh-file trying the command "sh snipsSuperTTS.sh" resulting in the error: "snipsSuperTTS.sh: 104: snipsSuperTTS.sh: Syntax error: "(" unexpected"
I don´t know how to solve this. The cache path "/home/pi/snipsSuperTTS/cache" was not created

Any clues are very welcome. Thank you very much!

@Psychokiller1888

This comment has been minimized.

Copy link
Owner Author

@Psychokiller1888 Psychokiller1888 commented Mar 1, 2020

Hi! As the error states, there's a syntax error on line 104 of you shell script

@Pittermaennchen

This comment has been minimized.

Copy link

@Pittermaennchen Pittermaennchen commented Mar 1, 2020

Thank you for the quick reply!

I thought so, but I did not change anything in that line.

Lines 104-107 are:
"function mycroft() {
text=$(sed 's/<[^>]*>//g' <<< "$text")
."$mycroftPath/mimic" -t "$text" -o "$outfile" -voice "$mycroftPath""/voices/cmu_us_""$voice"".flitevox"
}"

@hokascha

This comment has been minimized.

Copy link

@hokascha hokascha commented Mar 1, 2020

@Pittermaennchen check the lines before 103. Might have lost a } ?

@Pittermaennchen

This comment has been minimized.

Copy link

@Pittermaennchen Pittermaennchen commented Mar 1, 2020

@Pittermaennchen check the lines before 103. Might have lost a } ?

hm. I can't find the source of the error. :(

The lines before are:

outfile="$1"
service="$2"
lang="$3"
country="$4"
voice="$5"
gender="$6"
text="$7"
sampleRate="$8"

if [ "$service" = "mycroft" ] || [ "$service" = "picotts" ]; then
status="offline"
else
echo -e "GET http://google.com HTTP/1.0\n\n" | nc google.com 80 > /dev/null 2>&1
if [ $? -eq 0 ]; then
status="online"
else
status="offline"
fi
# Alternative for some people having problem pinging google.com. Comment the above and uncomment the following
#wget -q --tries=1 --timeout=1 --spider http://google.com
#if [[ $? -eq 0 ]]; then
# status="online"
#else
# status="offline"
#fi
fi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.