ForcePilot/backend/package/yuxi/channel/extensions/feishu/reactions.py
Kris 5e91bb9985 feat(feishu): 新增飞书渠道完整插件实现
新增飞书渠道插件,包含基础配置、事件处理、消息收发、工具调用、权限管理等完整功能模块,支持WebSocket长连接、卡片消息、流式响应、群管理、审批通知等能力
2026-05-21 10:46:42 +08:00

130 lines
4.6 KiB
Python

from __future__ import annotations
import logging
from yuxi.channel.extensions.feishu.client import get_client
from yuxi.channel.extensions.feishu.types import EMOJI_TYPE_MAP
logger = logging.getLogger(__name__)
def normalize_emoji_type(name: str) -> str | None:
name_upper = name.upper().replace(":", "")
if name_upper in EMOJI_TYPE_MAP:
return EMOJI_TYPE_MAP[name_upper]
return None
def is_supported_emoji(name: str) -> bool:
return normalize_emoji_type(name) is not None
async def add_reaction(
app_id: str,
app_secret: str,
domain: str,
message_id: str,
emoji_type: str,
http_timeout_ms: int = 30000,
) -> dict:
normalized = normalize_emoji_type(emoji_type)
if not normalized:
return {"success": False, "error": f"Unsupported emoji type: {emoji_type}"}
try:
client = get_client(app_id, app_secret, domain, http_timeout_ms)
import lark_oapi
req = lark_oapi.im.v1.CreateMessageReactionRequest(
message_id=message_id,
request_body=lark_oapi.im.v1.CreateMessageReactionRequestBody(
reaction_type={"emoji_type": normalized},
),
)
resp = await client.im.v1.message_reaction.create_async(req)
if resp.success():
return {"success": True, "reaction_id": getattr(resp.data, "reaction_id", "")}
else:
return {"success": False, "error": getattr(resp, "msg", ""), "code": getattr(resp, "code", 0)}
except ImportError:
return {"success": False, "error": "lark-oapi SDK not installed"}
except Exception:
logger.exception("Feishu add_reaction error")
return {"success": False, "error": "Internal error"}
async def remove_reaction(
app_id: str,
app_secret: str,
domain: str,
message_id: str,
emoji_type: str,
http_timeout_ms: int = 30000,
) -> dict:
normalized = normalize_emoji_type(emoji_type)
if not normalized:
return {"success": False, "error": f"Unsupported emoji type: {emoji_type}"}
try:
client = get_client(app_id, app_secret, domain, http_timeout_ms)
import lark_oapi
list_req = lark_oapi.im.v1.ListMessageReactionRequest(message_id=message_id)
list_resp = await client.im.v1.message_reaction.list_async(list_req)
if list_resp.success() and list_resp.data:
items = getattr(list_resp.data, "items", []) or []
for item in items:
if getattr(item, "reaction_type", {}).get("emoji_type", "") == normalized:
reaction_id = getattr(item, "reaction_id", "")
if reaction_id:
del_req = lark_oapi.im.v1.DeleteMessageReactionRequest(
message_id=message_id,
reaction_id=reaction_id,
)
del_resp = await client.im.v1.message_reaction.delete_async(del_req)
if del_resp.success():
return {"success": True}
else:
return {"success": False, "error": getattr(del_resp, "msg", "")}
return {"success": False, "error": "Reaction not found"}
except ImportError:
return {"success": False, "error": "lark-oapi SDK not installed"}
except Exception:
logger.exception("Feishu remove_reaction error")
return {"success": False, "error": "Internal error"}
async def list_reactions(
app_id: str,
app_secret: str,
domain: str,
message_id: str,
http_timeout_ms: int = 30000,
) -> dict:
try:
client = get_client(app_id, app_secret, domain, http_timeout_ms)
import lark_oapi
req = lark_oapi.im.v1.ListMessageReactionRequest(message_id=message_id)
resp = await client.im.v1.message_reaction.list_async(req)
if resp.success() and resp.data:
items = getattr(resp.data, "items", []) or []
reactions = []
for item in items:
reactions.append({
"reaction_id": getattr(item, "reaction_id", ""),
"emoji_type": getattr(item, "reaction_type", {}).get("emoji_type", ""),
"count": getattr(item, "count", 0),
})
return {"success": True, "items": reactions}
else:
return {"success": False, "error": getattr(resp, "msg", "")}
except ImportError:
return {"success": False, "error": "lark-oapi SDK not installed"}
except Exception:
logger.exception("Feishu list_reactions error")
return {"success": False, "error": "Internal error"}