Partager via


API multimodales en temps réel

La première intégration de l’API en temps réel pour le noyau sémantique a été ajoutée, elle est actuellement disponible uniquement dans Python et considérée comme expérimentale. Cela est dû au fait que les services sous-jacents sont toujours en cours de développement et sont soumis à des modifications, et que nous devrons peut-être apporter des modifications majeures à l'API dans Semantic Kernel, en apprenant des clients comment utiliser ce service et en ajoutant d'autres fournisseurs de ces types de modèles et d'API.

Abstraction du client en temps réel

Pour prendre en charge différentes API en temps réel de différents fournisseurs, à l’aide de différents protocoles, une nouvelle abstraction cliente a été ajoutée au noyau. Ce client est utilisé pour se connecter au service en temps réel et envoyer et recevoir des messages. Le client est responsable de la gestion de la connexion au service, de l’envoi de messages et de la réception de messages. Le client est également responsable de la gestion des erreurs qui se produisent pendant le processus d’envoi/réception de messages lors de la connexion. Compte tenu de la façon dont ces modèles fonctionnent, ils peuvent être considérés davantage comme des agents que comme de simples complétions de conversation. Ainsi, ils suivent également des instructions et, plutôt qu'un message système, conservent leur propre état interne et peuvent être sollicités pour effectuer des tâches en notre nom.

API en temps réel

Tout client en temps réel implémente les méthodes suivantes :

Méthode Description
create_session Crée une session
update_session Met à jour une session existante
delete_session Supprime une session existante
receive Il s’agit d’une méthode de générateur asynchrone qui écoute les messages du service et les génère à mesure qu’ils arrivent.
send Envoie un message au service

Implémentations Python

La version python du noyau sémantique prend actuellement en charge les clients en temps réel suivants :

Client Protocole Modalités Appel de fonction activé Description
OpenAI WebSocket Texte & Audio Oui L’API OpenAI Realtime est une API websocket qui vous permet d’envoyer et de recevoir des messages en temps réel, ce connecteur utilise le package Python OpenAI pour se connecter et recevoir et envoyer des messages.
OpenAI WebRTC Texte & Audio Oui L’API OpenAI Realtime est une API webRTC qui vous permet d’envoyer et de recevoir des messages en temps réel, elle a besoin d’une piste audio compatible webRTC au moment de la création de session.
Azur Websocket Texte & Audio Oui L’API Azure Realtime est une API websocket qui vous permet d’envoyer et de recevoir des messages en temps réel, qui utilise le même package que le connecteur Websocket OpenAI.

Commencer

Pour commencer avec l’API Realtime, vous devez installer le package semantic-kernel avec le realtime supplémentaire.

pip install semantic-kernel[realtime]

Selon la façon dont vous souhaitez gérer l’audio, vous devrez peut-être des packages supplémentaires pour interagir avec des haut-parleurs et des microphones, comme pyaudio ou sounddevice.

Clients WebSocket

Vous pouvez ensuite créer un noyau et y ajouter le client en temps réel. Cela montre comment procéder avec une connexion AzureRealtimeWebsocket, vous pouvez remplacer AzureRealtimeWebsocket par OpenAIRealtimeWebsocket sans aucune autre modification.

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="")

Il existe deux points importants à noter, le premier est que le realtime_client est un gestionnaire de contexte asynchrone, cela signifie que vous pouvez l’utiliser dans une fonction asynchrone et utiliser async with pour créer la session. La seconde est que la méthode receive est un générateur asynchrone, cela signifie que vous pouvez l’utiliser dans une boucle for pour recevoir des messages à mesure qu’ils arrivent.

Client WebRTC

La configuration d’une connexion WebRTC est un peu plus complexe et nous avons donc besoin d’un paramètre supplémentaire lors de la création du client. Ce paramètre, audio_track doit être un objet qui implémente le protocole MediaStreamTrack du package aiortc, ce qui est également illustré dans les exemples liés ci-dessous.

Pour créer un client qui utilise WebRTC, procédez comme suit :

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="")

Ces deux exemples reçoivent l’audio en tant que RealtimeAudioEvent, puis ils passent cela à un objet audio_player non spécifié.

Fonction de rappel de sortie audio

En regard de cela, nous avons un paramètre appelé audio_output_callback sur la méthode receive et sur la création de classe. Ce rappel sera invoqué avant toute autre manipulation de l'audio et reçoit un tableau numpy des données audio, au lieu d'être analysé dans AudioContent et renvoyé en tant que RealtimeAudioEvent que vous pouvez ensuite gérer, comme cela se déroule ci-dessus. Cela a prouvé qu'il offre une sortie audio plus fluide, car il y a moins de surcharge entre l'arrivée des données audio et leur transmission au lecteur.

Cet exemple montre comment définir et utiliser le audio_output_callback:

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="")

Échantillons

Il existe quatre exemples dans notre dépôt, ils couvrent à la fois les principes de base à l’aide de websockets et de WebRTC, ainsi qu’une configuration plus complexe, y compris l’appel de fonction. Enfin, il existe une démonstration plus complexe qui utilise Azure Communication Services pour vous permettre d’appeler votre API améliorée en temps réel du noyau sémantique.