websocket_event.py 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import os
  2. import json
  3. import logging
  4. import asyncio
  5. import sys
  6. from typing import Optional
  7. # 将项目根目录添加到 python 路径,确保可以作为独立脚本运行
  8. PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", ".."))
  9. if PROJECT_ROOT not in sys.path:
  10. sys.path.append(PROJECT_ROOT)
  11. from agent.tools.builtin.feishu.feishu_client import FeishuClient, FeishuMessageEvent, FeishuDomain
  12. from agent.tools.builtin.feishu.chat import (
  13. FEISHU_APP_ID,
  14. FEISHU_APP_SECRET,
  15. get_contact_by_id,
  16. load_chat_history,
  17. save_chat_history,
  18. update_unread_count,
  19. _convert_feishu_msg_to_openai_content
  20. )
  21. # 配置日志
  22. logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  23. logger = logging.getLogger("FeishuWebsocket")
  24. class FeishuMessageListener:
  25. def __init__(self):
  26. self.client = FeishuClient(
  27. app_id=FEISHU_APP_ID,
  28. app_secret=FEISHU_APP_SECRET,
  29. domain=FeishuDomain.FEISHU
  30. )
  31. def handle_incoming_message(self, event: FeishuMessageEvent):
  32. """处理收到的飞书消息事件"""
  33. # 1. 识别联系人
  34. # 优先使用 sender_open_id 匹配联系人,如果没有则尝试 chat_id
  35. contact = get_contact_by_id(event.sender_open_id) or get_contact_by_id(event.chat_id)
  36. if not contact:
  37. logger.warning(f"收到未知发送者的消息: open_id={event.sender_open_id}, chat_id={event.chat_id}")
  38. # 对于未知联系人,我们可以选择忽略,或者记录到 'unknown' 分类
  39. contact = {"name": "未知联系人", "open_id": event.sender_open_id}
  40. contact_name = contact.get("name")
  41. logger.info(f"收到来自 [{contact_name}] 的消息: {event.content[:50]}...")
  42. # 2. 转换为 OpenAI 多模态格式
  43. # 构造一个类似 get_message_list 返回的字典对象,以便重用转换逻辑
  44. msg_dict = {
  45. "message_id": event.message_id,
  46. "content_type": event.content_type,
  47. "content": event.content, # 对于 text, websocket 传来的已经是解析后的字符串;对于 image 则是原始 JSON 字符串
  48. "sender_id": event.sender_open_id,
  49. "sender_type": "user" # WebSocket 收到的一般是用户消息,除非是机器人自己的回显(通常会过滤)
  50. }
  51. openai_content = _convert_feishu_msg_to_openai_content(self.client, msg_dict)
  52. # 3. 维护聊天记录
  53. history = load_chat_history(contact_name)
  54. new_message = {
  55. "role": "user",
  56. "message_id": event.message_id,
  57. "timestamp": os.path.getmtime(os.path.join(os.path.dirname(__file__), "chat.py")), # 简单模拟一个时间戳,实际应使用事件时间
  58. "content": openai_content
  59. }
  60. history.append(new_message)
  61. save_chat_history(contact_name, history)
  62. # 4. 更新未读计数
  63. update_unread_count(contact_name, increment=1)
  64. logger.info(f"已更新 [{contact_name}] 的聊天记录并增加未读计数")
  65. def start(self):
  66. """启动监听"""
  67. logger.info("正在启动飞书消息实时监听...")
  68. try:
  69. self.client.start_websocket(
  70. on_message=self.handle_incoming_message,
  71. blocking=True
  72. )
  73. except KeyboardInterrupt:
  74. logger.info("监听已停止")
  75. except Exception as e:
  76. logger.error(f"监听过程中出现错误: {e}")
  77. if __name__ == "__main__":
  78. listener = FeishuMessageListener()
  79. listener.start()