实现了 Teams 机器人所需的全功能组件,包括: - 基础命令解析与帮助卡片生成 - 租户验证与访问控制 - 自定义 UA 与媒体工具 - 消息分块、批注处理与会话管理 - 防抖、缓存与配置路由能力 - 投票、配对、审计与运行时状态管理 - TTS 语音合成与卡片构建工具 - 群组管理与权限控制逻辑
148 lines
4.0 KiB
Python
148 lines
4.0 KiB
Python
"""Microsoft Teams Adaptive Card 构建器。
|
|
|
|
提供常用交互卡片的构建函数,返回 Adaptive Card JSON schema (v1.5)。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
|
|
def build_vote_card(
|
|
title: str,
|
|
options: list[str],
|
|
callback_data: dict[str, Any] | None = None,
|
|
max_selections: int | None = None,
|
|
) -> dict[str, Any]:
|
|
choices = [{"title": opt, "value": opt} for opt in options[:12]]
|
|
|
|
allow_multi = max_selections is not None and max_selections > 1
|
|
choice_set: dict[str, Any] = {
|
|
"type": "Input.ChoiceSet",
|
|
"id": "voteOption",
|
|
"style": "expanded",
|
|
"isMultiSelect": allow_multi,
|
|
"choices": choices,
|
|
}
|
|
if allow_multi:
|
|
choice_set["maxSelections"] = max_selections
|
|
|
|
return {
|
|
"type": "AdaptiveCard",
|
|
"version": "1.5",
|
|
"body": [
|
|
{"type": "TextBlock", "size": "Large", "weight": "Bolder", "text": title},
|
|
choice_set,
|
|
],
|
|
"actions": [
|
|
{
|
|
"type": "Action.Submit",
|
|
"title": "投票",
|
|
"data": callback_data or {},
|
|
}
|
|
],
|
|
}
|
|
|
|
|
|
def build_confirm_card(
|
|
title: str,
|
|
message: str,
|
|
confirm_text: str = "确认",
|
|
cancel_text: str = "取消",
|
|
confirm_data: dict[str, Any] | None = None,
|
|
cancel_data: dict[str, Any] | None = None,
|
|
) -> dict[str, Any]:
|
|
return {
|
|
"type": "AdaptiveCard",
|
|
"version": "1.5",
|
|
"body": [
|
|
{"type": "TextBlock", "size": "Large", "weight": "Bolder", "text": title},
|
|
{"type": "TextBlock", "text": message, "wrap": True},
|
|
],
|
|
"actions": [
|
|
{
|
|
"type": "Action.Submit",
|
|
"title": confirm_text,
|
|
"style": "positive",
|
|
"data": confirm_data or {"action": "confirm"},
|
|
},
|
|
{
|
|
"type": "Action.Submit",
|
|
"title": cancel_text,
|
|
"style": "default",
|
|
"data": cancel_data or {"action": "cancel"},
|
|
},
|
|
],
|
|
}
|
|
|
|
|
|
def build_info_card(
|
|
title: str,
|
|
facts: dict[str, str],
|
|
subtitle: str | None = None,
|
|
) -> dict[str, Any]:
|
|
body: list[dict[str, Any]] = [
|
|
{"type": "TextBlock", "size": "Large", "weight": "Bolder", "text": title},
|
|
]
|
|
if subtitle:
|
|
body.append({"type": "TextBlock", "text": subtitle, "isSubtle": True, "wrap": True})
|
|
body.append(
|
|
{
|
|
"type": "FactSet",
|
|
"facts": [{"title": k, "value": v} for k, v in facts.items()],
|
|
}
|
|
)
|
|
return {"type": "AdaptiveCard", "version": "1.5", "body": body}
|
|
|
|
|
|
def build_input_card(
|
|
title: str,
|
|
fields: list[dict[str, Any]],
|
|
submit_text: str = "提交",
|
|
callback_data: dict[str, Any] | None = None,
|
|
) -> dict[str, Any]:
|
|
body: list[dict[str, Any]] = [
|
|
{"type": "TextBlock", "size": "Large", "weight": "Bolder", "text": title},
|
|
]
|
|
for field in fields:
|
|
body.append(field)
|
|
|
|
return {
|
|
"type": "AdaptiveCard",
|
|
"version": "1.5",
|
|
"body": body,
|
|
"actions": [
|
|
{
|
|
"type": "Action.Submit",
|
|
"title": submit_text,
|
|
"data": callback_data or {},
|
|
}
|
|
],
|
|
}
|
|
|
|
|
|
def wrap_as_attachment(card: dict[str, Any]) -> dict[str, Any]:
|
|
return {
|
|
"contentType": "application/vnd.microsoft.card.adaptive",
|
|
"content": card,
|
|
}
|
|
|
|
|
|
def create_hero_card(
|
|
title: str,
|
|
text: str,
|
|
images: list[str] | None = None,
|
|
buttons: list[dict[str, str]] | None = None,
|
|
) -> dict[str, Any]:
|
|
card: dict[str, Any] = {
|
|
"contentType": "application/vnd.microsoft.card.hero",
|
|
"content": {"title": title, "text": text},
|
|
}
|
|
if images:
|
|
card["content"]["images"] = [{"url": url} for url in images]
|
|
if buttons:
|
|
card["content"]["buttons"] = [
|
|
{"type": "imBack", "title": btn["title"], "value": btn["value"]} for btn in buttons
|
|
]
|
|
return card
|