Преглед изворни кода

Merge branch 'zhayujie:master' into master

Haikui Yang пре 2 година
родитељ
комит
d6c4789688

+ 1 - 1
app.py

@@ -43,7 +43,7 @@ def run():
             # os.environ['WECHATY_PUPPET_SERVICE_ENDPOINT'] = '127.0.0.1:9001'
 
         channel = channel_factory.create_channel(channel_name)
-        if channel_name in ["wx", "wxy", "terminal", "wechatmp", "wechatmp_service", "wechatcom_app", "wework", const.FEISHU]:
+        if channel_name in ["wx", "wxy", "terminal", "wechatmp", "wechatmp_service", "wechatcom_app", "wework", const.FEISHU,const.DINGTALK]:
             PluginManager().load_plugins()
 
         # startup channel

+ 3 - 0
channel/channel_factory.py

@@ -40,5 +40,8 @@ def create_channel(channel_type):
     elif channel_type == const.FEISHU:
         from channel.feishu.feishu_channel import FeiShuChanel
         return FeiShuChanel()
+    elif channel_type == const.DINGTALK:
+        from channel.dingtalk.dingtalk_channel import DingTalkChanel
+        return DingTalkChanel()
 
     raise RuntimeError

+ 164 - 0
channel/dingtalk/dingtalk_channel.py

@@ -0,0 +1,164 @@
+"""
+钉钉通道接入
+
+@author huiwen
+@Date 2023/11/28
+"""
+
+# -*- coding=utf-8 -*-
+import uuid
+
+import requests
+import web
+from channel.dingtalk.dingtalk_message import DingTalkMessage
+from bridge.context import Context
+from bridge.reply import Reply, ReplyType
+from common.log import logger
+from common.singleton import singleton
+from config import conf
+from common.expired_dict import ExpiredDict
+from bridge.context import ContextType
+from channel.chat_channel import ChatChannel, check_prefix
+from common import utils
+import json
+import os
+
+
+
+import argparse
+import logging
+from dingtalk_stream import AckMessage
+import dingtalk_stream
+
+@singleton
+class DingTalkChanel(ChatChannel,dingtalk_stream.ChatbotHandler):
+    dingtalk_client_id = conf().get('dingtalk_client_id')
+    dingtalk_client_secret = conf().get('dingtalk_client_secret')
+    
+    def setup_logger(self):
+        logger = logging.getLogger()
+        handler = logging.StreamHandler()
+        handler.setFormatter(
+            logging.Formatter('%(asctime)s %(name)-8s %(levelname)-8s %(message)s [%(filename)s:%(lineno)d]'))
+        logger.addHandler(handler)
+        logger.setLevel(logging.INFO)
+        return logger
+    def __init__(self):
+        super().__init__()
+        super(dingtalk_stream.ChatbotHandler, self).__init__()
+        
+        self.logger = self.setup_logger()
+        # 历史消息id暂存,用于幂等控制
+        self.receivedMsgs = ExpiredDict(60 * 60 * 7.1)
+        
+        logger.info("[dingtalk] client_id={}, client_secret={} ".format(
+            self.dingtalk_client_id, self.dingtalk_client_secret))
+        # 无需群校验和前缀
+        conf()["group_name_white_list"] = ["ALL_GROUP"]
+        
+        
+
+    def startup(self):
+       
+        credential = dingtalk_stream.Credential( self.dingtalk_client_id, self.dingtalk_client_secret)
+        client = dingtalk_stream.DingTalkStreamClient(credential)
+        client.register_callback_handler(dingtalk_stream.chatbot.ChatbotMessage.TOPIC,self)
+        client.start_forever()
+
+    def handle_single(self, cmsg:DingTalkMessage):
+        # 处理单聊消息
+        #  
+    
+        if cmsg.ctype == ContextType.VOICE:
+           
+            logger.debug("[dingtalk]receive voice msg: {}".format(cmsg.content))
+        elif cmsg.ctype == ContextType.IMAGE:
+            logger.debug("[dingtalk]receive image msg: {}".format(cmsg.content))
+        elif cmsg.ctype == ContextType.PATPAT:
+            logger.debug("[dingtalk]receive patpat msg: {}".format(cmsg.content))
+        elif cmsg.ctype == ContextType.TEXT:
+            expression = cmsg.my_msg
+            
+        cmsg.content = conf()["single_chat_prefix"][0] + cmsg.content
+        
+        context = self._compose_context(cmsg.ctype, cmsg.content, isgroup=False, msg=cmsg)
+        
+        if context:
+            self.produce(context)
+
+    def handle_group(self, cmsg:DingTalkMessage):
+        # 处理群聊消息
+        #  
+    
+        if cmsg.ctype == ContextType.VOICE:
+           
+            logger.debug("[dingtalk]receive voice msg: {}".format(cmsg.content))
+        elif cmsg.ctype == ContextType.IMAGE:
+            logger.debug("[dingtalk]receive image msg: {}".format(cmsg.content))
+        elif cmsg.ctype == ContextType.PATPAT:
+            logger.debug("[dingtalk]receive patpat msg: {}".format(cmsg.content))
+        elif cmsg.ctype == ContextType.TEXT:
+            expression = cmsg.my_msg
+            
+        cmsg.content = conf()["group_chat_prefix"][0] + cmsg.content
+        context = self._compose_context(cmsg.ctype, cmsg.content, isgroup=True, msg=cmsg)
+        context['no_need_at']=True
+        if context:
+            self.produce(context)
+
+
+    async def process(self, callback: dingtalk_stream.CallbackMessage):
+       
+
+
+        try:
+            
+            incoming_message = dingtalk_stream.ChatbotMessage.from_dict(callback.data)
+            dingtalk_msg = DingTalkMessage(incoming_message)
+            if incoming_message.conversation_type == '1':
+                self.handle_single(dingtalk_msg)
+            else:
+                self.handle_group(dingtalk_msg)   
+            return AckMessage.STATUS_OK, 'OK'
+        except Exception as e:
+            logger.error(e)
+            return self.FAILED_MSG
+
+
+    def send(self, reply: Reply, context: Context):
+
+
+        incoming_message = context.kwargs['msg'].incoming_message
+        self.reply_text(reply.content, incoming_message)
+       
+        
+
+
+
+    # def _compose_context(self, ctype: ContextType, content, **kwargs):
+    #     context = Context(ctype, content)
+    #     context.kwargs = kwargs
+    #     if "origin_ctype" not in context:
+    #         context["origin_ctype"] = ctype
+
+    #     cmsg = context["msg"]
+    #     context["session_id"] = cmsg.from_user_id
+    #     context["receiver"] = cmsg.other_user_id
+
+    #     if ctype == ContextType.TEXT:
+    #         # 1.文本请求
+    #         # 图片生成处理
+    #         img_match_prefix = check_prefix(content, conf().get("image_create_prefix"))
+    #         if img_match_prefix:
+    #             content = content.replace(img_match_prefix, "", 1)
+    #             context.type = ContextType.IMAGE_CREATE
+    #         else:
+    #             context.type = ContextType.TEXT
+    #         context.content = content.strip()
+
+    #     elif context.type == ContextType.VOICE:
+    #         # 2.语音请求
+    #         if "desire_rtype" not in context and conf().get("voice_reply_voice"):
+    #             context["desire_rtype"] = ReplyType.VOICE
+
+    #     return context

+ 40 - 0
channel/dingtalk/dingtalk_message.py

@@ -0,0 +1,40 @@
+from bridge.context import ContextType
+from channel.chat_message import ChatMessage
+import json
+import requests
+from common.log import logger
+from common.tmp_dir import TmpDir
+from common import utils
+from dingtalk_stream import ChatbotMessage
+
+class DingTalkMessage(ChatMessage):
+    def __init__(self, event: ChatbotMessage):
+        super().__init__(event)
+        
+        self.msg_id = event.message_id
+        msg_type = event.message_type
+        self.incoming_message =event
+        self.sender_staff_id = event.sender_staff_id
+        
+        self.create_time = event.create_at
+        if event.conversation_type=="1":
+            self.is_group = False
+        else:
+            self.is_group = True
+        
+
+        if msg_type == "text":
+            self.ctype = ContextType.TEXT
+            
+            self.content = event.text.content.strip()
+        
+        self.from_user_id = event.sender_id
+        self.to_user_id = event.chatbot_user_id
+        self.other_user_nickname = event.conversation_title
+        
+        user_id = event.sender_id
+        nickname =event.sender_nick
+
+        
+
+      

+ 1 - 0
common/const.py

@@ -22,3 +22,4 @@ MODEL_LIST = ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4", "wenxin", "wenxin-4
 
 # channel
 FEISHU = "feishu"
+DINGTALK = "dingtalk"   

+ 5 - 1
config.py

@@ -132,7 +132,11 @@ available_setting = {
     "feishu_app_secret": "",  # 飞书机器人APP secret
     "feishu_token": "",  # 飞书 verification token
     "feishu_bot_name": "",  # 飞书机器人的名字
-
+    
+    # 钉钉配置
+    "dingtalk_client_id": "",  # 钉钉机器人Client ID 
+    "dingtalk_client_secret": "",  # 钉钉机器人Client Secret 
+    
     # chatgpt指令自定义触发词
     "clear_memory_commands": ["#清除记忆"],  # 重置会话指令,必须以#开头
     # channel配置

+ 3 - 0
requirements-optional.txt

@@ -33,3 +33,6 @@ curl_cffi
 
 # tongyi qwen
 broadscope_bailian
+
+# google
+google-generativeai