Создание расширения сообщений на основе API
Примечание.
Расширения сообщений на основе API поддерживают только команды поиска.
Расширения сообщений на основе API — это возможность приложения Microsoft Teams, которая интегрирует внешние API непосредственно в Teams, повышая удобство использования приложения и обеспечивая простой пользовательский интерфейс. Расширения сообщений на основе API поддерживают команды поиска и могут использоваться для получения и отображения данных из внешних служб в Teams, упрощая рабочие процессы, уменьшая необходимость переключения между приложениями.
Прежде чем приступить к работе, убедитесь, что вы соответствуете следующим требованиям:
1. Описание OpenAPI (OAD)
Убедитесь, что вы придерживаетесь следующих рекомендаций для документа OpenAPI Description (OAD):
- Поддерживаются версии OpenAPI 2.0 и 3.0.x.
- Поддерживаемые форматы — JSON и YAML.
- Текст запроса, если он присутствует, должен иметь значение application/Json.
- Определите URL-адрес сервера протокола HTTPS для
servers.url
свойства. - Поддерживаются только методы HTTP POST и GET.
- Документ Описание OpenAPI должен иметь
operationId
. - Допускается только один обязательный параметр без значения по умолчанию.
- Обязательный параметр со значением по умолчанию считается необязательным.
- Пользователи не должны вводить параметр для заголовка или файла cookie.
- Операция не должна иметь обязательный заголовок или параметры файла cookie без значений по умолчанию.
- Убедитесь, что в документе Описание OpenAPI отсутствуют удаленные ссылки.
- Создание массивов для запроса не поддерживается; однако вложенные объекты в тексте запроса JSON поддерживаются.
- Teams не поддерживает
oneOf
конструкции ,anyOf
,allOf
иnot
(swagger.io).
Следующий код является примером документа OpenAPI Description:
openapi: 3.0.1
info:
title: OpenTools Plugin
description: A plugin that allows the user to find the most appropriate AI tools for their use cases, with their pricing information.
version: 'v1'
servers:
- url: https://gptplugin.opentools.ai
paths:
/tools:
get:
operationId: searchTools
summary: Search for AI Tools
parameters:
- in: query
name: search
required: true
schema:
type: string
description: Used to search for AI tools by their category based on the keywords. For example, ?search="tool to create music" will give tools that can create music.
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/searchToolsResponse'
"400":
description: Search Error
content:
application/json:
schema:
$ref: '#/components/schemas/searchToolsError'
components:
schemas:
searchToolsResponse:
required:
- search
type: object
properties:
tools:
type: array
items:
type: object
properties:
name:
type: string
description: The name of the tool.
opentools_url:
type: string
description: The URL to access the tool.
main_summary:
type: string
description: A summary of what the tool is.
pricing_summary:
type: string
description: A summary of the pricing of the tool.
categories:
type: array
items:
type: string
description: The categories assigned to the tool.
platforms:
type: array
items:
type: string
description: The platforms that this tool is available on.
description: The list of AI tools.
searchToolsError:
type: object
properties:
message:
type: string
description: Message of the error.
Дополнительные сведения см. в разделе Структура OpenAPI.
2. Манифест приложения
Убедитесь, что вы придерживаетесь следующих рекомендаций для манифеста приложения:
Задайте для версии манифеста приложения значение
1.17
.Задайте значение
composeExtensions.composeExtensionType
apiBased
.Определите
composeExtensions.apiSpecificationFile
в качестве относительного пути к файлу описания OpenAPI в папке. Это связывает манифест приложения со спецификацией API.Определите
apiResponseRenderingTemplateFile
в качестве относительного пути к шаблону отрисовки ответа. Это указывает расположение шаблона, используемого для отрисовки ответов API.Каждая команда должна иметь ссылку на шаблон отрисовки ответа. При этом каждая команда подключается к соответствующему формату ответа.
Свойство
Commands.id
в манифесте приложения должно соответствовать свойству в описанииoperationId
OpenAPI.Если обязательный параметр не имеет значения по умолчанию, команда
parameters.name
в манифесте приложения должна соответствовать в документеparameters.name
Описание OpenAPI.Если обязательный параметр отсутствует, команда
parameters.name
в манифесте приложения должна соответствовать необязательнымparameters.name
в описании OpenAPI.Убедитесь, что параметры каждой команды точно совпадают с именами параметров, определенных для операции в спецификации OpenAPI.
Шаблон отрисовки ответа должен быть определен для каждой команды, которая используется для преобразования ответов из API.
Полное описание не должно превышать 128 символов.
{ "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.17/MicrosoftTeams.schema.json", + "manifestVersion": "1.17", "version": "1.0.0", "id": "04805b4b-xxxx-xxxx-xxxx-4dbc1cac8f89", "packageName": "com.microsoft.teams.extension", "developer": { "name": "Teams App, Inc.", "websiteUrl": "https://www.example.com", "privacyUrl": "https://www.example.com/termofuse", "termsOfUseUrl": "https://www.example.com/privacy" }, "icons": { "color": "color.png", "outline": "outline.png" }, "name": { "short": "AI tools", "full": "AI tools" }, "description": { "short": "AI tools", "full": "AI tools" }, "accentColor": "#FFFFFF", "composeExtensions": [ { + "composeExtensionType": "apiBased", + "authorization": { + "authType": "apiSecretServiceAuth ", + "apiSecretServiceAuthConfiguration": { + "apiSecretRegistrationId": "9xxxxxxx-7xxx-4xxx-bxxx-1xxxxxxxxxxx" + } + }, + "apiSpecificationFile": "aitools-openapi.yml", "commands": [ { "id": "searchTools", "type": "query", "context": [ "compose", "commandBox" ], "title": "search for AI tools", "description": "search for AI tools", "parameters": [ { "name": "search", "title": "search query", "description": "e.g. search='tool to create music'" } ], + "apiResponseRenderingTemplateFile": "response-template.json" } ] } ], "validDomains": [] }
Параметры
Имя | Описание |
---|---|
composeExtensions.composeExtensionType |
Compose тип расширения. Обновите значение на apiBased . |
composeExtensions.authorization |
Сведения об авторизации для расширения сообщений на основе API |
composeExtensions.authorization.authType |
Перечисление возможных типов авторизации. Поддерживаемые значения: none , apiSecretServiceAuth и microsoftEntra . |
composeExtensions.authorization.apiSecretServiceAuthConfiguration |
Объект, фиксирующий сведения, необходимые для проверки подлинности службы. Применимо, только если тип проверки подлинности имеет значение apiSecretServiceAuth . |
composeExtensions.authorization.apiSecretServiceAuthConfiguration.apiSecretRegistrationId |
Идентификатор регистрации возвращается, когда разработчик отправляет ключ API через портал разработчика. |
composeExtensions.apiSpecificationFile |
Ссылается на файл описания OpenAPI в пакете приложения. Включить, если тип имеет значение apiBased . |
composeExtensions.commands.id |
Уникальный идентификатор, назначенный команде поиска. Запрос пользователя включает этот идентификатор. Идентификатор должен совпадать с OperationId доступным в описании OpenAPI. |
composeExtensions.commands.context |
Массив, в котором определены точки входа для расширения сообщений. Значения по умолчанию: compose и commandBox . |
composeExtensions.commands.parameters |
Определяет статический список параметров для команды . Имя должно сопоставляться с в parameters.name описании OpenAPI. Если вы ссылаетесь на свойство в схеме текста запроса, имя должно сопоставляться с properties.name параметрами запроса или . |
composeExtensions.commands.apiResponseRenderingTemplateFile |
Шаблон, используемый для форматирования ответа JSON из API разработчика в ответ адаптивной карточки. [Обязательно] |
Дополнительные сведения см. в разделе ComposeExtensions.
3. Шаблон отрисовки ответа
Примечание.
Teams поддерживает адаптивные карточки до версии 1.5, а адаптивные карточки Designer поддерживают до версии 1.6.
-
Определите URL-адрес ссылки на схему в свойстве
$schema
, чтобы установить структуру шаблона. -
Поддерживаемые значения для
responseLayout
grid
иlist
, которые определяют способ визуального представления ответа. -
Рекомендуется
jsonPath
для массивов или если данные для адаптивной карточки не являются корневым объектом. Например, если данные вложены вproductDetails
, путь JSON будет иметь значениеproductDetails
. -
Определите
jsonPath
в качестве пути к соответствующим данным или массиву в ответе API. Если путь указывает на массив, то каждая запись в массиве привязывается к шаблону адаптивной карточки и возвращается в виде отдельного результата. [Необязательно] - Получите пример ответа для проверки шаблона отрисовки ответа. Это служит в качестве теста, чтобы убедиться, что шаблон работает должным образом.
- Используйте такие средства, как Fiddler или Postman , чтобы вызвать API и убедиться, что запрос и ответ действительны. Этот шаг имеет решающее значение для устранения неполадок и подтверждения правильности работы API.
- С помощью Designer адаптивной карточки можно привязать ответ API к шаблону отрисовки ответа и просмотреть адаптивную карточку. Вставьте шаблон в РЕДАКТОР ПОЛЕЗНЫХ ДАННЫХ КАРТОЧКИ и вставьте пример записи ответа в РЕДАКТОР ОБРАЗЦОВ ДАННЫХ.
Следующий код является примером шаблона отрисовки ответа:
Пример шаблона отрисовки ответа
{
"version": "1.0",
"jsonPath": "repairs",
"responseLayout": "grid",
"responseCardTemplate": {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.4",
"body": [
{
"type": "Container",
"items": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "TextBlock",
"text": "Title: ${if(title, title, 'N/A')}",
"wrap": true
},
{
"type": "TextBlock",
"text": "Description: ${if(description, description, 'N/A')}",
"wrap": true
},
{
"type": "TextBlock",
"text": "Assigned To: ${if(assignedTo, assignedTo, 'N/A')}",
"wrap": true
},
{
"type": "Image",
"url": "${image}",
"size": "Medium",
"$when": "${image != null}"
}
]
},
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "Image",
"url": "${if(image, image, '')}",
"size": "Medium"
}
]
}
]
},
{
"type": "FactSet",
"facts": [
{
"title": "Repair ID:",
"value": "${if(id, id, 'N/A')}"
},
{
"title": "Date:",
"value": "${if(date, date, 'N/A')}"
}
]
}
]
}
]
},
"previewCardTemplate": {
"title": "Title: ${if(title, title, 'N/A')}",
"subtitle": "Description: ${if(description, description, 'N/A')}",
"text": "Assigned To: ${if(assignedTo, assignedTo, 'N/A')}",
"image": {
"url": "${image}",
"$when": "${image != null}"
}
}
}
Карточка предварительного просмотра
Расширенная адаптивная карточка
Параметры
Свойство | Тип | Описание | Обязательный |
---|---|---|---|
version |
string |
Версия схемы текущего шаблона отрисовки ответа. | Да |
jsonPath |
string |
Путь к соответствующему разделу в результатах, к которым должны применяться responseCardTemplate и previewCardTemplate. Если значение не задано, корневой объект обрабатывается как соответствующий раздел. Если соответствующий раздел является массивом, каждая запись сопоставляется с responseCardTemplate и previewCardTemplate. | Нет |
responseLayout |
responseLayoutType |
Указывает макет результатов во всплывающем элементе расширения сообщения. Поддерживаемые типы: list и grid . |
Да |
responseCardTemplate |
adaptiveCardTemplate |
Шаблон для создания адаптивной карточки из результирующих записей. | Да |
previewCardTemplate |
previewCardTemplate |
Шаблон для создания предварительного карта из записи результата. Результирующий карта предварительного просмотра отображается во всплывающем меню расширения сообщения. | Да |
Путь JSON
Путь JSON необязателен, но его следует использовать для массивов или где объект, используемый в качестве данных для адаптивного карта, не является корневым объектом. Путь JSON должен соответствовать формату, определенному Newtonsoft. Если путь JSON указывает на массив, то каждая запись в этом массиве привязана к шаблону адаптивного карта и возвращается в виде отдельных результатов.
Пример Предположим, что у вас есть приведенный ниже код JSON для списка продуктов и вы хотите создать карта результат для каждой записи.
{
"version": "1.0",
"title": "All Products",
"warehouse": {
"products": [
...
]
}
}
Как видите, массив результатов находится в разделе "products", который вложен в "warehouse", поэтому путь JSON будет "warehouse.products".
Используйте https://adaptivecards.io/designer/ для предварительного просмотра адаптивной карта, вставив шаблон в полезные данные карточки Редактор, а затем возьмите пример записи ответа из массива или для объекта и вставьте его в редактор данных справа. Убедитесь, что карта правильно отрисовывается и соответствует вашему вкусу. Обратите внимание, что Teams поддерживает карточки до версии 1.5, а конструктор поддерживает 1.6.
Сопоставление схемы
Свойства в документе Описание OpenAPI сопоставляются с шаблоном адаптивной карточки следующим образом:
string
,number
,integer
boolean
типы преобразуются в TextBlock.Пример
Исходная схема:
string
,number
,integer
иboolean
name: type: string example: doggie
Целевая схема:
Textblock
{ "type": "TextBlock", "text": "name: ${if(name, name, 'N/A')}", "wrap": true }
array
: массив преобразуется в контейнер в адаптивной карточке.Пример
Исходная схема:
array
type: array items: required: - name type: object properties: id: type: integer category: type: object properties: name: type: string
Целевая схема:
Container
{ "type": "Container", "$data": "${$root}", "items": [ { "type": "TextBlock", "text": "id: ${if(id, id, 'N/A')}", "wrap": true }, { "type": "TextBlock", "text": "category.name: ${if(category.name, category.name, 'N/A')}", "wrap": true } ] }
object
: объект преобразуется во вложенное свойство в адаптивной карточке.Пример
Исходная схема:
object
components: schemas: Pet: category: type: object properties: id: type: integer name: type: string
Целевая схема: вложенное свойство в адаптивной карточке
{ "type": "TextBlock", "text": "category.id: ${if(category.id, category.id, 'N/A')}", "wrap": true }, { "type": "TextBlock", "text": "category.name: ${if(category.name, category.name, 'N/A')}", "wrap": true }
image
: если свойство является URL-адресом изображения, оно преобразуется в элемент Image в адаптивной карточке.Пример
Исходная схема:
image
image: type: string format: uri description: The URL of the image of the item to be repaired
Целевая схема:
"Image"
{ "type": "Image", "url": "${image}", "$when": "${image != null}" }
Расширение сообщений на основе API можно создать с помощью портала разработчика для Teams, набора средств Teams для Visual Studio Code, интерфейса командной строки (CLI) или Visual Studio.
Чтобы создать расширение сообщений на основе API с помощью портала разработчика, выполните следующие действия.
Перейдите на портал разработчика.
Перейдите в раздел Приложения.
Выберите + Создать приложение.
Введите имя приложения и выберите версию манифеста в качестве общедоступной предварительной версии разработчика (devPreview).
Нажмите Добавить.
В левой области в разделе Настройка обновите следующие основные сведения:
- Полное имя
- Краткое описание
- Длинное описание
- Название разработчика или компании
- Веб-сайт (должен быть допустимым URL-адресом HTTPS)
- Политика конфиденциальности
- Условия использования
Выберите Сохранить.
Выберите Функции приложений.
Выберите Расширение сообщений.
В разделе Тип расширения сообщений выберите API.
- Если вы получили заявление об отказе от ответственности, которое считывает расширение сообщений Bot, уже используется пользователями. Вы хотите изменить тип расширения сообщений на API?, выберите Да, изменить.
В разделе Спецификация OpenAPI выберите Отправить сейчас.
Выберите документ Описание OpenAPI в формате JSON или YAML и нажмите кнопку Открыть.
Выберите Сохранить. Появится всплывающее окно со спецификацией API сообщения, успешно сохраненной.
Выберите Пункт Получил.
Добавление команд
Примечание.
Расширения сообщений, созданные на основе API, поддерживают только один параметр.
Вы можете добавить команды и параметры в расширение сообщений, чтобы добавить команды:
В разделе Тип расширения сообщений выберите Добавить.
Откроется всплывающее окно Добавить команду со списком всех доступных API из документа Описание OpenAPI.
Выберите API из списка и нажмите кнопку Далее.
В разделе Шаблон ответа выберите Отправить сейчас.
Примечание.
Если у вас несколько API, обязательно отправьте шаблон ответа адаптивной карточки для каждого API.
Выберите файл шаблона ответа адаптивной карточки в формате JSON и нажмите кнопку Открыть.
Следующие атрибуты автоматически обновляются из шаблона адаптивной карточки:
- Тип команды
- Идентификатор команды
- Заголовок команды
- Имя параметра
- Описание параметра
В разделе Сведения обновите описание команды.
Если вы хотите запустить команду с помощью триггера в Microsoft 365 Copilot, включите переключатель Автоматически выполнять эту команду, когда пользователь открывает расширение.
Нажмите Добавить. Команда успешно добавлена.
Выберите Сохранить.
В разделе Проверка подлинности и авторизация выберите любой из следующих параметров:
- Нет проверки подлинности (не рекомендуется)
- Ключ API
- OAuth
Создается расширение сообщений на основе API.
Чтобы протестировать расширение сообщений на основе API, созданное на портале разработчика, можно использовать следующие методы:
Предварительный просмотр в Teams. Откройте расширение для сообщений и выберите Предварительный просмотр в Teams в правом верхнем углу. Вы будете перенаправлены в Teams, где вы можете добавить приложение в Teams для предварительного просмотра приложения.
Скачать пакет приложения. На странице расширения сообщения выберите Пакет приложения в левой области, а затем в левом верхнем углу окна выберите Скачать пакет приложения. Пакет приложения загружается на локальный компьютер в файле .zip. Вы можете отправить пакет приложения в команды и протестировать расширение сообщений.
Несколько параметров
Несколько параметров позволяют расширениям сообщений на основе API иметь несколько типов входных данных для команд запроса. Например, можно искать аниме по жанру, рейтингу, состоянию и дате.
Можно указать типы входных данных, заголовки, описания и обязательные поля для параметров манифеста.
- Свойство
isRequired
в поле параметра указывает, является ли параметр обязательным для команды запроса. - Свойство
name
поля в манифестеparameters
приложения должно соответствовать полюid
в документе Описание OpenAPI для соответствующего параметра.
Пример
"composeExtensions": [
{
"composeExtensionType": "apiBased",
"apiSpecificationFile": "apiSpecificationFiles/openapi.json",
"commands": [
{
"context": [
"compose"
],
"type": "query",
"title": "Search Animes",
"id": "getAnimeSearch",
"parameters": [
{
"name": "q",
"title": "Search Query",
"description": "The search query",
"isRequired": true
},
{
"name": "type",
"inputType": "choiceset",
"title": "Type",
"description": "Available anime types",
"choices": [
{
"title": "TV",
"value": "tv"
},
{
"title": "OVA",
"value": "ova"
},
{
"title": "Movie",
"value": "movie"
},
{
"title": "Special",
"value": "special"
},
{
"title": "ONA",
"value": "ona"
},
{
"title": "Music",
"value": "music"
}
]
},
{
"name": "status",
"inputType": "choiceset",
"title": "Status",
"description": "Available airing statuses",
"choices": [
{
"title": "Airing",
"value": "airing"
},
{
"title": "Completed",
"value": "complete"
},
{
"title": "Upcoming",
"value": "upcoming"
}
]
},
{
"name": "rating",
"inputType": "choiceset",
"title": "Rating",
"description": "Available ratings",
"choices": [
{
"title": "G",
"value": "g"
},
{
"title": "PG",
"value": "pg"
},
{
"title": "PG-13",
"value": "pg13"
},
{
"title": "R",
"value": "r17"
},
{
"title": "R+",
"value": "r"
},
{
"title": "Rx",
"value": "rx"
}
]
}
],
"description": "Search animes",
"apiResponseRenderingTemplateFile": "response_json/getAnimeSearch.json"
},
{
"context": [
"compose"
],
"type": "query",
"title": "Search mangas",
"id": "getMangaSearch",
"parameters": [
{
"name": "q",
"title": "Search Query",
"description": "The search query",
"isRequired": true
},
{
"name": "type",
"inputType": "choiceset",
"title": "Type",
"description": "Available manga types",
"choices": [
{
"title": "Manga",
"value": "manga"
},
{
"title": "Novel",
"value": "novel"
},
{
"title": "Light Novel",
"value": "lightnovel"
},
{
"title": "One Shot",
"value": "oneshot"
},
{
"title": "Doujin",
"value": "doujin"
},
{
"title": "Manhwa",
"value": "manhwa"
},
{
"title": "Manhua",
"value": "manhua"
}
]
},
{
"name": "status",
"inputType": "choiceset",
"title": "Status",
"description": "Available manga statuses",
"choices": [
{
"title": "Publishing",
"value": "publishing"
},
{
"title": "Complete",
"value": "complete"
},
{
"title": "Hiatus",
"value": "hiatus"
},
{
"title": "Discontinued",
"value": "discontinued"
},
{
"title": "Upcoming",
"value": "upcoming"
}
]
},
{
"name": "start_date",
"title": "Start Date",
"description": "Start date of the manga",
"inputType": "date"
},
{
"name": "end_date",
"title": "End Date",
"description": "End date of the manga",
"inputType": "date"
}
],
Пошаговые руководства
Чтобы создать расширение сообщений на основе API, следуйте этим пошаговым руководствам.
- Для начинающих: создание расширения сообщений на основе API с помощью набора средств Teams.
- Для опытных пользователей: создайте расширение сообщений на основе API с нуля.
См. также
Platform Docs