mirror of
https://github.com/zhayujie/bot-on-anything.git
synced 2026-02-27 08:00:56 +08:00
34
README.md
34
README.md
@@ -11,7 +11,7 @@
|
||||
**应用:**
|
||||
|
||||
- [x] [终端](https://github.com/zhayujie/bot-on-anything#1%E5%91%BD%E4%BB%A4%E8%A1%8C%E7%BB%88%E7%AB%AF)
|
||||
- [ ] Web
|
||||
- [x] [Web](https://github.com/zhayujie/bot-on-anything#9web)
|
||||
- [x] [个人微信](https://github.com/zhayujie/bot-on-anything#2%E4%B8%AA%E4%BA%BA%E5%BE%AE%E4%BF%A1)
|
||||
- [x] [订阅号](https://github.com/zhayujie/bot-on-anything#3%E4%B8%AA%E4%BA%BA%E8%AE%A2%E9%98%85%E5%8F%B7)
|
||||
- [x] [服务号](https://github.com/zhayujie/bot-on-anything#4%E4%BC%81%E4%B8%9A%E6%9C%8D%E5%8A%A1%E5%8F%B7)
|
||||
@@ -393,3 +393,35 @@ http:/你的固定公网ip或者域名:端口/slack/events
|
||||
```
|
||||
https://slack.dev/bolt-python/tutorial/getting-started
|
||||
```
|
||||
|
||||
### 9.Web
|
||||
#### http
|
||||
**需要:** 服务器
|
||||
|
||||
|
||||
**依赖**
|
||||
|
||||
```bash
|
||||
pip3 install PyJWT flask
|
||||
```
|
||||
|
||||
**配置**
|
||||
|
||||
```bash
|
||||
"channel": {
|
||||
"type": "http",
|
||||
"http": {
|
||||
"http_auth_secret_key": "6d25a684-9558-11e9-aa94-efccd7a0659b",//jwt认证秘钥
|
||||
"http_auth_password": "6.67428e-11",//认证密码,仅仅只是自用,最初步的防御别人扫描端口后DDOS浪费tokens
|
||||
"port": "80"//端口
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
URL,如果端口是 80 ,可不填
|
||||
|
||||
```
|
||||
http:/你的固定公网ip或者域名:端口/
|
||||
```
|
||||
|
||||
@@ -41,5 +41,9 @@ def create_channel(channel_type):
|
||||
from channel.slack.slack_channel import SlackChannel
|
||||
return SlackChannel()
|
||||
|
||||
elif channel_type == const.HTTP:
|
||||
from channel.http.http_channel import HttpChannel
|
||||
return HttpChannel()
|
||||
|
||||
else:
|
||||
raise RuntimeError
|
||||
|
||||
107
channel/http/auth.py
Normal file
107
channel/http/auth.py
Normal file
@@ -0,0 +1,107 @@
|
||||
# encoding:utf-8
|
||||
|
||||
import jwt
|
||||
import datetime
|
||||
import time
|
||||
from flask import jsonify, request
|
||||
from common import const
|
||||
from config import channel_conf
|
||||
|
||||
|
||||
class Auth():
|
||||
def __init__(self, login):
|
||||
# argument 'privilegeRequired' is to set up your method's privilege
|
||||
# name
|
||||
self.login = login
|
||||
super(Auth, self).__init__()
|
||||
|
||||
@staticmethod
|
||||
def encode_auth_token(user_id, login_time):
|
||||
"""
|
||||
生成认证Token
|
||||
:param user_id: int
|
||||
:param login_time: datetime
|
||||
:return: string
|
||||
"""
|
||||
try:
|
||||
payload = {
|
||||
'iss': 'ken', # 签名
|
||||
'exp': datetime.datetime.utcnow() + datetime.timedelta(days=0, hours=10), # 过期时间
|
||||
'iat': datetime.datetime.utcnow(), # 开始时间
|
||||
'data': {
|
||||
'id': user_id,
|
||||
'login_time': login_time
|
||||
}
|
||||
}
|
||||
return jwt.encode(
|
||||
payload,
|
||||
channel_conf(const.HTTP).get('http_auth_secret_key'),
|
||||
algorithm='HS256'
|
||||
) # 加密生成字符串
|
||||
except Exception as e:
|
||||
return e
|
||||
|
||||
@staticmethod
|
||||
def decode_auth_token(auth_token):
|
||||
"""
|
||||
验证Token
|
||||
:param auth_token:
|
||||
:return: integer|string
|
||||
"""
|
||||
try:
|
||||
# 取消过期时间验证
|
||||
payload = jwt.decode(auth_token, channel_conf(const.HTTP).get(
|
||||
'http_auth_secret_key'), algorithms='HS256') # options={'verify_exp': False} 加上后不验证token过期时间
|
||||
if ('data' in payload and 'id' in payload['data']):
|
||||
return payload
|
||||
else:
|
||||
raise jwt.InvalidTokenError
|
||||
except jwt.ExpiredSignatureError:
|
||||
return 'Token过期'
|
||||
except jwt.InvalidTokenError:
|
||||
return '无效Token'
|
||||
|
||||
|
||||
def authenticate(password):
|
||||
"""
|
||||
用户登录,登录成功返回token
|
||||
:param password:
|
||||
:return: json
|
||||
"""
|
||||
authPassword = channel_conf(const.HTTP).get('http_auth_password')
|
||||
if (authPassword != password):
|
||||
return False
|
||||
else:
|
||||
login_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
||||
token = Auth.encode_auth_token(password, login_time)
|
||||
return token
|
||||
|
||||
|
||||
def identify(request):
|
||||
"""
|
||||
用户鉴权
|
||||
:return: list
|
||||
"""
|
||||
try:
|
||||
if (request is None):
|
||||
return False
|
||||
authorization = request.cookies.get('Authorization')
|
||||
if (authorization):
|
||||
payload = Auth.decode_auth_token(authorization)
|
||||
if not isinstance(payload, str):
|
||||
authPassword = channel_conf(
|
||||
const.HTTP).get('http_auth_password')
|
||||
password = payload['data']['id']
|
||||
if (password != authPassword):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
|
||||
except jwt.ExpiredSignatureError:
|
||||
#result = 'Token已更改,请重新登录获取'
|
||||
return False
|
||||
|
||||
except jwt.InvalidTokenError:
|
||||
#result = '没有提供认证token'
|
||||
return False
|
||||
66
channel/http/http_channel.py
Normal file
66
channel/http/http_channel.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# encoding:utf-8
|
||||
|
||||
import json
|
||||
from channel.http import auth
|
||||
from flask import Flask, request, render_template, make_response
|
||||
from datetime import timedelta
|
||||
from common import const
|
||||
from config import channel_conf
|
||||
from channel.channel import Channel
|
||||
http_app = Flask(__name__,)
|
||||
# 自动重载模板文件
|
||||
http_app.jinja_env.auto_reload = True
|
||||
http_app.config['TEMPLATES_AUTO_RELOAD'] = True
|
||||
|
||||
# 设置静态文件缓存过期时间
|
||||
http_app.config['SEND_FILE_MAX_AGE_DEFAULT'] = timedelta(seconds=1)
|
||||
|
||||
|
||||
@http_app.route("/chat", methods=['POST'])
|
||||
def chat():
|
||||
if (auth.identify(request) == False):
|
||||
return
|
||||
data = json.loads(request.data)
|
||||
if data:
|
||||
msg = data['msg']
|
||||
if not msg:
|
||||
return
|
||||
reply_text = HttpChannel().handle(data=data)
|
||||
return {'result': reply_text}
|
||||
|
||||
|
||||
@http_app.route("/", methods=['GET'])
|
||||
def index():
|
||||
if (auth.identify(request) == False):
|
||||
return login()
|
||||
return render_template('index.html')
|
||||
|
||||
|
||||
@http_app.route("/login", methods=['POST', 'GET'])
|
||||
def login():
|
||||
response = make_response("<html></html>",301)
|
||||
response.headers.add_header('content-type','text/plain')
|
||||
response.headers.add_header('location','./')
|
||||
if (auth.identify(request) == True):
|
||||
return response
|
||||
else:
|
||||
if request.method == "POST":
|
||||
token = auth.authenticate(request.form['password'])
|
||||
if (token != False):
|
||||
response.set_cookie(key='Authorization', value=token)
|
||||
return response
|
||||
else:
|
||||
return render_template('login.html')
|
||||
response.headers.set('location','./login?err=登录失败')
|
||||
return response
|
||||
|
||||
class HttpChannel(Channel):
|
||||
def startup(self):
|
||||
http_app.run(host='0.0.0.0', port=channel_conf(const.HTTP).get('port'))
|
||||
|
||||
def handle(self, data):
|
||||
context = dict()
|
||||
id = data["id"]
|
||||
context['from_user_id'] = str(id)
|
||||
return super().build_reply_content(data["msg"], context)
|
||||
|
||||
329
channel/http/static/1.css
Normal file
329
channel/http/static/1.css
Normal file
@@ -0,0 +1,329 @@
|
||||
|
||||
.typing_loader {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
-webkit-animation: typing 1s linear infinite alternate;
|
||||
-moz-animation: typing 1s linear infinite alternate;
|
||||
-ms-animation: typing 1s linear infinite alternate;
|
||||
animation: typing 1s linear infinite alternate;
|
||||
position: relative;
|
||||
left: -12px;
|
||||
margin: 7px 15px 6px;
|
||||
}
|
||||
ol,pre {
|
||||
background-color: #b1e3b1c4;
|
||||
border: 1px solid #c285e3ab;
|
||||
padding: 0.5rem 1.5rem 0.5rem;
|
||||
color: black;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.to .typing_loader {
|
||||
animation: typing-black 1s linear infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes typing {
|
||||
0% {
|
||||
background-color: rgba(255,255,255, 1);
|
||||
box-shadow: 12px 0px 0px 0px rgba(255,255,255,0.4), 24px 0px 0px 0px rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
50% {
|
||||
background-color: rgba(255,255,255, 0.4);
|
||||
box-shadow: 12px 0px 0px 0px rgba(255,255,255,1), 24px 0px 0px 0px rgba(255,255,255,0.4);
|
||||
}
|
||||
|
||||
100% {
|
||||
background-color: rgba(255,255,255, 0.2);
|
||||
box-shadow: 12px 0px 0px 0px rgba(255,255,255,0.4), 24px 0px 0px 0px rgba(255,255,255,1);
|
||||
}
|
||||
}
|
||||
|
||||
@-moz-keyframes typing {
|
||||
0% {
|
||||
background-color: rgba(255,255,255, 1);
|
||||
box-shadow: 12px 0px 0px 0px rgba(255,255,255,0.4), 24px 0px 0px 0px rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
50% {
|
||||
background-color: rgba(255,255,255, 0.4);
|
||||
box-shadow: 12px 0px 0px 0px rgba(255,255,255,1), 24px 0px 0px 0px rgba(255,255,255,0.4);
|
||||
}
|
||||
|
||||
100% {
|
||||
background-color: rgba(255,255,255, 0.2);
|
||||
box-shadow: 12px 0px 0px 0px rgba(255,255,255,0.4), 24px 0px 0px 0px rgba(255,255,255,1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes typing-black {
|
||||
0% {
|
||||
background-color: rgba(74, 74, 74, 1);
|
||||
box-shadow: 12px 0px 0px 0px rgba(74, 74, 74, 0.4), 24px 0px 0px 0px rgba(74, 74, 74, 0.2);
|
||||
}
|
||||
|
||||
50% {
|
||||
background-color: rgba(74, 74, 74, 0.4);
|
||||
box-shadow: 12px 0px 0px 0px rgba(74, 74, 74, 1), 24px 0px 0px 0px rgba(74, 74, 74,0.4);
|
||||
}
|
||||
|
||||
100% {
|
||||
background-color: rgba(74, 74, 74, 0.2);
|
||||
box-shadow: 12px 0px 0px 0px rgba(74, 74, 74,0.4), 24px 0px 0px 0px rgba(74, 74, 74,1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes typing {
|
||||
0% {
|
||||
background-color: rgba(255,255,255, 1);
|
||||
box-shadow: 12px 0px 0px 0px rgba(255,255,255,0.4), 24px 0px 0px 0px rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
50% {
|
||||
background-color: rgba(255,255,255, 0.4);
|
||||
box-shadow: 12px 0px 0px 0px rgba(255,255,255,1), 24px 0px 0px 0px rgba(255,255,255,0.4);
|
||||
}
|
||||
|
||||
100% {
|
||||
background-color: rgba(255,255,255, 0.2);
|
||||
box-shadow: 12px 0px 0px 0px rgba(255,255,255,0.4), 24px 0px 0px 0px rgba(255,255,255,1);
|
||||
}
|
||||
}
|
||||
|
||||
.convFormDynamic {
|
||||
text-align: center;
|
||||
margin: 10px 10px;
|
||||
padding: 0 !important;
|
||||
position: relative;
|
||||
border: 2px solid rgba(0, 40, 100, 0.12);
|
||||
}
|
||||
|
||||
.convFormDynamic textarea.userInputDynamic {
|
||||
border: none;
|
||||
padding: 7px 10px;
|
||||
overflow-x: hidden!important;
|
||||
outline: none;
|
||||
font-size: 0.905rem;
|
||||
float: left;
|
||||
width: calc(100% - 70px);
|
||||
line-height: 1.3em;
|
||||
min-height: 1.7em;
|
||||
max-height: 10rem;
|
||||
display: block;
|
||||
max-width: 89vw;
|
||||
margin-right: -1vw;
|
||||
resize: none;
|
||||
}
|
||||
.convFormDynamic textarea::-webkit-scrollbar{
|
||||
width: 2px;
|
||||
background-color: lawngreen;
|
||||
}
|
||||
.convFormDynamic textarea::-webkit-scrollbar-thumb{
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
|
||||
background-color: dodgerblue;
|
||||
}
|
||||
.convFormDynamic input.userInputDynamic {
|
||||
border: none;
|
||||
padding: 7px 10px;
|
||||
outline: none;
|
||||
font-size: 0.905rem;
|
||||
float: left;
|
||||
width: calc(100% - 70px);
|
||||
line-height: 1.3em;
|
||||
min-height: 1.7em;
|
||||
max-height: 10rem;
|
||||
display: block;
|
||||
max-width: 89vw;
|
||||
margin-right: -1vw;
|
||||
}
|
||||
|
||||
div.conv-form-wrapper div#messages {
|
||||
max-height: 71vh;
|
||||
height: auto !important;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
div.conv-form-wrapper div#messages:after {
|
||||
content: '';
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
div.conv-form-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
div.conv-form-wrapper div.wrapper-messages {
|
||||
position: relative;
|
||||
height: 76vh;
|
||||
max-height: 80vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
div.conv-form-wrapper:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
display: block;
|
||||
height: 30px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
background: linear-gradient(#fff, transparent);
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
div.conv-form-wrapper div.wrapper-messages, div.conv-form-wrapper div#messages {
|
||||
max-height: 71vh;
|
||||
}
|
||||
}
|
||||
|
||||
div.conv-form-wrapper div.wrapper-messages::-webkit-scrollbar, div#feed ul::-webkit-scrollbar, div.conv-form-wrapper div.options::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
/* remove scrollbar space */
|
||||
background: transparent;
|
||||
/* optional: just make scrollbar invisible */
|
||||
}
|
||||
|
||||
input[type="text"].userInputDynamic.error {
|
||||
color: #ac0000 !important;
|
||||
}
|
||||
|
||||
input[type="text"].userInputDynamic {
|
||||
border-radius: 3px;
|
||||
margin: 7px 10px;
|
||||
}
|
||||
|
||||
textarea.userInputDynamic.error {
|
||||
color: #ac0000 !important;
|
||||
}
|
||||
|
||||
textarea.userInputDynamic {
|
||||
border-radius: 3px;
|
||||
margin: 7px 10px;
|
||||
}
|
||||
|
||||
div.conv-form-wrapper div#messages {
|
||||
transition: bottom 0.15s, padding-bottom 0.15s;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
height: auto !important;
|
||||
width: 100%;
|
||||
padding-bottom: 20px;
|
||||
/*max-height: 71vh;*/
|
||||
}
|
||||
|
||||
div.conv-form-wrapper div.message {
|
||||
animation: slideTop 0.15s ease;
|
||||
}
|
||||
|
||||
div.conv-form-wrapper div.message:after {
|
||||
content: '';
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
div.conv-form-wrapper div.message.ready {
|
||||
animation: bounceIn 0.2s ease;
|
||||
transform-origin: 0 0 0;
|
||||
}
|
||||
|
||||
div.conv-form-wrapper div#messages div.message {
|
||||
border-radius: 20px;
|
||||
padding: 12px 22px;
|
||||
font-size: 0.905rem;
|
||||
display: inline-block;
|
||||
padding: 10px 15px 8px;
|
||||
border-radius: 20px;
|
||||
margin-bottom: 5px;
|
||||
float: right;
|
||||
clear: both;
|
||||
max-width: 65%;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
div.conv-form-wrapper div#messages div.message.to {
|
||||
float: left;
|
||||
background: lawngreen;
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
|
||||
div.conv-form-wrapper div#messages div.message.from {
|
||||
background: dodgerblue;
|
||||
color: #fff;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.message.to+.message.from, .message.from+.message.to {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
@keyframes slideTop {
|
||||
0% {
|
||||
margin-bottom: -25px;
|
||||
}
|
||||
|
||||
100% {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounceIn {
|
||||
0% {
|
||||
transform: scale(0.75, 0.75);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
.convFormDynamic button.submit {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
border: none;
|
||||
left:95%;
|
||||
margin: 5px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
border-radius: 8px;
|
||||
font-size: 1.6rem;
|
||||
width: 50px;
|
||||
height: 42px;
|
||||
border: 1px solid #b7b7b7;
|
||||
background: #c3c3c3;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.center-block {
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
float: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
button.submit.glow {
|
||||
border: 1px solid dodgerblue !important;
|
||||
background: dodgerblue !important;
|
||||
box-shadow: 0 0 5px 2px rgba(14, 144, 255,0.4);
|
||||
}
|
||||
.no-border {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.dragscroll {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
div.conv-form-wrapper div#messages::-webkit-scrollbar, div#feed ul::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
/* remove scrollbar space */
|
||||
background: transparent;
|
||||
/* optional: just make scrollbar invisible */
|
||||
}
|
||||
|
||||
span.clear {
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
134
channel/http/static/1.js
Normal file
134
channel/http/static/1.js
Normal file
@@ -0,0 +1,134 @@
|
||||
|
||||
function ConvState(wrapper, form, params) {
|
||||
this.id='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
var r = Math.random() * 16 | 0,
|
||||
v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
this.form = form;
|
||||
this.wrapper = wrapper;
|
||||
this.parameters = params;
|
||||
this.scrollDown = function () {
|
||||
$(this.wrapper).find('#messages').stop().animate({ scrollTop: $(this.wrapper).find('#messages')[0].scrollHeight }, 600);
|
||||
}.bind(this);
|
||||
};
|
||||
ConvState.prototype.printAnswer = function (answer = '我是ChatGPT, 一个由OpenAI训练的大型语言模型, 我旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。') {
|
||||
setTimeout(function () {
|
||||
var messageObj = $(this.wrapper).find('.message.typing');
|
||||
answer = marked.parse(answer);
|
||||
messageObj.html(answer);
|
||||
messageObj.removeClass('typing').addClass('ready');
|
||||
this.scrollDown();
|
||||
$(this.wrapper).find(this.parameters.inputIdHashTagName).focus();
|
||||
}.bind(this), 500);
|
||||
};
|
||||
ConvState.prototype.sendMessage = function (msg) {
|
||||
var message = $('<div class="message from">' + msg + '</div>');
|
||||
|
||||
$('button.submit').removeClass('glow');
|
||||
$(this.wrapper).find(this.parameters.inputIdHashTagName).focus();
|
||||
setTimeout(function () {
|
||||
$(this.wrapper).find("#messages").append(message);
|
||||
this.scrollDown();
|
||||
}.bind(this), 100);
|
||||
|
||||
var messageObj = $('<div class="message to typing"><div class="typing_loader"></div></div>');
|
||||
setTimeout(function () {
|
||||
$(this.wrapper).find('#messages').append(messageObj);
|
||||
this.scrollDown();
|
||||
}.bind(this), 150);
|
||||
var _this = this
|
||||
$.ajax({
|
||||
url: "./chat",
|
||||
type: "POST",
|
||||
timeout:60000,
|
||||
data: JSON.stringify({
|
||||
"id": _this.id,
|
||||
"msg": msg
|
||||
}),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
_this.printAnswer(data.result)
|
||||
},
|
||||
error:function () {
|
||||
_this.printAnswer("网络故障,对话未送达")
|
||||
},
|
||||
})
|
||||
};
|
||||
(function ($) {
|
||||
$.fn.convform = function () {
|
||||
var wrapper = this;
|
||||
$(this).addClass('conv-form-wrapper');
|
||||
|
||||
var parameters = $.extend(true, {}, {
|
||||
placeHolder: 'Type Here',
|
||||
typeInputUi: 'textarea',
|
||||
formIdName: 'convForm',
|
||||
inputIdName: 'userInput',
|
||||
buttonText: '▶'
|
||||
});
|
||||
|
||||
//hides original form so users cant interact with it
|
||||
var form = $(wrapper).find('form').hide();
|
||||
|
||||
var inputForm;
|
||||
parameters.inputIdHashTagName = '#' + parameters.inputIdName;
|
||||
inputForm = $('<div id="' + parameters.formIdName + '" class="convFormDynamic"><div class="options dragscroll"></div><textarea id="' + parameters.inputIdName + '" rows="1" placeholder="' + parameters.placeHolder + '" class="userInputDynamic"></textarea><button type="submit" class="submit">' + parameters.buttonText + '</button><span class="clear"></span></form>');
|
||||
|
||||
//appends messages wrapper and newly created form with the spinner load
|
||||
$(wrapper).append('<div class="wrapper-messages"><div class="spinLoader"></div><div id="messages"></div></div>');
|
||||
$(wrapper).append(inputForm);
|
||||
|
||||
var state = new ConvState(wrapper, form, parameters);
|
||||
|
||||
//prints first contact
|
||||
$.when($('div.spinLoader').addClass('hidden')).done(function () {
|
||||
var messageObj = $('<div class="message to typing"><div class="typing_loader"></div></div>');
|
||||
$(state.wrapper).find('#messages').append(messageObj);
|
||||
state.scrollDown();
|
||||
state.printAnswer();
|
||||
});
|
||||
|
||||
//binds enter to send message
|
||||
$(inputForm).find(parameters.inputIdHashTagName).keypress(function (e) {
|
||||
if (e.which == 13) {
|
||||
var input = $(this).val();
|
||||
e.preventDefault();
|
||||
if (input.trim() != '' && !state.wrapper.find(parameters.inputIdHashTagName).hasClass("error")) {
|
||||
$(parameters.inputIdHashTagName).val("");
|
||||
state.sendMessage(input);
|
||||
} else {
|
||||
$(state.wrapper).find(parameters.inputIdHashTagName).focus();
|
||||
}
|
||||
}
|
||||
autosize.update($(state.wrapper).find(parameters.inputIdHashTagName));
|
||||
})
|
||||
$(inputForm).find(parameters.inputIdHashTagName).on('input', function (e) {
|
||||
if ($(this).val().length > 0) {
|
||||
$('button.submit').addClass('glow');
|
||||
} else {
|
||||
$('button.submit').removeClass('glow');
|
||||
}
|
||||
});
|
||||
|
||||
$(inputForm).find('button.submit').click(function (e) {
|
||||
var input = $(state.wrapper).find(parameters.inputIdHashTagName).val();
|
||||
e.preventDefault();
|
||||
if (input.trim() != '' && !state.wrapper.find(parameters.inputIdHashTagName).hasClass("error")) {
|
||||
$(parameters.inputIdHashTagName).val("");
|
||||
state.sendMessage(input);
|
||||
} else {
|
||||
$(state.wrapper).find(parameters.inputIdHashTagName).focus();
|
||||
}
|
||||
autosize.update($(state.wrapper).find(parameters.inputIdHashTagName));
|
||||
});
|
||||
|
||||
if (typeof autosize == 'function') {
|
||||
$textarea = $(state.wrapper).find(parameters.inputIdHashTagName);
|
||||
autosize($textarea);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
})(jQuery);
|
||||
51
channel/http/templates/index.html
Normal file
51
channel/http/templates/index.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<!doctype html>
|
||||
<html lang="en" dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><!-- Title -->
|
||||
<title>ChatGPT</title><!-- Bootstrap Css -->
|
||||
<link href="./static/1.css" rel="stylesheet" />
|
||||
<style>
|
||||
button {
|
||||
font-family: 'Microsoft YaHei';
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="">
|
||||
<div class="no-border">
|
||||
<div id="chat" class="conv-form-wrapper">
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/marked/4.2.12/marked.min.js"></script>
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/autosize.js/6.0.1/autosize.min.js"></script>
|
||||
<script src="./static/1.js"></script>
|
||||
<script>
|
||||
var rollbackTo = false;
|
||||
var originalState = false;
|
||||
function storeState(a) {
|
||||
rollbackTo = a.current
|
||||
}
|
||||
function rollback(a) {
|
||||
if (rollbackTo != false) {
|
||||
if (originalState == false) {
|
||||
originalState = a.current.next
|
||||
}
|
||||
a.current.next = rollbackTo
|
||||
}
|
||||
}
|
||||
function restore(a) {
|
||||
if (originalState != false) {
|
||||
a.current.next = originalState
|
||||
}
|
||||
}
|
||||
jQuery(function (a) {
|
||||
var b = a("#chat").convform()
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
63
channel/http/templates/login.html
Normal file
63
channel/http/templates/login.html
Normal file
@@ -0,0 +1,63 @@
|
||||
<!doctype html>
|
||||
<html lang="en" dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><!-- Title -->
|
||||
<title>登录</title><!-- Bootstrap Css -->
|
||||
<style>
|
||||
.login-form {
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.5);
|
||||
border-radius: 8px;
|
||||
width: 350px;
|
||||
max-width: 100%;
|
||||
padding: 15px 35px 15px;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -160px 0 0 -200px;
|
||||
}
|
||||
|
||||
.Button {
|
||||
width: 80px;
|
||||
margin: 3px 1px 0 5px;
|
||||
padding: 0 10px;
|
||||
background-color: #16a0d3;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
font-family: "Microsoft Yahei";
|
||||
font-size: 12px;
|
||||
height: 27px;
|
||||
color: #FFF;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="">
|
||||
<form name="login" class="login-form" action="./login" method="post" autocomplete="off">
|
||||
<input type="password" name="password" placeholder="Password" style="border: none; height: 25px;width: 250px;"
|
||||
required>
|
||||
</input>
|
||||
<input type="submit" class="Button" value="登录" />
|
||||
<span style="color:red">
|
||||
<p id="err"></p>
|
||||
</span>
|
||||
</form>
|
||||
</body>
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
|
||||
<script>
|
||||
$(function () {
|
||||
var err=getUrlParam('err')
|
||||
$('#err')[0].innerHTML=err
|
||||
});
|
||||
function getUrlParam(name) {
|
||||
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
|
||||
var r = window.location.search.substr(1).match(reg);
|
||||
if (r != null) return decodeURI(r[2]); return null;
|
||||
}
|
||||
</script>
|
||||
|
||||
</html>
|
||||
@@ -7,6 +7,7 @@ QQ = "qq"
|
||||
GMAIL = "gmail"
|
||||
TELEGRAM = "telegram"
|
||||
SLACK = "slack"
|
||||
HTTP = "http"
|
||||
|
||||
# model
|
||||
OPEN_AI = "openai"
|
||||
|
||||
@@ -41,6 +41,12 @@
|
||||
"slack": {
|
||||
"slack_bot_token": "xoxb-xxxx",
|
||||
"slack_signing_secret": "xxxx"
|
||||
},
|
||||
|
||||
"http": {
|
||||
"http_auth_secret_key": "6d25a684-9558-11e9-aa94-efccd7a0659b",
|
||||
"http_auth_password": "6.67428e-11",
|
||||
"port": "80"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user