Enviar notificações proativas para os usuários

APLICA-SE A: SDK v4

Normalmente, um bot envia uma mensagem a um usuário diretamente em resposta ao recebimento de uma mensagem do usuário. Ocasionalmente, um bot pode precisar enviar uma mensagem proativa, uma mensagem em resposta a um estímulo não originado pelo usuário.

As mensagens proativas podem ser úteis em vários cenários. Por exemplo, se o usuário tiver solicitado ao bot o monitoramento do preço de um produto, se o preço do produto cair 20%, o bot poderá alertar o usuário. Ou, se o bot precisar de um tempo para compilar uma resposta para a pergunta do usuário, ele poderá informar ao usuário sobre o atraso e permitir que a conversa continue enquanto isso. Quando o bot terminar de compilar a resposta para a pergunta, compartilhará essas informações com o usuário.

Este artigo aborda informações sobre mensagens proativas para bots em geral. Para obter informações sobre mensagens proativas no Microsoft Teams, confira

Observação

Os SDKs JavaScript, C# e Python do Bot Framework continuarão a ser compatíveis. No entanto, o SDK Java está sendo desativado, com o suporte final de longo prazo terminando em novembro de 2023.

Os bots existentes criados com o SDK para Java continuarão a funcionar.

Para a criação de novos bots, considere usar o Microsoft Copilot Studio e leia sobre como escolher a solução de copiloto certa.

Para obter mais informações, confira O futuro da criação de bots.

Pré-requisitos

Sobre a amostra proativa

Em geral, um bot como aplicativo tem algumas camadas:

  • O aplicativo Web que pode aceitar solicitações HTTP e é compatível especificamente com um ponto de extremidade de mensagens.
  • Um adaptador que lida com a conectividade com os canais.
  • Um manipulador para o turno, normalmente encapsulado em uma classe de bot que lida com o raciocínio de conversação para o aplicativo de bot.

Em resposta a uma mensagem recebida do usuário, o aplicativo chama o método de atividade de processo do adaptador, que cria um contexto de turno e turno, chama seu pipeline de middleware e, em seguida, chama o manipulador de turno do bot.

Para iniciar uma mensagem proativa, o aplicativo de bot precisa conseguir receber outras entradas. A lógica de aplicativo para iniciar uma mensagem proativa está fora do escopo do SDK. Para esse exemplo, um ponto de extremidade de notificação, além de um ponto de extremidade de mensagens padrão, é usado para acionar o turno proativo.

Em resposta a uma solicitação GET nesse ponto de extremidade de notificação, o aplicativo chama o método de continuação de conversa do adaptador, que se comporta de forma semelhante ao método de atividade de processo. O método de continuação de conversa:

  • Recebe uma referência de conversa apropriada para o usuário e o método de retorno de chamada a ser usado para o turno proativo.
  • Cria uma atividade de evento e um contexto de turno para o turno proativo.
  • Chama o pipeline de middleware do adaptador.
  • Chama o método de retorno de chamada fornecido.
  • O contexto de turno usa a referência de conversa para enviar qualquer mensagem ao usuário.

O exemplo tem um bot, um ponto de extremidade de mensagens e um ponto de extremidade extra que é usado para enviar mensagens proativas ao usuário, conforme mostrado na ilustração a seguir.

Diagrama de interação mostrando como o bot obtém uma referência de conversa e a usa para enviar uma mensagem proativa.

Recuperar e armazenar a referência de conversa

Quando o Bot Framework Emulator se conecta ao bot, ele recebe duas atividades de atualização de conversa. No manipulador de atividade de atualização de conversa do bot, a referência de conversa é recuperada e armazenada em um dicionário, conforme mostrado abaixo.

Bots\ProactiveBot.cs

private void AddConversationReference(Activity activity)
{
    var conversationReference = activity.GetConversationReference();
    _conversationReferences.AddOrUpdate(conversationReference.User.Id, conversationReference, (key, newValue) => conversationReference);
}

protected override Task OnConversationUpdateActivityAsync(ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
    AddConversationReference(turnContext.Activity as Activity);

    return base.OnConversationUpdateActivityAsync(turnContext, cancellationToken);
}

A referência de conversa inclui uma propriedade de conversa que descreve a conversa na qual a atividade existe. A conversa inclui uma propriedade de usuário que lista os usuários que participam da conversa e uma propriedade de URL de serviço que indica para onde as respostas à atividade atual podem ser enviadas. Uma referência de conversa válida é necessária para enviar mensagens proativas para os usuários. (Para o canal do Teams, o URL de serviço é mapeado para um servidor regionalizado).

Observação

Em um cenário real, você manteria as referências de conversa em um banco de dados em vez de usar um objeto na memória.

Enviar uma mensagem proativa

O segundo controlador, o controlador de notificação, é responsável por enviar a mensagem proativa ao usuário. Ele usa as seguintes etapas para gerar uma mensagem proativa.

  1. Recupera a referência da conversa para a qual será enviada a mensagem proativa.
  2. Chama o método de continuação de conversa do adaptador, fornecendo a referência de conversa e o manipulador de turno delegado a ser usado. (O método de continuação de conversa gera um contexto de turno para a conversa referenciada e, em seguida, chama o manipulador de turno especificado.)
  3. No delegado, usa o contexto de turno para enviar a mensagem proativa. Aqui, o delegado é definido no controlador de notificação e envia a mensagem proativa ao usuário.

Observação

Embora cada canal deva usar um URL de serviço estável, o URL pode mudar com o tempo. Para obter mais informações sobre o URL do serviço, confira as seções Estrutura básica da atividade e URL do serviço do esquema de atividades do Bot Framework.

Se o URL do serviço for alterado, as referências de conversas anteriores não serão mais válidas e as chamadas para continuar a conversa gerarão um erro ou uma exceção. Nesse caso, seu bot precisará adquirir uma nova referência de conversa para o usuário antes de poder enviar mensagens proativas novamente.

Controllers\NotifyController .cs

Sempre que a página de notificação do bot é solicitada, o controlador de notificação recupera as referências de conversa a partir do dicionário. Então, o controlador usa os métodos ContinueConversationAsync e BotCallback para enviar a mensagem proativa.

[Route("api/notify")]
[ApiController]
public class NotifyController : ControllerBase
{
    private readonly IBotFrameworkHttpAdapter _adapter;
    private readonly string _appId;
    private readonly ConcurrentDictionary<string, ConversationReference> _conversationReferences;

    public NotifyController(IBotFrameworkHttpAdapter adapter, IConfiguration configuration, ConcurrentDictionary<string, ConversationReference> conversationReferences)
    {
        _adapter = adapter;
        _conversationReferences = conversationReferences;
        _appId = configuration["MicrosoftAppId"] ?? string.Empty;
    }

    public async Task<IActionResult> Get()
    {
        foreach (var conversationReference in _conversationReferences.Values)
        {
            await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, conversationReference, BotCallback, default(CancellationToken));
        }
        
        // Let the caller know proactive messages have been sent
        return new ContentResult()
        {
            Content = "<html><body><h1>Proactive messages have been sent.</h1></body></html>",
            ContentType = "text/html",
            StatusCode = (int)HttpStatusCode.OK,
        };
    }

    private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken)
    {
        await turnContext.SendActivityAsync("proactive hello");
    }
}

Para enviar uma mensagem proativa, o adaptador requer uma ID do aplicativo para o bot. Em um ambiente de produção, você pode usar a ID do aplicativo do bot. Para testar o bot localmente com o Emulator, você pode usar a sequência vazia ("").

Testar seu bot

  1. Caso ainda não tenha feito isso, instale o Bot Framework Emulator.
  2. Execute o exemplo localmente em seu computador.
  3. Inicie o Emulator e conecte-se ao seu bot.
  4. Carregar à página de api/notificação do seu bot. Isso gerará uma mensagem proativa no Emulator.

Informações adicionais

Requisitos

Antes de poder enviar uma mensagem proativa, seu bot precisa de uma referência de conversa. Seu bot pode recuperar a referência de conversa de qualquer atividade que tenha recebido do usuário, mas isso normalmente exige que o usuário interaja com o bot pelo menos uma vez antes que o bot possa enviar uma mensagem proativa.

Muitos canais proíbem que um bot envie mensagens a um usuário, a menos que o usuário tenha enviado mensagens ao bot pelo menos uma vez. Alguns canais permitem exceções. Por exemplo, o canal do Teams permite que seu bot envie uma mensagem proativa (ou 1 por 1) para indivíduos em uma conversa em grupo já estabelecida que inclua o bot.

Considerações sobre o design

Ao implementar mensagens proativas em seu bot, não envie várias mensagens proativas em um curto período de tempo. Alguns canais impõem restrições sobre a frequência de envio de mensagens para o usuário de um bot, e desabilitarão o bot se ele violar essas restrições.

Para o tipo mais simples de mensagem proativa, o bot interpõe a mensagem na conversa quando é acionado, sem levar em conta o estado atual ou o tópico da conversa. Nesse cenário, a mensagem proativa interrompe o fluxo normal da conversa.

Para lidar com notificações de forma mais suave, considere outras maneiras de integrar a notificação no fluxo de conversa, como definir um sinalizador no estado da conversa ou adicionar a notificação a uma fila.

Sobre o turno proativo

O método de continuação da conversa usa a referência de conversa e um manipulador de retorno de chamada para:

  1. Criar um turno no qual o aplicativo de bot possa enviar a mensagem proativa. O adaptador cria uma atividade event para esse turno, com seu nome definido como "ContinueConversation".
  2. Enviar o turno pelo pipeline de middleware do adaptador.
  3. Chamar o manipulador de retorno de chamada de volta para executar a lógica personalizada.

No exemplo de mensagens proativas, o manipulador de retorno de chamada de turno é definido no controlador de notificação e envia a mensagem diretamente para a conversa, sem enviar a atividade proativa por meio do manipulador de turno normal do bot. O código de exemplo também não acessa nem atualiza o estado do bot no turno proativo.

Muitos bots funcionam com estado e usam o estado para gerenciar uma conversa em vários turnos. Quando o método de continuação de conversa cria um contexto de turno, o turno tem o usuário correto e o estado de conversa associado a ele, e você pode integrar turnos proativos à lógica do seu bot. Se você precisar que a lógica do bot esteja ciente da mensagem proativa, você tem algumas opções para fazer isso. Você poderá:

  • Forneça o manipulador de turno do bot como o manipulador de retorno de chamada de turno. O bot receberá então a atividade do evento "ContinueConversation".
  • Use o manipulador de retorno de chamada de turno para adicionar informações ao contexto de turno em primeiro lugar e, em seguida, chame o manipulador de turno do bot.

Em ambos os casos, você precisará projetar sua lógica de bot para gerenciar o evento proativo.

Próximas etapas