Skip to Content

Assistente Vocale su UNIHIKER M10 con OpenAI

Assistente Vocale su UNIHIKER M10 con OpenAI

L’UNIHIKER M10 è una scheda compatta che integra un sistema basato su Linux, sensori e interfacce hardware in un unico dispositivo. È dotata di un processore quad-core Arm Cortex-A35 con 512 MB di RAM e 16 GB di memoria eMMC.

La scheda include anche un touchscreen da 2,8 pollici con risoluzione 240 × 320 pixel, connettività Wi-Fi e Bluetooth. I sensori integrati comprendono un sensore di luce, accelerometro, giroscopio e microfono.

Poiché la scheda esegue Linux e supporta la programmazione in Python, può essere utilizzata per molte applicazioni. In questo tutorial imparerai come implementare un Assistente Vocale sulla scheda UNIHIKER M10. Il breve video seguente mostra l’Assistente Vocale:

Potresti dover aumentare il volume del tuo computer per sentire la mia voce. Nota inoltre che questo assistente non ha output vocale, anche se sarebbe facile aggiungerlo.

Componenti necessari

Ti servirà una scheda UNIHIKER M10. Puoi acquistarla su DFRobot o su Amazon, per esempio:

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

Hardware del Unihiker M10

L’UNIHIKER M10 è basato su un chip Rockchip RK3308. Questo chip utilizza quattro core Arm Cortex-A35 e funziona a una frequenza fino a 1,2 GHz. Il processore esegue un sistema operativo Debian Linux completo con Python 3.7 preinstallato. Sono inoltre preinstallate molte librerie scientifiche Python come Numpy, Matplotlib, Jupyter, Pandas, Seaborn, Tensorflow e altre.

La scheda include 512 MB di memoria di sistema DDR3, utilizzata dal sistema operativo Linux e dalle applicazioni utente. Lo storage dei programmi è fornito da 16 GB di memoria flash eMMC integrata.

Oltre al processore principale, la scheda integra un microcontrollore GD32VF103C8T6 come co-processore. Contiene 64 KB di memoria flash e 32 KB di SRAM. Il microcontrollore gestisce molte operazioni a livello hardware come la gestione dei sensori, il controllo dei GPIO e il funzionamento degli attuatori.

Display e Interfaccia Utente

L’UNIHIKER M10 è dotato di un display touchscreen a colori da 2,8 pollici con risoluzione 240 × 320 pixel. La scheda include un pulsante Home e due pulsanti utente programmabili etichettati A e B, come mostrato di seguito:

Buttons on UNIHIKER M10
Pulsanti su UNIHIKER M10

Sensori Integrati

I sensori integrati comprendono un sensore di luce, accelerometro, giroscopio e microfono. L’espansione hardware è possibile tramite porte USB, connettori Gravity per sensori e un connettore edge compatibile con micro:bit che espone interfacce GPIO, I2C, SPI e UART.

Front and back of UNIHIKER M10
Fronte e retro di UNIHIKER M10 (source)

Inoltre, un buzzer passivo e un LED di stato forniscono semplici output audio e visivi per notifiche e debug. Un altoparlante esterno può essere collegato tramite la porta USB.

Connettività e Rete

La comunicazione wireless è disponibile tramite un modulo combinato Wi-Fi e Bluetooth. La scheda supporta Wi-Fi a 2,4 GHz e Bluetooth 4.0. Il Wi-Fi può essere configurato tramite un’interfaccia Web accessibile all’indirizzo 10.1.2.3.

Interfacce e Opzioni di Espansione

La scheda offre diverse interfacce fisiche per collegare hardware esterno. Un connettore USB Type-C è usato per l’alimentazione e la comunicazione con un computer. La scheda può essere alimentata con una tensione di 5 V tramite questa porta.

Una porta USB Type-A host consente il collegamento di periferiche USB come dispositivi di archiviazione, tastiere o adattatori. La scheda include anche uno slot per schede microSD per espandere la capacità di archiviazione o trasferire file.

Inoltre, sono disponibili molteplici connettori di espansione per sensori e attuatori. I connettori a 3 pin compatibili con Gravity forniscono accesso a ingressi PWM e analogici. I connettori dedicati a 4 pin offrono comunicazione I2C per sensori e moduli digitali.

IO Connectors of UNIHIKER M10
Connettori IO di UNIHIKER M10 (source)

Connettore Edge

La scheda dispone anche di un connettore edge compatibile con micro:bit. Questo connettore espone fino a 19 pin GPIO e supporta interfacce come I2C, UART e SPI. Fornisce inoltre diversi ingressi ADC e uscite PWM per il controllo di hardware esterno. L’immagine seguente mostra il pinout del connettore edge:

Pinout of Edge Connector
Pinout del Connettore Edge (source)

Schema elettrico

Per informazioni tecniche più dettagliate consulta lo schema elettrico dell’UNIHIKER M10 linkato di seguito:

Specifiche Tecniche

La tabella seguente riassume le specifiche tecniche della scheda UNIHIKER M10:

Caratteristica Specifiche
Processore Principale Rockchip RK3308
Architettura CPU Quad-core Arm Cortex-A35
Frequenza CPU Fino a 1,2 GHz
Memoria di Sistema 512 MB DDR3
Memoria Interna 16 GB eMMC
Co-Processore Microcontrollore GD32VF103C8T6 RISC-V
Frequenza MCU Fino a 108 MHz
Memoria MCU 64 KB Flash, 32 KB SRAM
Sistema Operativo Debian Linux
Display Touchscreen da 2,8 pollici
Risoluzione Display 240 × 320 pixel
Connettività Wireless Wi-Fi 802.11 b/g/n (2.4 GHz), Bluetooth 4.0
Sensori Sensore di luce, IMU a 6 assi (accelerometro + giroscopio), microfono
Ingressi Utente Pulsante Home, pulsanti utente A/B, touchscreen
Uscita Audio Buzzer passivo
Porte USB 1 × USB-C (alimentazione e dati), 1 × USB-A host
Espansione Memoria Slot per scheda microSD
Interfacce di Espansione Connettori Gravity a 3 pin (analogico/PWM), connettori I2C
Connettore Edge Connettore edge compatibile con micro:bit
Interfacce Supportate GPIO, ADC, PWM, I2C, SPI, UART
Tensione di Funzionamento 5 V in ingresso via USB-C
Livello Logico 3,3 V
Corrente Tipica Fino a ~2 A
Dimensioni della Scheda Circa 51,6 mm × 83 mm × 13 mm

Programmare l’UNIHIKER M10

Ci sono varie applicazioni che puoi usare per programmare l’UNIHIKER M10, come Jupyter Notebook, Mind+, VSCode, Python IDLE o Thonny. Per istruzioni dettagliate su come configurare queste applicazioni consulta la Getting Started sezione della documentazione UNIHIKER.

Installare Thonny

Personalmente ho trovato Thonny il più semplice da usare per un piccolo progetto come questo tutorial. Per istruzioni su come installarlo, consulta la Download and Install sezione Thonny della documentazione UNIHIKER.

Collegare Thonny a UNIHIKER M10

Dopo aver installato Thonny collega il tuo UNIHIKER M10 al computer con il cavo USB. Poi apri Thonny e clicca su “Run -> Select interpreter …”:

Si aprirà una finestra di dialogo dove selezionerai “Remote Python 3 (SSH)” come interprete. In Host inserisci “10.1.2.3”, per Username inserisci “root” e come metodo di autenticazione scegli “password”:

Dopo aver cliccato su “Run -> Stop/Restart backend” Thonny sarà connesso al tuo UNIHIKER M10 e potrai modificare ed eseguire programmi Python su di esso.

Installare Putty e la libreria OpenAI

Successivamente ci servirà uno strumento che ci permetta di installare librerie Python, come la OpenAI libreria sull’UNIHIKER M10. Ho provato a installare librerie tramite Thonny (“Manage Packages”, “Open System Shell…”) ma non sono riuscito a farlo funzionare.

Invece ho usato Putty. Per istruzioni di installazione consulta la SSH Tools della documentazione UNIHIKER. Una volta installato, apri Putty e crea una sessione con 10.1.2.3 come HOST:

Poi clicca sul pulsante “Open” e nella shell di Putty inserisci “root” come username e “dfrobot” come password:

Ora puoi installare la libreria OpenAI con il comando “pip install openai”:

Se mancano altre librerie Python puoi installarle allo stesso modo. Nota però che l’UNIHIKER M10 deve essere collegato tramite cavo USB.

Configurare il Wi-Fi

Infine, dobbiamo configurare la connessione Wi-Fi, così che il nostro Assistente Vocale abbia accesso a internet per chiamare gli strumenti AI di OpenAI.

Per farlo, apri un browser e inserisci “10.1.2.3” nella barra degli indirizzi. Vedrai una pagina web con una voce “Network Settings” nella barra laterale. Cliccaci e inserisci le credenziali Wi-Fi nel dialog a destra:

Ottenere la chiave API OpenAI

Il nostro Assistente Vocale userà modelli AI forniti da OpenAI. Perciò ti servirà un account OpenAI. Vai su https://platform.openai.com e registrati con un indirizzo email o un account Google o Microsoft esistente.

Dopo aver verificato la tua email e completato la configurazione iniziale, accedi alla dashboard OpenAI, platform.openai.com/api-keys e trova o crea la tua API Key (=SECRET KEY) come mostrato di seguito:

OpenAI API keys
Chiavi API OpenAI

La API Key è una stringa unica e lunga, che inizia con “sk-proj-“, necessaria per autenticare le richieste API (vedi sotto). Successivamente dovrai copiare questa stringa intera nel codice dell’Assistente Vocale.

sk-proj-xcA.......................OtDu0U

Questo è tutto ciò che serve, ma ti consiglio di impostare anche un limite di utilizzo per il tuo account. Questo evita di incorrere in costi elevati a causa di un bug nel codice (ad esempio inviando centinaia di richieste).

Puoi impostare i Limiti di Utilizzo e consultare i Prezzi (Costi) per i diversi modelli AI nella scheda Billing (platform.openai.com/settings/organization/billing).

Ora siamo pronti per scrivere il codice per l’Assistente Vocale.

Codice per l’Assistente Vocale

In Thonny crea un nuovo file, io l’ho chiamato “assistant_tk.py” e copia e incolla il codice qui sotto.

Questo codice implementa un assistente vocale. Registra l’audio mentre si tiene premuto il pulsante A, trascrive il parlato in testo usando il modello Whisper di OpenAI, invia il testo a un modello GPT basato su Large Language Model (LLM) per una risposta, e mostra sia la domanda che la risposta nell’interfaccia grafica del dispositivo.

# www.makerguides.com
# Python 3.7
# openai 1.39.0
# PyAudio 0.2.11
# pinpong 0.6.1
# numpy 1.21.6

import time
import threading
import numpy as np
import pyaudio
import io
import wave
from openai import OpenAI
from pinpong.extension.unihiker import button_a
import tkinter as tk
from tkinter import ttk
from typing import List

API_KEY = "sk-proj-my-api-key"
DEVICE_INDEX = 2
SAMPLE_RATE = 16000
CHANNELS = 1
CHUNK = 1024

client = OpenAI(api_key=API_KEY)

# GUI -----------------------------------------------------

root = tk.Tk()
root.title("Voice Chatbot")
root.geometry("240x320")

status_var = tk.StringVar()
status_var.set("Hold Button A to speak")

status_label = ttk.Label(root, textvariable=status_var,
    font=("Arial", 11), anchor="center")
status_label.pack(fill="x", padx=6, pady=4)

frame = tk.Frame(root)
frame.pack(fill="both", expand=True)

scrollbar = tk.Scrollbar(frame, width=18)
scrollbar.pack(side="right", fill="y")

text_box = tk.Text(frame, wrap="word",
    yscrollcommand=scrollbar.set, font=("Arial", 10))
text_box.bind("<Motion>", lambda e: "break")
text_box.bind("<B1-Motion>", lambda e: "break")
text_box.bind("<Button-1>", lambda e: "break")
text_box.pack(side="left", fill="both", expand=True)

scrollbar.config(command=text_box.yview)


def set_status(text):
    status_var.set(text)
    root.update_idletasks()


def show_answer(text):
    text_box.delete("1.0", tk.END)
    text_box.insert(tk.END, text)
    text_box.see(tk.END)


# Audio helpers -----------------------------------------------

def normalize(pcm_bytes: bytes) -> bytes:
    samples = np.frombuffer(pcm_bytes, dtype=np.int16).astype(np.float32)
    peak = np.max(np.abs(samples))
    if peak == 0:
        return pcm_bytes
    gain = (0.9 * 32767) / peak
    normalized = np.clip(samples * gain, -32768, 32767).astype(np.int16)
    return normalized.tobytes()


def record_while_held() -> bytes:
    frames: List[bytes] = []

    pa = pyaudio.PyAudio()
    stream = pa.open(
        format=pyaudio.paInt16,
        channels=CHANNELS,
        rate=SAMPLE_RATE,
        input=True,
        input_device_index=DEVICE_INDEX,
        frames_per_buffer=CHUNK
    )

    set_status("Hold Button A to speak")

    while not button_a.is_pressed():
        time.sleep(0.01)

    set_status("recording...")

    while button_a.is_pressed():
        data = stream.read(CHUNK, exception_on_overflow=False)
        frames.append(data)

    stream.stop_stream()
    stream.close()
    pa.terminate()

    return b"".join(frames)


def pcm_to_wav(pcm_bytes: bytes) -> bytes:
    buf = io.BytesIO()
    with wave.open(buf, "wb") as wf:
        wf.setnchannels(CHANNELS)
        wf.setsampwidth(2)
        wf.setframerate(SAMPLE_RATE)
        wf.writeframes(pcm_bytes)
    return buf.getvalue()


# OpenAI -----------------------------------------------

def transcribe(wav_bytes: bytes) -> str:
    audio_file = io.BytesIO(wav_bytes)
    audio_file.name = "recording.wav"

    set_status("transcribing...")
    response = client.audio.transcriptions.create(
        model="whisper-1",
        file=audio_file,
        language="en",
        temperature=0
    )
    return response.text


def ask_gpt(question: str) -> str:
    set_status("thinking...")
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {
                "role": "system",
                "content": "You are a helpful assistant. Answer clearly and concisely."
            },
            {"role": "user", "content": question}
        ],
    )
    return response.choices[0].message.content


# Main assistant loop -----------------------------------------------

def assistant_loop():
    while True:
        raw_pcm = record_while_held()
        if not raw_pcm:
            continue

        normalized_pcm = normalize(raw_pcm)
        wav_bytes = pcm_to_wav(normalized_pcm)
        question = transcribe(wav_bytes)
        answer = ask_gpt(question)

        set_status("ready")
        show_answer(question + "\n\n" + answer)


threading.Thread(target=assistant_loop, daemon=True).start()
root.mainloop()

Importazioni

Il codice inizia importando diversi moduli necessari per il suo funzionamento. Questi includono librerie standard come time, threading e io per la gestione del tempo, l’esecuzione concorrente e la gestione di flussi di byte. Importa anche numpy per operazioni numeriche su dati audio, pyaudio per la registrazione audio, e wave per la gestione del formato audio WAV.

Il client Python di OpenAI è importato per interagire con l’API di OpenAI. Il modulo specifico UNIHIKER button_a è importato per rilevare la pressione dei pulsanti. Infine, tkinter e ttk sono importati per creare l’interfaccia grafica, e List da typing è usato per i type hinting.

import time
import threading
import numpy as np
import pyaudio
import io
import wave
from openai import OpenAI
from pinpong.extension.unihiker import button_a
import tkinter as tk
from tkinter import ttk
from typing import List

Costanti e Inizializzazione Client

Vengono definite diverse costanti per configurare i parametri di registrazione audio, come la chiave API per OpenAI, l’indice del dispositivo di input audio, la frequenza di campionamento, il numero di canali e la dimensione del buffer audio. Viene quindi creato un oggetto client OpenAI usando la chiave API fornita, abilitando la comunicazione con i servizi OpenAI.

API_KEY = "sk-proj-my-api-key"
DEVICE_INDEX = 2
SAMPLE_RATE = 16000
CHANNELS = 1
CHUNK = 1024

client = OpenAI(api_key=API_KEY)

Ricorda di sostituire il valore fittizio “sk-proj-my-api-key” per API_KEY con la tua chiave API OpenAI!

Interfaccia Grafica (GUI)

La GUI è costruita usando tkinter. Viene creata una finestra principale con un titolo e dimensioni fisse. Viene aggiunta un’etichetta di stato per informare l’utente sullo stato corrente, come l’invito a tenere premuto il pulsante A per parlare o messaggi di progresso.

Sotto l’etichetta di stato, è presente una casella di testo con barra di scorrimento per mostrare la domanda trascritta e la risposta dell’assistente. La casella di testo è impostata in sola lettura disabilitando le interazioni del mouse che modificherebbero il contenuto.

root = tk.Tk()
root.title("Voice Chatbot")
root.geometry("240x320")

status_var = tk.StringVar()
status_var.set("Hold Button A to speak")

status_label = ttk.Label(root, textvariable=status_var,
    font=("Arial", 11), anchor="center")
status_label.pack(fill="x", padx=6, pady=4)

frame = tk.Frame(root)
frame.pack(fill="both", expand=True)

scrollbar = tk.Scrollbar(frame, width=18)
scrollbar.pack(side="right", fill="y")

text_box = tk.Text(frame, wrap="word",
    yscrollcommand=scrollbar.set, font=("Arial", 10))
text_box.bind("<Motion>", lambda e: "break")
text_box.bind("<B1-Motion>", lambda e: "break")
text_box.bind("<Button-1>", lambda e: "break")
text_box.pack(side="left", fill="both", expand=True)

scrollbar.config(command=text_box.yview)

Funzioni di Stato e Visualizzazione

Due funzioni di supporto gestiscono gli aggiornamenti della GUI. La funzione set_status() aggiorna il testo dell’etichetta di stato e forza l’aggiornamento immediato della GUI. La funzione show_answer() cancella la casella di testo, inserisce nuovo testo e scorre fino alla fine per mostrare il contenuto più recente.

def set_status(text):
    status_var.set(text)
    root.update_idletasks()


def show_answer(text):
    text_box.delete("1.0", tk.END)
    text_box.insert(tk.END, text)
    text_box.see(tk.END)

Funzioni Audio

Il codice include diverse funzioni per la gestione dell’audio. La funzione normalize() prende i byte audio PCM grezzi, li converte in campioni floating-point e li scala in modo che l’ampiezza massima raggiunga il 90% del range massimo di un intero a 16 bit. Questa normalizzazione garantisce un volume audio costante per la trascrizione.

def normalize(pcm_bytes: bytes) -> bytes:
    samples = np.frombuffer(pcm_bytes, dtype=np.int16).astype(np.float32)
    peak = np.max(np.abs(samples))
    if peak == 0:
        return pcm_bytes
    gain = (0.9 * 32767) / peak
    normalized = np.clip(samples * gain, -32768, 32767).astype(np.int16)
    return normalized.tobytes()

La funzione record_while_held() registra l’audio dal dispositivo di input specificato mentre il pulsante A è premuto.

Inizializza uno stream PyAudio con i parametri configurati e attende che il pulsante A venga premuto. Poi legge continuamente blocchi audio e li aggiunge a una lista finché il pulsante non viene rilasciato. I frame audio registrati vengono concatenati e restituiti come byte raw PCM.

def record_while_held() -> bytes:
    frames: List[bytes] = []

    pa = pyaudio.PyAudio()
    stream = pa.open(
        format=pyaudio.paInt16,
        channels=CHANNELS,
        rate=SAMPLE_RATE,
        input=True,
        input_device_index=DEVICE_INDEX,
        frames_per_buffer=CHUNK
    )

    set_status("Hold Button A to speak")
    while not button_a.is_pressed():
        time.sleep(0.01)

    set_status("recording...")
    while button_a.is_pressed():
        data = stream.read(CHUNK, exception_on_overflow=False)
        frames.append(data)

    stream.stop_stream()
    stream.close()
    pa.terminate()

    return b"".join(frames)

La funzione pcm_to_wav() converte i byte PCM raw in un flusso di byte in formato WAV usando il modulo wave. Questo è necessario perché l’API di trascrizione OpenAI si aspetta file audio in formati standard come WAV.

def pcm_to_wav(pcm_bytes: bytes) -> bytes:
    buf = io.BytesIO()
    with wave.open(buf, "wb") as wf:
        wf.setnchannels(CHANNELS)
        wf.setsampwidth(2)
        wf.setframerate(SAMPLE_RATE)
        wf.writeframes(pcm_bytes)
    return buf.getvalue()

Interazione con l’API OpenAI

Due funzioni gestiscono la comunicazione con l’API OpenAI. La funzione transcribe() invia i byte audio WAV al modello Whisper per ottenere una trascrizione testuale. Aggiorna l’etichetta di stato per indicare che la trascrizione è in corso e restituisce il testo riconosciuto.

def transcribe(wav_bytes: bytes) -> str:
    audio_file = io.BytesIO(wav_bytes)
    audio_file.name = "recording.wav"

    set_status("transcribing...")

    response = client.audio.transcriptions.create(
        model="whisper-1",
        file=audio_file,
        language="en",
        temperature=0
    )

    return response.text

La funzione ask_gpt() invia la domanda trascritta a un modello di completamento chat basato su GPT. Imposta lo stato su “thinking…” mentre attende la risposta. Poi costruisce il messaggio di sistema che istruisce il modello a essere un assistente utile. Infine, la funzione restituisce il testo della risposta dell’assistente.

def ask_gpt(question: str) -> str:
    set_status("thinking...")
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {
                "role": "system",
                "content": "You are a helpful assistant. Answer clearly and concisely."
            },
            {"role": "user", "content": question}
        ],
    )

    return response.choices[0].message.content

Ciclo Principale dell’Assistente

La funzionalità principale è eseguita nella funzione assistant_loop(), che gira in un thread separato per mantenere la GUI reattiva.

Attende continuamente che l’utente tenga premuto il pulsante A e registra l’audio mentre il pulsante è premuto. Se non viene catturato audio, ricomincia il ciclo. Altrimenti normalizza l’audio, lo converte in formato WAV, trascrive il parlato e interroga il modello GPT per una risposta.

Dopo l’elaborazione, aggiorna lo stato a “ready” e mostra sia la domanda che la risposta nella casella di testo.

def assistant_loop():
    while True:
        raw_pcm = record_while_held()
        if not raw_pcm:
            continue

        normalized_pcm = normalize(raw_pcm)
        wav_bytes = pcm_to_wav(normalized_pcm)

        question = transcribe(wav_bytes)
        answer = ask_gpt(question)

        set_status("ready")
        show_answer(question + "\n\n" + answer)

Avvio dell’Assistente e Mainloop della GUI

Infine, il ciclo dell’assistente viene avviato in un thread daemon, permettendo di girare in background. Viene quindi avviato il mainloop degli eventi della GUI con root.mainloop(), che mantiene la finestra aperta e reattiva alle interazioni dell’utente.

threading.Thread(target=assistant_loop, daemon=True).start()
root.mainloop()

Messaggi di errore

Se esegui il codice potresti vedere i seguenti avvisi nella console di Thonny:

ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.iec958
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.iec958
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.iec958
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm_oss.c:377:(_snd_pcm_oss_open) Unknown field port
ALSA lib pcm_oss.c:377:(_snd_pcm_oss_open) Unknown field port
ALSA lib pcm_a52.c:823:(_snd_pcm_a52_open) a52 is only for playback
ALSA lib conf.c:5014:(snd_config_expand) Unknown parameters {AES0 0x6 AES1 0x82 AES2 0x0 AES3 0x2  CARD 0}
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM iec958:{AES0 0x6 AES1 0x82 AES2 0x0 AES3 0x2  CARD 0}
ALSA lib pcm_usb_stream.c:486:(_snd_pcm_usb_stream_open) Invalid type for card
ALSA lib pcm_usb_stream.c:486:(_snd_pcm_usb_stream_open) Invalid type for card

Questo accade perché quando inizializzi pyaudio.PyAudio(), la libreria ALSA (Advanced Linux Sound Architecture) sottostante scansiona il sistema per tutti i dispositivi audio e configurazioni possibili (come audio surround 5.1, HDMI o digitale S/PDIF).

Poiché l’UNIHIKER M10 è un Single Board Computer compatto, non ha “altoparlanti posteriori” o “porte modem”, quindi ALSA segnala che non li trova. Se il tuo codice funziona e gestisce l’audio dopo questi avvisi, la configurazione è corretta.

Conclusioni

In questo tutorial hai imparato come implementare un Assistente Vocale sull’UNIHIKER M10 usando i servizi OpenAI. Per altri esempi di codice più semplici dai un’occhiata alla Python Coding Examples della documentazione UNIHIKER.

Nota che potresti facilmente estendere e migliorare l’Assistente Vocale aggiungendo una cronologia chat e funzionalità di chiamata a strumenti. Inoltre, ho usato Tkinter per creare un’interfaccia semplice, ma per una GUI migliore potresti usare QtPy, che è preinstallato sull’UNIHIKER M10.

Inoltre, potresti aggiungere un altoparlante, via USB, Bluetooth o line-out, per far rispondere l’Assistente Vocale con audio. Vedi il tutorial AI Language Tutor with UNIHIKER M10 per un esempio.

Per un Vision Chatbot che può vedere e rispondere a domande su immagini, consulta il nostro tutorial Vision Chatbot with DFRobot ESP32-S3 AI Camera and OpenAI. E per altri esempi AI, vedi la AI Projects sezione della documentazione UNIHIKER.

Se hai domande sentiti libero di lasciarle nella sezione commenti.

Buon divertimento con il tinkering 😉