Browse Source

Merge pull request #1559 from huiwenTT/dingdinggpt

钉钉机器人
master
zhayujie GitHub 11 months ago
parent
commit
eb809055d4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 214 additions and 2 deletions
  1. +1
    -1
      app.py
  2. +3
    -0
      channel/channel_factory.py
  3. +164
    -0
      channel/dingtalk/dingtalk_channel.py
  4. +40
    -0
      channel/dingtalk/dingtalk_message.py
  5. +1
    -0
      common/const.py
  6. +5
    -1
      config.py

+ 1
- 1
app.py View File

@@ -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 View File

@@ -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 View File

@@ -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 View File

@@ -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 View File

@@ -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 View File

@@ -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配置


Loading…
Cancel
Save