Freigeben über


Multi-Modal-APIs in Echtzeit

Die erste Echtzeit-API-Integration für semantischen Kernel wurde hinzugefügt, sie ist derzeit nur in Python verfügbar und gilt als experimentell. Dies liegt daran, dass die zugrunde liegenden Dienste noch entwickelt werden und Änderungen unterliegen, und wir müssen möglicherweise grundlegende Änderungen an der API im semantischen Kernel vornehmen, da wir von Kunden erfahren, wie sie dies verwenden können und wie wir andere Anbieter dieser Art von Modellen und APIs hinzufügen.

Echtzeit-Client-Abstraktion

Um unterschiedliche Echtzeit-APIs von verschiedenen Anbietern zu unterstützen, wurde mit unterschiedlichen Protokollen eine neue Clientstraktion zum Kernel hinzugefügt. Dieser Client wird verwendet, um eine Verbindung mit dem Echtzeitdienst herzustellen und Nachrichten zu senden und zu empfangen. Der Client ist dafür verantwortlich, die Verbindung mit dem Dienst zu verarbeiten, Nachrichten zu senden und Nachrichten zu empfangen. Der Client ist auch für die Behandlung von Fehlern verantwortlich, die während der Verbindung oder des Sendens/Empfangens von Nachrichten auftreten. In Anbetracht der Funktionsweise dieser Modelle können sie mehr als reguläre Chatabschlüsse betrachtet werden. Sie können als Agenten angesehen werden, da sie Anweisungen entgegennehmen, anstatt eine Systemnachricht zu verwenden. Weiterhin behalten sie ihren eigenen internen Zustand und können aufgerufen werden, um in unserem Auftrag zu arbeiten.

Echtzeit-API

Jeder Echtzeitclient implementiert die folgenden Methoden:

Methode Beschreibung
create_session Erstellt eine neue Sitzung
update_session Aktualisiert eine vorhandene Sitzung
delete_session Löscht eine vorhandene Sitzung.
receive Dies ist eine asynchrone Generatormethode, die Nachrichten vom Dienst empfängt und diese, sobald sie eintreffen, liefert.
send Sendet eine Nachricht an den Dienst.

Python-Implementierungen

Die Python-Version des semantischen Kernels unterstützt derzeit die folgenden Echtzeitclients:

Kunde Protokoll Modalitäten Funktionsaufruf aktiviert Beschreibung
OpenAI Websocket Text & Ton Ja Die OpenAI Realtime-API ist eine websocket-basierte API, mit der Sie Nachrichten in Echtzeit senden und empfangen können, dieser Connector verwendet das OpenAI Python-Paket, um Nachrichten zu verbinden und zu empfangen und zu senden.
OpenAI WebRTC Text & Ton Ja Die OpenAI Realtime-API ist eine webRTC-basierte API, mit der Sie Nachrichten in Echtzeit senden und empfangen können, es benötigt eine webRTC-kompatible Audiospur zur Sitzungserstellungszeit.
Azure Websocket Text & Ton Ja Die Azure Realtime-API ist eine websocket-basierte API, mit der Sie Nachrichten in Echtzeit senden und empfangen können. Dies verwendet dasselbe Paket wie der OpenAI-Websocket-Connector.

Erste Schritte

Um mit der Realtime-API zu beginnen, müssen Sie das semantic-kernel-Paket mit dem zusätzlichen realtime installieren.

pip install semantic-kernel[realtime]

Je nachdem, wie Sie Audio verarbeiten möchten, benötigen Sie möglicherweise zusätzliche Pakete für die Schnittstelle mit Lautsprechern und Mikrofonen, z. B. pyaudio oder sounddevice.

Websocket-Clients

Anschließend können Sie einen Kernel erstellen und den Echtzeitclient hinzufügen. Dies zeigt, wie Sie dies mit einer AzureRealtimeWebsocket-Verbindung tun können, Sie können AzureRealtimeWebsocket ohne weitere Änderungen durch OpenAIRealtimeWebsocket ersetzen.

from semantic_kernel.connectors.ai.open_ai import (
    AzureRealtimeWebsocket,
    AzureRealtimeExecutionSettings,
    ListenEvents,
)
from semantic_kernel.contents import RealtimeAudioEvent, RealtimeTextEvent

# this will use environment variables to get the api key, endpoint, api version and deployment name.
realtime_client = AzureRealtimeWebsocket()
settings = AzureRealtimeExecutionSettings(voice='alloy')
async with realtime_client(settings=settings, create_response=True):
    async for event in realtime_client.receive():
        match event:
            # receiving a piece of audio (and send it to a undefined audio player)
            case RealtimeAudioEvent():
                await audio_player.add_audio(event.audio)
            # receiving a piece of audio transcript
            case RealtimeTextEvent():
                # Semantic Kernel parses the transcript to a TextContent object captured in a RealtimeTextEvent
                print(event.text.text, end="")
            case _:
                # OpenAI Specific events
                if event.service_type == ListenEvents.SESSION_UPDATED:
                    print("Session updated")
                if event.service_type == ListenEvents.RESPONSE_CREATED:
                    print("\nMosscap (transcript): ", end="")

Es gibt zwei wichtige Punkte zu beachten: Der erste ist, dass der realtime_client ein asynchroner Kontext-Manager ist. Dies bedeutet, dass Sie es in einer asynchronen Funktion verwenden und async with verwenden können, um die Sitzung zu erstellen. Die zweite ist, dass die receive-Methode ein asynchroner Generator ist. Dies bedeutet, dass Sie sie in einer For-Schleife verwenden können, um Nachrichten zu empfangen, sobald sie eingehen.

WebRTC-Client

Das Einrichten einer WebRTC-Verbindung ist etwas komplexer, daher benötigen wir beim Erstellen des Clients einen zusätzlichen Parameter. Dieser Parameter, audio_track muss ein Objekt sein, das das MediaStreamTrack Protokoll des aiortc-Pakets implementiert, dies wird auch in den unten verknüpften Beispielen veranschaulicht.

Um einen Client zu erstellen, der WebRTC verwendet, gehen Sie wie folgt vor:

from semantic_kernel.connectors.ai.open_ai import (
    ListenEvents,
    OpenAIRealtimeExecutionSettings,
    OpenAIRealtimeWebRTC,
)
from aiortc.mediastreams import MediaStreamTrack

class AudioRecorderWebRTC(MediaStreamTrack):
    # implement the MediaStreamTrack methods.

realtime_client = OpenAIRealtimeWebRTC(audio_track=AudioRecorderWebRTC())
# Create the settings for the session
settings = OpenAIRealtimeExecutionSettings(
    instructions="""
You are a chat bot. Your name is Mosscap and
you have one goal: figure out what people need.
Your full name, should you need to know it, is
Splendid Speckled Mosscap. You communicate
effectively, but you tend to answer with long
flowery prose.
""",
    voice="shimmer",
)
audio_player = AudioPlayer
async with realtime_client(settings=settings, create_response=True):
    async for event in realtime_client.receive():
        match event.event_type:
            # receiving a piece of audio (and send it to a undefined audio player)
            case "audio":
                await audio_player.add_audio(event.audio)
            case "text":
                # the model returns both audio and transcript of the audio, which we will print
                print(event.text.text, end="")
            case "service":
                # OpenAI Specific events
                if event.service_type == ListenEvents.SESSION_UPDATED:
                    print("Session updated")
                if event.service_type == ListenEvents.RESPONSE_CREATED:
                    print("\nMosscap (transcript): ", end="")

Beide Beispiele empfangen die Audiodaten als RealtimeAudioEvent und übergeben diese dann an ein nicht angegebenes audio_player-Objekt.

Audioausgaberückruf

Daneben haben wir einen Parameter namens audio_output_callback für die receive-Methode und die Klassenerstellung. Dieser Rückruf wird zuerst aufgerufen, noch bevor eine weitere Verarbeitung der Audiodaten erfolgt. Dabei wird ein numpy-Array der Audiodaten erhalten, anstatt dass die Daten in AudioContent analysiert und als RealtimeAudioEvent zurückgegeben werden, das Sie dann bearbeiten können, wie es oben geschieht. Es hat sich gezeigt, dass die Audioausgabe reibungsloser ist, weil es weniger Aufwand zwischen dem Eingang der Audiodaten und deren Übergabe an den Player gibt.

In diesem Beispiel wird gezeigt, wie Sie die audio_output_callbackdefinieren und verwenden:

from semantic_kernel.connectors.ai.open_ai import (
    ListenEvents,
    OpenAIRealtimeExecutionSettings,
    OpenAIRealtimeWebRTC,
)
from aiortc.mediastreams import MediaStreamTrack

class AudioRecorderWebRTC(MediaStreamTrack):
    # implement the MediaStreamTrack methods.

class AudioPlayer:
    async def play_audio(self, content: np.ndarray):
        # implement the audio player

realtime_client = OpenAIRealtimeWebRTC(audio_track=AudioRecorderWebRTC())
# Create the settings for the session
settings = OpenAIRealtimeExecutionSettings(
    instructions="""
You are a chat bot. Your name is Mosscap and
you have one goal: figure out what people need.
Your full name, should you need to know it, is
Splendid Speckled Mosscap. You communicate
effectively, but you tend to answer with long
flowery prose.
""",
    voice="shimmer",
)
audio_player = AudioPlayer
async with realtime_client(settings=settings, create_response=True):
    async for event in realtime_client.receive(audio_output_callback=audio_player.play_audio):
        match event.event_type:
            # no need to handle case: "audio"
            case "text":
                # the model returns both audio and transcript of the audio, which we will print
                print(event.text.text, end="")
            case "service":
                # OpenAI Specific events
                if event.service_type == ListenEvents.SESSION_UPDATED:
                    print("Session updated")
                if event.service_type == ListenEvents.RESPONSE_CREATED:
                    print("\nMosscap (transcript): ", end="")

Proben

Es gibt vier Beispiele in unserer Repository-, sie decken sowohl die Grundlagen mit Websockets als auch WebRTC sowie ein komplexeres Setup ab, einschließlich Funktionsaufrufen. Schließlich gibt es eine komplexere Demo, die Azure Communication Services verwendet, damit Sie Ihre erweiterte API des Semantik-Kernels aufrufen können.