-
-
Save Osmiogrzesznik/4636fa4ae59d26079c47604561509565 to your computer and use it in GitHub Desktop.
One TTS to rule them all
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment