Беседа с ботом Microsoft Teams

Важно!

Эта статья основана на пакете SDK Bot Framework версии 3. Если вы ищете текущую документацию по пакету SDK версии 4.6 или более поздней, см. раздел Боты для бесед.

Беседа — это серия сообщений, отправляемых ботом одним или несколькими пользователями. Существует три типа бесед (также называемых областью) в Teams:

  • teams: также называются беседами канала, которые видимы для всех участников канала.
  • personal: беседы между ботами и одним пользователем
  • groupChat: беседа между ботом и двумя или более пользователями

Поведение бота немного отличается в зависимости от типа беседы, в которых он участвует:

Чтобы бот работал в определенной области, он должен быть указан как поддерживающий эту область в манифесте. Области определены и описаны далее в справочнике по манифестам.

Упреждающие сообщения

Боты могут участвовать в беседе или инициировать ее. Большинство сообщений отправляется в ответ на другое сообщение. Если бот инициирует беседу, это называется упреждающим сообщением. Вот некоторые примеры.

  • Приветствия
  • Уведомления о событиях
  • Сообщения опроса

Основы разговора

Каждое сообщение является объектом Activity типа messageType: message. Когда пользователь отправляет сообщение, Teams отправляет его боту; в частности, он отправляет объект JSON в конечную точку обмена сообщениями бота. Бот проверяет сообщение, чтобы определить его тип и ответить соответствующим образом.

Боты также поддерживают сообщения в стиле событий. Дополнительные сведения см. в статье Обработка событий бота в Microsoft Teams. В настоящее время речь не поддерживается.

Сообщения обычно одинаковы во всех областях, но существуют различия в способах доступа к боту в пользовательском интерфейсе и различия в фоновом режиме, о которых необходимо знать.

Базовая беседа обрабатывается через соединитель Bot Framework, единый REST API, позволяющий боту взаимодействовать с Teams и другими каналами. Пакет SDK Bot Builder предоставляет простой доступ к этому API, дополнительные функции для управления потоком и состоянием беседы, а также простые способы внедрения когнитивных служб, таких как обработка на естественном языке (NLP).

Содержимое сообщения

Бот может отправлять форматированный текст, изображения и карточки. Пользователи могут отправлять боту форматированный текст и изображения. Вы можете указать тип содержимого, которое бот может обрабатывать, на странице параметров Microsoft Teams для вашего бота.

Формат От пользователя к боту От бота к пользователю Примечания
Форматированный текст
Изображения Размер не должен превышать 1024×1024 МБ и 1 МБ в формате PNG, JPEG или GIF. GIF с анимацией не поддерживается.
Карточки Сведения о поддерживаемых карточках см. в Справочнике по карточкам Teams.
Эмодзи В настоящее время Teams поддерживает эмодзи через UTF-16, например U+1F600 для ухмыляющейся рожицы.

Дополнительные сведения о типах взаимодействия с ботами, поддерживаемых Bot Framework, на которых основаны боты в Teams, см. в документации по Bot Framework о потоке беседы, и связанных понятиям в документации по пакету SDK для Bot Builder для .NET и пакету SDK для Bot Builder для Node.js.

Форматирование сообщения

Можно задать необязательное свойство TextFormat для message, чтобы управлять отображением текстового содержимого сообщения. Подробное описание поддерживаемого форматирования в сообщениях ботов см. в разделе Форматирование сообщений. Можно задать необязательное свойство TextFormat, чтобы управлять отображением текстового содержимого сообщения.

Подробные сведения о том, Teams поддерживает форматирование текста в командах, см. в разделе Форматирование текста в сообщениях бота.

Дополнительные сведения о форматировании карточек в сообщениях см. в разделе Форматирование карточек.

Сообщения с картинкой

Картинки отправляются путем добавления вложений к сообщению. Дополнительные сведения о вложениях см. в документации по Bot Framework.

Изображения могут иметь не более 1024× 1024 МБ и 1 МБ в формате PNG, JPEG или GIF; анимированный GIF не поддерживается.

Рекомендуется указать высоту и ширину каждого изображения с помощью XML. При использовании Markdown размер изображения по умолчанию — 256×256. Например:

  • Используйте <img src="http://aka.ms/Fo983c" alt="Duck on a rock" height="150" width="223"></img>
  • Не используйте ![Duck on a rock](http://aka.ms/Fo983c)

Получение сообщений

В зависимости от объявленных областей бот может получать сообщения в следующих контекстах:

  • личный чат. Пользователи могут взаимодействовать с ботом в приватной беседе, просто выбрав добавленного бота в истории чата или введя его имя или идентификатор приложения в поле "Кому:" в новом чате.
  • Каналы. Бот может быть упомянут в канале (@botname), если он был добавлен в команду. Обратите внимание, что дополнительные ответы боту в канале требуют упоминания бота. Бот не будет отвечать на ответы, в которых он не упоминается.

Для входящих сообщений бот получает объект Activity типа messageType: message. Хотя объект Activity может содержать другие типы информации, например обновления каналов, отправляемые боту, тип message представляет собой связь между ботом и пользователем.

Бот получает полезные данные, содержащие сообщение Text пользователя и другую информацию о пользователе, источнике сообщения и сведениях о Teams. Обратите внимание:

  • timestamp Дата и время сообщения в формате UTC.
  • localTimestamp Дата и время сообщения в часовом поясе отправителя.
  • channelId Всегда "msteams". Это относится к каналу bot Framework, а не каналу Teams.
  • from.id Уникальный и зашифрованный идентификатор этого пользователя для бота; подходит в качестве ключа, если вашему приложению необходимо хранить пользовательские данные. Он уникален для вашего бота и не может использоваться напрямую вне вашего экземпляра бота любым значимым способом для идентификации этого пользователя.
  • channelData.tenant.id Идентификатор клиента для пользователя.

Примечание.

from.id уникален для вашего бота и не может использоваться напрямую вне вашего экземпляра бота любым значимым способом для идентификации этого пользователя.

Объединение каналов и личных взаимодействий с ботом

При взаимодействии в канале бот должен уметь переводить определенные беседы с пользователем в автономный режим. Например, предположим, что пользователь пытается координировать сложную задачу, такую как планирование, с группой участников группы. Вместо того, чтобы отображать всю последовательность взаимодействий на канале, рассмотрите возможность отправки пользователю личного сообщения в чате. Бот должен иметь возможность легко переключать пользователя между личными беседами и беседами в канале беспроблемно.

Примечание.

Не забудьте обновить канал после завершения взаимодействия, чтобы уведомить других участников группы.

Пример полной входящей схемы

{
    "type": "message",
    "id": "1485983408511",
    "timestamp": "2017-02-01T21:10:07.437Z",
    "localTimestamp": "2017-02-01T14:10:07.437-07:00",
    "serviceUrl": "https://smba.trafficmanager.net/amer/",
    "channelId": "msteams",
    "from": {
        "id": "29:1XJKJMvc5GBtc2JwZq0oj8tHZmzrQgFmB39ATiQWA85gQtHieVkKilBZ9XHoq9j7Zaqt7CZ-NJWi7me2kHTL3Bw",
        "name": "Megan Bowen",
        "aadObjectId": "7faf8ab2-3d56-4244-b585-20c8a42ed2b8"
    },
    "conversation": {
        "conversationType": "personal",
        "id": "a:17I0kl9EkpE1O9PH5TWrzrLNwnWWcfrU7QZjKR0WSfOpzbfcAg2IaydGElSo10tVr4C7Fc6GtieTJX663WuJCc1uA83n4CSrHSgGBj5XNYLcVlJAs2ZX8DbYBPck201w-"
    },
    "recipient": {
        "id": "28:c9e8c047-2a74-40a2-b28a-b162d5f5327c",
        "name": "Teams TestBot"
    },
    "textFormat": "plain",
    "text": "Hello Teams TestBot",
    "entities": [
      { 
        "locale": "en-US",
        "country": "US",
        "platform": "Windows",
        "timezone": "America/Los_Angeles",
        "type": "clientInfo"
      }
    ],
    "channelData": {
        "tenant": {
            "id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
        }
    },
    "locale": "en-US"
}

Примечание.

Текстовое поле для входящих сообщений иногда содержит упоминания. Обязательно проверьте и удалите их. Дополнительные сведения см. в разделе Упоминания.

Данные канала Teams

Объект channelData содержит сведения, относящиеся к Teams, и является окончательным источником идентификаторов команд и каналов. Эти идентификаторы следует кэшировать и использовать в качестве ключей для локального хранилища.

Типичный объект channelData в действии, отправленном боту, содержит следующие сведения:

  • eventType Тип события Teams, который передается только в случае событий изменения канала.
  • tenant.idMicrosoft Entra идентификатор клиента; передается во всех контекстах.
  • team Передается только в контекстах канала, а не в личном чате.
  • channel Передается только в контексте канала при упоминании бота или для событий в каналах в командах, где бот был добавлен.
  • channelData.teamsTeamId Не рекомендуется. Это свойство включено только для обратной совместимости.
  • channelData.teamsChannelId Не рекомендуется. Это свойство включено только для обратной совместимости.

Пример объекта channelData (событие channelCreated)

"channelData": {
    "eventType": "channelCreated",
    "tenant": {
        "id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
    },
    "channel": {
        "id": "19:693ecdb923ac4458a5c23661b505fc84@thread.skype",
        "name": "My New Channel"
    },
    "team": {
        "id": "19:693ecdb923ac4458a5c23661b505fc84@thread.skype"
    }
}

Пример .NET

Пакет Microsoft.Bot.Connector.Teams предоставляет специализированный объект TeamsChannelData, который предоставляет свойства для доступа к сведениям, относящимся к Teams.

TeamsChannelData channelData = activity.GetChannelData<TeamsChannelData>();
string tenantId = channelData.Tenant.Id;

Отправка ответов на сообщения

Чтобы ответить на существующее сообщение, вызовите ReplyToActivity .NET или session.send Node.js. Пакет SDK Bot Builder обрабатывает все сведения.

Если вы решите использовать REST API, также можно вызвать конечную точку /v3/conversations/{conversationId}/activities/{activityId}.

Само содержимое сообщения может содержать простой текст или некоторые карточки и действия с карточками, предоставленные Bot Framework.

Обратите внимание, что в исходящей схеме вы всегда должны использовать ту же схему serviceUrl, что и полученную. Имейте в виду, что значение serviceUrl имеет тенденцию быть стабильным, но может измениться. Когда приходит новое сообщение, ваш бот должен проверить сохраненное значение serviceUrl.

Обновление сообщений

Вместо того, чтобы ваши сообщения были статическими снимками данных, бот может динамически обновлять сообщения после их отправки. Динамические обновления сообщений можно использовать для таких сценариев, как обновление опроса, изменение доступных действий после нажатия кнопки или любое другое асинхронное изменение состояния.

Новое сообщение не обязательно должно совпадать с исходным по типу. Например, если исходное сообщение содержало вложение, новое сообщение может быть простым текстовым сообщением.

Примечание.

Вы можете обновлять только содержимое, отправленное в сообщениях с одним вложением и макетах карусели. Публикация обновлений сообщений с несколькими вложениями в макете списка не поддерживается.

REST API

Чтобы выдать обновление сообщения, выполните запрос PUT к конечной точке /v3/conversations/<conversationId>/activities/<activityId>/ , используя заданный идентификатор действия. Для выполнения этого сценария необходимо кэшировать идентификатор действия, возвращенный исходным вызовом POST.

PUT /v3/conversations/19%3Aja0cu120i1jod12j%40skype.net/activities/012ujdo0128
{
    "type": "message",
    "text": "This message has been updated"
}

Пример .NET

Метод UpdateActivityAsync можно использовать в пакете SDK Bot Builder для обновления существующего сообщения.

public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
  if (activity.Type == ActivityTypes.Message)
  {
    ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
    Activity reply = activity.CreateReply($"You sent {activity.Text} which was {activity.Text.Length} characters");
    var msgToUpdate = await connector.Conversations.ReplyToActivityAsync(reply);
    Activity updatedReply = activity.CreateReply($"This is an updated message");
    await connector.Conversations.UpdateActivityAsync(reply.Conversation.Id, msgToUpdate.Id, updatedReply);
  }
}

Пример Node.js

Метод session.connector.update можно использовать в пакете SDK Bot Builder для обновления существующего сообщения.

function sendCardUpdate(bot, session, originalMessage, address) {

  var origAttachment = originalMessage.data.attachments[0];
  origAttachment.content.subtitle = 'Assigned to Larry Jin';

  var updatedMsg = new builder.Message()
    .address(address)
    .textFormat(builder.TextFormat.markdown)
    .addAttachment(origAttachment)
    .toMessage();

  session.connector.update(updatedMsg, function(err, addresses) {
    if (err) {
      console.log(`Could not update the message`);
    }
  });
}

Начало беседы (упреждающий обмен сообщениями)

Вы можете создать личную беседу с пользователем или начать новую цепочку ответов в канале для бота группы. Это позволяет отправлять сообщения пользователю или пользователям, при этом им не требуется сначала инициировать контакт с ботом. Дополнительные сведения см. в следующих статьях:

Дополнительные сведения о беседах, запущенных ботами, см. в разделе упреждающий обмен сообщениями для ботов.

Удаление сообщений

Сообщения можно удалить с помощью connector.delete() метода в пакете SDK BotBuilder.

bot.dialog('BotDeleteMessage', function (session: builder.Session) {
  var msg = new teams.TeamsMessage(session).text("Bot will delete this message in 5 sec.")
  bot.send(msg, function (err, response) {
    if (err) {
      console.log(err);
      session.endDialog();
    }

    console.log('Proactive message response:');
    console.log(response);
    console.log('---------------------------------------------------')
    setTimeout(function () {
      var activityId: string = null;
      var messageAddress: builder.IChatConnectorAddress = null;
      if (response[0]){
        messageAddress = response[0];
        activityId = messageAddress.id;
      }

      if (activityId == null)
      {
        console.log('Message failed to send.');
        session.endDialog();
        return;
      }

      // Bot delete message
      let address: builder.IChatConnectorAddress  = {
        channelId: 'msteams',
        user: messageAddress.user,
        bot: messageAddress.bot,
        id : activityId,
        serviceUrl : (<builder.IChatConnectorAddress>session.message.address).serviceUrl,
        conversation: {
          id: session.message.address.conversation.id
        }
      };

      connector.delete(address, function (err) {
        if (err)
        {
          console.log(err);
        }
        else
        {
          console.log("Message: " + activityId + " deleted successfully.");
        }

        // Try editing deleted message would fail
        var newMsg = new builder.Message().address(address).text("To edit message.");
        connector.update(newMsg.toMessage(), function (err, address) {
          if (err)
          {
            console.log(err);
            console.log('Deleted message can not be edited.');
          }
          else
          {
            console.log("There is something wrong. Message: " + activityId + " edited successfully.");
            console.log(address);
          }

          session.endDialog();
        });
      });
    }, 5000);
  });
})