Taper une question et lire la réponse, c'est ainsi que la plupart des applications parlent aujourd'hui à un modèle de langage. Les API temps réel changent cela. OpenAI Realtime et Gemini Live prennent la voix de l'utilisateur au moment où elle est prononcée et répondent avec leur propre voix, assez vite pour tenir une conversation. Y arriver à la main veut dire diffuser de l'audio dans les deux sens, décider quand l'utilisateur a fini de parler, arrêter l'agent quand il est interrompu et exécuter des outils au milieu de tout cela.
sgcWebSockets 2026.10 ajoute TsgcAIVoiceAgent, un composant qui fait tout cela. Il écoute, détecte quand l'utilisateur a fini un tour de parole, répond et appelle vos outils. Il est disponible pour Delphi 7 à 13 et pour .NET.
TsgcAIVoiceAgent en action : détection des tours de parole, interruption, transcriptions en direct et appels d'outils. Également sur YouTube.
Démarrage rapide
Choisissez le fournisseur, définissez la clé API, une voix et les instructions, gérez OnTranscript et appelez Start. Voilà un assistant vocal fonctionnel.
oVoice := TsgcAIVoiceAgent.Create(nil);
oVoice.Provider := vapOpenAI;
oVoice.OpenAIOptions.ApiKey := 'API_KEY';
oVoice.OpenAIOptions.Voice := 'alloy';
oVoice.Instructions := 'You are a friendly assistant. Answer briefly.';
oVoice.OnTranscript := oVoiceTranscript;
oVoice.OnError := oVoiceError;
oVoice.Start;
OnTranscript livre des transcriptions en direct des deux côtés de la conversation, l'utilisateur et l'agent, pour que l'écran puisse suivre ce qui se dit :
procedure TForm1.oVoiceTranscript(Sender: TObject;
aRole: TsgcAIVoiceAgentRole; const aText: string; aFinal: Boolean);
begin
if aFinal then
begin
if aRole = varUser then
Memo1.Lines.Add('You: ' + aText)
else
Memo1.Lines.Add('Agent: ' + aText);
end;
end;
OpenAI Realtime ou Gemini Live, WebSocket ou WebRTC
Deux fournisseurs sont pris en charge, OpenAI Realtime et Gemini Live. Le changement se fait avec une seule propriété et les options correspondantes :
oVoice.Provider := vapGemini;
oVoice.GeminiOptions.ApiKey := 'GEMINI_API_KEY';
oVoice.Start;
La session fonctionne sur WebSocket. Avec OpenAI, elle peut aussi fonctionner sur WebRTC :
oVoice.Provider := vapOpenAI;
oVoice.Transport := vatWebRTC;
oVoice.OpenAIOptions.ApiKey := 'API_KEY';
oVoice.Start;
Audio intégré, ou le vôtre
Sous Windows, Android et iOS, le microphone et le haut-parleur sont intégrés, si bien que le démarrage rapide ci-dessus suffit. Sur toute autre plateforme, ou quand l'audio vient d'ailleurs, désactivez le périphérique. Votre application envoie l'audio avec SendAudio et reçoit la réponse dans OnAudioOutput.
oVoice.Audio.UseDevice := False;
oVoice.Audio.Format := vafPCM16;
oVoice.Audio.SampleRate := 16000;
oVoice.Start;
// ... 20 ms of PCM16 mono at 16 kHz = 640 bytes
SetLength(vChunk, 640);
FillChar(vChunk[0], Length(vChunk), 0);
oVoice.SendAudio(vChunk);
Répondre au téléphone
La téléphonie parle G.711, tout comme l'agent vocal. Réglez le format audio sur mu-law ou A-law à 8 kHz, et les octets d'un appel entrent et sortent directement, sans aucune conversion dans votre code.
oVoice.Provider := vapOpenAI;
oVoice.OpenAIOptions.ApiKey := 'API_KEY';
oVoice.Instructions := 'You answer the phone of a restaurant and take bookings.';
oVoice.Audio.UseDevice := False;
oVoice.Audio.Format := vafG711ULaw;
oVoice.OnAudioOutput := oVoicePhoneAudioOutput;
oVoice.Start;
procedure TForm1.DoPhoneAudioReceived(const aData: TBytes);
begin
// ... G.711 mu-law, 8 kHz, as it arrives from the RTP stream of the call
oVoice.SendAudio(aData);
end;
procedure TForm1.oVoicePhoneAudioOutput(Sender: TObject;
const aData: TBytes);
begin
// ... already G.711 mu-law at 8 kHz: send it back to the caller
SendToPhone(aData);
end;
Détection des tours de parole
La détection des tours de parole décide quand l'utilisateur a fini de parler et que l'agent doit répondre. Il existe quatre modes.
- Server VAD laisse le fournisseur détecter la fin du tour de parole par détection d'activité vocale.
- Semantic VAD écoute ce qui est dit, pas seulement le silence, si bien qu'une pause au milieu d'une phrase ne coupe pas la parole à l'utilisateur.
- Client VAD détecte le tour de parole côté client.
- Manual est un mode presser-pour-parler : votre application décide où se termine le tour de parole.
oVoice.TurnDetection.Mode := vtdServerVAD;
oVoice.TurnDetection.Threshold := 0.6;
oVoice.TurnDetection.PrefixPaddingMs := 300;
oVoice.TurnDetection.SilenceDurationMs := 700;
oVoice.TurnDetection.Mode := vtdSemanticVAD;
oVoice.TurnDetection.Eagerness := 'low';
Avec le mode presser-pour-parler, validez l'audio et demandez une réponse quand l'utilisateur relâche le bouton :
procedure TForm1.btnTalkMouseUp(Sender: TObject);
begin
// ... TurnDetection.Mode is vtdManual
oVoice.CommitAudio;
oVoice.CreateResponse;
end;
Interruption
Les gens interrompent, et un bon agent vocal les laisse faire. Avec l'interruption, quand l'utilisateur commence à parler, l'agent arrête de parler et la réponse est annulée. La réponse est aussi tronquée à ce que l'utilisateur a réellement entendu, de sorte que l'historique de la conversation ne prétend pas que l'agent a dit des mots qui n'ont jamais été joués.
oVoice.BargeIn := True;
oVoice.OnTurnStarted := oVoiceTurnStarted;
oVoice.OnTurnEnded := oVoiceTurnEnded;
oVoice.OnBargeIn := oVoiceBargeIn;
procedure TForm1.oVoiceBargeIn(Sender: TObject);
begin
Memo1.Lines.Add('The user interrupted the agent.');
end;
Outils
Un agent vocal devient utile quand il peut faire des choses. Déclarez un outil avec un nom, une description et un schéma JSON pour ses paramètres, et répondez-y dans OnToolCall.
procedure TForm1.StartWeatherAssistant;
var
oTool: TsgcAIVoiceAgentTool;
begin
oVoice.Provider := vapOpenAI;
oVoice.OpenAIOptions.ApiKey := 'API_KEY';
oVoice.Instructions := 'You are a weather assistant. ' +
'Call get_weather to know the weather of a city before answering.';
oVoice.Tools.Clear;
oTool := oVoice.Tools.Add;
oTool.Name := 'get_weather';
oTool.Description := 'Returns the current weather of a city.';
oTool.Parameters := '{"type":"object","properties":' +
'{"city":{"type":"string","description":"Name of the city"}},' +
'"required":["city"]}';
oVoice.OnToolCall := oVoiceWeatherToolCall;
oVoice.OnTranscript := oVoiceTranscript;
oVoice.Start;
end;
procedure TForm1.oVoiceWeatherToolCall(Sender: TObject;
const aCallId, aName, aArguments: string; var aResult: string;
var aHandled: Boolean);
var
oJSON: TsgcJSON;
vCity: string;
begin
if aName <> 'get_weather' then
Exit; // ... not mine: the MCP client, if any, gets the call
oJSON := TsgcJSON.Create(nil);
Try
oJSON.Read(aArguments);
vCity := '';
if Assigned(oJSON.Node['city']) then
vCity := oJSON.Node['city'].Value;
Finally
oJSON.Free;
End;
// ... replace with a call to your weather service
aResult := '{"city":"' + vCity + '","temperature":21,"sky":"clear"}';
aHandled := True;
end;
Les outils peuvent aussi venir d'un serveur MCP. Affectez un client MCP et ses outils sont proposés à l'agent automatiquement :
oMCP := TsgcWSAPIClient_MCP.Create(nil);
oMCP.MCPOptions.HttpOptions.URL := 'https://localhost:5001/mcp';
oVoice.MCPClient := oMCP;
oVoice.Start;
La démo : un assistant vocal de boutique
La démo Delphi dans Demos\15.AI\02.Applications\09.VoiceAgent est un assistant de boutique à qui vous parlez. Elle fonctionne sur un catalogue de produits tenu dans un TDataSet et donne à l'agent quatre outils : find_products pour chercher dans le catalogue, get_product pour lire un produit, update_stock pour changer le stock, et count_low_stock pour lister les produits qui ont besoin d'être réapprovisionnés. Demandez-lui ce qui vient à manquer, puis dites-lui de réapprovisionner un produit, et regardez la grille changer pendant qu'il répond.
Disponibilité
TsgcAIVoiceAgent arrive dans sgcWebSockets 2026.10, pour Delphi 7 à 13 et pour .NET, dans l'édition Enterprise. Le reste des nouveautés de la version se trouve dans l'article sgcWebSockets 2026.10, et les autres composants d'IA sont sur la page produit IA.
À lire aussi
- Extraction de documents par IA pour Delphi et .NET, également nouveau dans la 2026.10
- Un client Server-Sent Events pour Delphi et .NET
Des questions ou des retours ? Contactez-nous. Vous recevrez une réponse des personnes qui ont écrit le code.
