mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-03-19 21:38:18 +08:00
新增钉钉机器人(Stream模式)
This commit is contained in:
2
app.py
2
app.py
@@ -43,7 +43,7 @@ def run():
|
|||||||
# os.environ['WECHATY_PUPPET_SERVICE_ENDPOINT'] = '127.0.0.1:9001'
|
# os.environ['WECHATY_PUPPET_SERVICE_ENDPOINT'] = '127.0.0.1:9001'
|
||||||
|
|
||||||
channel = channel_factory.create_channel(channel_name)
|
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()
|
PluginManager().load_plugins()
|
||||||
|
|
||||||
# startup channel
|
# startup channel
|
||||||
|
|||||||
@@ -40,5 +40,8 @@ def create_channel(channel_type):
|
|||||||
elif channel_type == const.FEISHU:
|
elif channel_type == const.FEISHU:
|
||||||
from channel.feishu.feishu_channel import FeiShuChanel
|
from channel.feishu.feishu_channel import FeiShuChanel
|
||||||
return FeiShuChanel()
|
return FeiShuChanel()
|
||||||
|
elif channel_type == const.DINGTALK:
|
||||||
|
from channel.dingtalk.dingtalk_channel import DingTalkChanel
|
||||||
|
return DingTalkChanel()
|
||||||
|
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
|||||||
151
channel/dingtalk/dingtalk_channel.py
Normal file
151
channel/dingtalk/dingtalk_channel.py
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
"""
|
||||||
|
钉钉通道接入
|
||||||
|
|
||||||
|
@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_app_id = conf().get('dingtalk_app_id')
|
||||||
|
dingtalk_app_secret = conf().get('dingtalk_app_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] app_id={}, app_secret={} ".format(
|
||||||
|
self.dingtalk_app_id, self.dingtalk_app_secret))
|
||||||
|
# 无需群校验和前缀
|
||||||
|
conf()["group_name_white_list"] = ["ALL_GROUP"]
|
||||||
|
conf()["single_chat_prefix"] = []
|
||||||
|
|
||||||
|
def startup(self):
|
||||||
|
|
||||||
|
credential = dingtalk_stream.Credential( self.dingtalk_app_id, self.dingtalk_app_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
|
||||||
|
|
||||||
|
|
||||||
|
context = self._compose_context(cmsg.ctype, cmsg.content, isgroup=False, msg=cmsg)
|
||||||
|
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_single(dingtalk_msg)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
return AckMessage.STATUS_OK, 'OK'
|
||||||
|
|
||||||
|
class dingtalkController:
|
||||||
|
# 类常量
|
||||||
|
FAILED_MSG = '{"success": false}'
|
||||||
|
SUCCESS_MSG = '{"success": true}'
|
||||||
|
MESSAGE_RECEIVE_TYPE = "im.message.receive_v1"
|
||||||
|
|
||||||
|
def GET(self):
|
||||||
|
return "dingtalk service start success!"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
39
channel/dingtalk/dingtalk_message.py
Normal file
39
channel/dingtalk/dingtalk_message.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
user_id = event.sender_id
|
||||||
|
nickname =event.sender_nick
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -20,3 +20,4 @@ MODEL_LIST = ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4", "wenxin", "wenxin-4
|
|||||||
|
|
||||||
# channel
|
# channel
|
||||||
FEISHU = "feishu"
|
FEISHU = "feishu"
|
||||||
|
DINGTALK = "dingtalk"
|
||||||
|
|||||||
@@ -123,7 +123,11 @@ available_setting = {
|
|||||||
"feishu_app_secret": "", # 飞书机器人APP secret
|
"feishu_app_secret": "", # 飞书机器人APP secret
|
||||||
"feishu_token": "", # 飞书 verification token
|
"feishu_token": "", # 飞书 verification token
|
||||||
"feishu_bot_name": "", # 飞书机器人的名字
|
"feishu_bot_name": "", # 飞书机器人的名字
|
||||||
|
|
||||||
|
# 钉钉配置
|
||||||
|
"dingtalk_app_id": "", # 钉钉机器人应用APP Id
|
||||||
|
"dingtalk_app_secret": "", # 钉钉机器人APP secret
|
||||||
|
|
||||||
# chatgpt指令自定义触发词
|
# chatgpt指令自定义触发词
|
||||||
"clear_memory_commands": ["#清除记忆"], # 重置会话指令,必须以#开头
|
"clear_memory_commands": ["#清除记忆"], # 重置会话指令,必须以#开头
|
||||||
# channel配置
|
# channel配置
|
||||||
|
|||||||
Reference in New Issue
Block a user