Voice SDK
Le VoiceSDK offre des capacités de conversation vocale avancées avec l'intégration automatique du système de chat et des hooks React pour construire des applications compatibles avec la voix. Créez des interactions vocales naturelles avec des agents IA, complètes avec visualisation audio, transcription et gestion de conversation. Dans cet article, vous trouverez un exemple de démarrage rapide qui vous permettra non seulement de vous lancer rapidement, mais aussi de comprendre comment cela fonctionne. Le reste de l'article détaille les diverses méthodes que vous pouvez utiliser, à quoi elles servent et les meilleures pratiques.
Installation
npm install @odin-ai-staging/sdk @elevenlabs/react
Démarrage rapide
Conversation vocale basique
Dans cet exemple, vous apprendrez comment implémenter des conversations vocales en temps réel en utilisant le VoiceSDK dans les applications TypeScript et React. Vous commencez par initialiser le VoiceSDK avec vos identifiants API, y compris un agentId spécifique qui définit quel agent vocal IA gérera la conversation, puis utilisez startVoiceConversation() pour démarrer une session vocale avec des gestionnaires de rappel qui vous permettent de répondre aux événements de connexion, de recevoir des messages IA, de gérer les déconnexions et de traiter les transcriptions en direct de ce que dit l'utilisateur (isFinal indiquant quand une phrase complète a été reconnue). L'option saveToChat vous permet de persister la conversation vocale en tant que texte dans votre historique de chat pour une référence ultérieure. Pour les applications React, vous utiliserez le hook useVoiceConversation, qui fournit une interface plus propre avec la gestion d'état intégrée : il vous donne une variable status pour suivre l'état de la connexion, les méthodes startSession() et endSession() pour contrôler la conversation, setVolume() pour ajuster les niveaux audio, getInputByteFrequencyData() pour visualiser l'entrée audio (parfait pour créer des affichages de forme d'onde) et conversationState qui contient des informations en temps réel comme les niveaux de volume actuels. Cela vous donne tout ce dont vous avez besoin pour créer des applications vocales compatibles avec l'IA avec reconnaissance et synthèse vocale en temps réel, parfait pour créer des assistants vocaux, des interfaces sans mains ou des expériences conversationnelles d'IA, avec le hook React gérant toute la gestion d'état complexe et les connexions WebSocket pour vous.
import { VoiceSDK } from '@odin-ai-staging/sdk';
// Initialiser le SDK
const voiceSDK = new VoiceSDK({
baseUrl: 'https://your-api-endpoint.com/',
projectId: 'your-project-id',
apiKey: 'your-api-key',
apiSecret: 'your-api-secret',
agentId: 'your-agent-id'
});
// Démarrer une conversation vocale
async function startVoiceChat() {
const sessionId = await voiceSDK.startVoiceConversation({
saveToChat: true,
callbacks: {
onConnect: () => console.log('Voix connectée'),
onMessage: (message) => console.log('Message vocal:', message),
onDisconnect: () => console.log('Voix déconnectée'),
onTranscription: (text, isFinal) => {
if (isFinal) console.log('Utilisateur a dit:', text);
}
}
});
console.log('Session vocale démarrée:', sessionId);
}
Utilisation du hook React
import { useVoiceConversation } from '@odin-ai-staging/sdk';
function VoiceChat() {
const {
status,
startSession,
endSession,
setVolume,
getInputByteFrequencyData,
conversationState
} = useVoiceConversation({
sdkConfig: {
baseUrl: 'https://your-api-endpoint.com/',
projectId: 'your-project-id',
agentId: 'your-agent-id'
},
callbacks: {
onConnect: () => console.log('Connecté !'),
onMessage: (message) => console.log('Message:', message)
}
});
return (
<div>
<button
onClick={() => startSession()}
disabled={status === 'connected'}
>
Démarrer le chat vocal
</button>
<button
onClick={() => endSession()}
disabled={status !== 'connected'}
>
Terminer le chat
</button>
<div>Statut: {status}</div>
<div>Volume: {conversationState.volume}</div>
</div>
);
}
Configuration
Interface VoiceSDKConfig
interface VoiceSDKConfig extends BaseClientConfig {
agentId?: string; // ID d'agent par défaut pour les conversations
defaultVoiceSettings?: VoiceSettings; // Configuration vocale par défaut
}
Paramètres vocaux
interface VoiceSettings {
stability?: number; // Stabilité vocale (0.0 à 1.0)
similarityBoost?: number; // Amplification de similarité vocale (0.0 à 1.0)
style?: number; // Style vocal (0.0 à 1.0)
useSpeakerBoost?: boolean; // Activer l'amplification du haut-parleur
}
Exemple de configuration :
const voiceSDK = new VoiceSDK({
baseUrl: 'https://api.example.com/',
projectId: 'proj_123',
apiKey: 'your-api-key',
apiSecret: 'your-api-secret',
agentId: 'agent_456',
defaultVoiceSettings: {
stability: 0.8,
similarityBoost: 0.7,
style: 0.3,
useSpeakerBoost: true
}
});
Fonctionnalités principales
Sessions de conversation vocale
Le VoiceSDK gère les sessions de conversation vocale avec intégration automatique du chat :
interface VoiceConversationSession {
id: string; // Identifiant de session
chatId?: string; // ID de chat associé
startTime: number; // Horodatage du début de session
endTime?: number; // Horodatage de fin de session
messages: VoiceMessage[]; // Messages vocaux de la session
metadata?: {
agentId?: string;
voiceSettings?: VoiceSettings;
totalDuration?: number;
userInfo?: { name: string; id: string };
};
}
Messages vocaux
interface VoiceMessage {
id: string; // ID du message
type: 'user_speech' | 'ai_speech' | 'system';
text: string; // Texte transcrit/généré
audioUrl?: string; // URL du fichier audio
timestamp: number; // Horodatage du message
duration?: number; // Durée audio en secondes
voiceSettings?: VoiceSettings; // Paramètres vocaux utilisés
saved?: boolean; // Enregistré ou non en base de données
}
Gestion des sessions
startVoiceConversation(options?)
Démarrer une nouvelle session de conversation vocale.
async startVoiceConversation(
options?: StartVoiceConversationOptions
): Promise<string>
Options StartVoiceConversationOptions :
interface StartVoiceConversationOptions {
callbacks?: VoiceConversationCallbacks;
saveToChat?: boolean; // Enregistrement automatique dans l'historique de chat
existingChatId?: string; // Continuer un chat existant
agentId?: string; // Remplacer l'agent par défaut
voiceSettings?: VoiceSettings; // Paramètres vocaux personnalisés
userInfo?: { name: string; id: string };
}
Exemple :
const sessionId = await voiceSDK.startVoiceConversation({
saveToChat: true,
existingChatId: 'chat_123',
voiceSettings: {
stability: 0.9,
similarityBoost: 0.8
},
userInfo: {
name: 'Jean Dupont',
id: 'user_456'
},
callbacks: {
onConnect: () => console.log('Conversation vocale démarrée'),
onMessage: (message) => handleVoiceMessage(message),
onTranscription: (text, isFinal) => {
if (isFinal) displayTranscription(text);
},
onConversationSaved: (chatId, messageId) => {
console.log(`Conversation enregistrée dans le chat ${chatId}`);
}
}
});
endVoiceSession(sessionId, reason?)
Terminer une session de conversation vocale.
async endVoiceSession(sessionId: string, reason?: string): Promise<void>
Exemple :
await voiceSDK.endVoiceSession(sessionId, 'Utilisateur a terminé la conversation');
getVoiceState(sessionId)
Obtenir l'état actuel de la conversation vocale.
getVoiceState(sessionId: string): VoiceConversationState | null
Exemple :
const state = voiceSDK.getVoiceState(sessionId);
if (state) {
console.log('Statut de connexion:', state.connectionStatus);
console.log('Est en train de parler:', state.isSpeaking);
console.log('Volume:', state.volume);
}
Intégration React
Hook useVoiceConversation
Le hook useVoiceConversation fournit l'intégration React avec la gestion d'état :
function useVoiceConversation(options: VoiceHookOptions): {
// Propriétés du hook
status: VoiceStatus;
isSpeaking: boolean;
startSession: (config?: VoiceSessionConfig) => Promise<string>;
endSession: () => Promise<void>;
setVolume: (options: { volume: number }) => void;
// Propriétés SDK améliorées
conversationState: VoiceConversationState;
currentSessionId: string | null;
getInputByteFrequencyData: () => Uint8Array | null;
getOutputByteFrequencyData: () => Uint8Array | null;
}
Exemple React complet :
import React, { useState } from 'react';
import { useVoiceConversation } from '@odin-ai-staging/sdk';
function VoiceConversationComponent() {
const [messages, setMessages] = useState<string[]>([]);
const [isRecording, setIsRecording] = useState(false);
const {
status,
isSpeaking,
startSession,
endSession,
setVolume,
conversationState,
currentSessionId,
getInputByteFrequencyData
} = useVoiceConversation({
sdkConfig: {
baseUrl: process.env.REACT_APP_API_BASE_URL,
projectId: process.env.REACT_APP_PROJECT_ID,
agentId: process.env.REACT_APP_AGENT_ID
},
callbacks: {
onConnect: () => {
console.log('Connecté au chat vocal');
setIsRecording(true);
},
onDisconnect: () => {
console.log('Déconnecté du chat vocal');
setIsRecording(false);
},
onTranscription: (text, isFinal) => {
if (isFinal) {
setMessages(prev => [...prev, `Vous: ${text}`]);
}
},
onMessage: (message) => {
if (message.type === 'ai_speech') {
setMessages(prev => [...prev, `IA: ${message.text}`]);
}
},
onError: (error) => {
console.error('Erreur vocale:', error);
setIsRecording(false);
}
}
});
const handleStartConversation = async () => {
try {
await startSession({
saveToChat: true,
voiceSettings: {
stability: 0.8,
similarityBoost: 0.7
}
});
} catch (error) {
console.error('Impossible de démarrer la conversation:', error);
}
};
const handleEndConversation = async () => {
try {
await endSession();
} catch (error) {
console.error('Impossible de terminer la conversation:', error);
}
};
const handleVolumeChange = (volume: number) => {
setVolume({ volume });
};
return (
<div className="voice-conversation">
<div className="controls">
<button
onClick={handleStartConversation}
disabled={status === 'connected'}
>
Démarrer le chat vocal
</button>
<button
onClick={handleEndConversation}
disabled={status !== 'connected'}
>
Terminer le chat vocal
</button>
</div>
<div className="status">
<div>Statut: {status}</div>
<div>En train de parler: {isSpeaking ? 'Oui' : 'Non'}</div>
<div>Enregistrement: {isRecording ? 'Oui' : 'Non'}</div>
<div>Volume: {conversationState.volume}</div>
</div>
<div className="volume-control">
<label>Volume:</label>
<input
n type="range"
min="0"
max="100"
value={conversationState.volume}
onChange={(e) => handleVolumeChange(parseInt(e.target.value))}
/>
</div>
<div className="messages">
{messages.map((message, index) => (
<div key={index} className="message">
{message}
</div>
))}
</div>
{currentSessionId && (
<AudioVisualizer
getInputData={getInputByteFrequencyData}
isActive={status === 'connected'}
/>
)}
</div>
);
}
Contrôles vocaux
Contrôle du volume
// Définir le volume (0-100)
await voiceSDK.setVolume(sessionId, 75);
Contrôle du microphone
// Désactiver/activer le microphone
await voiceSDK.setMicrophoneMuted(sessionId, true); // Désactiver
await voiceSDK.setMicrophoneMuted(sessionId, false); // Activer
Mises à jour des paramètres vocaux
// Mettre à jour les paramètres vocaux pendant la conversation
await voiceSDK.updateVoiceSettings(sessionId, {
stability: 0.9,
similarityBoost: 0.8,
style: 0.4
});
Visualisation audio
Données audio en temps réel
// Obtenir les données de fréquence audio pour la visualisation
const audioData = voiceSDK.getAudioFrequencyData(sessionId);
if (audioData) {
const inputData = audioData.input; // Entrée audio de l'utilisateur
const outputData = audioData.output; // Sortie audio de l'IA
// Utiliser pour la visualisation audio
renderAudioVisualization(inputData, outputData);
}
Composant de visualisation audio
import React, { useRef, useEffect } from 'react';
interface AudioVisualizerProps {
getInputData: () => Uint8Array | null;
isActive: boolean;
}
function AudioVisualizer({ getInputData, isActive }: AudioVisualizerProps) {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
if (!isActive) return;
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
const animate = () => {
const data = getInputData();
if (data) {
// Effacer le canevas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Dessiner les barres de fréquence
const barWidth = canvas.width / data.length;
for (let i = 0; i < data.length; i++) {
const barHeight = (data[i] / 255) * canvas.height;
ctx.fillStyle = `hsl(${i * 2}, 100%, 50%)`;
ctx.fillRect(
i * barWidth,
canvas.height - barHeight,
barWidth - 1,
barHeight
);
}
}
requestAnimationFrame(animate);
};
animate();
}, [isActive, getInputData]);
return (
<canvas
ref={canvasRef}
width={400}
height={100}
className="audio-visualizer"
/>
);
}
Intégration du chat
Enregistrement automatique du chat
Les conversations vocales peuvent être automatiquement enregistrées dans votre système de chat :
const sessionId = await voiceSDK.startVoiceConversation({
saveToChat: true, // Activer l'enregistrement automatique
existingChatId: 'chat_123', // Optionnel : continuer un chat existant
callbacks: {
onConversationSaved: (chatId, messageId) => {
console.log(`Conversation vocale enregistrée dans le chat ${chatId}`);
// Mettre à jour l'interface utilisateur pour afficher la conversation enregistrée
refreshChatHistory(chatId);
}
}
});
Intégration manuelle du chat
// Obtenir l'historique de conversation à partir de la session vocale
const messages = voiceSDK.getConversationHistory(sessionId);
// Enregistrer dans le chat manuellement
for (const message of messages) {
if (message.type === 'user_speech') {
await chatSDK.sendMessage(message.text, {
chatId: 'chat_123',
metadata: {
voiceMessage: true,
audioUrl: message.audioUrl,
sessionId: sessionId
}
});
}
}
Mises à jour contextuelles
Envoyer du contexte supplémentaire à la conversation vocale :
// Envoyer le contexte de l'historique de chat
await voiceSDK.sendContextualUpdate(
sessionId,
'L\'utilisateur a précédemment posé des questions sur les prix. La conversation actuelle porte sur les fonctionnalités.'
);
Gestion des erreurs
try {
const sessionId = await voiceSDK.startVoiceConversation({
callbacks: {
onError: (error) => {
console.error('Erreur de conversation vocale:', error);
// Gérer les types d'erreur spécifiques
if (error.message.includes('microphone')) {
showMicrophonePermissionDialog();
} else if (error.message.includes('network')) {
showNetworkErrorMessage();
}
},
onDisconnect: (details) => {
console.log('Déconnecté:', details?.reason);
// Gérer différentes raisons de déconnexion
if (details?.reason === 'user_ended') {
showConversationSummary();
} else if (details?.reason === 'error') {
showReconnectOption();
}
}
}
});
} catch (error) {
console.error('Impossible de démarrer la conversation vocale:', error);
if (error.message.includes('agent')) {
showAgentConfigError();
}
}
Exemples
Support client avec voix
import { VoiceSDK, ChatSDK } from '@odin-ai-staging/sdk';
class VoiceCustomerSupport {
private voiceSDK: VoiceSDK;
private chatSDK: ChatSDK;
private activeSession?: string;
constructor() {
const config = {
baseUrl: process.env.API_BASE_URL,
projectId: process.env.PROJECT_ID,
apiKey: process.env.API_KEY,
apiSecret: process.env.API_SECRET,
};
this.voiceSDK = new VoiceSDK(config);
this.chatSDK = new ChatSDK(config);
}
async startSupportSession(customerId: string, issueType: string) {
try {
// Créer un nouveau chat pour cette session de support
const chat = await this.chatSDK.createChat(
`Support vocal - ${issueType}`,
[] // Pourrait ajouter des clés de document pertinentes en fonction du type de problème
);
// Démarrer la conversation vocale
this.activeSession = await this.voiceSDK.startVoiceConversation({
saveToChat: true,
existingChatId: chat.chat_id,
agentId: this.getAgentForIssueType(issueType),
userInfo: {
name: `Client ${customerId}`,
id: customerId
},
callbacks: {
onConnect: () => {
console.log('Session de support démarrée');
this.logSupportEvent('session_started', { customerId, issueType });
},
onTranscription: (text, isFinal) => {
if (isFinal) {
this.logSupportEvent('customer_spoke', {
customerId,
text: text.substring(0, 100) // Enregistrer les 100 premiers caractères
});
}
},
onMessage: (message) => {
if (message.type === 'ai_speech') {
this.logSupportEvent('agent_responded', {
customerId,
responseLength: message.text.length
});
}
},
onConversationSaved: (chatId, messageId) => {
console.log(`Conversation de support enregistrée dans le chat ${chatId}`);
},
onDisconnect: (details) => {
this.logSupportEvent('session_ended', {
customerId,
reason: details?.reason,
duration: this.getSessionDuration()
});
}
}
});
return {
sessionId: this.activeSession,
chatId: chat.chat_id
};
} catch (error) {
console.error('Impossible de démarrer la session de support:', error);
throw error;
}
}
async endSupportSession() {
if (this.activeSession) {
await this.voiceSDK.endVoiceSession(this.activeSession);
this.activeSession = undefined;
}
}
private getAgentForIssueType(issueType: string): string {
const agentMap = {
'technical': 'agent_technical_support',
'billing': 'agent_billing_support',
'general': 'agent_general_support'
};
return agentMap[issueType] || agentMap['general'];
}
private logSupportEvent(event: string, data: any) {
console.log(`Événement de support: ${event}`, data);
// Envoyer vers votre système d'analyse/journalisation
}
private getSessionDuration(): number {
// Calculer la durée de la session
return 0; // Espace réservé
}
}
Meilleures pratiques
Gestion des erreurs et solutions de secours
const voiceSupport = {
async startWithFallback() {
try {
return await this.voiceSDK.startVoiceConversation(options);
} catch (error) {
console.warn('Voix échouée, utilisation du chat texte comme solution de secours:', error);
// Solution de secours : chat texte uniquement
return await this.chatSDK.createChat('Chat support (texte)');
}
}
};
Gestion des ressources
class VoiceManager {
private activeSessions = new Set<string>();
async startSession(options: any) {
const sessionId = await this.voiceSDK.startVoiceConversation(options);
this.activeSessions.add(sessionId);
return sessionId;
}
async cleanup() {
// Terminer toutes les sessions actives
for (const sessionId of this.activeSessions) {
try {
await this.voiceSDK.endVoiceSession(sessionId);
} catch (error) {
console.warn('Impossible de terminer la session:', sessionId, error);
}
}
this.activeSessions.clear();
}
}
Optimisation des performances
// Utiliser React.memo pour les composants de visualisation audio
const AudioVisualizer = React.memo(({ getInputData, isActive }) => {
// Ralentir les mises à jour d'animation
const throttledAnimate = useCallback(
throttle(() => {
// Logique d'animation
}, 16), // ~60fps
[]
);
// ... logique du composant
});
Accessibilité
function VoiceAccessibleChat() {
const [transcript, setTranscript] = useState('');
const { startSession } = useVoiceConversation({
callbacks: {
onTranscription: (text, isFinal) => {
setTranscript(text);
// Mettre à jour le lecteur d'écran
if (isFinal) {
announceToScreenReader(`Vous avez dit: ${text}`);
}
}
}
});
return (
<div>
<button
aria-label="Démarrer la conversation vocale"
onClick={startSession}
>
🎤 Démarrer le chat vocal
</button>
<div
aria-live="polite"
aria-label="Transcription vocale"
>
{transcript}
</div>
</div>
);
}