{"id":19175859,"url":"https://github.com/connectai-e/feishu-webhook-proxy","last_synced_at":"2025-05-07T19:10:44.678Z","repository":{"id":196617134,"uuid":"696749435","full_name":"ConnectAI-E/Feishu-Webhook-Proxy","owner":"ConnectAI-E","description":"将飞书(Lark) webhook代理成websocket","archived":false,"fork":false,"pushed_at":"2024-03-13T11:43:42.000Z","size":33,"stargazers_count":5,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-27T18:34:16.485Z","etag":null,"topics":["feishu","lark","webhook","websocket"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ConnectAI-E.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-26T11:13:29.000Z","updated_at":"2024-02-07T03:24:35.000Z","dependencies_parsed_at":"2024-02-04T07:30:00.633Z","dependency_job_id":"ed5d9e8b-e639-46e5-8e4f-cca4c63e02e0","html_url":"https://github.com/ConnectAI-E/Feishu-Webhook-Proxy","commit_stats":null,"previous_names":["lloydzhou/feishu-webhook-proxy","connectai-e/feishu-webhook-proxy"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ConnectAI-E%2FFeishu-Webhook-Proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ConnectAI-E%2FFeishu-Webhook-Proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ConnectAI-E%2FFeishu-Webhook-Proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ConnectAI-E%2FFeishu-Webhook-Proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ConnectAI-E","download_url":"https://codeload.github.com/ConnectAI-E/Feishu-Webhook-Proxy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252940934,"owners_count":21828769,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["feishu","lark","webhook","websocket"],"created_at":"2024-11-09T10:25:55.846Z","updated_at":"2025-05-07T19:10:44.647Z","avatar_url":"https://github.com/ConnectAI-E.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Feishu(Lark)-Webhook-Proxy\n\n1. 将飞书(lark)webhook代理成websocket\n2. 企业自建应用不用创建公网的回调地址，直接本地使用websocket客户端连上这个转发地址\n\n\n# 设计\n1. 使用nchan维护websocket的连接\n2. 将飞书的回调消息，抽取飞书相关的头信息，外面包一层json，使用X-Request-Id作为唯一ID，推送给对应的channel，如果连接对应websocket的客户端回复了X-Request-Id对应的消息，就回复给飞书（这里主要用于第一次配置回调）\n3. 客户端自己保存飞书的密钥信息，从转发服务走的消息都是加密的。\n4. 客户端调用飞书其他接口，直接走自己的网络\n\n## 安全性\n1. 飞书回调消息都是加密的，只能由websocket客户端自己解密，转发服务是透明的。\n2. 如何确保自己的channel不会被别人恶意使用？\n\u003e 使用nginx basic auth，nchan支持auth_request，在对应的request里面使用basic auth就能做校验  \n\n\n## 实现\n- [x] 部署一个nchan（openresty版本）\n- [x] 配置一个internal的location，给内部转发飞书消息使用\n- [x] 配置一个location，作为飞书webhook转发（处理消息转发逻辑，如果是配置连接，就重定向到request_id对应的channel等待客户端返回challenge给飞书）\n\n\n# organization\n\u003e 使用一个organization对当前组织下面的所有bot进行管理\n\u003e 这样所有的消息可以通过`org_\u003cname\u003e`一个channel推送，这种模式下启动服务的时候可以不用提前注册所有的bot，可以动态的加入新的bot进去\n- [x] 对org_\u003cname\u003e的channel增加basic auth\n- [x] hook链接转发消息兼容organization\n- [x] 新增一个支持organization的client\n\n```\nclient = Client(bot1, bot2, org_name='org_lloyd', org_passwd='passwd')\n```\n\n\n# 使用\n\n## python sdk\n```\npip install ca-lark-websocket\n\nfrom connectai.lark.websocket import *\n\nclass MyBot(Bot):\n    def on_message(self, data, raw_message, **kwargs):\n        # 定义每一个机器人拿到消息后的处理逻辑\n        print('on_message', self.app_id, data, raw_message)\n        if 'header' in data:\n            if data['header']['event_type'] == 'im.message.receive_v1' and data['event']['message']['message_type'] == 'text':\n                message_id = data['event']['message']['message_id']\n                content = json.loads(data['event']['message']['content'])\n                text = content['text']\n                # 测试回复消息，初始化bot的时候，需要配置app_secret才能发出去消息\n                self.reply_text(message_id, 'reply: ' + text)\n                # 回复卡片消息\n                self.reply_card(message_id, FeishuMessageCard(\n                    FeishuMessageDiv('reply'),\n                    FeishuMessageHr(),\n                    FeishuMessageDiv(text),\n                    FeishuMessageNote(FeishuMessagePlainText('🤖'))\n                ))\n\nbot1 = MyBot('cli_xxx', app_secret='xxx', encrypt_key='xxx')\nbot2 = MyBot('cli_xxx', app_secret='xxx', encrypt_key='xxx')\n\n# 一个websocket连接，支持同时监听多个机器人回调消息\nclient = Client(bot1, bot2)\nclient.start()\n```\n\n## 集成openai\n\u003e test_openai.py文件中\n1. 继承Bot增加自己处理消息的回调\n```\nclass TextMessageBot(Bot):\n    def on_message(self, data, *args, **kwargs):\n        if 'header' in data:\n            if data['header']['event_type'] == 'im.message.receive_v1' and data['event']['message']['message_type'] == 'text':\n                content = json.loads(data['event']['message']['content'])\n                if self.app:\n                    return self.app.process_text_message(text=content['text'], **data['event']['message'])\n\n\n```\n2. 写一个应用：处理文本消息\n```\nclass Application(object):\n    def process_text_message(self, text, message_id, **kwargs):\n        if text == '/help' or text == '帮助':\n            self.bot.reply_card(\n                message_id,\n                FeishuMessageCard(\n                    FeishuMessageDiv('👋 你好呀，我是一款基于OpenAI技术的智能聊天机器人'),\n                    FeishuMessageHr(),\n                    FeishuMessageDiv('🎒 **需要更多帮助**\\n文本回复 *帮助* 或 */help*', tag='lark_md'),\n                    header=FeishuMessageCardHeader('🎒需要帮助吗？'),\n                )\n            )\n        elif text:\n            chat = ChatOpenAI(\n                callbacks=[OpenAICallbackHandler(self.bot, message_id)],\n                **self.openai_options\n            )\n            system_message = [SystemMessage(content=self.system_role)] if self.system_role else []\n            chat_history = []  # TODO\n            messages = system_message + chat_history + [HumanMessage(content=text)]\n            message = chat(messages)\n            logging.debug(\"reply message %r\", message)\n        else:\n            logging.warn(\"empty text\", text)\n```\n3. 初始化应用，启动机器人\n```\nif __name__ == \"__main__\":\n    app = Application(\n        openai_api_base='',\n        openai_api_key='',\n        app_id='',\n        app_secret='',\n        encrypt_key='',\n        verification_token='',\n    )\n    client = Client(app.bot)\n    client.start(True)  # debug mode\n\n```\n\n### 运行示例\n```\npip install ca-lark-websocket langchain openai click\npython test_openai.py\n```\n![image](https://github.com/ConnectAI-E/Feishu-Webhook-Proxy/assets/1826685/531c8ff5-3b46-4c15-9600-e02dae55cee2)\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconnectai-e%2Ffeishu-webhook-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fconnectai-e%2Ffeishu-webhook-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconnectai-e%2Ffeishu-webhook-proxy/lists"}