mirror of
https://github.com/zhayujie/bot-on-anything.git
synced 2026-01-19 09:41:07 +08:00
add dingding channel
This commit is contained in:
29
README.md
29
README.md
@@ -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)
|
||||
|
||||
### 通用配置
|
||||
|
||||
|
||||
@@ -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
102
channel/dd/dd_channel.py
Normal 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}×tamp={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"[]({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}
|
||||
@@ -8,6 +8,7 @@ GMAIL = "gmail"
|
||||
TELEGRAM = "telegram"
|
||||
SLACK = "slack"
|
||||
HTTP = "http"
|
||||
DINGDING = "dingding"
|
||||
|
||||
# model
|
||||
OPEN_AI = "openai"
|
||||
|
||||
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user