Skip to content

Instantly share code, notes, and snippets.

@DanBmh
Forked from Psychokiller1888/snipsSuperTTS.sh
Last active April 4, 2020 21:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save DanBmh/1cf91324f1eb1ddf109937fc3bd6b577 to your computer and use it in GitHub Desktop.
Save DanBmh/1cf91324f1eb1ddf109937fc3bd6b577 to your computer and use it in GitHub Desktop.
One TTS to rule them all
#! /usr/bin/env bash
# By Psycho and Others
# 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
# This script: https://gist.github.com/DanBmh/1cf91324f1eb1ddf109937fc3bd6b577
####### 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 their owner to "_snips" => sudo chown -R _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", "1.0", "0.0"]
# - Restart snips: sudo systemctl restart snips-*
# 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
# 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
# Debugging:
# Run script by hand and look for audio files:
# . /home/pi/snipsSuperTTS/snipsSuperTTS.sh "test123.wav" "google" "en" "US" "Wavenet-C" "--" "Hello, i am speaking to you" "22050" "1.0" "0.0"
# Check output of snips-tts service:
# sudo systemctl stop snips-tts.service; snips-tts -vvv
# Start tts service again: sudo systemctl start snips-tts.service
# Check syslog: tail -f /var/log/syslog
# Check content of cache files and temporary files
####### MycroftAI - Mimic ##############################################################################################
# https://github.com/MycroftAI/mimic
# This one is pretty long to install, but hey, the quality compared to pico is worth it!
# 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.
# Example: command = ["/home/pi/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "mycroft", "%%LANG%%", "--", "slt_hts", "--", "%%TEXT%%", "22050", "--", "--"]
# 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
#------------------------------------
# Set the following option to True to use Mycroft instead of pico. Don't forget to set the path too
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 create a txt file with your api key and set the path accordingly:
#googleWavenetAPIKey=$(</home/pi/snipsSuperTTS/google_api_key.txt)
#------------------------------------
# Example: command = ["/home/pi/snipsSuperTTS/snipsSuperTTS.sh", "%%OUTPUT_FILE%%", "google", "%%LANG%%", "US", "Wavenet-C", "--", "%%TEXT%%", "22050", "1.0", "0.0"]
####### 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'
#------------------------------------
# Example: 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"
speed="$9"
pitch="${10}"
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"
}
function offline_voice(){
if [[ "$useMycroft" = true ]]; then
mycroft
else
picotts
fi
}
# ======================================================================================================================
if [ "$service" = "google" ]; then
cache="$cache""/google/"
mkdir -p "$cache"
text=${text//\'/\\\'}
languageCode="$lang"-"$country"
googleVoice="$languageCode"-"$voice"
md5string="$text"_"$googleVoice"_"$sampleRate"_"$lang"_"$speed"_"$pitch"
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
offline_voice
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'
},
'audioConfig':{
'audioEncoding':'MP3',
'sampleRateHertz':'$sampleRate',
'speakingRate':'$speed',
'pitch':'$pitch'
}
}" \
"https://texttospeech.googleapis.com/v1/text:synthesize?key="$googleWavenetAPIKey > "$downloadFile"
sed 's/audioContent//' "$downloadFile" > "$downloadFile".tmp
cat "$downloadFile".tmp | tr -d '\n ":{}' > "$downloadFile".tmp2
base64 "$downloadFile".tmp2 --decode >"$downloadFile".mp3
mpg123 --quiet --wav "$cachefile" "$downloadFile".mp3
rm "$downloadFile" &&
rm "$downloadFile".tmp &&
rm "$downloadFile".tmp2 &&
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
offline_voice
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" = "google_translate" ]; then
cache="$cache""/google_translate/"
mkdir -p "$cache"
md5string="$text"_"$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
offline_voice
else
wget -q -U Mozilla -O "$downloadFile" "http://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&tl=$lang&q=$text"
mpg123 --quiet --wav "$cachefile" "$downloadFile"
rm "$downloadFile"
cp "$cachefile" "$outfile"
fi
fi
elif [ "$service" = "picotts" ]; then
picotts
elif [ "$service" = "mycroft" ]; then
mycroft
else
offline_voice
fi
@DanBmh
Copy link
Author

DanBmh commented Sep 3, 2019

Added speed and pitch parameters for google wavenet.
Added account free google translate tts, as suggested by @a1higgins-oss.
Did some formatting for better readability.
Added some comments and moved google api key to extra file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment