

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Démarrage d'un flux de conversation vers un bot Amazon Lex V2
<a name="start-stream-conversation"></a>

Vous utilisez cette [StartConversation](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_StartConversation.html)opération pour démarrer un flux entre l'utilisateur et le bot Amazon Lex V2 dans votre application. La `POST` demande de l'application établit une connexion entre votre application et le bot Amazon Lex V2. Cela permet à votre application et au bot de commencer à échanger des informations par le biais d'événements.

**Note**  
Lors de l'utilisation StartConversation, si la durée audio de l'énoncé dépasse la valeur configurée pour`max-length-ms`, Amazon Lex V2 coupe le son à la durée spécifiée.

L'`StartConversation`opération est prise en charge uniquement dans les cas suivants SDKs : 
+ [Kit AWS SDK pour C\$1\$1](https://docs.aws.amazon.com/goto/SdkForCpp/runtime.lex.v2-2020-08-07/StartConversation)
+ [Kit AWS SDK pour Java V2](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lexruntimev2/LexRuntimeV2AsyncClient.html)
+ [Kit de développement logiciel AWS pour v3 JavaScript ](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-lex-runtime-v2/index.html#aws-sdkclient-lex-runtime-v2)
+ [AWS SDK pour Ruby V3](https://docs.aws.amazon.com/goto/SdkForRubyV3/runtime.lex.v2-2020-08-07/StartConversation)

Le premier événement que votre application doit envoyer au bot Amazon Lex V2 est un [ConfigurationEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_ConfigurationEvent.html). Cet événement inclut des informations telles que le format du type de réponse. Les paramètres que vous pouvez utiliser dans un événement de configuration sont les suivants :
+ **responseContentType**— Détermine si le bot répond aux entrées de l'utilisateur par du texte ou de la parole.
+ **SessionState** — Informations relatives à la session de streaming avec le bot, telles que l'intention prédéterminée ou l'état du dialogue.
+ **WelcomeMessages** — Spécifie les messages de bienvenue adressés à l'utilisateur au début de sa conversation avec un bot. Ces messages sont diffusés avant que l'utilisateur ne saisisse quoi que ce soit. Pour activer un message de bienvenue, vous devez également spécifier des valeurs pour les `dialogAction` paramètres `sessionState` et. 
+ **DisablePlayback** — Détermine si le bot doit attendre un signal du client avant de commencer à écouter les informations de l'appelant. Par défaut, la lecture est activée. La valeur de ce champ est donc`false`.
+ **RequestAttributes** — Fournit des informations supplémentaires pour la demande.

Pour plus d'informations sur la manière de spécifier les valeurs des paramètres précédents, consultez le type de [ConfigurationEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_ConfigurationEvent.html)données de l'[StartConversation](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_StartConversation.html)opération.

Chaque flux entre un bot et votre application ne peut comporter qu'un seul événement de configuration. Une fois que votre application a envoyé un événement de configuration, le bot peut recevoir des communications supplémentaires de votre application.

Si vous avez indiqué que votre utilisateur utilise le son pour communiquer avec le bot Amazon Lex V2, votre application peut envoyer les événements suivants au bot au cours de cette conversation :
+ [AudioInputEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_AudioInputEvent.html)— Contient un bloc audio dont la taille maximale est de 320 octets. Votre application doit utiliser plusieurs événements d'entrée audio pour envoyer un message du serveur au bot. Chaque événement d'entrée audio du flux doit avoir le même format audio.
+ [DTMFInputÉvénement](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_DTMFInputEvent.html) — Envoie une entrée DTMF au bot. Chaque pression sur une touche DTMF correspond à un seul événement.
+ [PlaybackCompletionEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_PlaybackCompletionEvent.html)— Informe le serveur qu'une réponse provenant de l'entrée de l'utilisateur lui a été retransmise. Vous devez utiliser un événement de fin de lecture si vous envoyez une réponse audio à l'utilisateur. Si votre événement `disablePlayback` de configuration l'est`true`, vous ne pouvez pas utiliser cette fonctionnalité.
+ [DisconnectionEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_DTMFInputEvent.html)— Informe le bot que l'utilisateur s'est déconnecté de la conversation.

Si vous avez indiqué que l'utilisateur utilise du texte pour communiquer avec le bot, votre application peut envoyer les événements suivants au bot au cours de cette conversation :
+ [TextInputEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_TextInputEvent.html)— Texte envoyé par votre application au bot. Un événement de saisie de texte peut contenir jusqu'à 512 caractères.
+ [PlaybackCompletionEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_PlaybackCompletionEvent.html)— Informe le serveur qu'une réponse provenant de l'entrée de l'utilisateur lui a été retransmise. Vous devez utiliser cet événement si vous retransmettez du son à l'utilisateur. Si votre événement `disablePlayback` de configuration l'est`true`, vous ne pouvez pas utiliser cette fonctionnalité.
+ [DisconnectionEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_DTMFInputEvent.html)— Informe le bot que l'utilisateur s'est déconnecté de la conversation.

Vous devez encoder chaque événement que vous envoyez à un bot Amazon Lex V2 dans le bon format. Pour de plus amples informations, veuillez consulter [Encodage de flux d’événements](event-stream-encoding.md).

Chaque événement possède un identifiant d'événement. Pour résoudre les problèmes susceptibles de survenir dans le flux, attribuez un identifiant d'événement unique à chaque événement en entrée. Vous pouvez ensuite résoudre les problèmes de traitement éventuels avec le bot.

Amazon Lex V2 utilise également des horodatages pour chaque événement. Vous pouvez utiliser ces horodatages en plus de l'identifiant de l'événement pour résoudre les problèmes de transmission réseau.

Au cours de la conversation entre l'utilisateur et le bot Amazon Lex V2, celui-ci peut envoyer les événements sortants suivants en réponse à l'utilisateur :
+ [IntentResultEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_IntentResultEvent.html)— Contient l'intention déterminée par Amazon Lex V2 à partir de l'énoncé de l'utilisateur. Chaque événement de résultat interne inclut :
  + **InputMode** — Type d'énoncé utilisé par l'utilisateur. Les valeurs valides sont `Speech`, `DTMF` ou `Text`.
  + **interprétations** : interprétations qu'Amazon Lex V2 détermine à partir de l'énoncé de l'utilisateur.
  + **RequestAttributes** — Si vous n'avez pas modifié les attributs de la demande à l'aide d'une fonction lambda, il s'agit des mêmes attributs que ceux transmis au début de la conversation.
  + **SessionId** — Identifiant de session utilisé pour la conversation.
  + **SessionState — État** de la session de l'utilisateur avec Amazon Lex V2.
+ [TranscriptEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_TranscriptEvent.html)— Si l'utilisateur fournit une entrée à votre application, cet événement contient la transcription de l'énoncé de l'utilisateur au bot. Votre application ne reçoit pas de message `TranscriptEvent` s'il n'y a aucune entrée utilisateur.

  La valeur de l'événement de transcription envoyé à votre application varie selon que vous avez spécifié le mode audio (voix et DMTF) ou le texte comme mode de conversation :
  + Transcription de la saisie vocale — Si l'utilisateur parle avec le bot, l'événement de transcription est la transcription du son de l'utilisateur. Il s'agit d'une transcription de tous les discours depuis le moment où l'utilisateur commence à parler jusqu'au moment où il finit de parler.
  + Transcription de l'entrée DTMF — Si l'utilisateur tape sur un clavier, l'événement de transcription contient tous les chiffres que l'utilisateur a pressés lors de sa saisie.
  + Transcription de la saisie de texte : si l'utilisateur saisit du texte, l'événement de transcription contient tout le texte saisi par l'utilisateur.
+ [TextResponseEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_TextResponseEvent.html)— Contient la réponse du bot au format texte. Une réponse textuelle est renvoyée par défaut. Si vous avez configuré Amazon Lex V2 pour renvoyer une réponse audio, ce texte est utilisé pour générer une réponse audio. Chaque événement de réponse textuelle contient un tableau d'objets de message que le bot renvoie à l'utilisateur.
+ [AudioResponseEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_AudioResponseEvent.html)— Contient la réponse audio synthétisée à partir du texte généré dans le`TextResponseEvent`. Pour recevoir des événements de réponse audio, vous devez configurer Amazon Lex V2 pour fournir une réponse audio. Tous les événements de réponse audio ont le même format audio. Chaque événement contient des segments audio d'une taille maximale de 100 octets. Amazon Lex V2 envoie un fragment audio vide dont le `bytes` champ est défini `null` pour indiquer la fin de l'événement de réponse audio à votre application.
+ [PlaybackInterruptionEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_PlaybackInterruptionEvent.html)— Lorsqu'un utilisateur interrompt une réponse envoyée par le bot à votre application, Amazon Lex V2 déclenche cet événement pour arrêter la lecture de la réponse.
+ [HeartbeatEvent](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_HeartbeatEvent.html)— Amazon Lex V2 renvoie régulièrement cet événement pour empêcher l'expiration du délai de connexion entre votre application et le bot.

## Séquence chronologique des événements d'une conversation audio lors de l'utilisation d'un bot Amazon Lex V2
<a name="audio-conversation-sequence"></a>

Les diagrammes suivants montrent une conversation audio en streaming entre un utilisateur et un bot Amazon Lex V2. L'application diffuse du son en continu vers le bot, qui recherche les entrées de l'utilisateur à partir de l'audio. Dans cet exemple, l'utilisateur et le bot utilisent la parole pour communiquer. Chaque diagramme correspond à un énoncé de l'utilisateur et à la réponse du bot à cet énoncé.

Le schéma suivant montre le début d'une conversation entre l'application et le bot. Le flux commence à l'heure zéro (t0). 

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


La liste suivante décrit les événements du schéma précédent.
+ t0 : L'application envoie un événement de configuration au bot pour démarrer le flux.
+ t1 : L'application diffuse des données audio. Ces données sont divisées en une série d'événements d'entrée provenant de l'application.
+ t2 : Pour *l'énoncé utilisateur 1*, le bot détecte un événement d'entrée audio lorsque l'utilisateur commence à parler.
+ t2 : Pendant que l'utilisateur parle, le bot envoie un battement de cœur pour maintenir la connexion. Il envoie ces événements par intermittence pour s'assurer que la connexion n'expire pas.
+ t3 : Le bot détecte la fin de l'énoncé de l'utilisateur.
+ t4 : Le bot renvoie un événement de transcription contenant une transcription du discours de l'utilisateur à l'application. C'est le début de la *réponse du bot à l'énoncé 1 de l'utilisateur*.
+ t5 : Le bot envoie un événement de résultat d'intention pour indiquer l'action que l'utilisateur souhaite effectuer.
+ t6 : Le bot commence à fournir sa réponse sous forme de texte dans un événement de réponse textuelle.
+ t7 : Le bot envoie une série d'événements de réponse audio à l'application pour qu'elle soit diffusée par l'utilisateur.
+ t8 : Le bot envoie un autre événement de battement de cœur pour maintenir la connexion par intermittence.

Le schéma suivant est une continuation du schéma précédent. Il montre que l'application envoie un événement de fin de lecture au bot pour indiquer qu'elle a arrêté de lire la réponse audio pour l'utilisateur. L'application renvoie à l'*utilisateur la réponse du bot à l'énoncé 1* de l'utilisateur. L'utilisateur répond à la *réponse du bot à l'énoncé utilisateur 1* par *l'énoncé utilisateur* 2.

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


La liste suivante décrit les événements du schéma précédent :
+ t10 : L'application envoie un événement de fin de lecture pour indiquer qu'elle a fini de lire le message du bot à l'utilisateur.
+ t11 : L'application renvoie la réponse de l'utilisateur au bot sous forme *d'énoncé utilisateur 2*.
+ t12 : Pour la *réponse du bot à l'énoncé 2 de l'utilisateur*, le bot attend que l'utilisateur arrête de parler, puis commence à fournir une réponse audio.
+ t13 : Pendant que le bot envoie la *réponse du bot à l'énoncé utilisateur 2* à l'application, le bot détecte le début de l'énoncé *utilisateur* 3. Le bot arrête la *réponse du bot à l'énoncé 2 de l'utilisateur* et envoie un événement d'interruption de lecture.
+ t14 : Le bot envoie un événement d'interruption de lecture à l'application pour signaler que l'utilisateur a interrompu l'invite.

Le schéma suivant montre la *réponse du bot à l'énoncé 3 de l'utilisateur* et indique que la conversation se poursuit une fois que le bot a répondu à l'énoncé de l'utilisateur.

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


# Utiliser l'API pour démarrer une conversation en streaming
<a name="using-streaming-api"></a>

Lorsque vous lancez un flux vers un bot Amazon Lex V2, vous effectuez les tâches suivantes :

1. Créez une connexion initiale avec le serveur.

1. Configurez les informations d'identification de sécurité et les détails du bot. Les détails du bot indiquent si le bot prend en charge le DTMF et l'entrée audio, ou la saisie de texte.

1. Envoyez des événements au serveur. Ces événements sont des données texte ou audio provenant de l'utilisateur.

1. Traitez les événements envoyés depuis le serveur. Au cours de cette étape, vous déterminez si le résultat du bot est présenté à l'utilisateur sous forme de texte ou de parole.

Les exemples de code suivants initialisent une conversation en streaming avec un bot Amazon Lex V2 et votre machine locale. Vous pouvez modifier le code en fonction de vos besoins.

Le code suivant est un exemple de demande utilisant le AWS SDK pour Java pour démarrer la connexion à un bot et configurer les détails et les informations d'identification du bot.

```
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();
        }
    }
}
```

Le code suivant est un exemple de demande utilisant le AWS SDK pour Java pour envoyer des événements au bot. Le code de cet exemple utilise le microphone de votre ordinateur pour envoyer des événements audio.

```
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();
        }
    }
}
```

Le code suivant est un exemple de demande utilisant le AWS SDK pour Java pour gérer les réponses du bot. Le code de cet exemple configure Amazon Lex V2 pour qu'il vous renvoie une réponse audio.

```
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;
    }

}
```

Pour configurer un bot afin qu'il réponde aux événements d'entrée par du son, vous devez d'abord vous abonner aux événements audio d'Amazon Lex V2, puis configurer le bot pour qu'il fournisse une réponse audio aux événements d'entrée de l'utilisateur.

Le code suivant est un AWS SDK pour Java exemple de souscription à des événements audio depuis 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);
            }
        }
    }
}
```

L' AWS SDK pour Java exemple suivant configure le bot Amazon Lex V2 pour fournir une réponse audio aux événements d'entrée.

```
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();
    }
}
```