add dingding channel

This commit is contained in:
wujiyu115
2023-03-29 10:05:08 +08:00
parent ad99c5909c
commit 9133965614
5 changed files with 144 additions and 0 deletions

View File

@@ -492,6 +492,35 @@ pip3 install PyJWT flask
服务器运行:部署后访问 `http://公网域名或IP:端口`
### 10.钉钉
**依赖**
```bash
pip3 install requests flask
```
**配置**
```bash
"channel": {
"type": "dingding",
"dingding": {
"image_create_prefix": ["画", "draw", "Draw"],
"port": "8081", //对外端口
"dd_token": "xx", //webhook地址的access_token
"dd_post_token": "xx", //钉钉post回消息时header中带的检验token
"dd_secret": "xx"// 安全加密加签串,群机器人中
}
}
```
钉钉开放平台说明: https://open.dingtalk.com/document/robots/customize-robot-security-settin.dingtalk.com/robot/send?access_token=906dadcbc7750fef5ff60d3445b66d5bbca32804f40fbdb59039a29b20b9a3f0gs
https://open.dingtalk.com/document/orgapp/custom-robot-access
**生成机器人**
地址: https://open-dev.dingtalk.com/fe/app#/corp/robot
添加机器人,在开发管理中设置服务器出口ip(在部署机执行curl ifconfig.me就可以得到)和消息接收地址(配置中的对外地址如 https://xx.xx.com:8081)
### 通用配置

View File

@@ -45,5 +45,9 @@ def create_channel(channel_type):
from channel.http.http_channel import HttpChannel
return HttpChannel()
elif channel_type == const.DINGDING:
from channel.dd.dd_channel import DDChannel
return DDChannel()
else:
raise RuntimeError("unknown channel_type in config.json: " + channel_type)

102
channel/dd/dd_channel.py Normal file
View File

@@ -0,0 +1,102 @@
# encoding:utf-8
import json
import hmac
import hashlib
import base64
import time
import requests
from urllib.parse import quote_plus
from common import log
from flask import Flask, request, render_template, make_response
from common import const
from common import functions
from config import channel_conf
from config import channel_conf_val
from channel.channel import Channel
class DDChannel(Channel):
def __init__(self):
self.dd_token = channel_conf(const.DINGDING).get('dd_token')
self.dd_post_token = channel_conf(const.DINGDING).get('dd_post_token')
self.dd_secret = channel_conf(const.DINGDING).get('dd_secret')
log.info("[DingDing] dd_secret={}, dd_token={} dd_post_token={}".format(self.dd_secret, self.dd_token, self.dd_post_token))
def startup(self):
http_app.run(host='0.0.0.0', port=channel_conf(const.DINGDING).get('port'))
def notify_dingding(self, answer):
data = {
"msgtype": "text",
"text": {
"content": answer
},
"at": {
"atMobiles": [
""
],
"isAtAll": False
}
}
timestamp = round(time.time() * 1000)
secret_enc = bytes(self.dd_secret, encoding='utf-8')
string_to_sign = '{}\n{}'.format(timestamp, self.dd_secret)
string_to_sign_enc = bytes(string_to_sign, encoding='utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc,
digestmod=hashlib.sha256).digest()
sign = quote_plus(base64.b64encode(hmac_code))
notify_url = f"https://oapi.dingtalk.com/robot/send?access_token={self.dd_token}&timestamp={timestamp}&sign={sign}"
try:
r = requests.post(notify_url, json=data)
reply = r.json()
# log.info("[DingDing] reply={}".format(str(reply)))
except Exception as e:
log.error(e)
def handle(self, data):
prompt = data['text']['content']
conversation_id = data['conversationId']
sender_id = data['senderId']
context = dict()
img_match_prefix = functions.check_prefix(
prompt, channel_conf_val(const.DINGDING, 'image_create_prefix'))
if img_match_prefix:
prompt = prompt.split(img_match_prefix, 1)[1].strip()
context['type'] = 'IMAGE_CREATE'
id = sender_id
context['from_user_id'] = str(id)
reply = super().build_reply_content(prompt, context)
if img_match_prefix:
if not isinstance(reply, list):
return reply
images = ""
for url in reply:
images += f"[!['IMAGE_CREATE']({url})]({url})\n"
reply = images
return reply
dd = DDChannel()
http_app = Flask(__name__,)
@http_app.route("/", methods=['POST'])
def chat():
# log.info("[DingDing] chat_headers={}".format(str(request.headers)))
log.info("[DingDing] chat={}".format(str(request.data)))
token = request.headers.get('token')
if dd.dd_post_token and token != dd.dd_post_token:
return {'ret': 203}
#TODO: Verify identity
data = json.loads(request.data)
if data:
content = data['text']['content']
if not content:
return
reply_text = dd.handle(data=data)
dd.notify_dingding(reply_text)
return {'ret': 200}
return {'ret': 201}

View File

@@ -8,6 +8,7 @@ GMAIL = "gmail"
TELEGRAM = "telegram"
SLACK = "slack"
HTTP = "http"
DINGDING = "dingding"
# model
OPEN_AI = "openai"

View File

@@ -58,6 +58,14 @@
"http_auth_secret_key": "6d25a684-9558-11e9-aa94-efccd7a0659b",
"http_auth_password": "6.67428e-11",
"port": "80"
},
"dingding": {
"image_create_prefix": ["画", "draw", "Draw"],
"port": "8081",
"dd_token": "xx",
"dd_post_token": "xx",
"dd_secret": "xx"
}
},
"common": {