OpenAI Realtime API: Echtzeit-Unterhaltungen mit Sprachmodellen | heise online

OpenAI Realtime API: Echtzeit-Unterhaltungen mit Sprachmodellen

Die OpenAI Realtime API ermöglicht natürlich wirkende, dynamische Gespräche mit großen Sprachmodellen. Ein Beispiel mit Node.js zeigt sie in Aktion.

vorlesen Druckansicht 5 Kommentare lesen
Kommunikation zwischen LLM und Mensch

(Bild: erzeugt mit Dalle-E durch iX)

Lesezeit: 14 Min.
Von
  • Marius Obert
Inhaltsverzeichnis

Chat-Unterhaltungen mit KI haben revolutioniert, wie Menschen mit Maschinen interagieren. Tools wie ChatGPT haben gezeigt, wie mächtig textbasierte Kommunikation sein kann – sie sind schnell, präzise und für alle zugänglich. Doch Sprache ist weit mehr als nur Worte auf einem Bildschirm. Unsere Stimmen tragen Emotionen, Nuancen und Tonalitäten, die in einem bloßen Textfeld oft verloren gehen. Vom freundlichen Lächeln im Tonfall bis hin zur Dringlichkeit in einer betonten Phrase: Stimme und Sprache bringen eine Tiefe in die Kommunikation, die ein reiner Textprompt nicht leisten kann.

Die OpenAI Realtime API (Beta) eröffnet neue Möglichkeiten, über die klassischen Chatbots hinauszugehen. Sie ermöglicht das Streaming von Text in Echtzeit sowie das Einbinden von Spracherkennung, Sprachsynthese und dynamischen Konversationsflüssen. Damit können Entwicklerinnen und Entwickler KI-Erlebnisse schaffen, die nicht nur intelligent, sondern auch menschlich wirken.

Marius Obert
Marius Obert

Marius Obert baut gerne Prototypen mit den neuesten Cloud-Technologien und spricht noch lieber darüber. Seine Karriere startete in der UI-Entwicklung im sonnigen Kalifornien. Während dieser Zeit lernte er Webtechnologien wie JavaScript im Allgemeinen und das gesamte Node.js-Ökosystem im Speziellen zu lieben.

Dadurch erschließen sich neue Anwendungsfelder. Naheliegend ist der Einsatz bei Telefonaten. Besonders in Callcentern und der Kundenkommunikation besitzt diese Technologie enormes Potenzial. KI-Systeme können hier nicht nur Routinefragen beantworten, sondern auch komplexe Anliegen analysieren, passende Antworten generieren und die Interaktion durch natürliches Sprechen optimieren. Und für den Fall, dass die KI wegen mangelnder Trainingsdaten mal nicht weiterweiß, lassen sich firmeninterne Datenquellen anbinden.

Im Folgenden wird gezeigt, wie man die Beta-Version der OpenAI Realtime API mit einer privaten API zur Preisfindung verknüpfen und per Telefonanruf für jeden zugänglich machen kann. Der Artikel beleuchtet die technischen Grundlagen dieser Integration, die Herausforderungen und Vorteile in der Praxis und wie diese Technologie die Zukunft der Kundenkommunikation transformieren kann.

Videos by heise

Noch zu Beginn des Jahres 2024 mussten Entwickler Text-to-Speech (TTS), Speech-to-Text (STT) und Large Language Models (LLMs) mühsam selbst kombinieren, um Sprach-KI-Anwendungen zu erstellen. Das brachte zahlreiche technische Herausforderungen mit sich, vor allem in Bezug auf Latenz und Wartezeiten. Eine kleine Unterbrechung von nur wenigen Sekunden zwischen Frage und Antwort kann ein Gespräch schnell unnatürlich wirken lassen.

Im Mai 2024 überraschte OpenAI die Entwickler-Community mit einer beeindruckenden Demo der GPT-4o Realtime Translation. Das System zeigte, wie Spracheingaben in Echtzeit verarbeitet, übersetzt und ausgegeben werden konnten – ohne merkliche Verzögerung. Plötzlich war klar: Eine robuste Echtzeitlösung für Sprache und Text war in greifbarer Nähe und die Erwartungen in der Community wuchsen. Danach wurde es aber erstmal einige Monate ruhig um das Thema. Am 1. Oktober 2024 brachte OpenAI dann die lang ersehnte Beta-Version der Realtime API auf den Markt. Mit dieser API wird die Vision, Sprache, Text und KI nahtlos zu verknüpfen, zur Realität. Die Realtime API bietet integrierte Funktionen für:

  • Spracherkennung (STT): Direkte Transkription von gesprochenem Text mit hoher Genauigkeit.
  • Echtzeit-Textverarbeitung: Verwendung der leistungsstarken GPT-4-Modelle für die Verarbeitung und Generierung von Text.
  • Sprachsynthese (TTS): Umwandlung von Antworten in menschlich klingende Sprache.

Die API ist speziell darauf ausgelegt, Latenzen zu minimieren und ein flüssiges Gesprächserlebnis zu ermöglichen – ein entscheidender Fortschritt für den Einsatz von KI in Anwendungen wie Telefonservices, virtuellen Assistenten oder Echtzeitübersetzungen. Aktuell kostet die API zwischen 10 und 100 US-Dollar pro 1 Million Audiotoken, je nach zugrundeliegendem Modell und dessen Version. Das entspricht laut OpenAI rund 0,006 beziehungsweise 0,06 US-Dollar pro gesprochener Minute. Hinzu kommen, je nach Anbieter, etwa 0,01 US-Dollar pro Minute für die Kommunikation per Telefon.

Um das volle Potenzial der API auszuschöpfen, hilft es, deren Architektur und zentrale Mechanismen zu verstehen (siehe Abbildung 1):

Eine Konversation (Session) besteht aus mehreren "Conversation Items", die von beiden Gesprächsteilnehmern stammen können (Abb. 1).

(Bild: OpenAI)

Die API strukturiert jede Konversation in sogenannte Conversation Items. Diese repräsentieren Einheiten im Dialog, wie eine Benutzereingabe, eine KI-Antwort oder Zwischenergebnisse. Entwicklerinnen und Entwickler können Items gezielt bearbeiten, etwa um den Verlauf einer Konversation zu ändern, irrelevante Teile zu entfernen oder Antworten neu zu formulieren. Das erleichtert die Steuerung komplexer Dialoge erheblich. Die API-Referenz enthält eine vollständige Liste mit allen Conversation Items. Nachfolgend kommen die für diesen Artikel relevanten zur Sprache.

Für natürliche Sprachinteraktionen ist die Turn Detection essenziell. Die API nutzt eine Voice Activity Detection (VAD), um Sprachpausen und Satzenden zu erkennen. Dadurch kann die KI zuverlässig bestimmen, wann das Gegenüber fertig gesprochen hat und sie mit ihrer Antwort beginnen soll. Das sorgt für flüssige Dialoge, ohne dass Nutzer explizite Eingabebefehle geben müssen. Entwickler können VAD-Parameter anpassen, um das Verhalten für spezifische Szenarien wie längere Antworten oder schnellere Reaktionen zu optimieren. Ist der Parameter ausgeschaltet, wartet die KI mit der Antwort, bis sie mittels Conversation Item dazu aufgefordert wird.

Manchmal ist es auch notwendig, eine laufende Konversation zu unterbrechen, etwa wenn der Nutzer oder die Nutzerin eine Aussage korrigieren möchte. Hierfür bietet die API das Item Truncate, mit dem Entwickler den aktuellen Konversationsfluss abbrechen und durch eine neue Eingabe ersetzen können. Das ermöglicht es, flexibel auf Nutzerwünsche einzugehen, ohne den Kontext der gesamten Sitzung zu verlieren.

Ein weiterer Schlüsselmechanismus ist Function Calling, der es der KI ermöglicht, während einer Konversation auf vordefinierte Funktionen zuzugreifen. Dies ist besonders nützlich, wenn die Anwendung zusätzliche Daten aus externen Quellen abrufen, Berechnungen durchführen oder Systeme steuern soll. Entwickler müssen diese Funktionen in ihrer Anwendung definieren und sicherstellen, dass die API korrekt auf sie zugreifen kann, um nahtlose Interaktionen zu gewährleisten.

Die API beinhaltet zudem ein integriertes Moderationssystem, das unerwünschte Inhalte automatisch erkennen kann und damit sichere und regelkonforme Anwendungen ermöglicht. Wenn eine Antwort blockiert wird, können Entwickler mithilfe von Response.cancel die Ausgabe sofort abbrechen und so den Dialog kontrolliert fortsetzen.

Schließlich spielt der Parameter Temperatur eine wichtige Rolle bei der Anpassung des Verhaltens der KI. Wie bei der Chatvariante ChatGPT beeinflusst diese Einstellung, wie kreativ oder deterministisch die Antworten des Modells ausfallen. Für strukturierte und präzise Antworten eignet sich ein Minimalwert (aktuell bei 0,6), während höhere Werte kreativere, aber potenziell unvorhersehbare Reaktionen hervorrufen. Entwickler sollten die Temperatur sorgfältig anpassen, um das Modell an die jeweiligen Anforderungen ihres Anwendungsfalls anzupassen.

Um die API besser kennenzulernen, empfiehlt es sich, die OpenAI Realtime Console von GitHub zu klonen und lokal auszuführen (siehe Abbildung 2). Dieses Tool ermöglicht es, Funktionsweisen der API in einer interaktiven Umgebung zu testen, die unterschiedlichen Events in Echtzeit zu beobachten und die Mechanismen hinter der API besser zu verstehen. Ansonsten kommt die Konsole mit zwei vorgefertigten Tools, die speziell dafür entwickelt wurden, um Function Calling auszuprobieren und dessen Integration in eigene Anwendungen zu erleichtern. Diese praktische Testumgebung ist der ideale Einstieg, um die API effizient zu nutzen.

Die Realtime Console eignet sich hervorragend, um die API lokal zu testen (Abb. 2).

(Bild: Screenshot (Marius Obert))

Es folgt ein vollständiges Beispiel für die Nutzung der OpenAI Realtime API mit Node.js. Die API wird mit einer Kommunikationsplattform, auch Communication-Platform-as-a-Service (CPaas) genannt, integriert, um eingehende Anrufe in Echtzeit von einer KI beantworten zu lassen. Solche Anbieter sind beispielsweise Twilio, Vonage oder Infobip. Dieses praktische Beispiel zeigt, wie Sprache als Schnittstelle genutzt werden kann, um intelligente KI-Systeme mit bewährten Kommunikationsmitteln wie Telefonie zu kombinieren.

Warum WebSockets?

Traditionelle APIs basieren auf HTTP-Anfragen, die eine Anfrage senden und auf eine Antwort warten. Für Echtzeitanwendungen wie Telefonie ist diese Methode jedoch ungeeignet, da sie Latenzzeiten erzeugt und keine kontinuierliche Datenübertragung unterstützt. Hier kommen WebSockets ins Spiel.

WebSockets sind bidirektionale Kommunikationskanäle, die es ermöglichen, Datenströme zwischen einem Server und einem Client offenzuhalten. Dadurch lassen sich kontinuierlich Daten – wie Audio- oder Textinhalte – in Echtzeit übertragen. Das vorliegende Beispiel verbindet zwei WebSocket-Kanäle miteinander: einen zwischen Twilio und Server und einen zwischen Server und OpenAI-API. Diese Struktur sorgt für eine nahtlose, latenzarme Kommunikation.

Im ersten Abschnitt des Codes werden die benötigten Abhängigkeiten importiert. Hierbei handelt es sich um:

  • Fastify als Webframework
  • Zusätzliche Fastify-Plug-ins für Formulardaten und WebSocket-Funktionalität
  • WebSocket für die bidirektionale Kommunikation
  • dotenv zum Laden von Umgebungsvariablen
import Fastify from 'fastify';
import fastifyFormBody from '@fastify/formbody';
import fastifyWs from '@fastify/websocket';
import WebSocket from 'ws';
import dotenv from 'dotenv';

Der API-Schlüssel für OpenAI wird als Umgebungsvariable aus einer .env-Datei geladen. Falls sie fehlt, wird das Programm mit einer Fehlermeldung beendet. Dies stellt sicher, dass der Server nur mit den korrekten Konfigurationsdaten startet.

// Lese Umgebungsvariablen aus einer .env-Datei
dotenv.config();

const { OPENAI_API_KEY } = process.env;

if (!OPENAI_API_KEY) {
   console.error('Fehlende Umgebungsvariable. Bitte definieren Sie diese in einer .env-Datei.');
   process.exit(1);
}

Die Route /incoming-call wird bei einem eingehenden Anruf an die verwendete Nummer angerufen. Die verwendete Kommunikationsplattform sendet Anrufinformationen an diese URL. Der Server antwortet mit einem TwiML-Dokument, das den Anruf steuert:

  • Eine Begrüßungsnachricht wird über <Say> abgespielt.
  • Der Anruf wird an einen WebSocket-Stream weitergeleitet, der an die Route /media-stream angebunden ist.

Die Konfiguration des Streams erfolgt über <Stream>-Tags und kann optionale Parameter wie die Anrufer-ID enthalten.

// Initisalisiere Fastify-Server
const fastify = Fastify();
fastify.register(fastifyFormBody);
fastify.register(fastifyWs);

fastify.all('/incoming-call', async (request, reply) => {
   const twimlResponse = `<?xml version="1.0" encoding="UTF-8"?>
                         <Response>
                         <Say language="de-De">Viel Spaß beim Testen des Sprachassistenten!</Say>
                             <Connect>
                                 <Stream url="wss://${request.headers.host}/media-stream"/>
                             </Connect>
                         </Response>`;

   reply.type('text/xml').send(twimlResponse);
});

Die Route /media-stream ist das Herzstück des Programms. Sie verarbeitet die WebSocket-Verbindung zwischen Twilio und dem Server und leitet Daten von Twilio zu OpenAI weiter. Beim Aufbau dieser Verbindung geschieht Folgendes:

Nachdem die Variablen für die Sitzungsdefinition definiert sind, initialisiert das Programm eine zweite WebSocket-Verbindung zur OpenAI Realtime API. Anschließend erfolgt die Konfiguration der WebSocket-Verbindungen zu OpenAI und Twilio. Dabei wird sichergestellt, dass Sitzungen beim Aufbau der Verbindung initialisiert und eingehende Nachrichten aus beiden Quellen korrekt verarbeitet werden.

Zusätzlich protokollieren die eingerichteten Handler Verbindungsabbrüche oder Fehler und schließen bei Bedarf die jeweilige Verbindung. Da sich die API noch im Beta-Status befindet, wird direkt mit WebSockets gearbeitet, um Nachrichten zu senden und zu empfangen. OpenAI arbeitet bereits an einem SDK, das die Verarbeitung der Events abstrahieren soll. Dieses SDK ist jedoch derzeit noch nicht über npm verfügbar und lässt sich ausschließlich via GitHub herunterladen.

// WebSocket-Route für die WebSocket-Verbindung zwischen Twilio und OpenAI
fastify.register(async (fastify) => {
   fastify.get('/media-stream', { websocket: true }, (twilioWs, req) => {
       console.log('Anrufer verbunden');

       // Zustandsvariablen
       let streamSid = null, lastAssistantItem = null,
           responseStartTimestampTwilio = null,
           latestMediaTimestamp = 0, markQueue = [];

       const openAiWs = new WebSocket('wss://api.openai.com/v1/realtime?model=gpt-4o-mini-realtime-preview-2024-12-17', {
           headers: {
               Authorization: `Bearer ${OPENAI_API_KEY}`,
               "OpenAI-Beta": "realtime=v1"
           }
       });

       openAiWs.on('open', initialisiereOpenAiSession);
       openAiWs.on('message', verarbeiteOpenAiNachrichten);
       openAiWs.on('close', () => {
           console.log('Disconnected from the OpenAI Realtime API');
       });
       openAiWs.on('error', (error) => {
           console.error('Error in the OpenAI WebSocket:', error);
       });
       twilioWs.on('message', verarbeiteAnruferNachrichten);
       twilioWs.on('close', () => {
           if (openAiWs.readyState === WebSocket.OPEN) openAiWs.close();
           console.log('Client disconnected.');
       });


       function initialisiereOpenAiSession() {
           console.log('Verbunden mit der OpenAI Realtime API');
           …
       };

       function verarbeiteAnruferNachrichten(message) {
           …
       };

       // Liste der Ereignistypen, die protokolliert werden sollen. Vergleiche mit der OpenAI-Dokumentation https://platform.openai.com/docs/api-reference/realtime
       const LOG_EVENT_TYPES = [
           'error',
           "conversation.item.created",
           "response.function_call_arguments.done",
       ];
       function verarbeiteOpenAiNachrichten(data) {
          …
       };

   });
});

Dieser Abschnitt konfiguriert die Sitzung mit der OpenAI Realtime API, um den Austausch von Audiostreams und Textnachrichten zu ermöglichen:

  • Die Audiostream-Einstellungen input_audio_format und output_audio_format stellen sicher, dass die Daten für die Telefonübertragung geeignet sind.
  • Spezifische Instruktionen für den Sprachassistenten sorgen für knappe und hilfreiche Antworten.
  • Eine bereitgestellte Preisberechnung für Reisen dient als Beispiel für zusätzliche Funktionen.
  • Das erste Gesprächselement des Benutzers ("Hallo") wird an die API gesendet, um die Konversation zu starten.
  • Die KI wird angewiesen, direkt nach der Initialisierung zu antworten, um das Gespräch dynamisch fortzusetzen.
       function initialisiereOpenAiSession() {
           console.log('Verbunden mit der OpenAI Realtime API');
           const sessionUpdate = {
               type: 'session.update',
               session: {
                   turn_detection: { type: 'server_vad' },
                   input_audio_format: 'g711_ulaw',
                   output_audio_format: 'g711_ulaw',
                   voice: "alloy",
                   instructions: "Du bist ein hilfsbereiter Sprachassistent, der Fragen kurz und bündig beantwortet, ohne viel zu reden.",
                   modalities: ["text", "audio"],
                   temperature: 0.6,
                   tools: [
                       {
                           "name": "bewerte_reise_preis",
                           "description": "Falls der User nach dem Preis der Reise fragt, nutze diese Funktion, um den Preis zu berechnen.",
                           "type": "function",
                           "parameters": {
                               "type": "object",
                               "properties": {
                                   "start": {
                                       "type": "string",
                                       "description": "Ort, von dem die Reise startet"
                                   },
                                   "ziel": {
                                       "type": "string",
                                       "description": "Ort, an dem die Reise endet"
                                   },
                                   "verkehrsmittel": {
                                       "type": "string",
                                       "description": "Verkehrsmittel für die Reise"
                                   },
                                   "dauer": {
                                       "type": "integer",
                                       "description": "Dauer der Reise in Minuten"
                                   }
                               },
                               "additionalProperties": false,
                               "required": [
                                   "start",
                                   "ziel",
                                   "verkehrsmittel",
                                   "dauer",
                               ]
                           }
                       }
                   ],
               },
           };
           const initialConversationItem = {
               type: 'conversation.item.create',
               item: {
                   type: 'message',
                   role: 'user',
                   content: [
                       {
                           type: 'input_text',
                           text: 'Hallo'
                       }
                   ]
               }
           };


           // Initialisiere die Sitzung mit OpenAI
           openAiWs.send(JSON.stringify(sessionUpdate));
           // Sende das erste Konversationselement an OpenAI
           openAiWs.send(JSON.stringify(initialConversationItem));
           // Lasse die KI als Erstes antworten
           openAiWs.send(JSON.stringify({ type: 'response.create' }));
       };

In diesem Abschnitt wird der Audiostream des Anrufers verarbeitet:

  • Eingehende Audiodaten von der CPaaS leitet das Programm an die OpenAI-API.
  • Zustandsvariablen wie der Zeitstempel der letzten Audioübertragung werden aktualisiert, um die KI-Antwort dynamisch anpassen zu können, beispielsweise durch Abbruch der Antwort, falls der Anrufer sie unterbricht.
       function verarbeiteAnruferNachrichten(message) {
           try {
               const data = JSON.parse(message);

               switch (data.event) {
                   case 'media':
                       latestMediaTimestamp = data.media.timestamp;
                       if (openAiWs.readyState === WebSocket.OPEN) {
                           const audioAppend = {
                               type: 'input_audio_buffer.append',
                               audio: data.media.payload
                           };
                           openAiWs.send(JSON.stringify(audioAppend));
                       }
                       break;
                   case 'start':
                       streamSid = data.start.streamSid;
                       console.log('Beginn des Anruferstreams', streamSid);

                       // Zurücksetzen der Zustandsvariablen
                       responseStartTimestampTwilio = null;
                       latestMediaTimestamp = 0;
                       break;
                   case 'mark':
                       if (markQueue.length > 0) {
                           markQueue.shift();
                       }
                       break;
                   default:
                       break;
               }
           } catch (error) {
               console.error('Error parsing message:', error, 'Message:', message);
           }
       };

Hier geschieht die Verarbeitung der Interaktionen zwischen der Kommunikationsplattform, der KI und potenziellen Funktionen:

  • Logging bestimmter Konversationsereignisse (zum Beispiel eine Antwort der KI oder ein Funktionsaufruf), um die Verarbeitung nachzuvollziehen.
  • Weiterleiten der Audioantworten der KI an den Anruf-Stream und entsprechende Markierung, um ihre Verarbeitung zu optimieren.
  • Bei einem Funktionsaufruf, wie der Berechnung eines Reisepreises, wird dieser ausgeführt, das Ergebnis an OpenAI zurückgesendet und anschließend die Antwort der KI erstellt.
  • Wenn OpenAI erkennt, dass der Benutzer zu sprechen beginnt, bricht die KI-Antwort umgehend ab, um einen natürlichen Gesprächsfluss zu gewährleisten.

Diese Mechanismen sorgen für eine robuste Echtzeitkommunikation zwischen den beteiligten Komponenten und bieten die Grundlage für die Integration zusätzlicher Funktionen.

       function verarbeiteOpenAiNachrichten(data) {
           try {
               const response = JSON.parse(data);

               if (LOG_EVENT_TYPES.includes(response.type)) {
                   console.log(`Received event: ${response.type}`, response);
               }

               // Leite das Audio-Delta von OpenAI an Twilio weiter
               if (response.type === 'response.audio.delta' && response.delta) {
                   const audioDelta = {
                       event: 'media',
                       streamSid: streamSid,
                       media: { payload: response.delta }
                   };
                   twilioWs.send(JSON.stringify(audioDelta));

                   // Markiere den aktuellen Zeitpunkt im Stream, damit wir wissen, wann die Antwort abgeschnitten werden soll
                   if (!responseStartTimestampTwilio) {
                       responseStartTimestampTwilio = latestMediaTimestamp;
                   }
                   if (response.item_id) {
                       lastAssistantItem = response.item_id;
                   }
                   if (streamSid) {
                       const markEvent = {
                           event: 'mark',
                           streamSid: streamSid,
                           mark: { name: 'responsePart' }
                       };
                       twilioWs.send(JSON.stringify(markEvent));
                       markQueue.push('responsePart');
                   }
               }

               // Wenn die Spracherkennung von OpenAI beginnt, dann schneide die vorherige Antwort ab
               if (response.type === 'input_audio_buffer.speech_started') {
                   if (markQueue.length > 0 && responseStartTimestampTwilio != null) {
                       const elapsedTime = latestMediaTimestamp - responseStartTimestampTwilio;

                       if (lastAssistantItem) {
                           const truncateEvent = {
                               type: 'conversation.item.truncate',
                               item_id: lastAssistantItem,
                               content_index: 0,
                               audio_end_ms: elapsedTime
                           };
                           openAiWs.send(JSON.stringify(truncateEvent));
                       }

                       twilioWs.send(JSON.stringify({
                           event: 'clear',
                           streamSid: streamSid
                       }));

                       // Reset
                       markQueue = [];
                       lastAssistantItem = null;
                       responseStartTimestampTwilio = null;
                   }
               }

               if (response.type === 'response.function_call_arguments.done') {
                   const { start, ziel, verkehrsmittel, dauer } = JSON.parse(response.arguments);

                   const preis = Math.round(Math.random() * 10 * dauer);

                   console.log(`Der zufällige Preis für die Reise von ${start} nach ${ziel} mit ${verkehrsmittel} beträgt ${preis}€`);

                   openAiWs.send(JSON.stringify({
                       type: 'conversation.item.create',
                       item: {
                           type: 'function_call_output',
                           call_id: response.call_id,
                           output: JSON.stringify({ preis }),
                       }
                   }));
                   // Damit die KI weiter antwortet
                   openAiWs.send(JSON.stringify({ type: 'response.create' }));
               }

           } catch (error) {
               console.error('Fehlermeldung der OpenAI Realtime API:', error, 'Raw message:', data);
           }
       };
fastify.listen({ port: 3000 }, (err) => {
   if (err) {
       console.error(err);
       process.exit(1);
   }
   console.log(`Server gestartet`);
});

Bevor man das Programm ausführen kann, sind alle benötigten Abhängigkeiten zu installieren. Daher ist sicherzustellen, dass Node.js und npm auf dem System verfügbar sind. Dann navigiert man im Terminal in das Verzeichnis der Datei und führt die folgenden Befehle aus:

npm fastify ws dotenv @fastify/formbody @fastify/websocket

node ki-hotline.js

Sobald der Server gestartet ist, wird er auf Port 3000 lauschen.

Damit die CPaas Anfragen an unseren Server senden kann, ist eine öffentliche URL notwendig. Hier bietet sich ngrok an, ein Tool zur einfachen Erstellung von sicheren Tunneln zu lokalen Servern. Man kann nun ngrok installieren und es mit dem folgenden Befehl starten:

ngrok http 3000

ngrok generiert eine öffentliche URL (zum Beispiel https://abcdef.ngrok.io).

Dann meldet man sich in der CPaaS-Konsole an und geht zu den Einstellungen der eigenen Telefonnummer (Phone Numbers -> Manage -> Active Numbers). Dort lässt sich die kostenlos bereitgestellte Rufnummer verwenden und darauf klicken. Im Abschnitt Voice Configuration -> A Call comes in kann man, wie in Abbildung 3 zu sehen, die Webhook-URL eingeben:

  • Voice configuration: Setzen Sie die URL auf https://abcdef.ngrok.io/incoming-call.
  • Wählen Sie als Methode HTTP POST.

Die Konfiguration der Telefonnummer zum lokalen Programm (Abb. 3)

(Bild: Screenshot (Marius Obert))

Nach der Konfiguration leitet Twilio eingehende Anrufe an den lokalen Server weiter. Man kann nun Anrufe tätigen und den Sprachassistenten in Aktion erleben.

Mit diesen Schritten ist es möglich, die Verbindung zwischen Telefon und OpenAI Realtime API herzustellen und die Interaktivität seiner Anwendung zu testen. Nun kann man die KI alles Mögliche fragen. Besonders interessant wird es, wenn man nach dem Preis einer Verbindung zwischen zwei Städten fragt – dann wird nämlich Function Calling aktiviert. Viel Erfolg!

Die OpenAI Realtime API eröffnet neue Möglichkeiten für sprachbasierte KI-Anwendungen, ist jedoch derzeit noch im Beta-Status. Entwickler sollten sich bewusst sein, dass sich die Spezifikation in dieser Phase ändern kann. In der Praxis zeigt die API bereits ihre Stärken, doch es gibt auch noch Schwächen: Insbesondere auf Deutsch treten gelegentlich Schwierigkeiten auf, komplexe oder unklare Sätze korrekt zu interpretieren. Hier besteht noch Optimierungsbedarf, um auch andere Sprachen genauso präzise zu unterstützen wie Englisch.

Ein weiteres technisches Limit liegt im maximalen Kontextfenster des Modells. Nach etwa 15 Minuten Gespräch erreicht das Modell seine Kapazitätsgrenze, sodass es frühere Teile der Unterhaltung "vergisst". In lang andauernden Gesprächen kann dies dazu führen, dass der Verlauf nicht mehr vollständig nachvollzogen wird. Für viele praxisnahe Szenarien ist das jedoch kein Hindernis, solange die Anwendung diese Grenze berücksichtigt.

Trotz dieser Einschränkungen bietet die API ein vielversprechendes Werkzeug, um KI-Software in der Praxis einzusetzen. Besonders in der Telefonie, bei Übersetzungsdiensten oder als interaktives Assistenzsystem ist bereits jetzt das große Potenzial erkennbar. Für Entwickler ist die Realtime API ein spannendes Feld, das sich für die Erforschung und Integration in verschiedenste Anwendungsfälle lohnt.

(mai)