Enregistrer les données d’utilisateur et de conversation

S'APPLIQUE À : SDK v4

Un bot est par nature sans état. Une fois que votre bot est déployé, il ne peut pas s’exécuter dans le même processus ni sur le même ordinateur d’un tour à l’autre. Votre bot peut toutefois peut avoir besoin de suivre le contexte d’une conversation pour pouvoir gérer son comportement et se rappeler les réponses aux questions précédentes. Les fonctionnalités d’état et de stockage du SDK Bot Framework permettent d’ajouter un état à votre bot. Les bots utilisent la gestion de l’état et les objets de stockage pour gérer et conserver l’état. Le gestionnaire d’état fournit une couche d’abstraction qui vous permet d’accéder aux propriétés d’état à l’aide d’accesseurs de propriété, indépendamment du type de stockage sous-jacent.

Remarque

Les kits SDK JavaScript, C# et Python Bot Framework continueront d’être pris en charge. Toutefois, le kit de développement logiciel (SDK) Java est mis hors service avec une prise en charge finale à long terme se terminant en novembre 2023.

Les bots existants créés avec le kit de développement logiciel (SDK) Java continueront de fonctionner.

Pour la nouvelle génération de bots, envisagez d'utiliser Power Virtual Agents et découvrez comment choisir la solution de chatbot appropriée.

Pour plus d’informations, consultez Les futures versions de bot.

Prérequis

À propos de cet exemple

Quand il reçoit l’entrée utilisateur, cet exemple vérifie l’état de conversation stocké pour voir si cet utilisateur a précédemment été invité à fournir son nom. Si ce n’est pas le cas, le nom de l’utilisateur est demandé et cette entrée est stockée dans l’état utilisateur. Dans l'affirmative, le nom stocké dans l'état utilisateur sert à communiquer avec l'utilisateur. Par ailleurs, ses données d'entrée ainsi que l'heure de réception et l'ID du canal d'entrée sont renvoyés à l'utilisateur. Les valeurs d'heure et d'ID de canal sont récupérées à partir des données de conversation utilisateur, puis enregistrées dans l'état de conversation. Le diagramme suivant montre la relation entre le bot, le profil utilisateur et les classes de données de conversation.

Définir les classes

La première étape de la configuration de la gestion d’état consiste à définir les classes qui contiennent les informations à gérer dans l’état utilisateur et l’état de conversation. L’exemple utilisé dans cet article définit les classes suivantes :

  • Dans UserProfile.cs, vous définissez une classe UserProfile pour les informations utilisateur qui seront collectées par le bot.
  • Dans ConversationData.cs, vous définissez une classe ConversationData pour contrôler l'état de votre conversation pendant la collecte des informations utilisateur.

Les exemples de code suivants illustrent les définitions des classes UserProfile et ConversationData.

UserProfile.cs

public class UserProfile
{
    public string Name { get; set; }
}

ConversationData.cs

public class ConversationData
{
    // The time-stamp of the most recent incoming message.
    public string Timestamp { get; set; }

    // The ID of the user's channel.
    public string ChannelId { get; set; }

    // Track whether we have already asked the user's name
    public bool PromptedUserForName { get; set; } = false;
}

Créer des objets d’état utilisateur et de conversation

Ensuite, vous inscrivez MemoryStorage qui est utilisé pour créer les objets UserState et ConversationState. Les objets d’état utilisateur et de conversation sont créés lors de Startup et la dépendance est injectée dans le constructeur de bot. Les autres services inscrits qui disponibles pour un bot sont les suivants : un fournisseur d’informations d’identification, un adaptateur et l’implémentation de bot.

Startup.cs

// {
//     TypeNameHandling = TypeNameHandling.All,
// var storage = new BlobsStorage("<blob-storage-connection-string>", "bot-state");

// With a custom JSON SERIALIZER, use this instead.
// var storage = new BlobsStorage("<blob-storage-connection-string>", "bot-state", jsonSerializer);

/* END AZURE BLOB STORAGE */

Bots/StateManagementBot.cs

private BotState _conversationState;
private BotState _userState;

public StateManagementBot(ConversationState conversationState, UserState userState)
{
    _conversationState = conversationState;
    _userState = userState;
}

Ajouter des accesseurs de propriété d’état

Vous pouvez à présent créer des accesseurs de propriété à l'aide de la méthode CreateProperty qui fournit un gestionnaire à l'objet BotState. Chaque accesseur de propriété d’état vous permet d’obtenir ou de définir la valeur de la propriété d’état associée. Avant d'utiliser les propriétés de l'état, utilisez chaque accesseur pour charger la propriété à partir du stockage et la récupérer depuis le cache de l'état. Pour obtenir la clé incluse dans l'étendue appropriée et associée à la propriété d'état, vous appelez la méthode GetAsync.

Bots/StateManagementBot.cs

var conversationStateAccessors = _conversationState.CreateProperty<ConversationData>(nameof(ConversationData));
var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));

Accéder à l’état à partir du bot

La section précédente présente les étapes nécessaires au moment de l’initialisation pour ajouter des accesseurs de propriété d’état à notre bot. Vous pouvez à présent utiliser ces accesseurs au moment de l'exécution pour lire et écrire des informations d'état. L’exemple de code ci-dessous utilise le flux logique suivant :

  • Si userProfile.Name est vide et conversationData.PromptedUserForName a la valeur true, vous récupérez le nom d'utilisateur fourni et le stockez dans l'état de l'utilisateur.
  • Si userProfile.Name est vide et conversationData.PromptedUserForName a la valeur false, vous demandez le nom de l'utilisateur.
  • Si userProfile.Name a été stocké, vous récupérez l'heure du message et l'ID du canal à partir de l'entrée de l'utilisateur, vous renvoyez toutes les données à l'utilisateur et vous stockez les données récupérées dans l'état de la conversation.

Bots/StateManagementBot.cs

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    // Get the state properties from the turn context.

    var conversationStateAccessors = _conversationState.CreateProperty<ConversationData>(nameof(ConversationData));
    var conversationData = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationData());

    var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
    var userProfile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile());

    if (string.IsNullOrEmpty(userProfile.Name))
    {
        // First time around this is set to false, so we will prompt user for name.
        if (conversationData.PromptedUserForName)
        {
            // Set the name to what the user provided.
            userProfile.Name = turnContext.Activity.Text?.Trim();

            // Acknowledge that we got their name.
            await turnContext.SendActivityAsync($"Thanks {userProfile.Name}. To see conversation data, type anything.");

            // Reset the flag to allow the bot to go through the cycle again.
            conversationData.PromptedUserForName = false;
        }
        else
        {
            // Prompt the user for their name.
            await turnContext.SendActivityAsync($"What is your name?");

            // Set the flag to true, so we don't prompt in the next turn.
            conversationData.PromptedUserForName = true;
        }
    }
    else
    {
        // Add message details to the conversation data.
        // Convert saved Timestamp to local DateTimeOffset, then to string for display.
        var messageTimeOffset = (DateTimeOffset)turnContext.Activity.Timestamp;
        var localMessageTime = messageTimeOffset.ToLocalTime();
        conversationData.Timestamp = localMessageTime.ToString();
        conversationData.ChannelId = turnContext.Activity.ChannelId.ToString();

        // Display state data.
        await turnContext.SendActivityAsync($"{userProfile.Name} sent: {turnContext.Activity.Text}");
        await turnContext.SendActivityAsync($"Message received at: {conversationData.Timestamp}");
        await turnContext.SendActivityAsync($"Message received from: {conversationData.ChannelId}");
    }
}

Avant de quitter le gestionnaire de tours, vous utilisez la méthode SaveChangesAsync() des objets de gestion de l'état pour écrire toutes les modifications de l'état dans le stockage.

Bots/StateManagementBot.cs

public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
    await base.OnTurnAsync(turnContext, cancellationToken);

    // Save any state changes that might have occurred during the turn.
    await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}

Tester votre bot

  1. Téléchargez et installez la dernière version de Bot Framework Emulator.
  2. Exécutez l’exemple en local sur votre machine. Si vous avez besoin d'instructions, consultez le fichier README pour C#, JavaScript, Java, ou Python.
  3. Utilisez l'émulateur pour tester votre exemple de bot.

Informations supplémentaires

Cet article décrit comment ajouter un état à votre bot. Consultez le tableau suivant pour plus d'informations sur les rubriques connexes.

Rubrique Notes
Confidentialité Si vous prévoyez de stocker les données personnelles de l’utilisateur, vous devez veiller au respect du Règlement général sur la protection des données.
Gestion de l’état Tous les appels de gestion d’état sont asynchrones et, par défaut, le dernier qui écrit gagne (last-writer-wins). Dans la pratique, vous devez obtenir, définir et enregistrer l’état dans votre bot de la façon la plus rapprochée possible. Pour une discussion sur la façon d'implémenter le verrouillage optimiste, consultez Implémenter un stockage personnalisé pour votre bot.
Données critique sur l'activité Utilisez l'état du bot pour stocker les préférences, le nom d'utilisateur ou le dernier élément commandé. En revanche, ne l'utilisez pas pour stocker des données critiques. Pour les données critiques, créez vos propres composants de stockage ou écrivez directement dans le stockage.
Texte de reconnaissance L’exemple utilise les bibliothèques Microsoft/Recognizers-Text pour analyser et valider les entrées utilisateur. Pour plus d’informations, consultez la page de présentation.

Étapes suivantes

Découvrez comment poser une série de questions à l'utilisateur, valider ses réponses et enregistrer ses données.