Инициировать действия с расширениями обмена сообщениями

Важно!

Статьи в этом разделе основаны на SDK bot Framework v3. Если требуется текущая документация (версия 4.6 или более поздний вариант SDK), см. раздел Взаимодействие с расширениями обмена сообщениями, ориентированное на задачи.

Расширения обмена сообщениями на основе действий позволяют пользователям запускать действия во внешних службах во время Teams.

Пример карточки расширения обмена сообщениями

В следующих разделах описано, как это сделать:

Добавление расширения обмена сообщениями в приложение

Расширение обмена сообщениями — это облачная служба, которая прослушивает запросы пользователей и отвечает структурированными данными, такими как карточка. Вы интегрируете свою службу с Microsoft Teams с помощью объектов Bot Activity Framework. Наши расширения .NET и Node.js для SDK bot Builder помогут вам добавить в приложение функциональность расширения обмена сообщениями.

Схема потока сообщений для расширений обмена сообщениями

Регистрация в bot Framework

Если вы еще этого не сделали, сначала необходимо зарегистрировать бота в Microsoft Bot Framework. Для получения и ответа на запросы пользователей в расширении обмена сообщениями будут использоваться ID приложения Майкрософт и конечные точки вызова для вашего бота, как определено там. Не забудьте включить канал Microsoft Teams для бота.

Записыв свой код приложения-бота и пароль приложения, вам потребуется предоставить код приложения в манифесте приложения.

Обновление манифеста приложения

Как и в ботах и вкладок, вы обновляете манифест приложения, чтобы включить свойства расширения обмена сообщениями. Эти свойства регулируют, как отображается и ведет себя расширение обмена сообщениями в Microsoft Teams клиенте. Расширения обмена сообщениями поддерживаются начиная с v1.0 манифеста.

Объявление расширения обмена сообщениями

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

Примечание

Манифест относится к расширениям обмена сообщениями как composeExtensions . Это необходимо для поддержания обратной совместимости.

Определение расширения — это объект, который имеет следующую структуру:

Имя свойства Назначение Обязательный?
botId Уникальный идентификатор приложения Майкрософт для бота, зарегистрированный в Bot Framework. Это обычно должно быть таким же, как ИД для общего Teams приложения. Да
scopes Массив, объявляющий, можно ли добавить это расширение или области personal team (или оба). Да
canUpdateConfiguration Включает Параметры меню. Нет
commands Массив команд, поддерживаемых этим расширением обмена сообщениями. Вы ограничены 10 командами. Да

Определение команд

Расширение обмена сообщениями должно объявить одну команду, которая появляется, когда пользователь выбирает ваше приложение из кнопки More (⋯) в окне составить.

Снимок экрана списка расширений обмена сообщениями в Teams

В манифесте приложения элемент команды — это объект со следующей структурой:

Имя свойства Назначение Обязательный? Минимальная версия манифеста
id Уникальный ID, который вы назначаете этой команде. Запрос пользователя будет включать этот ID. Да 1.0
title Имя команды. Это значение отображается в пользовательском интерфейсе. Да 1.0
description Справка текста, указывающее, что делает эта команда. Это значение отображается в пользовательском интерфейсе. Да 1.0
type Установите тип команды. Возможные значения: query и action. Если не представлено значение по умолчанию, установлено query значение . Нет 1.4
initialRun Необязательный параметр, используемый query с командами. Если заданной для true, указывает, что эта команда должна быть выполнена, как только пользователь выберет эту команду в пользовательском интерфейсе. Нет 1.0
fetchTask Необязательный параметр, используемый action с командами. Установите для true, чтобы получить адаптивную карту или веб-URL-адрес для отображения в модуле задач. Это используется, когда входные данные в команду динамически, а не статический action набор параметров. Обратите внимание, что если задан истинный список статических параметров для команды, игнорируется. Нет 1.4
parameters Статический список параметров для команды. Да 1.0
parameter.name Имя параметра. Это отправляется в службу в запросе пользователя. Да 1.0
parameter.description Описывает цели этого параметра или пример значения, которое должно быть предоставлено. Это значение отображается в пользовательском интерфейсе. Да 1.0
parameter.title Краткое удобное название параметра или метка. Да 1.0
parameter.inputType Задай тип необходимого ввода. Возможные text значения: textarea , , , , number date time toggle . По умолчанию text установлено значение . Нет 1.4
context Необязательный массив значений, определяя контекст, в котором доступно действие сообщения. Возможные значения message , compose или commandBox . Значение по умолчанию: ["compose", "commandBox"]. Нет 1.5

Расширения сообщений типа действия

Чтобы инициировать действия из расширения обмена сообщениями, установите type параметр action . Ниже приведен пример манифеста с поиском и командой создания. Одно расширение обмена сообщениями может иметь до 10 различных команд. Это может включать как несколько команд поиска, так и несколько команд на основе действий.

Полный пример манифеста приложения

{
  "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.8/MicrosoftTeams.schema.json",
  "manifestVersion": "1.5",
  "version": "1.0",
  "id": "57a3c29f-1fc5-4d97-a142-35bb662b7b23",
  "packageName": "com.microsoft.teams.samples.Todo",
  "developer": {
    "name": "John Developer",
    "websiteUrl": "http://todobotservice.azurewebsites.net/",
    "privacyUrl": "http://todobotservice.azurewebsites.net/privacy",
    "termsOfUseUrl": "http://todobotservice.azurewebsites.net/termsofuse"
  },
  "name": {
    "short": "To Do",
    "full": "To Do"
  },
  "description": {
    "short": "Find or create a new task in To Do",
    "full": "Find or create a new task in To Do"
  },
  "icons": {
    "outline": "todo-outline.jpg",
    "color": "todo-color.jpg"
  },
  "accentColor": "#ff6a00",
  "composeExtensions": [
    {
      "botId": "57a3c29f-1fc5-4d97-a142-35bb662b7b23",
      "canUpdateConfiguration": true,
      "commands": [
        {
          "id": "searchCmd",
          "description": "Search you Todo's",
          "title": "Search",
          "initialRun": true,
          "context": ["commandBox", "compose"],
          "parameters": [
            {
              "name": "searchKeyword",
              "description": "Enter your search keywords",
              "title": "Keywords"
            }
          ]
        },
        {
          "id": "addTodo",
          "description": "Create a To Do item",
          "title": "Create To Do",
          "type": "action",
          "context": ["commandBox", "message", "compose"],
          "parameters": [
            {
              "name": "Name",
              "description": "To Do Title",
              "title": "Title",
              "inputType": "text"
            },
            {
              "name": "Description",
              "description": "Description of the task",
              "title": "Description",
              "inputType": "textarea"
            },
            {
              "name": "Date",
              "description": "Due date for the task",
              "title": "Date",
              "inputType": "date"
            }
          ]
        },
        {
          "id": "reassignTodo",
          "description": "Reassign a todo item",
          "title": "Reassign a todo item",
          "type": "action",
          "fetchTask": false,
          "parameters": [
            {
              "name": "Name",
              "title": "Title"
              "inputType": "text"
            }
          ]
        }
      ]
    }
  ],
  "permissions": [
    "identity",
    "messageTeamMembers"
  ],
  "validDomains": [
    "todobotservice.azurewebsites.net",
    "*.todobotservice.azurewebsites.net"
  ]
}

Инициировать действия из сообщений

Помимо инициации действий из области составить сообщение, вы также можете использовать расширение обмена сообщениями, чтобы инициировать действие из сообщения. Это позволит отправлять содержимое сообщения боту для обработки и необязательный ответ на это сообщение с помощью метода, описанного в Ответ на отправку. Ответ будет вставлен в качестве ответа на сообщение, которое пользователи могут изменить перед отправкой. Пользователи могут получить доступ к расширению обмена сообщениями из меню переполнения, а затем выбрать, ... Take action как на следующем изображении:

Пример инициирования действия из сообщения

Чтобы расширение обмена сообщениями работало из сообщения, добавьте параметр к объекту расширения обмена сообщениями в манифесте приложения, как в context commands следующем примере. Допустимые строки context для массива "message" являются , "commandBox" и "compose" . Значение по умолчанию — ["compose", "commandBox"]. Подробные сведения о параметре см. в разделе Определение context команд:

"composeExtensions": [
  {
    "botId": "57a3c29f-1fc5-4d97-a142-35bb662b7b23",
    "canUpdateConfiguration": true,
    "commands": [
      {
        "id": "reassignTodo",
        "description": "Reassign a todo item",
        "title": "Create To Do",
        "type": "Action",
        "context": ["message"],
        "fetchTask": true
    }]
    ...

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

{
  "name": "composeExtension/submitAction",
  "type": "invoke",
...
  "value": {
    "commandId": "setReminder",
    "commandContext": "message",
    "messagePayload": {
      "id": "1111111111",
      "replyToId": null,
      "createdDateTime": "2019-02-25T21:29:36.065Z",
      "lastModifiedDateTime": null,
      "deleted": false,
      "subject": "Message subject",
      "summary": null,
      "importance": "normal",
      "locale": "en-us",
      "body": {
        "contentType": "html",
        "content": "this is the message"
    },
      "from": {
        "device": null,
        "conversation": null,
        "user": {
          "userIdentityType": "aadUser",
          "id": "wxyz12ab8-ab12-cd34-ef56-098abc123876",
          "displayName": "Jamie Smythe"
        },
        "application": null
      },
      "reactions": [
        {
          "reactionType": "like",
          "createdDateTime": "2019-02-25T22:40:40.806Z",
          "user": {
            "device": null,
            "conversation": null,
            "user": {
              "userIdentityType": "aadUser",
              "id": "qrst12346-ab12-cd34-ef56-098abc123876",
              "displayName": "Jim Brown"
            },
            "application": null
          }
        }
      ],
      "mentions": [
        {
          "id": 0,
          "mentionText": "Sarah",
          "mentioned": {
            "device": null,
            "conversation": null,
            "user": {
              "userIdentityType": "aadUser",
              "id": "ab12345678-ab12-cd34-ef56-098abc123876",
              "displayName": "Sarah"
            },
            "application": null
          }
        }
      ]
    }
  ...

Тестирование с помощью загрузки

Вы можете протестировать расширение обмена сообщениями, загрузив приложение. Дополнительные сведения см. в сайте Uploading your app in a team.

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

Сбор входных данных от пользователей

Существует три способа сбора сведений от пользователя в Teams.

Список статических параметров

В этом методе необходимо определить статический список параметров манифеста, как показано выше в команде "Создание для работы". Для использования этого метода задана настройка и определение fetchTask false параметров в манифесте.

Когда пользователь выбирает команду со статичными параметрами, Teams создает форму в модуле задач с заданными параметрами в манифесте. При нажатии composeExtension/submitAction Отправка отправляется боту. Дополнительные сведения о ожидаемом наборе ответов см. в ответе на отправку.

Динамический ввод с помощью адаптивной карты

В этом методе служба может определить настраиваемую адаптивную карту для сбора ввода пользователя. Для этого подхода установите параметр fetchTask в true манифесте. Если вы заданы, все статические параметры, определенные fetchTask true для команды, будут проигнорированы.

В этом методе служба получает событие и отвечает адаптивным ответом модуля задач на основе composeExtension/fetchTask карт. Ниже приводится пример ответа с адаптивной картой:

{
    "task": {
        "type": "continue",
        "value": {
            "card": {
                "contentType": "application/vnd.microsoft.card.adaptive",
                "content": {
                    "body": [
                        {
                            "type": "TextBlock",
                            "text": "Please enter the following information:"
                        },
                        {
                            "type": "TextBlock",
                            "text": "Name"
                        },
                        {
                            "type": "Input.Text",
                            "spacing": "None",
                            "title": "New Input.Toggle",
                            "placeholder": "Placeholder text"
                        },
                        {
                            "type": "TextBlock",
                            "text": "Date of birth"
                        },
                        {
                            "type": "Input.Date",
                            "spacing": "None",
                            "title": "New Input.Toggle"
                        }
                    ],
                    "type": "AdaptiveCard",
                    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                    "version": "1.0"
                }
            }
        }
    }
}

Бот также может отвечать ответом auth/config, если пользователю необходимо проверить подлинность или настроить расширение перед получением ввода пользователя.

Динамический ввод с помощью веб-представления

В этом методе служба может показать основанный виджет, чтобы показать любой пользовательский <iframe> пользовательский интерфейс и собрать пользовательский ввод. Для этого подхода установите параметр fetchTask в true манифесте.

Так же, как и в потоке адаптивной карты, служба отправляет событие и отвечает ответом целевого модуля на основе fetchTask URL-адресов. Ниже приводится пример ответа с адаптивной картой:

{
    "task": {
        "value": {
            "url": "http://mywebapp.com/input"
        },
        "type": "continue"
    }
}

Запрос на установку разговорного бота

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

Чтобы облегчить этот поток, когда расширение обмена сообщениями сначала получает проверку вызова, чтобы узнать, установлен ли ваш бот composeExtension/fetchTask в текущем контексте. Вы можете получить это, попытавшись получить вызов реестра. Например, если бот не установлен, возвращается адаптивная карта с действием, которое запрашивает установку бота пользователем. Пользователь должен иметь разрешение на установку приложений в этом расположении. Если они не могут установить, сообщение подсказок, чтобы связаться с администратором.

Вот пример ответа:

{
  "type": "AdaptiveCard",
  "body": [
    {
      "type": "TextBlock",
      "text": "Looks like you haven't used Disco in this team/chat"
    }
  ],
  "actions": [
    {
      "type": "Action.Submit",
      "title": "Continue",
      "data": {
        "msteams": {
          "justInTimeInstall": true
        }
      }
    }
  ],
  "version": "1.0"
}

Как только пользователь завершит установку, ваш бот получит еще одно сообщение вызова с name = composeExtension/submitAction и value.data.msteams.justInTimeInstall = true .

Вот пример вызова:

{
  "value": {
    "commandId": "giveKudos",
    "commandContext": "compose",
    "context": {
      "theme": "default"
    },
    "data": {
      "msteams": {
        "justInTimeInstall": true
      }
    }
  },
  "conversation": {
    "id": "19:7705841b240044b297123ad7f9c99217@thread.skype"
  },
  "name": "composeExtension/submitAction",
  "imdisplayname": "Bob Smith"
}

Ответьте на вызов тем же ответом, на который вы ответили бы, если бы бот уже был установлен.

Реагирование на отправку

Как только пользователь завершит ввод, бот получит событие с набором composeExtension/submitAction командных ИД и значений параметров.

Это различные ожидаемые ответы на submitAction .

Ответ модуля задач

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

Compose extension auth/config response

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

Compose extension result response

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

{
  "composeExtension": {
    "type": "result",
    "attachmentLayout": "list",
    "preview": {
          "contentType": "application/vnd.microsoft.card.thumbnail",
          "content": {
            "title": "85069: Create a cool app",
            "images": [
              {
                "url": "https://placekitten.com/200/200"
              }
            ]
          }
        },
    "attachments": [
      {  
        "contentType": "application/vnd.microsoft.teams.card.o365connector",
        "content": {
          "sections": [
            {
              "activityTitle": "[85069]: Create a cool app",
              "activityImage&quot;: &quot;https://placekitten.com/200/200"
            },
            {
              "title": "Details",
              "facts": [
                {
                  "name": "Assigned to:",
                  "value&quot;: &quot;[Larry Brown](mailto:larryb@example.com)"
                },
                {
                  "name": "State:",
                  "value": "Active"
                }
              ]
            }
          ]
        }
      }
    ]
  }
}

Ответьте адаптивным сообщением карточки, отправленным от бота

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

  1. Пользователь выбирает расширение обмена сообщениями, чтобы вызвать модуль задач.
  2. Для настройки опроса пользователь использует модуль задач.
  3. После отправки модуля задач конфигурации приложение использует сведения, представленные в модуле задач, для изготовления адаптивной карты и отправляет ее в качестве ответа botMessagePreview клиенту.
  4. Затем пользователь может просмотреть сообщение адаптивной карты, прежде чем бот вставляет его в канал. Если бот еще не является участником канала, щелкнув, Send он добавит бота.
  5. Взаимодействие с адаптивной картой изменит сообщение перед отправкой.
  6. После выбора пользователем бота сообщение будет Send отправляться в канал.

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

Примечание

Должен содержать действие с 1 адаптивным activityPreview вложением message карт.

{
  "composeExtension": {
    "type": "botMessagePreview",
    "activityPreview": {
      "type": "message",
      "attachments":  [
        {
          "contentType": "application/vnd.microsoft.card.adaptive",
          "content": << Card Payload >>
        }
      ]
    }
  }
}

Теперь расширению сообщения потребуется ответить на два новых типа взаимодействий и value.botMessagePreviewAction = "send" value.botMessagePreviewAction = "edit" . Ниже приведен пример value объекта, необходимого для обработки:

{
  "name": "composeExtension/submitAction",
  "type": "invoke",
  "conversation": { "id": "19:c366b75791784100b6e8b515fd55b063@thread.skype" },
  "imdisplayname": "Pranav Smith",
  ...
  "value": {
    "botMessagePreviewAction": "send" | "edit",
    "botActivityPreview": [
      {
        "type": "message/card",
        "attachments": [
          {
            "content":
              {
                "type": "AdaptiveCard",
                "body": [{<<card payload>>}]
              },
            "contentType" : "application/vnd.microsoft.card.adaptive"
          }
        ],
        "context": { "theme": "default" }
      }
    ],
  }
}

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

teamChatConnector.onComposeExtensionSubmitAction((
    event: builder.IEvent,
    request: teamBuilder.IComposeExtensionActionCommandRequest,
    callback: (err: Error, result: any, statusCode: number) => void) => {
        let invokeValue = (<any> event).value;

        if (invokeValue.botMessagePreviewAction ) {
            let attachment = invokeValue.botActivityPreview[0].attachments[0];

            if (invokeValue.botMessagePreviewAction === 'send') {
                let msg = new builder.Message()
                    .address(event.address)
                    .addAttachment(attachment);
                teamChatConnector.send([msg.toMessage()],
                    (error) => {
                        if(error){
                            //TODO: Handle error and callback
                        }
                        else {
                            callback(null, null, 200);
                        }
                    }
                );
            }

            else if (invokeValue.botMessagePreviewAction === 'edit') {
              // Create the card and populate with user-inputted information
              let card = { ... }

              let taskResponse = {
                task: {
                  type: "continue",
                  value: {
                    title: "Card Preview",
                    card: {
                      contentType: 'application/vnd.microsoft.card.adaptive',
                      content: card
                    }
                  }
                }
              }
              callback(null, taskResponse, 200);
            }

        else {
            let attachment = {
                  //create adaptive card
                };
            let activity = new builder.Message().addAttachment(attachment).toMessage();
            let response = teamBuilder.ComposeExtensionResponse.messagePreview()
                .preview(activity)
                .toResponse();
            callback(null, response, 200);
        }
    });