Text to Speech on a Raspberry Pi using Google Translate

For a couple of upcoming projects, I’ve been trying to find a way of making a Raspberry Pi take an input of a piece of text and vocalise it through a pair of connected speakers (so-called Speech Synthesis). There are a number of methods listed on the eLinux wiki page on the subject, however I found the suggested available packages produced rather robotic sounding results, and I was after something a bit more natural and pleasant sounding, rather than something to scare the bejeezus out of me every time it speaks. The most natural sounding offering is a hidden and unofficial API provided through the Google Translate service, which produces some very nice sounding audio, and is very accurate most of the time. Unfortunately, it’s limited to 100 characters at a time, which starts to be a problem when you want to read out large swathes of text.

There are a few scripts that I found (including this one from Dan Fountain) that offer an interface to this API, however the majority of them just split the input at the 100 character mark (or by the previous space to it), which leads to broken sounding sentences in some cases, where the pre-existing punctuation could be used. In order to get something slightly more natural sounding, I set about bodging together some Python, and came up with the following:

Please note: this script no longer works! Google made some changes to their TTS engine during July 2015 which meant this script would no longer work, as the translate_tts request would be redirected to a CAPTCHA page. There is an updated version of the script available in my SVN repository, and now at Github as well

#!/usr/bin/python

# googletts
# Created by Matt Dyson (mattdyson.org)
# http://mattdyson.org/blog/2014/07/text-to-speech-on-a-raspberry-pi-using-google-translate/
# Some inspiration taken from http://danfountain.com/2013/03/raspberry-pi-text-to-speech/

# Version 1.0 (12/07/14)

# Process some text input from our arguments, and then pass them to the Google translate engine
# for Text-To-Speech translation in nicely formatted chunks (the API cannot handle more than 100
# characters at a time).
# Splitting is done first by any punctuation (.,;:) and then by splitting by the MAX_LEN defined
# below.
# mpg123 is required for playing the resultant MP3 file that is returned by Google TTS

from subprocess import call
import sys
import re

MAX_LEN = 100 # Maximum length of a segment to send to Google for TTS
LANGUAGE = "en" # Language to use with TTS - this won't do any translation, just the voice it's spoken with

fullMsg = ""
i = 1

# Read our system arguments and add them into a single string
while i<len(sys.argv):
   fullMsg += sys.argv[i] + " "
   i+=1

# Split our full text by any available punctuation
parts = re.split("[\.\,\;\:]", fullMsg)

# The final list of parts to send to Google TTS
processedParts = []

while len(parts)>0: # While we have parts to process
   part = parts.pop(0) # Get first entry from our list

   if len(part)>MAX_LEN:
      # We need to do some cutting
      cutAt = part.rfind(" ",0,MAX_LEN) # Find the last space within the bounds of our MAX_LEN

      cut = part[:cutAt]

      # We need to process the remainder of this part next
      # Reverse our queue, add our remainder to the end, then reverse again
      parts.reverse()
      parts.append(part[cutAt:])
      parts.reverse()
   else:
      # No cutting needed
      cut = part

   cut = cut.strip() # Strip any whitespace
   if cut is not "": # Make sure there's something left to read
      # Add into our final list
      processedParts.append(cut.strip())

for part in processedParts:
   # Use mpg123 to play the resultant MP3 file from Google TTS
   call(["mpg123","-q","http://translate.google.com/translate_tts?tl=%s&q=%s" % (LANGUAGE,part)])

This can also be downloaded from my projects repository at http://projects.mattdyson.org/projects/speech/googletts, where updated versions may be available. The package mpg123 is required to play the resulting MP3 file that Google Translate returns. The easiest way to get this script installed will be with the following (run as root on your Raspberry Pi):

$ apt-get install mpg123
$ cd /usr/bin/
$ svn co http://projects.mattdyson.org/projects/speech speech
$ chmod +x speech/googletts
$ ln -s speech/googletts
$ googletts "Hello world, the installation of the text to speech script is now complete"

Unfortunately, if a clause of a sentence is longer than 100 characters there will still be an unwanted pause in the middle, as the script does not know where best to split the text, and if you’re using a lot of punctuation you might find the text takes a long time to read back. I’d be welcome to incorporate any improvements people may suggest!

18 thoughts on “Text to Speech on a Raspberry Pi using Google Translate

  1. Brilliant! Any idea how I can make this script work with special characters? Running “http://translate.google.com/translate_tts?tl=sv&q=Smörgåsbord” in the browser works like a charm. But through the script the swedish characters “åäö” doesn’t work.

    • I have absolutely no idea how to get character accents/special characters working in bash/python unfortunately! I’d suggest some Googling, please post back if you find an answer!

    • In order to have correctly pronounced special characters you’ll need to include “&ie=UTF-8” in the query string.
      @Matt: Thanks for the script!

  2. Hi Matt,
    I’m having a very strange issue with the script. The ONLY thing message that works (as in, returns an audio file) is if I type a single NAME. It’s quite strange. Nothing else seems to work. If I put any other words in the message I get a “400 Bad Request” error. Thoughts?

    Cheers,

    Dean

    • Hi Dean,
      Unfortunately I have no idea what could be causing that, could you include the full command you’re using that fails, and the complete error output?

      • I’m using the exact script above, but I’m inserting my desired message into the fullMsg = “” portion of the script. Perhaps I’m going about this all wrong? Is the script supposed to speak any input from the terminal? At the moment I’m just running the command:

        python translate.py (which contains the above script with my added message)

        The error message I get when I put anything other that someone’s name is:

        http_open: HTTP/1.0 400 Bad Request
        http://translate.google.com: No such file or directory

        But if I put the a name, let’s say “Dean” into the script, it doesn’t return an error and just says “Dean”
        Sorry if I’ve got it all wrong. I’m pretty new to Python as it is.
        Thanks again!!

      • The script is designed to read the text provided by the command-line arguments, however adding the message into the fullMsg = "" line should also work. It looks like your Pi isn’t able to access the internet for some reason, which is why the request to http://translate.google.com is failing. I don’t know why this works intermittently when you use a single word though!

        • Gahhh! This is so frustrating haha. I can get it to say a single word (not just a name now) in both the command line and by inserting the message in the script as you suggested.

  3. Pingback: How do I use a printed text output from one script as the command line argument for another? | 我爱源码网

  4. When I type in ln -s speech/googletts, I get the response: ln: failed to create symbolic link ‘./googletts’: File exists.

    What does this mean, and how can I fix it?

    • Hi Stephen,
      Make sure you’re running that command inside the /usr/bin/ directory, if you’re inside /usr/bin/speech/ when you run it then you’ll get that error.

  5. Hi there, any solutions for Deans Issue yet? I am having the same problem, one word works, more than that returns a “http://translate.google.com: No such file or directory” error.

    Is it necessary to have the script run in a certain location? Because I didn´t put it into etc..

    Thanks a lot

    • I have no idea what’s causing that unfortunately! Might be worth changing the last few lines and print-ing the query string that is produced, and seeing if something is wrong with what’s being generated. Maybe the part variable needs URL encoding first?

      • I had the same issue, solved by URL encoding on the part variable. I just changed the end of the script (don’t forget to import urllib) :

        encodedQuery = urllib.urlencode({'q': part})
        call(["mpg123","-q","http://translate.google.com/translate_tts?tl=%s&%s&ie=%s&total=1&idx=0&client=t" % (LANGUAGE,encodedQuery,ENCODING)])

  6. Hi,

    thanks for the fix. I use google*s t2s in my “RaspRadio”: When you press a button, google’s voice tells you which station you are just listening to. (RaspRadio is an oldfashioned radio receiver which does not have a display that simply shows you the station name .. ….)

  7. Hi,

    I have a problem. Your script has worked very good during 2 days but now Google detected my computer as “unusual traffic”.

    If I visit “http://translate.google.com/translate_tts?tl=fr&q=test&ie=UTF-8&total=1&idx=0&client=t” , I have the following message:
    Our systems have detected unusual traffic from your computer network. Please try your request again later. Why did this happen?
    IP address: 217.xx.xx.69
    Time: 2015-12-01T08:50:20Z
    URL: http://www.google.com/

    Do you have a solution?
    Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *