En este post describiré cómo instalar pyttsx3 con espeak y pondré unos programas ejemplo, donde el primero es un ejemplo del uso básico, y el segundo es una pequeña aplicación que dice la hora o alguna frace pequeña cada vez que se presiona un botón.
pytssx3 es una librería de interfase entre python 3 y los motores de texto a voz tales como SAPI5 (windows), espeak (Linux o windows) y NSSS (Mac). Ahunque existen otras librerías de conversión de texto a voz como gTTS (Google Text to Speech) con la cual se obtiene una voz mucho más realista, solo se pueden realizar 50 sintetizaciones de voz por día (no good) y requiere de una conexión permanente a internet (no good). Otra diferencia es que gTTS solo puede generar archivos de sonido que uno debe reproducir para escuchar, mientras que en pytssx3 se puede generar la señal audible (hacer hablar) y opcionalmente guardar como archivo de sonido.
Se recomienda usar la versión de python mas reciente. A continuación pondré los pasos a seguir para instalar lo necesario.
1. Instalar espeak.
En FEDORA, correr como root (super usuario) el siguiente comando en una terminal:
dnf install espeak
con esto se instalan espeak y todas las voces con sus variantes de las voces disponibles.
En UBUNTU o RASPBIAN (Raspberry pi 3) correr como root (super usuario) el siguiente comando en una terminal:
sudo apt install espeak
con esto se instalan espeak y todas las voces con sus variantes de las voces disponibles..
En Windows se debe instalar con el archivo ejecutable, lo puede descargar de la siguiente dirección:
http://espeak.sourceforge.net/download.html
En el instalador se requiere especificar que voces se quieren instalar. Por ejemplo si quiero instalar el idioma español latino agrego
spanish-latin-am. Además existen varios modificadores de voz, como por ejemplo
+f5 (variante femenia de en este idioma
). Si quisiera instalar una la voz con esa variante, podría poner
spanish-latin-am+f5 en el instalador, como se muestra en la imagen de abajo.
Tambien esta el español de españa que es
spanish. Los modificadores aplicables a cualquier voz son los siguientes:
corak, f1, f2, f3, f4, f5, m1, m2, m3, m4, m6, m7, whisper, whisperf, klatt, klatt2, klatt3, klatt4.
 |
Ejemplo: instalasr español latino con modificador +f5 y español latino normal |
Si quieres instalar todas las voces en español con todas las variantes, copia y pega esto:
spanish-latin-am+corak spanish-latin-am+whisper spanish-latin-am+whisperf spanish-latin-am+f1 spanish-latin-am+f2 spanish-latin-am+f3 spanish-latin-am+f4 spanish-latin-am+f5 spanish-latin-am+m1 spanish-latin-am+m2 spanish-latin-am+m3 spanish-latin-am+m4 spanish-latin-am+m5 spanish-latin-am+m6 spanish-latin-am+m7 spanish-latin-am+klatt spanish-latin-am+klatt2 spanish-latin-am+klatt3 panish-latin-am+klatt4 spanish+corak spanish+whisper spanish+whisperf spanish+f1 spanish+f2 spanish+f3 spanish+f4 spanish+f5 spanish+m1 spanish+m2 spanish+m3 spanish+m4 spanish+m5 spanish+m6 spanish+m7 spanish+klatt spanish+klatt2 spanish+klatt3 spanish+klatt4
2.- Instalar librerías de Python 3:
En FEDORA o UBUNTU o RASPBIAN o Windows poner en una terminal o linea de comandos:
pip3 install pyttsx3
Posiblemente nesecites correrlo como root (super usuario).
En WINDOWS podrías necesitar instalar también pypiwin32 si arroja un error al importar la librería en python, pero es mejor ir a lo seguro e instalarla desde el inicio.
pip3 install pypiwin32
EJEMPLO 1 (Uso básico):
En el programa que se muestra más abajo, se ejemplifica el uso de pyttsx3. En este ejemplo se inicia por averiguar cuáes voces que están disponibles. Por ejemplo: en linux la voz en español latino es "spanish-latin-am", en windows es algo parecido a "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\eSpeak_2" (es posible que tengas que cambiarlo en el programa de abajo, debido a que el nombre depende de cuantos idiomas y variantes hayas instalado). Después se elige la voz en español, en seguida se ajusta la velocidad y volumen de la voz elegida y por último pronuncia la célebre frase "Hola mundo".
#!/usr/bin/env python3
#-*- coding: utf-8 -*-
#------------------------------------------------------
# Desarrollado por Carlos Alberto Rodriguez Martinez
# http://mecatroncharly.blogspot.com/p/blog-page.html
#
# Este es un programa que dice "Hola mundo" con voz audible
#------------------------------------------------------
from platform import system
import pyttsx3
ThisOS = system() # averiguar Sistema operativo actual
engine = pyttsx3.init() # inicializar motor de voz
#---------------------------------------
# Encoontrar voces isponibles
#---------------------------------------
voices = engine.getProperty('voices')
male_language_count = 0
female_language_count = 0
none_language_count = 0
for voice in voices:
print("------------------------")
print(" - ID: %s" % voice.id)
print(" - Nombre: %s" % voice.name)
print(" - Lenguajes: %s" % voice.languages)
print(" - Genero: %s" % voice.gender)
print(" - Edad: %s" % voice.age)
if voice.gender == 'male':
male_language_count += 1
if voice.gender == 'female':
female_language_count +=1
if voice.gender == 'none':
none_language_count += 1
print ('Voces Masculinas : %d' % male_language_count)
print ('Voces femeninas : %d' % female_language_count)
print ('Voces neutras : %d' % none_language_count)
#--------------------------------------
# CONFIGURAR VOZ E IDIOMA
#--------------------------------------
if ThisOS == 'Linux':
engine.setProperty('voice', 'spanish-latin-am+f5') #ASIGNAR Español latino
# agregar +f5 para simular voz femenina (1-5)
if ThisOS == 'Windows':
engine.setProperty('voice','HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\eSpeak_4')
engine.setProperty('rate' ,140) # Aumentar velocidad 40%
engine.setProperty('volume',1.0) # Poner el volumen al 100%: Minimo:0, Maximo: 1
#--------------------------------------
# HABLAR
#--------------------------------------
engine.say("Hola mundo!") # Hablar
engine.runAndWait() # Esperar a que terine de Hablar
engine.stop() # Detener motor tts
EJEMPLO 2
Este programa es un poco mas complicado pero mas cool, la aplicación dice la hora actual o dice cualquier otra cosa que se le indique. Se utiliza una cola FIFO (librería "
queue") donde se ponen en cola las fraces (que podría ser la hora o la frase que se indique) cada vez que se presiona el botón correspondiente. La librería "
threading" se utiliza para crear un hilo separado del hilo principal. Este hilo se encarga de revisar constantemente si hay fraces en cola, si es asi, llama a la funcion que dice las fraces que haya en cola, dependiendo del numero de veces que se haya presionado el botón. El programa también tiene su control de velocidad, de volumen y selección de voces en español.
 |
Interfase gráfica en windows. |
La interfase en Linux cambia un poco debido a que se pueden combinar los mods con las voces.
 |
Interfase gráfica en Linux. |
Para correr este ejemplo nesesitas tener instaladas las librerías: "wxpython" y "queue". Este programa fué probado en windows 7 y Linux (Fedora 30) con python 3.6 y 3.7.
Te dejo comentarios en el código fuente para ayudatre a entender que es lo que sucede.
#!/usr/bin/env python3
#-*- coding: utf-8 -*-
#------------------------------------------------------
# Desarrollado por Carlos Alberto rodriguez Martinez
# http://mecatroncharly.blogspot.com/p/blog-page.html
#
# Este es un programa que dice la hora con voz audible
#------------------------------------------------------
import wx
import pyttsx3
from platform import system
from datetime import datetime
from queue import Queue
from time import sleep
from threading import Thread
class SayTimeApp(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None,-1,"Di la hora")
self.ThisOS = system() # averiguar Sistema operativo actual.
self.createGUI() # Crear los elementos de la GUI
self.Lista = Queue() # Una cola FIFO para que no se traslapen las funciones
self.thread = Thread(target = self.WrkrThred) # poner funcion WrkrThred en un hilo
self.thread.daemon = True # Poner hilo en modo daemon, si el programa termina, tambien el hilo
self.thread.start() # Iniciar hilo
self.VoiceNames = [] # Para guardar los nombres de las voces
self.voicesIDs = [] # para guardar los IDs de las voces (winndows)
self.getVoiceList() # Averiguar voces disponibles y llenar combobox
def createGUI(self):
MainPanel = wx.Panel(self) # contenedor de Frames
#es util para separar el frame principal de las barras de herramientas y
#la barra de estado
BtnDiHora = wx.Button(MainPanel,
label = "Decir la hora",
pos = (125, 10),
size = (300, 50))
#----------------------------------------------------------------
BtnDiTexto = wx.Button(MainPanel,
label = "Decir esto",
pos = wx.DefaultPosition,
size = wx.DefaultSize)
self.TxTDecir = wx.TextCtrl(MainPanel,
wx.ID_ANY,
wx.EmptyString,
wx.DefaultPosition,
wx.DefaultSize,
0)
DecirAlgoSizr = wx.BoxSizer(wx.HORIZONTAL)
DecirAlgoSizr.Add(BtnDiTexto, 0, wx.ALL, 5)
DecirAlgoSizr.Add(self.TxTDecir, 1, wx.ALL|wx.CENTER|wx.EXPAND, 5)
#----------------------------------------------------------------
self.ComboVoices = wx.ComboBox(MainPanel,
choices = [],
style = wx.CB_READONLY|wx.ALIGN_CENTER)
StticBoxVoices = wx.StaticBox(MainPanel, -1, 'Voz')
StticBVoicsSizr = wx.StaticBoxSizer(StticBoxVoices, wx.VERTICAL)
StticBVoicsSizr.Add(self.ComboVoices, 0, wx.ALL|wx.CENTER|wx.EXPAND, 5)
#----------------------------------------------------------------
self.SpeedSlider = wx.Slider(MainPanel,
value = 140,
minValue = 50,
maxValue = 300,
style = wx.SL_HORIZONTAL|wx.SL_LABELS)
StticBoxSpeed = wx.StaticBox(MainPanel, -1, '% Velocidad')
StticBxSpeedSizr = wx.StaticBoxSizer(StticBoxSpeed, wx.VERTICAL)
StticBxSpeedSizr.Add(self.SpeedSlider, 0, wx.ALL|wx.CENTER|wx.EXPAND, 5)
#----------------------------------------------------------------
self.VolumSlider = wx.Slider(MainPanel,
value = 100,
minValue = 0,
maxValue = 100,
style = wx.SL_HORIZONTAL|wx.SL_LABELS)
StticBoxVolume = wx.StaticBox(MainPanel, -1, '% Volumen')
StticBxVolumeSizr = wx.StaticBoxSizer(StticBoxVolume, wx.VERTICAL)
StticBxVolumeSizr.Add(self.VolumSlider, 0, wx.ALL|wx.CENTER|wx.EXPAND, 5)
#----------------------------------------------------------------
if self.ThisOS == 'Linux': #en linux
mods = ['f5','f4','f3','f2','f1','klatt4','klatt3','klatt2','klatt',
'm7','m6','m5','m4','m3','m2','m1','whisper','whispef','croak',]
self.ComboMods = wx.ComboBox(MainPanel,
choices = mods,
style = wx.CB_READONLY|wx.ALIGN_CENTER)
StticBoxMods = wx.StaticBox(MainPanel, -1, 'Mods')
StticBoxModsSizr = wx.StaticBoxSizer(StticBoxMods, wx.VERTICAL)
StticBoxModsSizr.Add(self.ComboMods, 0, wx.ALL|wx.CENTER|wx.EXPAND, 5)
#------------------------------------------------------------
# BINDS
#------------------------------------------------------------
BtnDiHora .Bind(wx.EVT_BUTTON, self.DiHora)
BtnDiTexto.Bind(wx.EVT_BUTTON, self.DiTexto)
#------------------------------------------------------------
# Main layout
#------------------------------------------------------------
MainSizer = wx.BoxSizer(wx.VERTICAL)
MainSizer.Add(BtnDiHora, 0, wx.ALL|wx.CENTER|wx.EXPAND, 5)
MainSizer.Add(DecirAlgoSizr, 0, wx.ALL|wx.CENTER|wx.EXPAND, 5)
MainSizer.Add(StticBVoicsSizr, 0, wx.ALL|wx.CENTER|wx.EXPAND, 5)
if self.ThisOS == 'Linux': #en linux
MainSizer.Add(StticBoxModsSizr, 0, wx.ALL|wx.CENTER|wx.EXPAND, 5)
MainSizer.Add(StticBxSpeedSizr, 0, wx.ALL|wx.CENTER|wx.EXPAND, 5)
MainSizer.Add(StticBxVolumeSizr, 0, wx.ALL|wx.CENTER|wx.EXPAND, 5)
MainPanel.SetSizer(MainSizer)
MainPanel.Layout()
MainPanel.Fit()
self.Layout()
self.Fit()
def DiTexto(self,evt):
Texto = self.TxTDecir.GetValue()
if Texto != "": #S no hay algo, no hacer nada
self.Lista.put(Texto)
def DiHora(self, evt):
# obtener frace
self.Lista.put(self.getcurrTime()) # poner esta frace en cola.
def getcurrTime(self):
currentTime = datetime.now() #Que hora es ahora
currminuto = currentTime.strftime('%M') #obtener minuto como string
hora = currentTime.strftime('%I') #obtener hora como string
if hora[0] == '0':
hora = hora[0 : 0 : ] + hora[0 + 1 : :] #si hay cero a la izquierda, quitarlo
if currminuto[0] == '0':
currminuto = currminuto[0 : 0 : ] + currminuto[0 + 1 : :] #si hay cero a la izquierda, quitarlo
if currminuto == '0':
currminuto = ''
texto = ""
if hora == '1':
texto = "Es la una "+ str(currminuto)
else:
texto = "Son las "+str(hora)+" "+ str(currminuto)
return texto
def WrkrThred(self): #Esta es la funcion del ilo (thread)
while True:
sleep(0.1)
if self.Lista.empty() == False: # Mientras que la lista no este vacia
self.SaySomething(self.Lista.get()) # Decir todo lo que este en cola
def SetupVoice (self): # configurar voz
if self.ThisOS == 'Linux': #en linux
self.engine.setProperty('voice', self.ComboVoices.GetStringSelection()+"+"+self.ComboMods.GetValue())
if self.ThisOS == 'Windows': #en windows
index = self.ComboVoices.GetSelection() # obtener el indice de seleccion del combobox
self.engine.setProperty('voice',self.voicesIDs[index]) # obtener el nombe ID de la voz y asignarla
self.engine.setProperty('rate' ,self.SpeedSlider.GetValue()) # Asignar % velocidad
self.engine.setProperty('volume',self.VolumSlider.GetValue()/100) # Asignar volumen: Minimo:0, Maximo: 1 (por eso /100)
def SaySomething(self, something):
self.engine = pyttsx3.init() # inicializar motor de voz.
self.SetupVoice() # inicializar voz
self.engine.say(something) # Indicar que es lo que se va a decir
self.engine.runAndWait() # Esperar a que terine de Hablar
self.engine.stop() # Detener motor
def getVoiceList(self):
engine = pyttsx3.init() # inicializar un motor de voz localmente en esta funcion
voices = engine.getProperty('voices')
engine.stop() # Parar el motor
for voice in voices:
if voice.name.lower().find("spanish") !=-1: # Restringir las voces al espanol
self.VoiceNames.append(voice.name)
self.voicesIDs .append(voice.id)
self.ComboVoices.SetItems(self.VoiceNames)
self.ComboVoices.SetSelection(0)
if __name__ == '__main__':
app = wx.App()
frame = SayTimeApp()
frame.Show()
app.MainLoop()