Corso
OpenAI ha introdotto una nuova generazione di modelli audio focalizzati sul miglioramento delle funzionalità speech-to-text e text-to-speech. Questi ultimi modelli promettono una precisione superiore, soprattutto in situazioni complesse come accenti o ambienti rumorosi, e offrono interazioni vocali più personalizzabili.
In questo tutorial ti mostrerò passo dopo passo come usare i nuovi modelli audio di OpenAI per costruire un assistente IA voce-a-voce. L'obiettivo è sviluppare un assistente in grado di capire l'input parlato e rispondere con una voce sintetizzata in modo naturale, adattata a esigenze specifiche.
L'Audio API di OpenAI
Questa nuova release di OpenAI include tre modelli:
gpt-4o-mini-tts: un modello text-to-audio in grado di generare audio a partire dal testo con toni e voci diversi. Una caratteristica interessante di questo modello text-to-speech è che possiamo guidare il suono della voce fornendo istruzioni testuali specifiche. Questo offre un alto livello di personalizzazione, permettendo di creare esperienze vocali uniche e su misura. Puoi provarlo su OpenAI.fm.-
gpt-4o-transcribeegpt-4o-mini-transcribe: due modelli audio-to-text progettati per convertire il parlato in testo scritto. La loro funzione principale è fornire trascrizioni audio molto accurate e affidabili. Questi modelli mostrano un tasso di errore di parola (WER) inferiore, il che significa che commettono meno errori nel riconoscere le parole rispetto alle soluzioni precedenti.

Questi nuovi modelli hanno il seguente pricing:

Progetto di assistente vocale
In questo tutorial ti guiderò nella creazione di un assistente vocale IA direttamente dal terminale. Questo assistente vocale replicherà essenzialmente un popolare modello IA testuale, ma interagirà interamente tramite linguaggio parlato. Immagina di poter parlare direttamente al computer, fare qualsiasi domanda e ricevere quasi istantaneamente una risposta vocale.
Useremo un'architettura semplice ma efficace. Inizieremo utilizzando il microfono per catturare il tuo prompt parlato. Una volta registrato, convertiremo questo input audio in testo con l'aiuto di modelli speech-to-text avanzati.
Questo testo verrà poi passato a un large language model per generare una risposta adeguata. Infine, riconvertiremo la risposta testuale in audio, permettendo all'assistente di “parlarti” la risposta. Ogni passaggio è pensato per garantire che il nostro assistente vocale sia accurato e coinvolgente.

Sebbene OpenAI offra una Realtime API dedicata che può migliorare le interazioni semplificando l'intero processo, noi sceglieremo un approccio diverso. La Realtime API, pur essendo impressionante e perfetta per chi cerca integrazioni rapide, spesso è più costosa e offre meno flessibilità.
Scegliendo di costruire il progetto usando componenti separati per ogni step, otteniamo un maggiore controllo sulla personalizzazione del nostro assistente IA. Questo approccio ci consente di scegliere i modelli da usare, ottimizzando per esigenze specifiche, che si tratti di accuratezza, velocità o preferenze sul tono della risposta. In questo modo, il nostro assistente vocale diventa non solo uno strumento potente, ma anche altamente su misura, capace di adattarsi a requisiti di progetto unici.
Tutto il codice sviluppato qui è disponibile in questa repository GitHub.
Setup in Python
Per iniziare, creeremo un nuovo ambiente Anaconda chiamato audio-demo. Gli ambienti di Anaconda permettono di creare spazi isolati per ogni progetto in cui installare versioni specifiche dei pacchetti senza conflitti. Esegui i seguenti comandi nel tuo terminale:
conda create -n audio-demo -y python=3.9
conda activate audio-demo
pip install openai
pip install numpy
pip install dotenv
pip install sounddevice
pip install scipy
Vediamo nel dettaglio cosa fanno i comandi e i pacchetti:
- Creazione dell'ambiente:
conda create -n audio-demo -y python=3.9: crea un nuovo ambiente chiamatoaudio-democon Python 3.9. Il flag-yaccetta automaticamente le installazioni senza chiedere conferma.
- Attivazione dell'ambiente:
conda activate audio-demo: attiva il nuovo ambienteaudio-demoper lavorarci dentro.
- Installazione dei pacchetti:
pip install openai: la libreria OpenAI fornisce un accesso semplice ai modelli e alle API di OpenAI.pip install numpy: NumPy è una libreria essenziale per il calcolo numerico.pip install dotenv: Dotenv aiuta a caricare le variabili d'ambiente da un file.env, semplificando e rendendo più sicura la gestione della configurazione.pip install sounddevice: Sounddevice ci consente di registrare e riprodurre suoni con funzioni semplici, ideale per gestire input e output audio in Python.pip install scipy: SciPy si basa su NumPy e offre funzionalità aggiuntive per il calcolo scientifico e tecnico, come l'elaborazione dei segnali. Nel nostro caso lo useremo per salvare il file audio.
Con l'ambiente audio-demo pronto, possiamo iniziare a lavorare sul nostro assistente IA che elabora input audio. Questo setup strutturato ci aiuta a mantenere uno spazio di sviluppo pulito, assicurando che tutte le dipendenze siano al loro posto.
Impostazione della chiave API di OpenAI
Per usare le API di OpenAI ci serve una chiave API. Vai alla pagina delle chiavi API e genera una chiave cliccando sul pulsante "Generate new secret key". Copia la chiave, crea un file chiamato .env e incollala lì nel seguente formato:
OPENAI_API_KEY=<paste_your_api_key_here>
Esempio di Text to Audio
Vediamo i passaggi per creare uno script Python che utilizza le funzionalità text-to-audio di OpenAI, trasformando il testo in voce con un tocco personalizzato. Scriviamo il codice in un file chiamato text_to_audio.py nella stessa cartella del file .env.
Importa le librerie necessarie
Per prima cosa importiamo le librerie necessarie per il nostro script:
import asyncio
from openai import AsyncOpenAI
from openai.helpers import LocalAudioPlayer
from dotenv import load_dotenv
Una panoramica rapida di cosa fanno questi import:
asyncio: libreria per scrivere codice asincrono in Python, essenziale per lavorare con API in streaming.AsyncOpenAI: parte della libreria OpenAI, fornisce strumenti per interagire in modo asincrono con le API di OpenAI.LocalAudioPlayer: helper di OpenAI che consente di riprodurre l'audio in locale sulla macchina.load_dotenv: carica le variabili d'ambiente dal file.env, dove conserviamo informazioni sensibili come le chiavi API.
Carica le variabili d'ambiente
Ora carichiamo la chiave API dal file .env usando la funzione load_dotenv:
load_dotenv()
In questo modo lo script accede in modo sicuro alla chiave API.
Inizializza OpenAI
Creiamo un'istanza di AsyncOpenAI per iniziare a interagire con l'API di OpenAI:
openai = AsyncOpenAI()
Scrivi la funzione principale
Definiamo ora la funzione principale, text_to_audio(), che utilizzerà la funzionalità text-to-audio di OpenAI per elaborare l'input e riprodurre l'audio risultante:
async def text_to_audio(text, tone_and_style_instructions):
async with openai.audio.speech.with_streaming_response.create(
model="gpt-4o-mini-tts",
voice="coral",
input=text,
instructions=tone_and_style_instructions,
response_format="pcm",
) as response:
await LocalAudioPlayer().play(response)
Spieghiamo rapidamente cosa abbiamo fatto:
- Specifichiamo i parametri
modelevoiceper controllare la sintesi vocale. Ilmodelusato ègpt-4o-mini-ttse la voce selezionata è "coral". - Il
response_formatè impostato su"pcm", adatto all'elaborazione audio. - Il
LocalAudioPlayerriproduce quindi la risposta audio generata dall'API.
Esegui la funzione
Completiamo lo script con le seguenti righe per fare in modo che la funzione text_to_audio() venga eseguita quando avviamo lo script:
if __name__ == "__main__":
asyncio.run(text_to_audio("Hello world!", "Enthusiastic voice."))
Questo blocco verifica se lo script è il modulo principale in esecuzione ed esegue la funzione text_to_audio() usando asyncio.run() per gestire la logica asincrona.
Con questi passaggi, lo script è pronto a convertire input testuale in voce tramite il servizio text-to-audio di OpenAI. Questo setup ci permette di sperimentare con input e stili diversi, dando vita al testo attraverso il suono.
Possiamo eseguire lo script con il comando:
python text_to_audio.py
Il codice completo è disponibile qui.
Trascrizione audio da file
In questa sezione vediamo come trascrivere un file audio in testo usando lo strumento di trascrizione audio di OpenAI. Il nostro script gestisce i file audio in modo asincrono per rendere il processo efficiente e rapido. Implementeremo questo script in un file chiamato audio_to_text.py.
Gli import e il setup iniziale sono gli stessi di prima, tranne che qui non serve importare LocalAudioPlayer. Ecco come possiamo scrivere una funzione che trascrive un file audio:
async def transcribe_audio(audio_filename = "audio.wav"):
audio_file = await asyncio.to_thread(open, audio_filename, "rb")
stream = await openai.audio.transcriptions.create(
model="gpt-4o-mini-transcribe",
file=audio_file,
response_format="text",
stream=True,
)
transcript = ""
async for event in stream:
if event.type == "transcript.text.delta":
print(event.delta, end="", flush=True)
transcript += event.delta
print()
audio_file.close()
return transcript
Vediamo cosa succede qui:
- Apertura del file audio:
audio_file = await asyncio.to_thread(open, audio_filename, "rb"): apre il file audio in modalità lettura binaria ("rb"). Il metodoasyncio.to_thread()consente di eseguire l'operazione di apertura file in un thread separato, evitando di bloccare il resto del programma.
- Creazione dello stream di trascrizione:
stream = await openai.audio.transcriptions. create(...): questa riga chiama l'API di trascrizione.- Specifichiamo il parametro
modelcomegpt-4o-mini-transcribe, progettato specificamente per la trascrizione. - Il parametro
filecontiene il nostro file audio aperto. response_format="text"indica all'API di restituire la trascrizione come testo.stream=Trueserve per ricevere la trascrizione in tempo reale: appena una parte dell'audio viene elaborata, viene restituita subito, accelerando la risposta.
- Elaborazione dello stream di trascrizione:
async for event in stream: avvia un loop per leggere gli eventi dallo stream di trascrizione man mano che si verificano.if event.type == "transcript.text.delta":: controlla il tipo di evento e lo elabora se è di tipotranscript.text.delta, che indica che una parte della trascrizione è pronta.print(event.delta, end="", flush=True): stampa la trascrizione incrementale non appena è disponibile, garantendo un output in tempo reale.
- Chiusura del file audio:
audio_file.close(): al termine della trascrizione, è buona norma chiudere il file audio per liberare risorse di sistema.
Eseguendo la funzione main(), possiamo convertire un file audio in testo in modo efficiente e in streaming, ottenendo feedback immediato. Questo setup è ideale per applicazioni che richiedono trascrizioni rapide o che coinvolgono file audio lunghi.
Puoi provarlo posizionando un file audio nella stessa cartella dello script, sostituendo audio.wav con il nome del tuo file audio ed eseguendo il comando:
python audio_to_text.py
Il codice completo è disponibile qui.
Trascrizione audio dal microfono
Poiché il nostro obiettivo è creare un assistente vocale, dobbiamo registrare il prompt vocale dell'utente in un file audio.
Creeremo un nuovo file chiamato record.py con una funzione chiamata record_audio. Questa funzione cattura il suono dal microfono e lo salva come file audio. Non entreremo troppo nei dettagli del funzionamento perché non è il focus principale dell'articolo:
import sounddevice as sd
import numpy as np
import scipy.io.wavfile as wavfile
SAMPLE_RATE = 44100 # Sample rate in Hz
def record_audio():
print("[INFO: Recording... Press <Enter> to stop]")
audio_data = [] # Initialize a list to store audio frames
def callback(indata, frames, time, status):
audio_data.append(indata.copy())
with sd.InputStream(samplerate=SAMPLE_RATE, channels=1, callback=callback, dtype='int16'):
input() # Wait for the user to press Enter to stop recording
print("[INFO: Recording complete]")
print()
audio_data = np.concatenate(audio_data) # Concatenate the list into a single array
filename = "output.wav"
wavfile.write(filename, SAMPLE_RATE, audio_data)
return audio_data
Quando chiamiamo questa funzione, inizierà a registrare dal microfono dell'utente. Attende finché l'utente non preme "Invio" e poi salva l'audio in un file con il nome indicato.
Per testarlo, possiamo combinare questa funzione con la funzione di trascrizione vista sopra per trascrivere un messaggio pronunciato dall'utente. Ecco come creare un nuovo file chiamato record_and_transcribe.py per implementarlo:
import asyncio
from audio_to_text import transcribe_audio
from audio_recorder import record_audio
async def main():
record_audio("prompt.wav")
await transcribe_audio("prompt.wav")
if __name__ == "__main__":
asyncio.run(main())
Puoi provarlo eseguendo il comando python record_and_transcribe.py. Lo script registrerà ciò che dici finché non premi "Invio" e poi trascriverà quanto detto.
Costruire un assistente audio
In questa sezione mettiamo tutto insieme per costruire un assistente audio. Lo implementiamo in un nuovo file chiamato audio_assistant.py seguendo questi passaggi:
- Registra il prompt vocale dell'utente usando la funzione
record_audio(). - Converti il prompt audio in testo con la funzione
transcribe_audio(). - Usa un normale modello text-to-text come
gpt-4oper generare una risposta. - Infine, converti la risposta testuale in audio usando la funzione
text_to_audio(). - Ripeti fino a quando l'utente non esce.
Il seguente diagramma lo illustra:

Ti incoraggio a provare a costruirlo da solo prima di proseguire.
Per prima cosa importiamo le funzioni implementate in precedenza e inizializziamo il client OpenAI.
# Import the functions we created
from text_to_audio import text_to_audio
from audio_to_text import transcribe_audio
from audio_recorder import record_audio
# Import other dependencies and initialize OpenAI
import asyncio
from openai import AsyncOpenAI
from dotenv import load_dotenv
load_dotenv()
openai = AsyncOpenAI()
Poi ci serve una funzione per generare la risposta. Usa la normale GPT API di OpenAI con un modello come gpt-4o o un qualsiasi altro modello text-to-text. Se è la tua prima volta, potresti dare un'occhiata a questo tutorial sulla GPT-4o API.
Ecco un'implementazione asincrona di questa funzione:
async def get_answer(prompt):
stream = await openai.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "user", "content": prompt}
],
stream=True,
)
answer = ""
async for chunk in stream:
content = chunk.choices[0].delta.content
if content is not None:
answer += content
print(content, end="", flush=True)
print("\n\n")
return answer
Per implementare il loop principale, seguiamo i passaggi descritti sopra:
async def main(tone_and_style_instructions):
await text_to_audio("Hello, how can I help you today?", tone_and_style_instructions)
while True:
record_audio("prompt.wav")
prompt = await transcribe_audio("prompt.wav")
print()
answer = await get_answer(prompt)
await text_to_audio(answer, tone_and_style_instructions)
Infine, eseguiamo il loop principale quando lo script viene avviato:
if __name__ == "__main__":
tone_and_style_instructions = "Enthusiastic voice."
asyncio.run(main(tone_and_style_instructions))
Ecco una demo in azione:
Il codice completo è disponibile qui.
Miglioramenti futuri
Se proviamo a usare l'assistente con istruzioni complesse su tono e stile, potremmo notare una disconnessione tra le parole e il tono. Ad esempio, considera le seguenti istruzioni per una voce da "Emo Teenager" tratte dal sito di OpenAI:
tone_and_style_instructions = """
Tone: Sarcastic, disinterested, and melancholic, with a hint of passive-aggressiveness.
Emotion: Apathy mixed with reluctant engagement.
Delivery: Monotone with occasional sighs, drawn-out words, and subtle disdain, evoking a classic emo teenager attitude.
"""
Il tono della voce dell'audio rispetterà questo stile, ma il contenuto testuale della risposta generata dalla funzione get_answer() non lo terrà in considerazione, con un po' di incoerenza. Ecco un esempio:
Per superare questo problema, possiamo abbinare al messaggio dell'utente, nella funzione get_answer(), un prompt di sistema che indichi che il testo generato deve seguire le istruzioni di tono e stile.
A tal fine, forniamo le tone_and_style_instructions come secondo argomento della funzione get_answer() e modifichiamo la richiesta di chat aggiungendo un messaggio di sistema:
async def get_answer(prompt, tone_and_style_instructions):
stream = await openai.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
"content":
f"""
The text you generate is being used in a text-to-voice model.
Make sure your answer matches the guidelines {tone_and_style_instructions}
"""
},
{"role": "user", "content": prompt}
],
stream=True,
)
answer = ""
async for chunk in stream:
content = chunk.choices[0].delta.content
if content is not None:
answer += content
print(content, end="", flush=True)
print("\n\n")
return answer
Ecco come risponde ora il modello:
Come puoi vedere, il testo generato ora rispetta le istruzioni di tono. Il codice completo è disponibile qui.
Costruire un assistente con la Agents API
Nel precedente esempio, abbiamo richiesto manualmente i modelli voice-to-text e text-to-voice per costruire un assistente vocale. In questo modo abbiamo imparato a usare esplicitamente i nuovi modelli della voice API di OpenAI.
Tuttavia, se l'obiettivo è creare un assistente vocale, c'è un modo più semplice usando la Agents API. Questa API è stata aggiornata per gestire automaticamente il flusso voice-to-text-to-voice che abbiamo implementato qui.
Se è la tua prima volta con la Agents API, potresti dare un'occhiata a questo tutorial su OpenAI Agents SDK.
Prima di iniziare, dobbiamo installare un'altra dipendenza:
pip install 'openai-agents[voice]'
Fatto questo, iniziamo importando tutto il necessario per eseguire un agent con una voice pipeline:
from dotenv import load_dotenv
load_dotenv()
import asyncio
from agents import Agent
from agents.voice import (
AudioInput,
SingleAgentVoiceWorkflow,
VoicePipeline,
VoicePipelineConfig,
TTSModelSettings,
)
from audio_recorder import record_audio
from audio_player import AudioPlayer
L'AudioPlayer non fa parte di alcun pacchetto. È importato da un file locale e contiene una semplice classe che ci aiuta a riprodurre l'audio in tempo reale. Questo è necessario perché con la VoicePipeline riceveremo l'audio a chunk, e riprodurremo ogni chunk man mano che lo riceviamo. Ecco il contenuto del file audio_player.py:
import numpy as np
import sounddevice as sd
class AudioPlayer:
def __enter__(self):
self.stream = sd.OutputStream(samplerate=24000, channels=1, dtype=np.int16)
self.stream.start()
return self
def __exit__(self, tp, val, tb):
self.stream.close()
def add_audio(self, audio_data):
self.stream.write(audio_data)
Il passo successivo è creare un agent:
agent = Agent(
name="Voice Assistant",
instructions="You’re a helpful assistant speaking to a human.",
model="gpt-4o-mini",
)
Ecco la descrizione dei parametri usati:
name: può essere qualsiasi cosa.instructions: definiscono cosa deve fare l'agent. Funzionano come prompt di sistema.model: il modello usato per generare le risposte.
L'agent svolge il ruolo della funzione get_answer() implementata in precedenza. Pensalo come la parte della pipeline che fornisce una risposta a un prompt testuale.
Poi definiamo la pipeline. Qui specifichiamo tutte le configurazioni relative alla voce:
pipeline = VoicePipeline(
workflow=SingleAgentVoiceWorkflow(agent),
stt_model="gpt-4o-mini-transcribe",
tts_model="gpt-4o-mini-tts",
config=VoicePipelineConfig(
tts_settings=TTSModelSettings(
voice="coral",
instructions="""
Speak in an enthusiastic voice.
"""
)
)
)
Ecco il dettaglio di alcuni parametri:
stt_model: il modello usato per convertire il parlato in testo.tts_model: il modello usato per convertire il testo in parlato.config: fornisce la configurazione della pipeline. Qui la usiamo per specificare la voce che vogliamo usare con iltts_model, oltre alle istruzioni di parlato.
Infine, eseguiamo il loop principale, in modo simile a prima:
async def main():
while True:
audio_input = AudioInput(buffer=record_audio())
result = await pipeline.run(audio_input)
with AudioPlayer() as player:
async for event in result.stream():
if event.type == "voice_stream_event_audio":
player.add_audio(event.data)
if __name__ == "__main__":
asyncio.run(main())
Puoi trovare un'implementazione completa qui.
Aggiungere strumenti
Nota che questo loop continuerà all'infinito, perché non abbiamo specificato una condizione di stop. In esecuzione, dovrai interrompere il processo manualmente. Un modo per implementare lo stop è fornire uno strumento all'agent.
Gli strumenti sono funzioni che forniamo all'agent affinché possa eseguirle per noi. In questo caso, potremmo fornire una funzione che arresta lo script. L'agent usa il nome e il commento della funzione per decidere se chiamarla.
from agents import function_tool
@function_tool
def stop_conversation():
"""Stop the conversation."""
exit()
Poi forniamo lo strumento all'agent:
agent = Agent(
…
tools=[stop_conversation], # Add this line when creating the agent
)
Con questa implementazione, se diciamo “Vorrei interrompere la conversazione”, l'agent capirà che deve chiamare la funzione stop_conversation(). Nota che questa implementazione non uscirà in modo pulito a causa di come è implementata la funzione stop_conversation().
Dai un'occhiata a questo file se vuoi uno script completo.
Usare più agent
Una caratteristica interessante della Agents API è la possibilità di configurare più agent che lavorano insieme. Ecco un esempio tratto dalla documentazione di OpenAI:
from agents.extensions.handoff_prompt import prompt_with_handoff_instructions
spanish_agent = Agent(
name="Spanish voice assistant",
handoff_description="A spanish speaking agent.",
instructions=prompt_with_handoff_instructions(
"You're speaking to a human, so be polite and concise. Speak in Spanish.",
),
model="gpt-4o-mini",
)
agent = Agent(
name="Voice Assistant",
instructions=prompt_with_handoff_instructions("""
You're speaking to a human, so be polite and concise.
If the user speaks in Spanish, handoff to the spanish agent.
"""),
model="gpt-4o-mini",
)
In questo esempio definiamo un secondo agent progettato per parlare spagnolo e modifichiamo il primo agent fornendo un prompt con handoff. Quando le istruzioni di handoff sono soddisfatte, il secondo agent subentra e continua la conversazione.
Lo script completo è disponibile qui.
Conclusione
Usando le funzionalità avanzate dei più recenti modelli audio di OpenAI, abbiamo creato un sistema che può trascrivere efficacemente il parlato in testo e generare una voce naturale a partire da risposte testuali. Questo progetto dimostra non solo il potenziale della tecnologia attuale, ma anche quanto questi strumenti siano diventati accessibili per gli sviluppatori interessati a creare soluzioni IA personalizzate.


