niubit dev

Un espacio de contenidos "tech" dedicado a los desarrolladores más inquietos.

Construimos un asistente de voz a medida con el que poder controlar dispositivos y servicios online.

Introducción

Los dispositivos asistentes de voz no son nada nuevo. Grandes compañías tecnológicas como Amazon o Google, hace unos 5 años que se empeñan en llenar nuestras casas con altavoces/micrófonos con la idea de que podamos usar sus servicios en todo momento facilitando la interacción con su interfaz de voz. Alrededor de estos aparatos han aparecido una serie de accesorios que nos permiten "domotizar" la casa. Encender/apagar luces, calefacción o aparatos domésticos, levantar persianas, abrir puertas, etc. Aunque en general estas soluciones son flexibles, robustas y bien diseñadas, siempre puede haber situaciones que no puedan cubrir, además de despertar dudas razonables sobre la privacidad que ofrecen. Es donde se abre la posibilidad de que seamos nosotros los que construyamos la solución con componentes y herramientas del universo maker. No sólo tenemos la posibilidad de personalizar el hardware todo lo necesario, sino que como veremos, también podemos hacerlo a nivel de software.

Hardware

Las posibilidades hoy en día para realizar un proyecto de este tipo, tanto a nivel de hardware como de software son muy numerosas. Así que vamos a acotar un poco el problema empezando por elegir la plataforma. Una de las que tenemos a mano en niubit y que es de nuestras favoritas, es Raspberry Pi. Como queremos que el asistente cuente con un interfaz vocal, vamos a necesitar incorporar hardware de audio. Raspberry Pi sólo dispone de salida de audio aunque sin amplificar y no tiene ninguna entrada. Por tanto, ya que vamos a necesitar ayuda con ambos canales, lo mejor es utilizar un módulo de sonido de los muchos que hay en el mercado. En niubit, disponíamos de los dos siguientes módulos utilizados en proyectos pasados:

El segundo de la lista anterior ya no se encuentra disponible. Google actualizó el kit por una versión más compacta pensada para que sirviera también para Raspberry Pi Zero. Está fabricado por Adafruit y puede adquirirse por separado.

Para seguir este artículo, nosotros vamos a utilizar el Google AIY Voice Kit v1 ya que incluye todo lo necesario desde un principio (pulsador para interactuar físicamente con el asistente, altavoz, carcasa). En caso de no contar con este kit se recomienda sin embargo utilizar el módulo de Keystudio que resulta muy económico y montado con una Raspberry Pi Zero 2 W sobre esta carcasa, parece una opción perfecta.

Software

En cuanto a las posibilidades de software, incluso en un hardware concreto como es Raspberry Pi, son también numerosas. En una rápida búsqueda hemos localizado los siguientes proyectos de software libre que podrían servirnos:

Hemos probado las dos últimas y la que más nos ha gustado ha sido Rhasspy. Ofrece un potente intérprete de frases preconfiguradas parametrizables con las que construir potentes interfaces vocales. Está además orientado a conectar con el sistema Home Assistant, también software libre, pensado para construir soluciones domóticas a medida. Conecta fácilmente con Node-RED, sistema fácil de programar para interconectar dispositivos IOT y servicios en internet.

Además de las cuatro soluciones de la lista, para montajes sencillos, se puede utilizar la plataforma Picovoice. No es software libre, pero se puede instalar y utilizar gratuitamente con algunas limitaciones en cuanto a las expresiones vocales que podemos entrenar en la plataforma. Eso sí, se ejecuta enteramente en nuestro hardware y de forma offline, por lo que al menos aparentemente no implica riesgos de privacidad.

También existe la posibilidad de utilizar la API de Google Assistant que es por ejemplo lo que invita a hacer el Google AIY Voice Kit, pero hemos preferido utilizar productos que realicen todo el trabajo sin salir de nuestra placa, por los motivos de seguridad y privacidad ya mencionados.

Instalación de ejemplo

Para ilustrar estas tecnologías vamos a construir una sencilla aplicación que desempeñe unas cuantas acciones como respuesta a nuestros comandos de voz. Los elementos que vamos a utilizar son:

  • Raspberry Pi 3
  • microSD para el sistema
  • Google AIY Voice Kit v1 (como se ha comentado en el apartado Hardware se puede sustituir fácilmente por otras placas de audio)
  • Altavoz
  • Carcasa 3D. Aunque el kit de Google incluye una carcasa de cartón, nosotros la hemos sustituido por una de las muchas que existen; en concreto ésta

Los pasos para construir el sistema son:

  1. Instalar la tarjeta de audio elegida, en nuestro caso la Voice HAT del Google AIY Voice Kit v1, en el GPIO de Raspberry Pi. Conectar también como mínimo un altavoz en el puerto correspondiente de la Voice HAT. Instalar todo en la carcasa elegida.
  2. Instalar el sistema Raspbian en su versión Lite en la microSD por medio de la utilidad Imager. El sitio oficial de descarga ofrece bastantes detalles y un vídeo detallando el proceso. También podemos seguir en parte la guía que incluimos en el anterior artículo del blog (apartado Instalación software) donde describíamos cómo instalar OctoPrint. Sólo habría que cambiar la selección que se hace en el paso 4 de aquella guía por la ruta: Raspberry Pi OS (other) > Raspberry Pi OS Lite (32-bit). Si no queremos conectar una pantalla y teclado a Raspberry Pi, habrá que acordarse de activar el acceso SSH y configurar la conexión de red a nuestro router (ya sea por WiFi o por cable) durante el proceso de instalación del sistema (Advance options pulsando Ctrl+Mays+X).
  3. Insertar la microSD en Raspberry Pi y alimentar. A partir de este punto, muchos de los pasos suponen teclear órdenes en la terminal del sistema de Raspberry Pi. Podremos hacerlo remotamente por SSH o con una pantalla y teclado conectados directamente.
  4. Actualizar los paquetes del sistema e instalar una serie de dependencias:
    $ sudo apt update && sudo apt -y upgrade
    $ sudo apt -y install git python3 python3-all-dev python3-distutils portaudio19-dev libsndfile1 espeak
  5. Instalar los drivers para la tarjeta de audio elegida. En la documentación de Rhasspy se dan detalles tanto para ReSpeker como para las dos placas de Google AIY Voice Kit. En nuestro caso usamos el segundo, por lo que hacemos lo siguiente:
    $ git clone https://github.com/google/aiyprojects-raspbian.git
    $ cd aiyprojects-raspbian
    $ git checkout voicekit
    $ sudo scripts/configure-driver.sh
    $ sudo scripts/install-alsa-config.sh
    $ sudo reboot
  6. Instalar el gestor de paquetes pip para Python (puede instalarse desde el gestor de paquetes apt de Raspbian, pero nosotros preferimos hacerlo de esta otra forma):
    $ wget https://bootstrap.pypa.io/get-pip.py
    $ python3 get-pip.py
  7. Reiniciar la sesión del terminal.
  8. Instalar los siguientes módulos Python:
    $ pip3 install -y pvporcupine pyaudio pyttsx3
  9. Acudir al sitio de Picovoice, crear una cuenta de usuario gratuita y generar una AccessKey desde la consola de Picovoice.
  10. Crear distintas WakeWords para las distintas acciones que queramos desempeñar con nuestro asistente de voz desde la sección Porcupine de la consola de Picovoice. Aquí hay que comentar que con la cuenta gratuita tenemos una limitación de 3 WakeWords al mes. Una vez creadas las WakeWords descargarlas. Deberemos obtener ficheros con extensión .ppn.
  11. Descargar el modelo del idioma español desde esta ruta. Debemos obtener un fichero con extensión .pv.

Con los pasos anteriores ya tendríamos todo listo. Sólo falta el programa. En nuestro caso hemos creado las tres siguientes WakeWords pensadas para desencadenar las siguientes acciones:

  • enciende: Encenderá el LED del botón del kit Google AIY Voice Kit v1. Este LED está conectado al GPIO25 de Raspberry Pi, por lo que será equivalente a activar dicho pin. Si por ejemplo conectamos un relé a este pin, podremos controlar una bombilla o cualquier aparato de la casa en lugar de un simple LED.
  • apaga: Apagará el LED.
  • qué hora es: Nos dirá la hora actual con un sintetizador de voz.

El programa que hemos creado para vincular las WakeWords a las acciones es el siguiente:

#!/usr/bin/env python3
import struct
import pyaudio
import pvporcupine
from gpiozero import LED
import pyttsx3
from   datetime  import datetime


# Constantes
ACCESS_KEY = "<SUSTITUIR POR ACCESS KEY PROPIA>"

# Variables
porcupine = None
pa = None
audio_stream = None
led = LED(25)
engine = pyttsx3.init()
engine.setProperty('voice', 'spanish')
engine.setProperty('rate', 120)
engine.setProperty('volume', 0.5)


# Funciones asociadas a acciones
def apagar():
    led.off()

def encender():
    led.on()

def decir_hora():
    hora_actual = datetime.now()
    minuto = str(int(hora_actual.strftime('%M')))
    hora   = str(int(hora_actual.strftime('%I')))
    if minuto == '0':
        minuto = ''

    texto = ""
    if hora == '1':
        texto = "Es la una "+ str(minuto)
    else:
        texto = "Son las "+str(hora)+" "+ str(minuto)

    engine.say(texto)
    engine.runAndWait()


# Matriz que asocia las WakeWords con las acciones
matriz_acciones = [apagar, encender, decir_hora]

# Inicializamos Porcupine
porcupine = pvporcupine.create(access_key=ACCESS_KEY,
                               keyword_paths=["apaga_es_raspberry-pi_v2_1_0.ppn",
                                              "enciende_es_raspberry-pi_v2_1_0.ppn",
                                              "qué-hora-es_es_raspberry-pi_v2_1_0.ppn"],
                               model_path="porcupine_params_es.pv")
pa = pyaudio.PyAudio()
audio_stream = pa.open(rate=porcupine.sample_rate,
                       channels=1,
                       format=pyaudio.paInt16,
                       input=True,
                       frames_per_buffer=porcupine.frame_length)

# Bucle principal
while True:
    pcm = audio_stream.read(porcupine.frame_length, exception_on_overflow = False)
    pcm = struct.unpack_from("h" * porcupine.frame_length, pcm)
    keyword_index = porcupine.process(pcm)

    if keyword_index >= 0:
        matriz_acciones[keyword_index]()

Guardar el fichero anterior por ejemplo con el nombre asistente.py y copiarlo por ejemplo al directorio /home/pi/asistente de Raspberry Pi (por medio de SSH si no queremos teclearlo directamente en la terminal). Junto a él, colocar en el mismo directorio los ficheros ppn de las WakeWords y el pv del modelo del español. Ya sólo queda ejecutar el programa con el intérprete de Python, para lo cual ejecutar lo siguiente en una terminal desde el mismo directorio donde hayamos colocado todos los ficheros:

$ python3 asistente.py

Si seguimos el código del programa, podemos ver que es sumamente sencillo y autoexplicativo. Realmente este programa pretendía servir como presentación/introducción de estas tecnologías. Para construir soluciones más sofisticadas convendría utilizar el sistema Rhino de Picovoice que ofrece más posibilidades de parametrización, no como Porcupine que simplemente espera escuchar las WakeWords para disparar eventos. Rhino permite extraer datos de las órdenes verbales. Con otros sistemas como Rhasspy todavía podríamos conseguir soluciones más complejas.

Sería conveniente hacer que el programa se autoarranque cuando se encienda Raspberrry Pi en lugar de tenerlo que lanzar manualmente. Esto se puede lograr de muchas maneras. Raspbian soporta el sistema de gestión de servicios systemd, por lo que podríamos hacer uso de él como se explica en estos apuntes. Otra forma sería incluir al final del fichero /etc/rc.local la siguiente llamada justo antes del exit 0 final (adaptando la ruta del fichero si es diferente):

su - pi -c "python3 /home/pi/asistente/asistente.py &"

Terminamos con un pequeño vídeo donde podemos ver en funcionamiento lo que hemos construido a lo largo de este artículo:

Esta página web utiliza cookies para que sea posible mejorar tu experiencia de navegación.