Teams 中的交互式通知机器人

Microsoft Teams 工具包,可生成捕获事件的应用程序,并将其作为交互式通知发送到Microsoft Teams 中的个人、群组聊天或频道。 可以纯文本或 自适应卡片的形式发送通知。 通知机器人模板创建一个应用,该应用使用 HTTP 发布请求触发的自适应卡片向 Teams 发送消息。

应用模板是使用 TeamsFx SDK 生成的,该 SDK 提供一组简单的函数(超过 Microsoft Bot Framework),以实现你的要求。 例如,旅行社在 Teams 中为其用户生成一个应用,以使其与天气预报保持同步。 在以程图中,Teams 应用使用自适应卡片向用户通知天气预报:

天气预报示例通知方案

可以在以下方案中发送机器人通知:

  • 你想要通知频道中的每个人或聊天中相同或相关的内容。

  • 卡片中高度可自定义的 UI

  • 需要快速响应、包括媒体内容或操作按钮。

  • 发送计划的通知

  • 在“活动”和“聊天”、“频道”或“应用”上点亮双锁屏提醒

  • 在源代码中添加模板。

  • 手动处理本地化。

优点

  • 使用 TeamsFx SDK 中的 API,为个人聊天、群组聊天和频道中的通知提供便利。

  • 通过使用自适应卡片自定义通知来增强用户体验。

  • 提供了多种机制来触发通知,例如使用 Azure Functions 的 HTTP 和计划计时器触发器。

  • 通知卡轻松地与机器人集成,并在机器人应用中提供一致的用户体验。

注意

发送通知之前,需要使用相应的范围安装机器人应用程序。

返回页首

基于事件的通知

Bot Framework SDK 提供在 Teams 中主动发送消息的功能。 TeamsFx SDK 提供在触发机器人事件时管理机器人对话引用的功能。 TeamsFx SDK 可识别以下机器人事件:

"事件" 行为
首次将机器人安装到人员、组或团队时。 将目标会话引用添加到存储。
从人员、组或团队卸载机器人时。 从存储中删除目标会话引用。
删除机器人安装的团队时。 从存储中删除目标会话引用。
机器人安装的团队还原时。 将目标会话引用添加到存储。
机器人发送消息时。 当目标会话引用不存在时,将其添加到存储。

新通知事件示例

发送通知时,TeamsFx SDK 会根据所选对话引用创建一个新对话,然后发送一条消息。 对于高级用法,可以直接访问聊天引用以执行自己的机器人逻辑:

// list all installation targets
for (const target of await notificationApp.notification.installations()) {
    // call Bot Framework's adapter.continueConversationAsync()
    await target.adapter.continueConversationAsync(
        target.botAppId,
        target.conversationReference,
        async (context) => {
            // your own bot logic
            await context...
        }
    );
}

返回页首

通知机器人安装

通知机器人需要安装到团队或群组聊天中,或者作为个人应用安装,具体取决于所需的范围。 在将机器人添加到应用之前,需要选择安装目标。

添加安装范围

有关更多安装选项,请参阅 配置默认安装选项。 有关卸载,请参阅 从 Teams 中删除应用

返回页首

自定义通知

可以进行以下自定义,以扩展通知模板以满足业务需求:

从事件源自定义触发点

可以自定义以下触发器:

  • Express 基于 的通知:

    • 当 HTTP 请求发送到 src/index.js 入口点时,默认实现会向 Teams 发送自适应卡片。 可以通过修改 src/index.js来自定义此事件。 典型的实现可以调用 API 来检索可根据需要发送自适应卡片的事件和/或数据。 可以执行以下操作来添加更多触发器:

      • 创建新的路由: server.post("/api/new-trigger", ...)
      • 从广泛使用的 npm 包(如 cronnode-schedule)或其他包添加计时器触发器 () 。

      注意

      默认情况下,Teams 工具包在 中src/index.js搭建单个express入口点基架。

  • 基于Azure Functions的通知:

    • 选择 timer 触发器时,默认实现的 Azure 函数计时器触发器 src/timerTrigger.ts 每隔 30 秒发送一个自适应卡片。 可以编辑文件 *Trigger/function.json 以自定义 schedule 属性。 有关详细信息,请参阅 Azure 函数文档

      计时器触发通知的示例

    • 选择 http 触发器时,HTTP 请求会触发通知,默认实现会将自适应卡片发送到 Teams。 可以通过自定义 src/*Trigger.ts来更改此事件。 此实现可以调用 API 来检索事件和/或数据,这可以根据需要发送自适应卡片。

      HTTP 触发的通知示例

  • Azure 函数触发器:

    • Event Hub 触发器用于在将事件推送到 Azure 事件中心时发送通知。

    • Cosmos DB 触发器用于在创建或更新 Cosmos 文档时发送通知。

有关支持触发器的详细信息,请参阅Azure Functions支持触发器

自定义通知内容

文件 src/adaptiveCards/notification-default.json 定义默认自适应卡片。 可以使用 自适应卡片设计器 来帮助直观地设计自适应卡片 UI。 定义 src/cardModels.ts 用于加载自适应卡数据的数据结构。 卡模型与自适应卡片之间的绑定是通过匹配名称(如CardData.title自适应卡片中的映射)${title}完成的。 可以添加、编辑或删除属性及其绑定,以根据需要自定义自适应卡片。

如果需要,还可以添加新卡片。 有关如何使用 ColumnSetFactSet生成具有动态内容列表或目录的不同类型的自适应卡片的详细信息,请参阅 自适应卡片通知示例

自定义发送通知的位置

可以自定义将通知发送到以下目标:

  • 个人聊天通知:

    // list all installation targets
    for (const target of await notificationApp.notification.installations()) {
        // "Person" means this bot is installed as Personal app
        if (target.type === "Person") {
            // Directly notify the individual person
            await target.sendAdaptiveCard(...);
        }
    }
    

  • 群聊通知:

    // list all installation targets
    for (const target of await notificationApp.notification.installations()) {
        // "Group" means this bot is installed to a Group Chat
        if (target.type === "Group") {
            // Directly notify the Group Chat
            await target.sendAdaptiveCard(...);
    
                // List all members in the Group Chat then notify each member
                const members = await target.members();
                for (const member of members) {
                    await member.sendAdaptiveCard(...);
                }
            }
    
    }
    

  • 向通道发送通知:

    // list all installation targets
    for (const target of await notificationApp.notification.installations()) {
        // "Channel" means this bot is installed to a Team (default to notify General channel)
        if (target.type === "Channel") {
            // Directly notify the Team (to the default General channel)
            await target.sendAdaptiveCard(...);
    
            // List all members in the Team then notify each member
            const members = await target.members();
            for (const member of members) {
                await member.sendAdaptiveCard(...);
            }
    
            // List all channels in the Team then notify each channel
            const channels = await target.channels();
            for (const channel of channels) {
                await channel.sendAdaptiveCard(...);
            }
        }
    }
    

  • 向特定通道发送通知:

    // find the first channel when the predicate is true.
    const channel = await notificationApp.notification.findChannel(c => Promise.resolve(c.info.name === "MyChannelName"));
    
    // send adaptive card to the specific channel.
    await channel?.sendAdaptiveCard(...);
    

    注意

    若要防止未定义的输出,请确保在团队的 “常规 ”频道中安装机器人应用。

  • 向特定人员发送通知:

    // find the first person when the predicate is true.
    const member = await notificationApp.notification.findMember(m => Promise.resolve(m.account.name === "Bob"));
    
    // send adaptive card to the specific person. 
    await member?.sendAdaptiveCard(...);
    

    注意

    若要防止未定义的输出和缺少通知,需要在通知安装范围中包含特定人员。

返回页首

自定义初始化

需要创建 ConversationBot 以发送通知。

注意

代码在项目中生成。

/** Javascript/Typescript: src/internal/initialize.*s **/
const notificationApp = new ConversationBot({
    // The bot id and password to create CloudAdapter.
    // See https://aka.ms/about-bot-adapter to learn more about adapters.
    adapterConfig: {
        MicrosoftAppId: config.botId,
        MicrosoftAppPassword: config.botPassword,
        MicrosoftAppType: "MultiTenant",
    },
    // Enable notification
    notification: {
        enabled: true,
    },
});

返回页首

自定义适配器

可以通过创建自己的适配器进行自定义,也可以在初始化后自定义适配器。 下面是用于创建适配器的代码示例:

// Create your own adapter
const adapter = new CloudAdapter(...);

// Customize your adapter, e.g., error handling
adapter.onTurnError = ...

const notificationApp = new ConversationBot({
    // use your own adapter
    adapter: adapter;
    ...
});

// Or, customize later
notificationApp.adapter.onTurnError = ...

返回页首

增加存储

存储可用于实现通知连接。 可以使用以下代码示例添加自己的存储:

// implement your own storage
class MyStorage implements NotificationTargetStorage {...}
const myStorage = new MyStorage(...);

// initialize ConversationBot with notification enabled and customized storage
const notificationApp = new ConversationBot({
    // The bot id and password to create CloudAdapter.
    // See https://aka.ms/about-bot-adapter to learn more about adapters.
    adapterConfig: {
        MicrosoftAppId: config.botId,
        MicrosoftAppPassword: config.botPassword,
        MicrosoftAppType: "MultiTenant",
    },
    // Enable notification
    notification: {
        enabled: true,
        storage: myStorage,
    },
});

如果未提供存储,则可以使用默认本地文件存储,它将通知连接存储在以下位置:

  • .notification.localstore.json 如果在本地运行,则为 。
  • ${process.env.TEMP}/.notification.localstore.json如果 设置为 1,则 process.env.RUNNING_ON_AZURE 为 。

如果使用默认的本地文件存储,Azure Web 应用和Azure Functions重启或重新部署期间清理本地文件。 还可以从 Teams 中卸载机器人,然后安装它以再次向存储添加连接。

不同于 NotificationTargetStorage Bot Framework SDK 的 自定义存储。 通知存储需要 read、、 和 list 功能,delete但 Bot Framework SDK 的存储具有 readwritedelete 功能,并且没有list功能。 write

有关 Azure Blob 存储的详细信息,请参阅 通知存储实现示例

注意

  • 建议将自己的共享存储用于生产环境。
  • 如果实现自己的 Bot Framework SDK 存储(例如 botbuilder-azure-blobs.BlobsStorage),则需要实现另一个存储来通知。 可以与不同的容器共享同一 Blob 连接字符串。

返回页首

为通知 API 添加身份验证

如果选择 HTTP 触发器,则基架通知 API 未启用身份验证或授权。 在将 API 用于生产之前,请确保为 API 添加身份验证或授权。 可以执行以下操作之一:

可以根据需要选择 API 的更多身份验证或授权解决方案。

返回页首

连接到现有 API

如果你没有所需的 SDK,并且想要在代码中调用外部 API,则可以使用 Teams:连接到 Microsoft Visual Studio Code Teams Toolkit 扩展中的 API 命令或 TeamsFx CLI 中的 teamsfx add api-connection 命令来启动代码以调用目标 API。 有关详细信息,请参阅 集成现有的第三方 API

Teams 机器人应用程序或 Teams 传入 Webhook

TeamsFx 支持两种方法来帮助将通知从系统发送到 Teams:

  • 创建 Teams 机器人应用。
  • 创建 Teams 传入 Webhook。

在下表中,可以看到两种不同方式的比较:

  Teams 机器人应用 Teams 传入 Webhook
消息个人 ✔️
消息群聊 ✔️
消息公共通道 ✔️ ✔️
消息专用频道 ✔️
发送卡消息 ✔️ ✔️
发送欢迎消息 ✔️
检索 Teams 上下文 ✔️
需要在 Teams 中执行安装步骤 ✔️
需要 Azure 资源 Azure 机器人服务

传入 Webhook 通知

传入的 Webhook 有助于将消息从应用发布到 Teams。 如果在任何通道中为团队启用了传入 Webhook,则会公开 HTTPS 终结点,该终结点接受格式正确的 JSON 并将消息插入该通道。 例如,可以在 DevOps 通道中创建传入 Webhook,配置生成,并同时部署和监视服务以发送警报。 TeamsFx 提供 传入 Webhook 通知示例 ,可帮助你:

返回页首

发送活动源通知

如果要为应用发送活动源通知,可以使用 Microsoft Graph 中的活动源通知 API。 有关详细信息,请参阅 向 Microsoft Teams 中的用户发送活动源通知

常见问题


为什么通知安装为空,即使机器人应用安装在 Teams 中?

Teams 仅在首次安装时发送事件。 如果在启动通知机器人服务之前已安装机器人应用,则安装事件未到达机器人服务或被省略。

可通过以下方式解决此问题:

  • 在群组聊天或频道中向个人机器人发送消息或提及机器人,这有助于使用正确的安装信息再次访问机器人服务。
  • 从 Teams 卸载机器人应用,然后重新安装或重新启动它。 可以将安装事件重新发送到机器人服务。

通知目标连接存储在持久性存储中。 如果使用默认的本地文件存储,则所有安装都存储在 下 .notification.localstore.json

注意

有关添加自己的存储的详细信息,请参阅 添加存储


发送通知时为什么会出现“错误请求”或“参数错误”错误?

如果通知安装与机器人 ID 或密码不匹配,则会收到“ 未能解密对话 ID ”错误。 此错误的一个可能原因是由于清理本地状态或重新预配而更改了机器人 ID 或密码。

可以通过清理通知存储来解决此问题。 清理后,在 Teams 中通知重新安装机器人,并确保新安装是最新的。 每个存储的通知安装都与一个机器人绑定。 如果能够检查通知存储,则其机器人字段应与正在运行的机器人匹配,例如具有相同 GUID 的机器人 ID。

注意

对于本地存储,默认位置为 .notification.localstore.json


重启或重新部署机器人应用后,为什么通知目标丢失?

通知目标连接存储在持久性存储中。 如果使用默认的本地文件存储,Azure Web 应用和Azure Functions重启或重新部署期间清理本地文件。 还可以从 Teams 中卸载机器人,然后安装它以再次向存储添加连接。 建议将自己的共享存储用于生产环境。


为什么在使用 API“findChannel” () 时返回未定义的错误?

当机器人应用安装到其他通道而不是通道时, General 可能会遇到未定义的错误。 若要修复此错误,可以从 Teams 卸载机器人应用,然后重新部署并重新启动它。 重新部署并重新启动后,请确保将机器人应用安装到通道中 General


我能否知道在通知项目中安装机器人的所有目标?

Microsoft Graph API 用于列出团队、组或聊天中安装的应用。 如有必要,请将团队、组或聊天迭代到要作为目标安装的应用中。 在通知项目中,它使用持久性存储来存储安装目标。 有关详细信息,请参阅 基于事件的通知


如何自定义 Azurite 侦听端口?

如果 Azurite 因端口正在使用而退出,则可以指定另一个侦听端口,并在 中local.settings.json更新 AzureWebJobsStorage连接字符串。


如何扩展通知机器人以支持命令和响应?
  1. 转到 bot\src\internal\initialize.ts(js) 并更新 conversationBot 初始化以启用通知功能:

    对话机器人初始化以启用通知功能。

  2. 若要将命令添加到机器人,请按照 Teams 中的命令机器人中的说明进行操作。


如何通过添加工作流机器人自适应卡片操作来扩展通知机器人?

自适应卡片操作处理程序功能使应用能够响应最终用户为完成顺序工作流而触发的自适应卡片操作。 自适应卡在卡中提供了一个或多个按钮,用于请求用户的输入,例如调用某些 API。 然后,自适应卡片在对话中发送另一个自适应卡片,以响应卡操作。

有关如何将自适应卡操作添加到命令机器人的详细信息,请参阅 Teams 中的工作流机器人


返回页首

分步指南

按照 分步 指南生成 Teams 通知机器人。

另请参阅