瀏覽代碼

首次提交

关习习 1 月之前
父節點
當前提交
34e44d53b9
共有 8 個文件被更改,包括 227 次插入2 次删除
  1. 3 1
      .gitignore
  2. 37 0
      MsgSend.py
  3. 25 1
      README.md
  4. 25 0
      api_server.py
  5. 85 0
      client/client.py
  6. 8 0
      config.example.yaml
  7. 40 0
      config.py
  8. 4 0
      requirements.txt

+ 3 - 1
.gitignore

@@ -3,7 +3,7 @@
 __pycache__/
 *.py[cod]
 *$py.class
-
+.idea
 # C extensions
 *.so
 
@@ -58,3 +58,5 @@ docs/_build/
 # PyBuilder
 target/
 
+config.yaml
+

+ 37 - 0
MsgSend.py

@@ -0,0 +1,37 @@
+import json
+import lark_oapi as lark
+from lark_oapi.api.im.v1 import *
+from config import config
+
+app_id = config.get("bot.app_id")
+app_secret = config.get("bot.app_secret")
+user_id = config.get("user.open_id")
+
+# 创建client
+client = lark.Client.builder() \
+    .app_id(app_id) \
+    .app_secret(app_secret) \
+    .log_level(lark.LogLevel.DEBUG) \
+    .build()
+
+def send_message(content: str):
+    message = {
+        "text": content
+    }
+    message = json.dumps(message, ensure_ascii=False)
+    message = message.encode('unicode_escape').decode()
+    # 构造请求对象
+    request: CreateMessageRequest = CreateMessageRequest.builder() \
+        .receive_id_type("open_id") \
+        .request_body(CreateMessageRequestBody.builder()
+                      .receive_id(user_id)
+                      .msg_type("text")
+                      .content(message)
+                      .build()) \
+        .build()
+
+    # 发起请求
+    client.im.v1.message.create(request)
+
+if __name__ == "__main__":
+    send_message("hello world")

+ 25 - 1
README.md

@@ -1,3 +1,27 @@
 # feishu_bot
 
-飞书机器人bot
+飞书机器人bot
+
+首先填写config.example.yaml中你的机器人配置
+```
+# bot相关参数,填写对应登录凭证
+bot:
+  app_id: YOUR_APP_ID
+  app_secret: YOUR_APP_SECRET
+
+# 用户参数,填写你的唯一认证信息原来跟你发送消息
+user:
+  open_id: YOUR_OPEN_ID
+```
+
+打开第一个命令行窗口
+启动client开启ws长连接用于接收消
+```
+python client/client.py
+```
+
+打开第二个命令行窗口
+启动API中台
+```
+python api_server.py
+```

+ 25 - 0
api_server.py

@@ -0,0 +1,25 @@
+from fastapi import FastAPI, Request
+import uvicorn
+from MsgSend import send_message
+import json
+
+app = FastAPI()
+
+@app.post("/record")
+async def record_endpoint(request: Request):
+    """
+    接收POST请求并返回ok
+    """
+    try:
+        data = await request.json()
+        content = json.loads(data.get("content", ""))
+        # 如果需要发送消息,取消下面一行的注释
+        send_message(content.get("text"))
+        print(f"Received data: {data.get('content', '')}")
+        return {"message": "ok"}
+    except Exception as e:
+        print(f"Error processing request: {e}")
+        return {"message": "error", "detail": str(e)}
+
+if __name__ == "__main__":
+    uvicorn.run(app, host="0.0.0.0", port=3000)

+ 85 - 0
client/client.py

@@ -0,0 +1,85 @@
+import lark_oapi as lark
+from lark_oapi.api.im.v1 import *
+from config import config
+import json
+import httpx
+import asyncio
+
+# 注册接收消息事件,处理接收到的消息。
+# Register event handler to handle received messages.
+# https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message/events/receive
+
+def do_p2_im_message_receive_v1(data: P2ImMessageReceiveV1) -> None:
+    """
+    "message_id": str,
+    "root_id": str,
+    "parent_id": str,
+    "create_time": int,
+    "update_time": int,
+    "chat_id": str,
+    "thread_id": str,
+    "chat_type": str,
+    "message_type": str,
+    "content": str,
+    "mentions": List[MentionEvent],
+    "user_agent": str,
+
+    构造该字典后返回
+    """
+    result = {
+        "message_id": data.event.message.message_id,
+        "root_id": data.event.message.root_id,
+        "parent_id": data.event.message.parent_id,
+        "create_time": data.event.message.create_time,
+        "update_time": data.event.message.update_time,
+        "chat_id": data.event.message.chat_id,
+        "thread_id": data.event.message.thread_id,
+        "chat_type": data.event.message.chat_type,
+        "message_type": data.event.message.message_type,
+        "content": data.event.message.content,
+        "mentions": data.event.message.mentions,
+        "user_agent": data.event.message.user_agent
+    }
+    print("--------on_message---------")
+    print(result)
+
+    try:
+        asyncio.create_task(_send_record_async(result))
+    except Exception as e:
+        print(f"发送数据到记录端点失败: {e}")
+
+async def _send_record_async(data):
+    """异步发送数据到记录端点"""
+    async with httpx.AsyncClient() as client:
+        try:
+            await client.post("http://localhost:3000/record", json=data, timeout=10)
+        except Exception as e:
+            print(f"异步发送数据到记录端点失败: {e}")
+
+# 注册事件回调
+# Register event handler.
+event_handler = (
+    lark.EventDispatcherHandler.builder("", "")
+    .register_p2_im_message_receive_v1(do_p2_im_message_receive_v1)
+    .build()
+)
+
+app_id = config.get("bot.app_id")
+app_secret = config.get("bot.app_secret")
+
+# 创建websocket长连接实例,开启监听
+wsClient = lark.ws.Client(
+    app_id,
+    app_secret,
+    event_handler=event_handler,
+    log_level=lark.LogLevel.INFO,
+)
+
+
+def main():
+    #  启动长连接,并注册事件处理器。
+    #  Start long connection and register event handler.
+    wsClient.start()
+
+if __name__ == "__main__":
+    main()

+ 8 - 0
config.example.yaml

@@ -0,0 +1,8 @@
+# bot相关参数,填写对应登录凭证
+bot:
+  app_id: YOUR_APP_ID
+  app_secret: YOUR_APP_SECRET
+
+# 用户参数,填写你的唯一认证信息原来跟你发送消息
+user:
+  open_id: YOUR_OPEN_ID

+ 40 - 0
config.py

@@ -0,0 +1,40 @@
+import yaml
+import os
+
+class Config:
+    def __init__(self, filename="config.yaml"):
+        self.filename = filename
+        self.config = self.load()
+
+    def load(self):
+        # 获取config.py文件所在的目录
+        config_dir = os.path.dirname(os.path.abspath(__file__))
+        # 构建配置文件的完整路径
+        config_path = os.path.join(config_dir, self.filename)
+        
+        # 检查配置文件是否存在
+        if not os.path.exists(config_path):
+            raise FileNotFoundError(f"配置文件 {config_path} 未找到")
+
+        with open(config_path, 'r', encoding="utf-8") as f:
+            self.config = yaml.safe_load(f)
+        return self.config
+
+    def get(self, key):
+        """
+        传入键返回值,如果有格式嵌套用 . 拼凑
+        如: app_id = config.get("bot.app_id")
+        """
+        keys = key.split(".")
+        if len(keys) == 1:
+            return self.config.get(keys[0])
+        conf = self.config
+        for k in keys:
+            conf = conf.get(k)
+        return conf
+
+config = Config()
+
+if __name__ == "__main__":
+    config = Config()
+    print(config.get("bot.app_id"))

+ 4 - 0
requirements.txt

@@ -0,0 +1,4 @@
+yaml
+lark_oapi
+json
+fastapi