ForcePilot/backend/package/yuxi/channels/adapters/googlechat/cards.py
Kris 87fc26cd15 refactor(googlechat): 整理并优化Google Chat适配器代码
- 调整依赖导入顺序与清理冗余空行
- 修复setup wizard步骤存储逻辑
- 新增消息编辑/转发标记、卡片控件支持
- 完善目标校验、媒体上传、配对存储功能
- 优化流式响应与错误处理逻辑
- 增强SSRF防护与配置灵活性
- 新增/扩展内置命令与卡片处理能力
- 调整媒体大小限制与类型参数
2026-05-13 16:09:31 +08:00

266 lines
7.2 KiB
Python

from __future__ import annotations
def build_approval_card(title: str, action_id: str, confirm_text: str = "确认", reject_text: str = "拒绝") -> dict:
return {
"cards_v2": [
{
"card_id": action_id,
"card": {
"header": {"title": title, "imageType": "SQUARE"},
"sections": [
{
"widgets": [
{
"buttonList": {
"buttons": [
_make_button(confirm_text, "approve", green=True),
_make_button(reject_text, "reject", green=False),
]
}
}
]
}
],
},
}
]
}
def build_poll_card(question: str, options: list[str], action_id: str) -> dict:
buttons = [_make_button(opt, f"poll_vote_{i}_{action_id}") for i, opt in enumerate(options)]
sections: list[dict] = []
while buttons:
chunk = buttons[:2]
buttons = buttons[2:]
sections.append({"widgets": [{"buttonList": {"buttons": chunk}}]})
return {
"cards_v2": [
{
"card_id": action_id,
"card": {
"header": {"title": question, "imageType": "SQUARE"},
"sections": sections,
},
}
]
}
def build_info_card(title: str, fields: dict[str, str]) -> dict:
widgets = []
for key, value in fields.items():
widgets.append(
{
"decoratedText": {
"topLabel": key,
"text": value,
}
}
)
return {
"cards_v2": [
{
"card": {
"header": {"title": title},
"sections": [{"widgets": widgets}],
}
}
]
}
def build_form_card(title: str, fields: list[dict], submit_action: str) -> dict:
widgets = []
for field in fields:
field_input_type = field.get("input_type", "SINGLE_LINE")
if field_input_type in ("SINGLE_SELECT", "MULTI_SELECT"):
widgets.append(
{
"selectionInput": {
"label": field.get("label", ""),
"name": field.get("name", ""),
"type": field_input_type,
"items": _build_selection_items(field.get("options", [])),
}
}
)
elif field_input_type in ("DATE_AND_TIME", "DATE_ONLY", "TIME_ONLY"):
widgets.append(
_make_date_time_picker(
name=field.get("name", ""),
label=field.get("label", ""),
type_=field_input_type,
value_ms_epoch=field.get("value_ms_epoch"),
)
)
elif field_input_type == "DIVIDER":
widgets.append({"divider": {}})
else:
widgets.append(
{
"textInput": {
"label": field.get("label", ""),
"name": field.get("name", ""),
"type": field_input_type,
}
}
)
widgets.append({"buttonList": {"buttons": [_make_button("提交", submit_action, green=True)]}})
return {
"cards_v2": [
{
"card": {
"header": {"title": title},
"sections": [{"widgets": widgets}],
}
}
]
}
def build_exec_approval_card(
title: str,
action_id: str,
detail_fields: dict[str, str] | None = None,
) -> dict:
widgets = []
if detail_fields:
for key, value in detail_fields.items():
widgets.append(
{
"decoratedText": {
"topLabel": key,
"text": value,
}
}
)
widgets.append(
{
"buttonList": {
"buttons": [
_make_button("确认执行", f"exec_approve_{action_id}", green=True),
_make_button("拒绝执行", f"exec_reject_{action_id}", green=False),
]
}
}
)
return {
"cards_v2": [
{
"card": {
"header": {"title": title, "imageType": "SQUARE"},
"sections": [{"widgets": widgets}],
}
}
]
}
def build_selection_card(
title: str,
selection_name: str,
label: str,
options: list[dict[str, str]],
selection_type: str = "SINGLE_SELECT",
submit_action: str | None = None,
) -> dict:
widgets = [
{
"selectionInput": {
"label": label,
"name": selection_name,
"type": selection_type,
"items": _build_selection_items(options),
}
}
]
if submit_action:
widgets.append({"buttonList": {"buttons": [_make_button("提交", submit_action, green=True)]}})
return {
"cards_v2": [
{
"card": {
"header": {"title": title},
"sections": [{"widgets": widgets}],
}
}
]
}
def _make_divider() -> dict:
return {"divider": {}}
def _build_selection_items(options: list[dict[str, str]]) -> list[dict]:
items = []
for opt in options:
items.append(
{
"text": opt.get("text", opt.get("label", "")),
"value": opt.get("value", ""),
"selected": opt.get("selected", False),
}
)
return items
def _make_button(text: str, action: str, green: bool = False) -> dict:
color = {"red": 0, "green": 0.6, "blue": 0} if green else {"red": 0.6, "green": 0, "blue": 0}
return {
"text": text,
"color": color,
"onClick": {"action": {"function": action}},
}
def _make_date_time_picker(
name: str,
label: str = "",
type_: str = "DATE_AND_TIME",
value_ms_epoch: int | None = None,
) -> dict:
widget = {
"dateTimePicker": {
"name": name,
"label": label,
"type": type_,
}
}
if value_ms_epoch is not None:
widget["dateTimePicker"]["valueMsEpoch"] = str(value_ms_epoch)
return widget
def _make_grid(column_count: int, items: list[dict]) -> dict:
return {
"grid": {
"columnCount": column_count,
"items": [{"widgets": [item]} for item in items],
}
}
def _make_columns(column_items: list[list[dict]]) -> dict:
return {"columns": {"columnItems": [{"widgets": col_widgets} for col_widgets in column_items]}}
def _make_link_button(text: str, url: str) -> dict:
return {
"text": text,
"onClick": {"openLink": {"url": url}},
}