新增飞书机器人适配器全套功能,包括: - 基础适配器入口与工具导出 - 消息格式化、卡片渲染、回复调度逻辑 - 会话ID生成、模型覆盖策略 - 消息发送缓存、顺序队列管理 - 飞书签名验证、加解密webhook请求 - 审批权限校验、机器人菜单事件处理 - 文档评论、钉消息、语音转码处理 - 静态/动态目录管理、子代理生命周期管理 - 各类工具集:聊天、云盘、文档、知识库API封装
158 lines
4.6 KiB
Python
158 lines
4.6 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from yuxi.channels.models import DeliveryResult
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
try:
|
|
import lark_oapi
|
|
|
|
HAS_LARK_SDK = True
|
|
except ImportError:
|
|
HAS_LARK_SDK = False
|
|
lark_oapi = None # type: ignore
|
|
|
|
FEISHU_EMOJI_MAP = {
|
|
"THUMBSUP": "👍",
|
|
"THUMBSDOWN": "👎",
|
|
"HEART": "❤️",
|
|
"SMILE": "😊",
|
|
"GRINNING": "😁",
|
|
"LAUGHING": "😆",
|
|
"CRY": "😢",
|
|
"ANGRY": "😡",
|
|
"SURPRISED": "😲",
|
|
"THINKING": "🤔",
|
|
"CLAP": "👏",
|
|
"OK": "👌",
|
|
"FIST": "✊",
|
|
"PRAY": "🙏",
|
|
"FIRE": "🔥",
|
|
"PARTY": "🎉",
|
|
"CHECK": "✅",
|
|
"CROSS": "❌",
|
|
"QUESTION": "❓",
|
|
"EXCLAMATION": "❗",
|
|
}
|
|
|
|
|
|
def emoji_type_to_emoji(emoji_type: str) -> str:
|
|
return FEISHU_EMOJI_MAP.get(emoji_type, emoji_type)
|
|
|
|
|
|
async def remove_reaction(
|
|
client: Any,
|
|
message_id: str,
|
|
reaction_id: str,
|
|
) -> DeliveryResult:
|
|
if not HAS_LARK_SDK:
|
|
return DeliveryResult(success=False, error="lark-oapi SDK not available")
|
|
|
|
try:
|
|
request = (
|
|
lark_oapi.api.im.v1.DeleteMessageReactionRequest.builder()
|
|
.message_id(message_id)
|
|
.reaction_id(reaction_id)
|
|
.build()
|
|
)
|
|
|
|
resp = await client.im.v1.message.reaction.delete(request)
|
|
if resp.success():
|
|
return DeliveryResult(success=True)
|
|
return DeliveryResult(success=False, error=resp.msg)
|
|
except Exception as e:
|
|
logger.error(f"[Feishu] remove_reaction failed: {e}")
|
|
return DeliveryResult(success=False, error=str(e))
|
|
|
|
|
|
async def list_reactions(
|
|
client: Any,
|
|
message_id: str,
|
|
*,
|
|
page_size: int = 20,
|
|
page_token: str = "",
|
|
) -> dict[str, Any]:
|
|
if not HAS_LARK_SDK:
|
|
return {"reactions": [], "total": 0}
|
|
|
|
try:
|
|
request = (
|
|
lark_oapi.api.im.v1.ListMessageReactionRequest.builder()
|
|
.message_id(message_id)
|
|
.page_size(page_size)
|
|
.page_token(page_token)
|
|
.build()
|
|
)
|
|
|
|
resp = await client.im.v1.message.reaction.list(request)
|
|
if resp.success():
|
|
items = []
|
|
for item in resp.data.get("items", []):
|
|
emoji_type = item.get("reaction_type", {}).get("emoji_type", "")
|
|
items.append(
|
|
{
|
|
"reaction_id": item.get("reaction_id", ""),
|
|
"emoji_type": emoji_type,
|
|
"emoji": emoji_type_to_emoji(emoji_type),
|
|
"count": item.get("count", 0),
|
|
"user_id": item.get("user_id", ""),
|
|
}
|
|
)
|
|
return {
|
|
"reactions": items,
|
|
"total": resp.data.get("total", 0),
|
|
"page_token": resp.data.get("page_token", ""),
|
|
"has_more": resp.data.get("has_more", False),
|
|
}
|
|
return {"reactions": [], "total": 0, "error": resp.msg}
|
|
except Exception as e:
|
|
logger.error(f"[Feishu] list_reactions failed: {e}")
|
|
return {"reactions": [], "total": 0, "error": str(e)}
|
|
|
|
|
|
async def clear_all_bot_reactions(
|
|
client: Any,
|
|
message_id: str,
|
|
bot_open_id: str,
|
|
) -> DeliveryResult:
|
|
if not HAS_LARK_SDK:
|
|
return DeliveryResult(success=False, error="lark-oapi SDK not available")
|
|
|
|
result = await list_reactions(client, message_id, page_size=50)
|
|
items = result.get("reactions", [])
|
|
removed = 0
|
|
errors = 0
|
|
|
|
for item in items:
|
|
reaction_id = item.get("reaction_id", "")
|
|
user_id = item.get("user_id", "")
|
|
if user_id != bot_open_id:
|
|
continue
|
|
if not reaction_id:
|
|
continue
|
|
|
|
try:
|
|
del_req = (
|
|
lark_oapi.api.im.v1.DeleteMessageReactionRequest.builder()
|
|
.message_id(message_id)
|
|
.reaction_id(reaction_id)
|
|
.build()
|
|
)
|
|
del_resp = await client.im.v1.message.reaction.delete(del_req)
|
|
if del_resp.success():
|
|
removed += 1
|
|
else:
|
|
errors += 1
|
|
logger.debug("[Feishu] Failed to remove reaction %s: %s", reaction_id, del_resp.msg)
|
|
except Exception as e:
|
|
errors += 1
|
|
logger.debug("[Feishu] Error removing reaction %s: %s", reaction_id, e)
|
|
|
|
if errors > 0:
|
|
logger.warning("[Feishu] clear_all_bot_reactions: removed=%d, errors=%d", removed, errors)
|
|
return DeliveryResult(success=removed > 0, error=f"Removed {removed}/{removed + errors}")
|
|
return DeliveryResult(success=True)
|