

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

# Starten eines Konversationsstreams zu einem Amazon Lex V2-Bot
<a name="start-stream-conversation"></a>

Sie verwenden den [StartConversation](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_StartConversation.html)Vorgang, um einen Stream zwischen dem Benutzer und dem Amazon Lex V2-Bot in Ihrer Anwendung zu starten. Die `POST` Anfrage von der Anwendung stellt eine Verbindung zwischen Ihrer Anwendung und dem Amazon Lex V2-Bot her. Dadurch können Ihre Anwendung und der Bot über Ereignisse Informationen miteinander austauschen.

**Anmerkung**  
Wenn bei Verwendung StartConversation die Audiodauer der Äußerung den konfigurierten Wert für überschreitet`max-length-ms`, unterbricht Amazon Lex V2 den Ton für die angegebene Dauer.

Der `StartConversation` Vorgang wird nur in den folgenden SDKs Fällen unterstützt: 
+ [AWS SDK für C\$1\$1](https://docs.aws.amazon.com/goto/SdkForCpp/runtime.lex.v2-2020-08-07/StartConversation)
+ [AWS SDK für Java V2](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lexruntimev2/LexRuntimeV2AsyncClient.html)
+ [AWS-SDK für JavaScript Version 3](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-lex-runtime-v2/index.html#aws-sdkclient-lex-runtime-v2)
+ [AWS SDK für Ruby V3](https://docs.aws.amazon.com/goto/SdkForRubyV3/runtime.lex.v2-2020-08-07/StartConversation)

Das erste Ereignis, das Ihre Bewerbung an den Amazon Lex V2-Bot senden muss, ist ein [ConfigurationEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_ConfigurationEvent.html). Dieses Ereignis enthält Informationen wie das Format des Antworttyps. Die folgenden Parameter können Sie in einem Konfigurationsereignis verwenden:
+ **responseContentType**— Legt fest, ob der Bot auf Benutzereingaben mit Text oder Sprache reagiert.
+ **sessionState** — Informationen zur Streaming-Sitzung mit dem Bot, z. B. vorgegebene Absicht oder Dialogstatus.
+ **WelcomeMessages** — Gibt die Willkommensnachrichten an, die dem Benutzer zu Beginn seiner Konversation mit einem Bot abgespielt werden. Diese Nachrichten werden abgespielt, bevor der Benutzer etwas eingibt. Um eine Willkommensnachricht zu aktivieren, müssen Sie auch Werte für die `dialogAction` Parameter `sessionState` und angeben. 
+ **DisablePlayback** — Legt fest, ob der Bot auf einen Hinweis vom Client warten soll, bevor er auf Anrufereingaben wartet. Standardmäßig ist die Wiedergabe aktiviert, der Wert dieses Felds ist also. `false`
+ **requestAttributes** — Stellt zusätzliche Informationen für die Anfrage bereit.

Informationen zum Angeben von Werten für die vorherigen Parameter finden Sie unter [ConfigurationEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_ConfigurationEvent.html)Datentyp des [StartConversation](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_StartConversation.html)Vorgangs.

Jeder Stream zwischen einem Bot und Ihrer Anwendung kann nur ein Konfigurationsereignis haben. Nachdem Ihre Anwendung ein Konfigurationsereignis gesendet hat, kann der Bot zusätzliche Kommunikation von Ihrer Anwendung entgegennehmen.

Wenn Sie angegeben haben, dass Ihr Benutzer Audio für die Kommunikation mit dem Amazon Lex V2-Bot verwendet, kann Ihre Anwendung während dieser Konversation die folgenden Ereignisse an den Bot senden:
+ [AudioInputEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_AudioInputEvent.html)— Enthält einen Audio-Chunk mit einer maximalen Größe von 320 Byte. Ihre Anwendung muss mehrere Audioeingabeereignisse verwenden, um eine Nachricht vom Server an den Bot zu senden. Jedes Audioeingabeereignis im Stream muss dasselbe Audioformat haben.
+ [DTMFInputEreignis](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_DTMFInputEvent.html) — Sendet eine DTMF-Eingabe an den Bot. Jeder DTMF-Tastendruck entspricht einem einzelnen Ereignis.
+ [PlaybackCompletionEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_PlaybackCompletionEvent.html)— Informiert den Server darüber, dass eine Antwort auf Benutzereingaben für ihn wiedergegeben wurde. Sie müssen ein Ereignis zum Abschluss der Wiedergabe verwenden, wenn Sie eine Audioantwort an den Benutzer senden. Wenn es sich `disablePlayback` bei Ihrem Konfigurationsereignis um ein Ereignis handelt`true`, können Sie diese Funktion nicht verwenden.
+ [DisconnectionEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_DTMFInputEvent.html)— Informiert den Bot darüber, dass der Benutzer die Verbindung zur Konversation unterbrochen hat.

Wenn Sie angegeben haben, dass der Benutzer Text verwendet, um mit dem Bot zu kommunizieren, kann Ihre Anwendung während dieser Konversation die folgenden Ereignisse an den Bot senden:
+ [TextInputEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_TextInputEvent.html)— Text, der von Ihrer Anwendung an den Bot gesendet wird. Ein Texteingabeereignis kann bis zu 512 Zeichen enthalten.
+ [PlaybackCompletionEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_PlaybackCompletionEvent.html)— Informiert den Server darüber, dass eine Antwort auf die Benutzereingabe für ihn wiedergegeben wurde. Sie müssen dieses Ereignis verwenden, wenn Sie dem Benutzer Audio wiedergeben. Wenn es sich bei `disablePlayback` Ihrer Konfiguration um ein Ereignis handelt`true`, können Sie diese Funktion nicht verwenden.
+ [DisconnectionEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_DTMFInputEvent.html)— Informiert den Bot darüber, dass der Benutzer die Verbindung zur Konversation unterbrochen hat.

Sie müssen jedes Ereignis, das Sie an einen Amazon Lex V2-Bot senden, im richtigen Format codieren. Weitere Informationen finden Sie unter [Ereignis-Stream-Kodierung](event-stream-encoding.md).

Jedes Ereignis hat eine Ereignis-ID. Um Probleme zu beheben, die im Stream auftreten könnten, weisen Sie jedem Eingabeereignis eine eindeutige Ereignis-ID zu. Anschließend können Sie alle Verarbeitungsfehler mit dem Bot beheben.

Amazon Lex V2 verwendet auch Zeitstempel für jedes Ereignis. Sie können diese Zeitstempel zusätzlich zur Ereignis-ID verwenden, um Probleme mit der Netzwerkübertragung zu beheben.

Während der Konversation zwischen dem Benutzer und dem Amazon Lex V2-Bot kann der Bot die folgenden ausgehenden Ereignisse als Antwort an den Benutzer senden:
+ [IntentResultEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_IntentResultEvent.html)— Enthält die Absicht, die Amazon Lex V2 anhand der Benutzeräußerung ermittelt hat. Jedes interne Ergebnisereignis beinhaltet:
  + **InputMode** — Die Art der Benutzeräußerung. Gültige Werte sind `Speech`, `DTMF` oder `Text`.
  + **Interpretationen** — Interpretationen, die Amazon Lex V2 anhand der Benutzeräußerung bestimmt.
  + **requestAttributes** — Wenn Sie die Anforderungsattribute nicht mithilfe einer Lambda-Funktion geändert haben, handelt es sich um dieselben Attribute, die zu Beginn der Konversation übergeben wurden.
  + **sessionId — Sitzungs-ID**, die für die Konversation verwendet wird.
  + **sessionState** — Der Status der Benutzersitzung mit Amazon Lex V2.
+ [TranscriptEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_TranscriptEvent.html)— Wenn der Benutzer eine Eingabe in Ihre Anwendung eingibt, enthält dieses Ereignis die Abschrift der Äußerung des Benutzers gegenüber dem Bot. Ihre Anwendung erhält keine, `TranscriptEvent` wenn keine Benutzereingabe erfolgt.

  Der Wert des an Ihre Anwendung gesendeten Transkriptereignisses hängt davon ab, ob Sie Audio (Sprache und DMTF) oder Text als Konversationsmodus angegeben haben:
  + Transkript der Spracheingabe — Wenn der Benutzer mit dem Bot spricht, ist das Transkriptionsereignis die Transkription des Audios des Benutzers. Es ist eine Abschrift der gesamten Sprache von dem Zeitpunkt an, an dem der Benutzer zu sprechen beginnt, bis zu dem Zeitpunkt, an dem er mit dem Sprechen aufhört.
  + Abschrift der DTMF-Eingabe — Wenn der Benutzer auf einer Tastatur tippt, enthält das Transkriptereignis alle Ziffern, die der Benutzer bei der Eingabe gedrückt hat.
  + Abschrift der Texteingabe — Wenn der Benutzer eine Texteingabe vornimmt, enthält das Transkriptionsereignis den gesamten Text der Benutzereingabe.
+ [TextResponseEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_TextResponseEvent.html)— Enthält die Bot-Antwort im Textformat. Standardmäßig wird eine Textantwort zurückgegeben. Wenn Sie Amazon Lex V2 so konfiguriert haben, dass eine Audioantwort zurückgegeben wird, wird dieser Text verwendet, um eine Audioantwort zu generieren. Jedes Textantwort-Ereignis enthält eine Reihe von Nachrichtenobjekten, die der Bot an den Benutzer zurückgibt.
+ [AudioResponseEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_AudioResponseEvent.html)— Enthält die Audioantwort, die aus dem in der generierten Text synthetisiert wurde. `TextResponseEvent` Um Audioantwortereignisse zu empfangen, müssen Sie Amazon Lex V2 so konfigurieren, dass eine Audioantwort bereitgestellt wird. Alle Audioantwort-Ereignisse haben dasselbe Audioformat. Jedes Ereignis enthält Audioblöcke von nicht mehr als 100 Byte. Amazon Lex V2 sendet einen leeren Audioblock, bei dem das `bytes` Feld auf gesetzt ist, `null` um das Ende des Audioantwortereignisses an Ihre Anwendung anzuzeigen.
+ [PlaybackInterruptionEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_PlaybackInterruptionEvent.html)— Wenn ein Benutzer eine Antwort unterbricht, die der Bot an Ihre Anwendung gesendet hat, löst Amazon Lex V2 dieses Ereignis aus, um die Wiedergabe der Antwort zu stoppen.
+ [HeartbeatEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_HeartbeatEvent.html)— Amazon Lex V2 sendet dieses Ereignis regelmäßig zurück, um zu verhindern, dass es bei der Verbindung zwischen Ihrer Anwendung und dem Bot zu einem Timeout kommt.

## Zeitliche Abfolge von Ereignissen für eine Audiokonversation bei Verwendung eines Amazon Lex V2-Bots
<a name="audio-conversation-sequence"></a>

Die folgenden Diagramme zeigen eine Streaming-Audiokonversation zwischen einem Benutzer und einem Amazon Lex V2-Bot. Die Anwendung streamt kontinuierlich Audio an den Bot, und der Bot sucht anhand des Audios nach Benutzereingaben. In diesem Beispiel verwenden sowohl der Benutzer als auch der Bot Sprache, um zu kommunizieren. Jedes Diagramm entspricht einer Benutzeräußerung und der Reaktion des Bots auf diese Äußerung.

Das folgende Diagramm zeigt den Beginn einer Konversation zwischen der Anwendung und dem Bot. Der Stream beginnt zum Zeitpunkt Null (t0). 

![\[Timeline showing audio input events from application and various response events from bot during a conversation.\]](http://docs.aws.amazon.com/de_de/lexv2/latest/dg/images/Streaming-Page-1.png)


In der folgenden Liste werden die Ereignisse des vorherigen Diagramms beschrieben.
+ t0: Die Anwendung sendet ein Konfigurationsereignis an den Bot, um den Stream zu starten.
+ t1: Die Anwendung streamt Audiodaten. Diese Daten werden in eine Reihe von Eingabeereignissen der Anwendung aufgeteilt.
+ t2: Bei *Benutzeräußerung 1* erkennt der Bot ein Audioeingabeereignis, wenn der Benutzer zu sprechen beginnt.
+ t2: Während der Benutzer spricht, sendet der Bot ein Heartbeat-Ereignis, um die Verbindung aufrechtzuerhalten. Er sendet diese Ereignisse in regelmäßigen Abständen, um sicherzustellen, dass die Verbindung nicht unterbrochen wird.
+ t3: Der Bot erkennt das Ende der Äußerung des Benutzers.
+ t4: Der Bot sendet ein Transkriptereignis zurück, das eine Abschrift der Sprache des Benutzers an die Anwendung enthält. Dies ist der Beginn der *Bot-Antwort auf Benutzeräußerung 1.*
+ t5: Der Bot sendet ein Absichtsergebnis, um die Aktion anzugeben, die der Benutzer ausführen möchte.
+ t6: Der Bot beginnt, seine Antwort als Text in einem Textantwortereignis bereitzustellen.
+ t7: Der Bot sendet eine Reihe von Audioantwortereignissen an die Anwendung, um sie für den Benutzer abzuspielen.
+ t8: Der Bot sendet ein weiteres Heartbeat-Ereignis, um die Verbindung zeitweise aufrechtzuerhalten.

Das folgende Diagramm ist eine Fortsetzung des vorherigen Diagramms. Es zeigt, dass die Anwendung ein Ereignis zum Abschluss der Wiedergabe an den Bot sendet, um anzuzeigen, dass die Audioantwort für den Benutzer nicht mehr abgespielt wurde. Die Anwendung gibt dem Benutzer die *Antwort des Bots auf die Benutzeräußerung 1* wieder. Der Benutzer reagiert auf die *Bot-Antwort auf Benutzeräußerung 1* mit *Benutzeräußerung 2.*

![\[Timeline of audio input events from user and response events from bot, showing interaction flow.\]](http://docs.aws.amazon.com/de_de/lexv2/latest/dg/images/Streaming-Page-2.png)


In der folgenden Liste werden die Ereignisse des vorherigen Diagramms beschrieben:
+ t10: Die Anwendung sendet ein Ereignis zum Abschluss der Wiedergabe, um anzuzeigen, dass die Wiedergabe der Bot-Nachricht an den Benutzer abgeschlossen ist.
+ t11: Die Anwendung sendet die Benutzerantwort als *Benutzeräußerung* 2 an den Bot zurück.
+ t12: Bei der *Bot-Antwort auf Benutzeräußerung 2 wartet* der Bot, bis der Benutzer aufhört zu sprechen, und beginnt dann, eine Audioantwort zu geben.
+ *t13: Während der Bot die *Bot-Antwort auf Benutzeräußerung 2* an die Anwendung sendet, erkennt der Bot den Beginn von Benutzeräußerung 3.* Der Bot stoppt die *Bot-Antwort auf Benutzeräußerung 2* und sendet ein Ereignis zur Unterbrechung der Wiedergabe.
+ t14: Der Bot sendet ein Ereignis zur Unterbrechung der Wiedergabe an die Anwendung, um zu signalisieren, dass der Benutzer die Aufforderung unterbrochen hat.

Das folgende Diagramm zeigt, wie der *Bot auf Benutzeräußerung 3 reagiert* und dass die Konversation fortgesetzt wird, nachdem der Bot auf die Benutzeräußerung reagiert hat.

![\[Diagram showing events flow between application, bot, and user utterances over time.\]](http://docs.aws.amazon.com/de_de/lexv2/latest/dg/images/Streaming-Page-3.png)


# Verwenden der API, um eine Streaming-Konversation zu starten
<a name="using-streaming-api"></a>

Wenn Sie einen Stream zu einem Amazon Lex V2-Bot starten, führen Sie die folgenden Aufgaben aus:

1. Stellen Sie eine erste Verbindung zum Server her.

1. Konfigurieren Sie die Sicherheitsanmeldedaten und Bot-Details. Zu den Bot-Details gehört, ob der Bot DTMF- und Audioeingaben oder Texteingaben akzeptiert.

1. Ereignisse an den Server senden. Bei diesen Ereignissen handelt es sich um Text- oder Audiodaten des Benutzers.

1. Vom Server gesendete Ereignisse verarbeiten. In diesem Schritt legen Sie fest, ob die Bot-Ausgabe dem Benutzer als Text oder Sprache präsentiert wird.

Die folgenden Codebeispiele initialisieren eine Streaming-Konversation mit einem Amazon Lex V2-Bot und Ihrem lokalen Computer. Sie können den Code an Ihre Bedürfnisse anpassen.

Der folgende Code ist eine Beispielanforderung, mit der die Verbindung AWS SDK für Java zu einem Bot hergestellt und die Bot-Details und Anmeldeinformationen konfiguriert werden.

```
package com.lex.streaming.sample;

import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.lexruntimev2.LexRuntimeV2AsyncClient;
import software.amazon.awssdk.services.lexruntimev2.model.ConversationMode;
import software.amazon.awssdk.services.lexruntimev2.model.StartConversationRequest;

import java.net.URISyntaxException;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

/**
 * The following code creates a connection with the Amazon Lex bot and configures the bot details and credentials.  
 * Prerequisite: To use this example, you must be familiar with the Reactive streams programming model.
 * For more information, see
 * https://github.com/reactive-streams/reactive-streams-jvm.
 * This example uses AWS SDK for Java for Amazon Lex V2.
 * <p>
 * The following sample application interacts with an Amazon Lex bot with the streaming API. It uses the Audio
 * conversation mode to return audio responses to the user's input.
 * <p>
 * The code in this example accomplishes the following:
 * <p>
 * 1. Configure details about the conversation between the user and the Amazon Lex bot. These details include the conversation mode and the specific bot the user is speaking with.
 * 2. Create an events publisher that passes the audio events to the Amazon Lex bot after you establish the connection. The code we provide in this example tells your computer to pick up the audio from
 * your microphone and send that audio data to Amazon Lex.
 * 3. Create a response handler that handles the audio responses from the Amazon Lex bot and plays back the audio to you.
 */
public class LexBidirectionalStreamingExample {

    public static void main(String[] args) throws URISyntaxException, InterruptedException {
        String botId = "";
        String botAliasId = "";
        String localeId = "";
        String accessKey = "";
        String secretKey = "";
        String sessionId = UUID.randomUUID().toString();
        Region region = Region.region_name; // Choose an AWS Region where the Amazon Lex Streaming API is available.

        AwsCredentialsProvider awsCredentialsProvider = StaticCredentialsProvider
                .create(AwsBasicCredentials.create(accessKey, secretKey));

        // Create a new SDK client. You need to use an asynchronous client.
        System.out.println("step 1: creating a new Lex SDK client");
        LexRuntimeV2AsyncClient lexRuntimeServiceClient = LexRuntimeV2AsyncClient.builder()
                .region(region)
                .credentialsProvider(awsCredentialsProvider)
                .build();


        // Configure the bot, alias and locale that you'll use to have a conversation.
        System.out.println("step 2: configuring bot details");
        StartConversationRequest.Builder startConversationRequestBuilder = StartConversationRequest.builder()
                .botId(botId)
                .botAliasId(botAliasId)
                .localeId(localeId);

        // Configure the conversation mode of the bot. By default, the
        // conversation mode is audio.
        System.out.println("step 3: choosing conversation mode");
        startConversationRequestBuilder = startConversationRequestBuilder.conversationMode(ConversationMode.AUDIO);

        // Assign a unique identifier for the conversation.
        System.out.println("step 4: choosing a unique conversation identifier");
        startConversationRequestBuilder = startConversationRequestBuilder.sessionId(sessionId);

        // Start the initial request.
        StartConversationRequest startConversationRequest = startConversationRequestBuilder.build();

        // Create a stream of audio data to the Amazon Lex bot. The stream will start after the connection is established with the bot.
        EventsPublisher eventsPublisher = new EventsPublisher();

        // Create a class to handle responses from bot. After the server processes the user data you've streamed, the server responds
        // on another stream.
        BotResponseHandler botResponseHandler = new BotResponseHandler(eventsPublisher);

        // Start a connection and pass in the publisher that streams the audio and process the responses from the bot.
        System.out.println("step 5: starting the conversation ...");
        CompletableFuture<Void> conversation = lexRuntimeServiceClient.startConversation(
                startConversationRequest,
                eventsPublisher,
                botResponseHandler);

        // Wait until the conversation finishes. The conversation finishes if the dialog state reaches the "Closed" state.
        // The client stops the connection. If an exception occurs during the conversation, the
        // client sends a disconnection event.
        conversation.whenComplete((result, exception) -> {
            if (exception != null) {
                eventsPublisher.disconnect();
            }
        });

        // The conversation finishes when the dialog state is closed and last prompt has been played.
        while (!botResponseHandler.isConversationComplete()) {
            Thread.sleep(100);
        }

        // Randomly sleep for 100 milliseconds to prevent JVM from exiting.
        // You won't need this in your production code because your JVM is
        // likely to always run.
        // When the conversation finishes, the following code block stops publishing more data and informs the Amazon Lex bot that there is no more data to send.
        if (botResponseHandler.isConversationComplete()) {
            System.out.println("conversation is complete.");
            eventsPublisher.stop();
        }
    }
}
```

Der folgende Code ist eine Beispielanforderung, mit der Ereignisse AWS SDK für Java an den Bot gesendet werden. Der Code in diesem Beispiel verwendet das Mikrofon Ihres Computers, um Audioereignisse zu senden.

```
package com.lex.streaming.sample;

import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import software.amazon.awssdk.services.lexruntimev2.model.StartConversationRequestEventStream;

/**
 * You use the Events publisher to send events to the Amazon Lex bot. When you establish a connection, the bot uses the
 * subscribe() method and enables the events publisher starts sending events to
 * your computer. The bot uses the "request" method of the subscription to make more requests. For more information on the request method, see https://github.com/reactive-streams/reactive-streams-jvm. 
 */
public class EventsPublisher implements Publisher<StartConversationRequestEventStream> {

    private AudioEventsSubscription audioEventsSubscription;

    @Override
    public void subscribe(Subscriber<? super StartConversationRequestEventStream> subscriber) {
        if (audioEventsSubscription == null) {

            audioEventsSubscription = new AudioEventsSubscription(subscriber);
            subscriber.onSubscribe(audioEventsSubscription);

        } else {
            throw new IllegalStateException("received unexpected subscription request");
        }
    }

    public void disconnect() {
        if (audioEventsSubscription != null) {
            audioEventsSubscription.disconnect();
        }
    }

    public void stop() {
        if (audioEventsSubscription != null) {
            audioEventsSubscription.stop();
        }
    }

    public void playbackFinished() {
        if (audioEventsSubscription != null) {
            audioEventsSubscription.playbackFinished();
        }
    }
}
```

Der folgende Code ist eine Beispielanforderung, die verwendet wird AWS SDK für Java , um Antworten des Bots zu verarbeiten. Der Code in diesem Beispiel konfiguriert Amazon Lex V2 so, dass es Ihnen eine Audioantwort wiedergibt.

```
package com.lex.streaming.sample;

import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.advanced.AdvancedPlayer;
import javazoom.jl.player.advanced.PlaybackEvent;
import javazoom.jl.player.advanced.PlaybackListener;
import software.amazon.awssdk.core.async.SdkPublisher;
import software.amazon.awssdk.services.lexruntimev2.model.AudioResponseEvent;
import software.amazon.awssdk.services.lexruntimev2.model.DialogActionType;
import software.amazon.awssdk.services.lexruntimev2.model.IntentResultEvent;
import software.amazon.awssdk.services.lexruntimev2.model.PlaybackInterruptionEvent;
import software.amazon.awssdk.services.lexruntimev2.model.StartConversationResponse;
import software.amazon.awssdk.services.lexruntimev2.model.StartConversationResponseEventStream;
import software.amazon.awssdk.services.lexruntimev2.model.StartConversationResponseHandler;
import software.amazon.awssdk.services.lexruntimev2.model.TextResponseEvent;
import software.amazon.awssdk.services.lexruntimev2.model.TranscriptEvent;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.concurrent.CompletableFuture;

/**
 * The following class is responsible for processing events sent from the Amazon Lex bot. The bot sends multiple audio events,
 * so the following code concatenates those audio events and uses a publicly available Java audio player to play out the message to
 * the user.
 */
public class BotResponseHandler implements StartConversationResponseHandler {

    private final EventsPublisher eventsPublisher;

    private boolean lastBotResponsePlayedBack;
    private boolean isDialogStateClosed;
    private AudioResponse audioResponse;


    public BotResponseHandler(EventsPublisher eventsPublisher) {
        this.eventsPublisher = eventsPublisher;
        this.lastBotResponsePlayedBack = false;// At the start, we have not played back last response from bot.
        this.isDialogStateClosed = false; // At the start, the dialog state is open.
    }

    @Override
    public void responseReceived(StartConversationResponse startConversationResponse) {
        System.out.println("successfully established the connection with server. request id:" + startConversationResponse.responseMetadata().requestId()); // would have 2XX, request id.
    }

    @Override
    public void onEventStream(SdkPublisher<StartConversationResponseEventStream> sdkPublisher) {

        sdkPublisher.subscribe(event -> {
            if (event instanceof PlaybackInterruptionEvent) {
                handle((PlaybackInterruptionEvent) event);
            } else if (event instanceof TranscriptEvent) {
                handle((TranscriptEvent) event);
            } else if (event instanceof IntentResultEvent) {
                handle((IntentResultEvent) event);
            } else if (event instanceof TextResponseEvent) {
                handle((TextResponseEvent) event);
            } else if (event instanceof AudioResponseEvent) {
                handle((AudioResponseEvent) event);
            }
        });
    }

    @Override
    public void exceptionOccurred(Throwable throwable) {
        System.err.println("got an exception:" + throwable);
    }

    @Override
    public void complete() {
        System.out.println("on complete");
    }

    private void handle(PlaybackInterruptionEvent event) {
        System.out.println("Got a PlaybackInterruptionEvent: " + event);
    }

    private void handle(TranscriptEvent event) {
        System.out.println("Got a TranscriptEvent: " + event);
    }


    private void handle(IntentResultEvent event) {
        System.out.println("Got an IntentResultEvent: " + event);
        isDialogStateClosed = DialogActionType.CLOSE.equals(event.sessionState().dialogAction().type());
    }

    private void handle(TextResponseEvent event) {
        System.out.println("Got an TextResponseEvent: " + event);
        event.messages().forEach(message -> {
            System.out.println("Message content type:" + message.contentType());
            System.out.println("Message content:" + message.content());
        });
    }

    private void handle(AudioResponseEvent event) {//Synthesize speech
        // System.out.println("Got a AudioResponseEvent: " + event);
        if (audioResponse == null) {
            audioResponse = new AudioResponse();
            //Start an audio player in a different thread.
            CompletableFuture.runAsync(() -> {
                try {
                    AdvancedPlayer audioPlayer = new AdvancedPlayer(audioResponse);

                    audioPlayer.setPlayBackListener(new PlaybackListener() {
                        @Override
                        public void playbackFinished(PlaybackEvent evt) {
                            super.playbackFinished(evt);

                            // Inform the Amazon Lex bot that the playback has finished.
                            eventsPublisher.playbackFinished();
                            if (isDialogStateClosed) {
                                lastBotResponsePlayedBack = true;
                            }
                        }
                    });
                    audioPlayer.play();
                } catch (JavaLayerException e) {
                    throw new RuntimeException("got an exception when using audio player", e);
                }
            });
        }

        if (event.audioChunk() != null) {
            audioResponse.write(event.audioChunk().asByteArray());
        } else {
            // The audio audio prompt has ended when the audio response has no
            // audio bytes.
            try {
                audioResponse.close();
                audioResponse = null;  // Prepare for the next audio prompt.
            } catch (IOException e) {
                throw new UncheckedIOException("got an exception when closing the audio response", e);
            }
        }
    }

    // The conversation with the Amazon Lex bot is complete when the bot marks the Dialog as DialogActionType.CLOSE
    // and any prompt playback is finished. For more information, see
    // https://docs.aws.amazon.com/lexv2/latest/dg/API_runtime_DialogAction.html.
    public boolean isConversationComplete() {
        return isDialogStateClosed && lastBotResponsePlayedBack;
    }

}
```

Um einen Bot so zu konfigurieren, dass er auf Eingabeereignisse mit Audio reagiert, müssen Sie zuerst Audioereignisse von Amazon Lex V2 abonnieren und dann den Bot so konfigurieren, dass er eine Audioantwort auf die Eingabeereignisse des Benutzers bereitstellt.

Der folgende Code ist ein AWS SDK für Java Beispiel für das Abonnieren von Audio-Events von Amazon Lex V2.

```
package com.lex.streaming.sample;

import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.services.lexruntimev2.model.AudioInputEvent;
import software.amazon.awssdk.services.lexruntimev2.model.ConfigurationEvent;
import software.amazon.awssdk.services.lexruntimev2.model.DisconnectionEvent;
import software.amazon.awssdk.services.lexruntimev2.model.PlaybackCompletionEvent;
import software.amazon.awssdk.services.lexruntimev2.model.StartConversationRequestEventStream;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;

public class AudioEventsSubscription implements Subscription {
    private static final AudioFormat MIC_FORMAT = new AudioFormat(8000, 16, 1, true, false);
    private static final String AUDIO_CONTENT_TYPE = "audio/lpcm; sample-rate=8000; sample-size-bits=16; channel-count=1; is-big-endian=false";
    //private static final String RESPONSE_TYPE = "audio/pcm; sample-rate=8000";
    private static final String RESPONSE_TYPE = "audio/mpeg";
    private static final int BYTES_IN_AUDIO_CHUNK = 320;
    private static final AtomicLong eventIdGenerator = new AtomicLong(0);

    private final AudioInputStream audioInputStream;
    private final Subscriber<? super StartConversationRequestEventStream> subscriber;
    private final EventWriter eventWriter;
    private CompletableFuture eventWriterFuture;


    public AudioEventsSubscription(Subscriber<? super StartConversationRequestEventStream> subscriber) {
        this.audioInputStream = getMicStream();
        this.subscriber = subscriber;
        this.eventWriter = new EventWriter(subscriber, audioInputStream);
        configureConversation();
    }

    private AudioInputStream getMicStream() {
        try {
            DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, MIC_FORMAT);
            TargetDataLine targetDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo);

            targetDataLine.open(MIC_FORMAT);
            targetDataLine.start();

            return new AudioInputStream(targetDataLine);
        } catch (LineUnavailableException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void request(long demand) {
        // If a thread to write events has not been started, start it.
        if (eventWriterFuture == null) {
            eventWriterFuture = CompletableFuture.runAsync(eventWriter);
        }
        eventWriter.addDemand(demand);
    }

    @Override
    public void cancel() {
        subscriber.onError(new RuntimeException("stream was cancelled"));
        try {
            audioInputStream.close();
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public void configureConversation() {
        String eventId = "ConfigurationEvent-" + String.valueOf(eventIdGenerator.incrementAndGet());

        ConfigurationEvent configurationEvent = StartConversationRequestEventStream
                .configurationEventBuilder()
                .eventId(eventId)
                .clientTimestampMillis(System.currentTimeMillis())
                .responseContentType(RESPONSE_TYPE)
                .build();

        System.out.println("writing config event");
        eventWriter.writeConfigurationEvent(configurationEvent);
    }

    public void disconnect() {

        String eventId = "DisconnectionEvent-" + String.valueOf(eventIdGenerator.incrementAndGet());

        DisconnectionEvent disconnectionEvent = StartConversationRequestEventStream
                .disconnectionEventBuilder()
                .eventId(eventId)
                .clientTimestampMillis(System.currentTimeMillis())
                .build();

        eventWriter.writeDisconnectEvent(disconnectionEvent);

        try {
            audioInputStream.close();
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }

    }
    //Notify the subscriber that we've finished.
    public void stop() {
        subscriber.onComplete();
    }

    public void playbackFinished() {
        String eventId = "PlaybackCompletion-" + String.valueOf(eventIdGenerator.incrementAndGet());

        PlaybackCompletionEvent playbackCompletionEvent = StartConversationRequestEventStream
                .playbackCompletionEventBuilder()
                .eventId(eventId)
                .clientTimestampMillis(System.currentTimeMillis())
                .build();

        eventWriter.writePlaybackFinishedEvent(playbackCompletionEvent);
    }

    private static class EventWriter implements Runnable {
        private final BlockingQueue<StartConversationRequestEventStream> eventQueue;
        private final AudioInputStream audioInputStream;
        private final AtomicLong demand;
        private final Subscriber subscriber;

        private boolean conversationConfigured;

        public EventWriter(Subscriber subscriber, AudioInputStream audioInputStream) {
            this.eventQueue = new LinkedBlockingQueue<>();

            this.demand = new AtomicLong(0);
            this.subscriber = subscriber;
            this.audioInputStream = audioInputStream;
        }

        public void writeConfigurationEvent(ConfigurationEvent configurationEvent) {
            eventQueue.add(configurationEvent);
        }

        public void writeDisconnectEvent(DisconnectionEvent disconnectionEvent) {
            eventQueue.add(disconnectionEvent);
        }

        public void writePlaybackFinishedEvent(PlaybackCompletionEvent playbackCompletionEvent) {
            eventQueue.add(playbackCompletionEvent);
        }

        void addDemand(long l) {
            this.demand.addAndGet(l);
        }

        @Override
        public void run() {
            try {

                while (true) {
                    long currentDemand = demand.get();

                    if (currentDemand > 0) {
                        // Try to read from queue of events.
                        // If nothing is in queue at this point, read the audio events directly from audio stream.
                        for (long i = 0; i < currentDemand; i++) {

                            if (eventQueue.peek() != null) {
                                subscriber.onNext(eventQueue.take());
                                demand.decrementAndGet();
                            } else {
                                writeAudioEvent();
                            }
                        }
                    }
                }
            } catch (InterruptedException e) {
                throw new RuntimeException("interrupted when reading data to be sent to server");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private void writeAudioEvent() {
            byte[] bytes = new byte[BYTES_IN_AUDIO_CHUNK];

            int numBytesRead = 0;
            try {
                numBytesRead = audioInputStream.read(bytes);
                if (numBytesRead != -1) {
                    byte[] byteArrayCopy = Arrays.copyOf(bytes, numBytesRead);

                    String eventId = "AudioEvent-" + String.valueOf(eventIdGenerator.incrementAndGet());

                    AudioInputEvent audioInputEvent = StartConversationRequestEventStream
                            .audioInputEventBuilder()
                            .audioChunk(SdkBytes.fromByteBuffer(ByteBuffer.wrap(byteArrayCopy)))
                            .contentType(AUDIO_CONTENT_TYPE)
                            .clientTimestampMillis(System.currentTimeMillis())
                            .eventId(eventId).build();

                    //System.out.println("sending audio event:" + audioInputEvent);
                    subscriber.onNext(audioInputEvent);
                    demand.decrementAndGet();
                    //System.out.println("sent audio event:" + audioInputEvent);
                } else {
                    subscriber.onComplete();
                    System.out.println("audio stream has ended");
                }

            } catch (IOException e) {
                System.out.println("got an exception when reading from audio stream");
                System.err.println(e);
                subscriber.onError(e);
            }
        }
    }
}
```

Im folgenden AWS SDK für Java Beispiel wird der Amazon Lex V2-Bot so konfiguriert, dass er eine Audioantwort auf die Eingabeereignisse liefert.

```
package com.lex.streaming.sample;

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.Optional;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class AudioResponse extends InputStream{

    // Used to convert byte, which is signed in Java, to positive integer (unsigned)
    private static final int UNSIGNED_BYTE_MASK = 0xFF;
    private static final long POLL_INTERVAL_MS = 10;

    private final LinkedBlockingQueue<Integer> byteQueue = new LinkedBlockingQueue<>();

    private volatile boolean closed;

    @Override
    public int read() throws IOException {
        try {
            Optional<Integer> maybeInt;
            while (true) {
                maybeInt = Optional.ofNullable(this.byteQueue.poll(POLL_INTERVAL_MS, TimeUnit.MILLISECONDS));

                // If we get an integer from the queue, return it.
                if (maybeInt.isPresent()) {
                    return maybeInt.get();
                }

                // If the stream is closed and there is nothing queued up, return -1.
                if (this.closed) {
                    return -1;
                }
            }
        } catch (InterruptedException e) {
            throw new IOException(e);
        }
    }

    /**
     * Writes data into the stream to be offered on future read() calls.
     */
    public void write(byte[] byteArray) {
        // Don't write into the stream if it is already closed.
        if (this.closed) {
            throw new UncheckedIOException(new IOException("Stream already closed when attempting to write into it."));
        }

        for (byte b : byteArray) {
            this.byteQueue.add(b & UNSIGNED_BYTE_MASK);
        }
    }

    @Override
    public void close() throws IOException {
        this.closed = true;
        super.close();
    }
}
```