Alexa y Siri son los asistentes de voz dominantes disponibles para el uso diario. Estos asistentes se han vuelto omnipresentes en casi todos los hogares, realizando tareas de la automatización del hogar, tomar notas, orientación de recetas y responder preguntas simples. Sin embargo, cuando se trata de responder preguntas, en la era de LLMS, obtener una respuesta concisa y basada en el contexto de estos asistentes de voz puede ser complicado, si no inexistente. Por ejemplo, si le pregunta al Asistente de Google cómo está reaccionando a Discurso de Jerome Powell En Jackson Hole el 22 de agosto, simplemente responderá que no sabe la respuesta y da algunos enlaces que puede leer. Eso es si tiene el Asistente de Google basado en pantalla.
A menudo, solo desea una respuesta rápida en los eventos actuales, o quiere saber si un manzano sobreviviría al invierno en Ohio, y a menudo asistentes de voz como Google y Siri no tienen una respuesta satisfactoria. Esto me interesó en construir mi propio asistente de voz, una que me daría una respuesta de oración simple y simple basada en su búsqueda en la web.
De los diversos motores de búsqueda alimentados por LLM disponibles, he sido un ávido usuario de perplejidad durante más de un año y lo uso exclusivamente para todas mis búsquedas, excepto las simples, donde todavía vuelvo a Google o Bing. La perplejidad, además de su índice web en vivo, que le permite proporcionar respuestas actualizadas, precisas y de origen, permite a los usuarios acceder a su funcionalidad a través de una API poderosa. Usando esta funcionalidad e integrándola con una simple Raspberry Pi, tenía la intención de crear un asistente de voz que lo haría:
- Responda a una palabra de vigilia y prepárate para responder a mi pregunta
- Responda mi pregunta en una oración simple y concisa
- Vuelve a la escucha pasiva sin vender mis datos o dar mis anuncios innecesarios
El hardware para el asistente
Para construir nuestro asistente de voz, se requieren algunos componentes clave de hardware. El núcleo del proyecto es un Raspberry Pi 5que sirve como procesador central para nuestra aplicación. Para la entrada de audio del asistente, elegí un simple Micrófono de cuello de cisne USB. Este tipo de micrófono es omnidireccional, lo que lo hace efectivo para escuchar la palabra de vigilia de diferentes partes de una habitación, y su naturaleza plug-and-play simplifica la configuración. Para la salida del asistente, un compacto Altavoz con alimentación de USB proporciona la salida de audio. Una ventaja clave de este altavoz es que utiliza un solo cable USB tanto para su señal de alimentación como de audio, lo que minimiza el desorden de cable.
Este enfoque de usar periféricos USB fácilmente disponibles hace que el ensamblaje de hardware sea sencillo, lo que nos permite enfocar nuestros esfuerzos en el software.
Preparando el entorno
Para consultar la perplejidad utilizando consultas personalizadas y para tener una palabra de vigilia para el asistente de voz, necesitamos generar un par de claves API. Para generar una clave API de perplejidad, se puede registrar para una cuenta de perplejidad, vaya al menú Configuración, seleccione la pestaña API y haga clic en “Generar la tecla API” para crear y copiar su clave personal para usar en aplicaciones. El acceso a la generación de clave API generalmente requiere un plan pagado o un método de pago, por lo que asegúrese de que la cuenta sea elegible antes de continuar.
Las plataformas que ofrecen personalización de Wake Word incluyen Picovoice Porcupine, Sensory Truly Handsfree y Snowboy, con Picovoice Porcupine que proporciona una consola en línea fácil para generar, probar e implementar palabras de estela personalizadas en dispositivos de escritorio, móviles y integrados. Un nuevo usuario puede generar una palabra personalizada para Puerco de picovoice Al registrarse para obtener una cuenta gratuita de la consola Picovoice, navegar a la página de puercoespín, seleccionar el lenguaje deseado, escribir en la palabra de vigilia personalizada y hacer clic en “tren” para producir y descargar el archivo de modelo específico de la plataforma (.ppn) para su uso. Asegúrese de probar la palabra de vigilia para su rendimiento antes de finalizar, ya que esto garantiza una detección confiable y falsos positivos mínimos. La palabra de estela que he entrenado y que usaré es “Hola Krishna”.
Codificando el asistente
El script de Python completo para este proyecto está disponible en mi github repositorio. En esta sección, veamos los componentes clave del código para comprender cómo funciona el asistente.
El guión se organiza en algunas funciones centrales que manejan los sentidos e inteligencia del asistente, todos administrados por un bucle central.
Configuración e inicialización
La primera parte del script está dedicada a la configuración. Maneja la carga de las claves API necesarias, los archivos de modelo e inicialización de los clientes para los servicios que utilizaremos.
# --- 1. Configuration ---
load_dotenv()
PICOVOICE_ACCESS_KEY = os.environ.get("PICOVOICE_ACCESS_KEY")
PERPLEXITY_API_KEY = os.environ.get("PERPLEXITY_API_KEY")
KEYWORD_PATHS = ["Krishna_raspberry-pi.ppn"] # My wake word pat
MODEL_NAME = "sonar"
Esta sección usa el dotenv biblioteca para cargar de forma segura sus claves de API secretas desde un .env Archivo, que es una mejor práctica que los mantiene fuera de su código fuente. También define variables clave como la ruta a su archivo de palabras de Wake Wake y el modelo de perplejidad específico que queremos consultar.
Detección de palabras de wake
Para que el asistente sea realmente manos libres, necesita escuchar continuamente una palabra de vigilia específica sin usar recursos significativos en el sistema. Esto se maneja por el while True: bucle en el main función, que utiliza el motor de puercoespín picovoice.
# This is the main loop that runs continuously
while True:
# Read a small chunk of raw audio data from the microphone
pcm = audio_stream.read(porcupine.frame_length)
pcm = struct.unpack_from("h" * porcupine.frame_length, pcm)
# Feed the audio chunk into the Porcupine engine for analysis
keyword_index = porcupine.process(pcm)
if keyword_index >= 0:
# Wake word was detected, proceed to handle the command...
print("Wake word detected!")
Este bucle es el corazón del estado de “escucha pasiva” del asistente. Continuamente lee marcos de audio pequeños y crudos de la transmisión de micrófono. Cada cuadro se pasa a la porcupine.process() función. Este es un altamente eficiente, desconectado Proceso que analiza el audio para el patrón acústico específico de su palabra de vigilia personalizada (“Krishna”). Si se detecta el patrón, porcupine.process() Devuelve un número no negativo, y el script procede a la fase activa de escuchar un comando completo.
Discurso a texto: convertir las preguntas del usuario en texto
Después de detectar la palabra de estela, el asistente debe escuchar y comprender la pregunta del usuario. Esto es manejado por el componente de voz a texto (STT).
# --- This logic is inside the main 'if keyword_index >= 0:' block ---
print("Listening for command...")
frames = []
# Record audio from the stream for a fixed duration (~10 seconds)
for _ in range(0, int(porcupine.sample_rate / porcupine.frame_length * 10)):
frames.append(audio_stream.read(porcupine.frame_length))
# Convert the raw audio frames into an object the library can use
audio_data = sr.AudioData(b"".join(frames), porcupine.sample_rate, 2)
try:
# Send the audio data to Google's service for transcription
command = recognizer.recognize_google(audio_data)
print(f"You (command): {command}")
except sr.UnknownValueError:
speak_text("Sorry, I didn't catch that.")
Una vez que se detecta la palabra de estela, el código registra activamente el audio del micrófono durante aproximadamente 10 segundos, capturando el comando hablado del usuario. Luego empaqueta estos datos de audio sin procesar y los envía al servicio de reconocimiento de voz de Google utilizando el speech_recognition biblioteca. El servicio procesa el audio y devuelve el texto transcrito, que luego se almacena en el command variable.
Obtener respuestas de la perplejidad
Una vez que el comando del usuario se ha convertido en texto, se envía a la API de perplejidad para obtener una respuesta inteligente y actualizada.
# --- This logic runs if a command was successfully transcribed ---
if command:
# Define the instructions and context for the AI
messages = [{"role": "system", "content": "You are an AI assistant. You are located in Twinsburg, Ohio. All answers must be relevant to Cleveland, Ohio unless asked for differently by the user. You MUST answer all questions in a single and VERY concise sentence."}]
messages.append({"role": "user", "content": command})
# Send the request to the Perplexity API
response = perplexity_client.chat.completions.create(
model=MODEL_NAME,
messages=messages
)
assistant_response_text = response.choices[0].message.content.strip()
speak_text(assistant_response_text)
Este bloque de código es el “cerebro” de la operación. Primero construye un messages Lista, que incluye un crítico aviso del sistema. Este aviso le da a la IA su personalidad y reglas, como responder en una sola oración y estar al tanto de su ubicación en Ohio. Luego se agrega el comando del usuario a esta lista, y el paquete completo se envía a la API de perplejidad. El script luego extrae el texto de la respuesta de la IA y lo pasa al speak_text función a leer en voz alta.
Texto a voz: respuesta de perplejidad convertida a la voz
El speak_text La función es lo que le da al asistente su voz.
def speak_text(text_to_speak, lang='en'):
# Define a function that converts text to speech, default language is English
print(f"Assistant (speaking): {text_to_speak}")
# Print the text for reference so the user can see what is being spoken
try:
pygame.mixer.init()
# Initialize the Pygame mixer module for audio playback
tts = gTTS(text=text_to_speak, lang=lang, slow=False)
# Create a Google Text-to-Speech (gTTS) object with the provided text and language
# 'slow=False' makes the speech sound more natural (not slow-paced)
mp3_filename = "response_audio.mp3"
# Set the filename where the generated speech will be saved
tts.save(mp3_filename)
# Save the generated speech as an MP3 file
pygame.mixer.music.load(mp3_filename)
# Load the MP3 file into Pygame's music player for playback
pygame.mixer.music.play()
# Start playing the speech audio
while pygame.mixer.music.get_busy():
pygame.time.Clock().tick(10)
# Keep the program running (by checking if playback is ongoing)
# This prevents the script from ending before the speech finishes
# The clock.tick(10) ensures it checks 10 times per second
pygame.mixer.quit()
# Quit the Pygame mixer once playback is complete to free resources
os.remove(mp3_filename)
# Delete the temporary MP3 file after playback to clean up
except Exception as e:
print(f"Error in Text-to-Speech: {e}")
# Catch and display any errors that occur during the speech generation or playback
Esta función toma una cadena de texto, la imprime como referencia, luego usa la biblioteca GTTS (Google Text-to-Speech) para generar un archivo de audio MP3 temporal. Reproduce el archivo a través de los altavoces del sistema usando la biblioteca PyGame, espera hasta que termine la reproducción y luego elimina el archivo. El manejo de errores se incluye para atrapar problemas durante el proceso.
Prueba del asistente
A continuación se muestra una demostración del funcionamiento del Asistente de voz personalizado. Para comparar su rendimiento con el Asistente de Google, he hecho la misma pregunta de Google y de el Asistente personalizado.
Como puede ver, Google proporciona enlaces a la respuesta en lugar de proporcionar un breve resumen de lo que el usuario quiere. El asistente personalizado va más allá y proporciona un resumen y es más útil e informativo.
Conclusión
En este artículo, observamos el proceso de construir un asistente de voz totalmente funcional y manos libres en una Raspberry Pi. Al combinar el poder de una palabra de vigilia personalizada y la API de perplejidad al usar Python, creamos un dispositivo de asistente de voz simple que ayuda a obtener información rápidamente.
La ventaja clave de este enfoque basado en LLM es su capacidad para ofrecer respuestas directas y sintetizadas a preguntas complejas y actuales, una tarea en la que los asistentes como Google Assistant a menudo se quedan cortos simplemente proporcionando una lista de enlaces de búsqueda. En lugar de actuar como una mera interfaz de voz para un motor de búsqueda, nuestro asistente funciona como un verdadero motor de respuestas, analizando los resultados web en tiempo real para dar una respuesta única y concisa. El futuro de los asistentes de voz se encuentra en esta integración más profunda e inteligente, y construir la suya es la mejor manera de explorarlo.