Last active
June 7, 2023 11:21
-
-
Save Psychokiller1888/cf10af3220b5cd6d9c92c709c6af92c2 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 | |
# 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 |
@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
@Pittermaennchen check the lines before 103. Might have lost a } ?