Aller au contenu principal

Fonctionnalités Speech-to-Speech dans Mastra

Introduction
Lien direct vers Introduction

La fonctionnalité Speech-to-Speech (STS) de Mastra fournit une interface standardisée pour des interactions en temps réel auprès de plusieurs fournisseurs. STS permet une communication audio bidirectionnelle continue en écoutant les événements des modèles Realtime. Contrairement à des opérations TTS et STT séparées, STS maintient une connexion ouverte qui traite la parole continuellement dans les deux directions.

Configuration
Lien direct vers Configuration

  • apiKey : votre clé API OpenAI. Par défaut, la variable d’environnement OPENAI_API_KEY est utilisée.
  • model : l’identifiant du modèle à utiliser pour les interactions vocales en temps réel, par exemple gpt-5.1-realtime.
  • speaker : l’identifiant vocal par défaut pour la synthèse vocale. Vous pouvez indiquer la voix à utiliser pour la sortie vocale.
const voice = new OpenAIRealtimeVoice({
apiKey: 'your-openai-api-key',
model: 'gpt-5.1-realtime',
speaker: 'alloy', // Default voice
})

// If using default settings the configuration can be simplified to:
const voice = new OpenAIRealtimeVoice()

Utiliser STS
Lien direct vers Utiliser STS

import { Agent } from '@mastra/core/agent'
import { OpenAIRealtimeVoice } from '@mastra/voice-openai-realtime'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'

const agent = new Agent({
id: 'agent',
name: 'OpenAI Realtime Agent',
instructions: `You are a helpful assistant with real-time voice capabilities.`,
model: 'openai/gpt-5.6-sol',
voice: new OpenAIRealtimeVoice(),
})

// Connect to the voice service
await agent.voice.connect()

// Listen for agent audio responses
agent.voice.on('speaker', ({ audio }) => {
playAudio(audio)
})

// Initiate the conversation
await agent.voice.speak('How can I help you today?')

// Send continuous audio from the microphone
const micStream = getMicrophoneStream()
await agent.voice.send(micStream)

Pour une présentation plus générale des fournisseurs vocaux associés aux Agents, consultez Voice dans Mastra.

Utiliser des Tools dans des sessions en temps réel
Lien direct vers Utiliser des Tools dans des sessions en temps réel

Les fournisseurs vocaux en temps réel peuvent utiliser les Tools configurés sur l’Agent. Ajoutez les Tools à la définition de Agent, puis connectez-vous et envoyez l’audio via le fournisseur vocal :

import { Agent } from '@mastra/core/agent'
import { OpenAIRealtimeVoice } from '@mastra/voice-openai-realtime'
import { calculate, search } from '../tools'

export const agent = new Agent({
id: 'speech-to-speech-agent',
name: 'Speech-to-Speech Agent',
instructions: 'You are a helpful assistant with speech-to-speech capabilities.',
model: 'openai/gpt-5.6-sol',
tools: {
search,
calculate,
},
voice: new OpenAIRealtimeVoice(),
})

Écouter les événements en temps réel
Lien direct vers Écouter les événements en temps réel

Les fournisseurs vocaux en temps réel émettent des événements que vous pouvez utiliser pour mettre à jour votre interface, lire l’audio de l’assistant, consigner les transcriptions et gérer les erreurs :

agent.voice.on('speaking', ({ audio }) => {
playAudio(audio)
})

agent.voice.on('writing', ({ text, role }) => {
console.log(`${role}: ${text}`)
})

agent.voice.on('error', error => {
console.error('Voice error:', error)
})

Les noms et les charges utiles des événements varient selon le fournisseur. Consultez la section du fournisseur ci-dessous ou sa référence pour obtenir la liste complète des événements.

Instances vocales par session
Lien direct vers Instances vocales par session

Une instance voice statique est partagée entre toutes les requêtes. Cela fonctionne pour une synthèse vocale ponctuelle, mais les fournisseurs en temps réel et Speech-to-Speech stockent l’état de la session, tel que la connexion WebSocket, les Tools, les instructions et le contexte de requête. Si un Agent gère plusieurs sessions actives simultanément, une instance partagée peut permettre à une session d’écraser l’état d’une autre.

Fournissez voice sous forme de résolveur lorsque chaque session active a besoin de sa propre instance vocale. Mastra exécute le résolveur à chaque appel de getVoice() et retourne une nouvelle instance pour ce contexte de requête :

import { Agent } from '@mastra/core/agent'
import { RequestContext } from '@mastra/core/request-context'
import { OpenAIRealtimeVoice } from '@mastra/voice-openai-realtime'

export const agent = new Agent({
id: 'support-line',
name: 'Support Line',
instructions: ({ requestContext }) => `Help user ${requestContext.get('user')}.`,
model: 'openai/gpt-5.6-sol',
voice: ({ requestContext }) =>
new OpenAIRealtimeVoice({
apiKey: requestContext.get('apiKey'),
}),
})

const requestContext = new RequestContext()
requestContext.set('user', 'user-123')
requestContext.set('apiKey', process.env.OPENAI_API_KEY)

const voice = await agent.getVoice({ requestContext })
await voice.connect()

Lorsque vous utilisez un résolveur :

  • Chaque appel à getVoice() retourne une nouvelle instance ; les sessions concurrentes ne partagent donc pas d’état.
  • Mastra n’ajoute pas de Tools ni d’instructions à une instance de résolveur. Configurez-les dans le résolveur ou sur le fournisseur.
  • Vous êtes responsable du cycle de vie de l’instance retournée ; appelez donc disconnect() ou close() lorsque la session se termine.

L’accesseur agent.voice n’a pas de contexte de requête ; il lève donc une erreur lorsque voice est un résolveur. Utilisez plutôt agent.getVoice({ requestContext }).

Google Gemini Live (Realtime)
Lien direct vers Google Gemini Live (Realtime)

import { Agent } from '@mastra/core/agent'
import { GeminiLiveVoice } from '@mastra/voice-google-gemini-live'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'

const agent = new Agent({
id: 'agent',
name: 'Gemini Live Agent',
instructions: 'You are a helpful assistant with real-time voice capabilities.',
// Model used for text generation; voice provider handles realtime audio
model: 'openai/gpt-5.6-sol',
voice: new GeminiLiveVoice({
apiKey: process.env.GOOGLE_API_KEY,
model: 'gemini-2.0-flash-exp',
speaker: 'Puck',
debug: true,
// Vertex AI option:
// vertexAI: true,
// project: 'your-gcp-project',
// location: 'us-central1',
// serviceAccountKeyFile: '/path/to/service-account.json',
}),
})

await agent.voice.connect()

agent.voice.on('speaker', ({ audio }) => {
playAudio(audio)
})

agent.voice.on('writing', ({ role, text }) => {
console.log(`${role}: ${text}`)
})

await agent.voice.speak('How can I help you today?')

const micStream = getMicrophoneStream()
await agent.voice.send(micStream)

Remarque :

  • Live API requiert GOOGLE_API_KEY. Vertex AI requiert le projet, l’emplacement et les identifiants du compte de service.
  • Événements : speaker (flux audio), writing (texte), turnComplete, usage et error.

AWS Nova Sonic (Realtime)
Lien direct vers AWS Nova Sonic (Realtime)

import { Agent } from '@mastra/core/agent'
import { NovaSonicVoice } from '@mastra/voice-aws-nova-sonic'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'

const agent = new Agent({
id: 'agent',
name: 'Nova Sonic Agent',
instructions: 'You are a helpful assistant with real-time voice capabilities.',
// Model used for text generation; voice provider handles realtime audio
model: 'openai/gpt-5.6-sol',
voice: new NovaSonicVoice({
region: 'us-east-1',
speaker: 'matthew',
// Static credentials are optional. The default AWS credential provider
// chain is used when none are passed.
}),
})

await agent.voice.connect()

// Assistant audio is emitted as 16-bit PCM on the `speaking` event
agent.voice.on('speaking', ({ audioData }) => {
if (audioData) playAudio(audioData)
})

agent.voice.on('writing', ({ role, text }) => {
console.log(`${role}: ${text}`)
})

await agent.voice.speak('How can I help you today?')

const micStream = getMicrophoneStream()
await agent.voice.send(micStream)

Remarque :

  • Régions disponibles : us-east-1, us-west-2 et ap-northeast-1.
  • L’authentification passe par la chaîne standard de fournisseurs d’identifiants AWS. Transmettez credentials pour la remplacer.
  • Événements : speaking (audio Int16Array), writing (texte avec generationStage), toolCall, interrupt, turnComplete, usage, session et error.

Inworld Realtime
Lien direct vers Inworld Realtime

import { Agent } from '@mastra/core/agent'
import { InworldRealtimeVoice } from '@mastra/voice-inworld'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'

const agent = new Agent({
id: 'agent',
name: 'Inworld Realtime Agent',
instructions: 'You are a helpful assistant with real-time voice capabilities.',
// Model used for text generation; voice provider handles realtime audio
model: 'openai/gpt-5.6-sol',
voice: new InworldRealtimeVoice({
apiKey: process.env.INWORLD_API_KEY,
model: 'inworld/models/gemma-4-26b-a4b-it',
speaker: 'Sarah',
// Typed Inworld realtime knobs (semantic VAD, playback speed, etc.)
// session: {
// audio: {
// output: { speed: 1.1 },
// input: { turn_detection: { type: 'semantic_vad', eagerness: 'high' } },
// },
// },
}),
})

await agent.voice.connect()

agent.voice.on('speaker', stream => {
playAudio(stream)
})

agent.voice.on('writing', ({ role, text }) => {
console.log(`${role}: ${text}`)
})

await agent.voice.speak('How can I help you today?')

const micStream = getMicrophoneStream()
await agent.voice.send(micStream)

Remarque :

  • Requiert INWORLD_API_KEY. Les clés API Inworld sont préencodées en Basic : collez-les telles quelles.
  • L’URL WebSocket ajoute une valeur ?key=...&protocol=realtime générée par le client. Le modèle est configuré par le session.update initial, et non dans l’URL.
  • Le protocole filaire d’Inworld est la spécification OpenAI Realtime GA ; les noms des événements correspondent donc à ceux de @mastra/voice-openai-realtime.
  • Les réglages Inworld en temps réel typés, notamment le routage de Tools MCP, le niveau d’empressement VAD sémantique, la vitesse de lecture, le modèle de transcription et les modalités de sortie, sont exposés par le champ constructeur session. Une échappatoire providerData non typée est également fusionnée en profondeur pour assurer la compatibilité future avec les nouvelles fonctionnalités Inworld.
  • Événements : speaker (flux audio PCM), speaking (Buffer audio par delta), writing (texte), conversation.item.added, conversation.item.done, function_call.arguments, tool-call-start, tool-call-result et error.