ForcePilot/backend/package/yuxi/channels/adapters/feishu/comment_handler.py
Kris a6fa7245e5 feat(feishu): 完整实现飞书适配器核心模块
新增飞书机器人适配器全套功能,包括:
- 基础适配器入口与工具导出
- 消息格式化、卡片渲染、回复调度逻辑
- 会话ID生成、模型覆盖策略
- 消息发送缓存、顺序队列管理
- 飞书签名验证、加解密webhook请求
- 审批权限校验、机器人菜单事件处理
- 文档评论、钉消息、语音转码处理
- 静态/动态目录管理、子代理生命周期管理
- 各类工具集:聊天、云盘、文档、知识库API封装
2026-05-12 00:43:59 +08:00

81 lines
2.4 KiB
Python

from __future__ import annotations
from typing import Any
from yuxi.channels.models import (
ChannelIdentity,
ChannelMessage,
ChannelType,
ChatType,
EventType,
MessageType,
)
def handle_comment_event(
channel_id: str,
channel_type: ChannelType,
raw_payload: dict[str, Any],
bot_open_id: str = "",
) -> ChannelMessage | None:
event = raw_payload.get("event", {})
comment = event.get("comment", {})
if not comment:
return None
comment_id = comment.get("comment_id", "") or event.get("comment_id", "")
content = comment.get("content", {}) or {}
comment_text = _extract_comment_text(content)
commenter = comment.get("commenter", {}) or event.get("commenter", {}) or {}
commenter_id = commenter.get("open_id", "") or commenter.get("user_id", "")
doc_info = event.get("doc", {}) or {}
doc_name = doc_info.get("name", "") or event.get("doc_name", "")
doc_url = doc_info.get("url", "") or event.get("doc_url", "")
doc_type = doc_info.get("type", "") or event.get("doc_type", "doc")
full_content = "[文档评论] "
if doc_name:
full_content += f"{doc_name}"
if doc_url:
full_content += f" ({doc_url})"
full_content += f"\n{comment_text}"
return ChannelMessage(
identity=ChannelIdentity(
channel_id=channel_id,
channel_type=channel_type,
channel_user_id=commenter_id,
channel_chat_id=f"comment_{comment_id}",
channel_message_id=comment_id,
),
event_type=EventType.SYSTEM_EVENT,
message_type=MessageType.TEXT,
chat_type=ChatType.DIRECT,
content=full_content,
metadata={
"event_subtype": "drive_comment",
"doc_name": doc_name,
"doc_url": doc_url,
"doc_type": doc_type,
"comment_id": comment_id,
"commenter_id": commenter_id,
},
)
def _extract_comment_text(content: dict[str, Any]) -> str:
elements = content.get("elements", [])
if not elements:
return content.get("text", "")
parts: list[str] = []
for elem in elements:
if isinstance(elem, str):
parts.append(elem)
continue
text = elem.get("textRun", {}).get("text", "") or elem.get("text", "")
if text:
parts.append(text)
return "".join(parts)