nonebot-plugin-l4d2-server 0.3.5a1__py3-none-any.whl → 0.3.5b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- README.md +17 -3
- nonebot_plugin_l4d2_server/__init__.py +17 -0
- nonebot_plugin_l4d2_server/command.py +4 -3
- nonebot_plugin_l4d2_server/config.py +22 -12
- nonebot_plugin_l4d2_server/data/L4D2/l4d2.json +27 -7
- nonebot_plugin_l4d2_server/l4d2_queries/__init__.py +1 -1
- nonebot_plugin_l4d2_server/l4d2_queries/maps.py +27 -0
- nonebot_plugin_l4d2_server/l4d2_queries/qqgroup.py +9 -7
- nonebot_plugin_l4d2_server/l4d2_server/web.py +221 -0
- nonebot_plugin_l4d2_server/l4d2_server/webUI.py +353 -0
- {nonebot_plugin_l4d2_server-0.3.5a1.dist-info → nonebot_plugin_l4d2_server-0.3.5b2.dist-info}/METADATA +21 -4
- {nonebot_plugin_l4d2_server-0.3.5a1.dist-info → nonebot_plugin_l4d2_server-0.3.5b2.dist-info}/RECORD +14 -11
- {nonebot_plugin_l4d2_server-0.3.5a1.dist-info → nonebot_plugin_l4d2_server-0.3.5b2.dist-info}/LICENSE +0 -0
- {nonebot_plugin_l4d2_server-0.3.5a1.dist-info → nonebot_plugin_l4d2_server-0.3.5b2.dist-info}/WHEEL +0 -0
README.md
CHANGED
@@ -294,6 +294,20 @@ anne:<br>
|
|
294
294
|
<details>
|
295
295
|
<summary>展开/收起</summary>
|
296
296
|
|
297
|
+
### 0.3.5--2022.3
|
298
|
+
|
299
|
+
- 新增ping查询(在ip里包括)
|
300
|
+
- 新增api查询(未完成)
|
301
|
+
|
302
|
+
### 0.3.4--2022.3.1
|
303
|
+
|
304
|
+
- 新增本地插件smx查询
|
305
|
+
- 增加了三个内置群服
|
306
|
+
- 修改了图片的UI,变好看了
|
307
|
+
- 删减了部分图片和字体,使得轻量化
|
308
|
+
- 修复了海量bug
|
309
|
+
- 修复了python3.8中typing错误
|
310
|
+
|
297
311
|
### 0.3.3--2022.2.26
|
298
312
|
|
299
313
|
- 重写协议,使用a2s库,同时解决win端不同报错无法输出
|
@@ -453,13 +467,13 @@ ubuntu20.04 python3.10
|
|
453
467
|
|
454
468
|
<h2 id="cx">服务器相关 </h2>
|
455
469
|
|
456
|
-
|
470
|
+
目前插件会内置经腐竹同意的服的查询(未来将使用api)
|
457
471
|
|
458
472
|
| 指令 | 服务器 | op | 数量 |
|
459
473
|
|:-----:|:----:|:----:|:----:|
|
460
|
-
| 云 | anne电信服云服 | 东 |
|
474
|
+
| 云 | anne电信服云服(暂时不提供) | 东 | 24
|
461
475
|
| 呆呆 | 呆呆的小窝 | 提莫大魔王 | 15
|
462
|
-
| 橘 | 橘希实香的小窝 | 橘希实香 |
|
476
|
+
| 橘 | 橘希实香的小窝 | 橘希实香 | 7
|
463
477
|
|
464
478
|
如果需要上传自己的ip可以Pr、iss或者进qq群
|
465
479
|
|
@@ -16,6 +16,8 @@
|
|
16
16
|
"""
|
17
17
|
from nonebot.matcher import Matcher
|
18
18
|
from nonebot.typing import T_State
|
19
|
+
from nonebot.params import CommandArg,ArgPlainText,RegexGroup,Arg,Command,RawCommand
|
20
|
+
|
19
21
|
from typing import Tuple,Union,List
|
20
22
|
from time import sleep
|
21
23
|
from .config import *
|
@@ -29,9 +31,11 @@ from .l4d2_image.vtfs import img_to_vtf
|
|
29
31
|
from .l4d2_queries.ohter import load_josn
|
30
32
|
from .l4d2_queries.qqgroup import write_json,ip_anne_list
|
31
33
|
from .l4d2_file import updown_l4d2_vpk,all_zip_to_one
|
34
|
+
from .l4d2_queries.maps import seach_map,map_dict_to_str
|
32
35
|
from .txt_to_img import mode_txt_to_img
|
33
36
|
# from .l4d2_server import RCONClient
|
34
37
|
from nonebot import get_bot, require
|
38
|
+
from .l4d2_server import web,webUI
|
35
39
|
scheduler = require("nonebot_plugin_apscheduler").scheduler
|
36
40
|
|
37
41
|
driver = get_driver()
|
@@ -453,6 +457,19 @@ async def _():
|
|
453
457
|
msg = mes_list(msg,name_smx).replace(" ","")
|
454
458
|
await find_vpk.finish(mode_txt_to_img(mes,msg))
|
455
459
|
|
460
|
+
@search_api.handle()
|
461
|
+
async def _(args:Message = CommandArg()):
|
462
|
+
msg:str = args.extract_plain_text()
|
463
|
+
# if msg.startswith('代码'):
|
464
|
+
# 建图代码返回三方图信息
|
465
|
+
data = await seach_map(msg,l4_master[0],l4_key)
|
466
|
+
# else:
|
467
|
+
if type(data) == str:
|
468
|
+
await search_api.finish(data)
|
469
|
+
else:
|
470
|
+
await search_api.finish(await map_dict_to_str(data))
|
471
|
+
|
472
|
+
|
456
473
|
@driver.on_shutdown
|
457
474
|
async def close_db():
|
458
475
|
"""关闭数据库"""
|
@@ -1,5 +1,5 @@
|
|
1
|
-
from nonebot import on_notice,on_command,on_regex,on_fullmatch,on_shell_command
|
2
|
-
|
1
|
+
from nonebot import on_notice,on_command,on_regex,on_fullmatch,on_shell_command,on_keyword
|
2
|
+
|
3
3
|
import re
|
4
4
|
import nonebot
|
5
5
|
from nonebot.permission import SUPERUSER
|
@@ -86,7 +86,8 @@ show_queries = on_command('showq',aliases={"求生订阅"},priority=20,block=Tru
|
|
86
86
|
join_server = on_command('showq',aliases={"求生加入"},priority=20,block=True)
|
87
87
|
connect_rcon = on_command("Rrcon", aliases={"求生连接", '求生链接','求生rcon'}, priority=50, block=False)
|
88
88
|
end_connect = ['stop', '结束', '连接结束', '结束连接']
|
89
|
-
|
89
|
+
search_api = on_command('search',aliases={'求生三方'}, priority=20, block=True)
|
90
|
+
which_map = on_keyword(("是什么图"),priority=20, block=False)
|
90
91
|
|
91
92
|
# 下载内容
|
92
93
|
up_workshop = on_command('workshop',aliases={'创意工坊下载','求生创意工坊'},priority=20,block=True)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import nonebot
|
2
2
|
from nonebot.permission import SUPERUSER
|
3
|
+
from nonebot import get_driver
|
3
4
|
from nonebot.adapters.onebot.v11.permission import (
|
4
5
|
GROUP_ADMIN,
|
5
6
|
GROUP_OWNER,
|
@@ -17,7 +18,11 @@ except:
|
|
17
18
|
file_format = (".vpk",".zip",".7z",'rar')
|
18
19
|
# 权限
|
19
20
|
|
20
|
-
|
21
|
+
driver = get_driver()
|
22
|
+
try:
|
23
|
+
NICKNAME: str = list(driver.config.nickname)[0]
|
24
|
+
except Exception:
|
25
|
+
NICKNAME = 'bot'
|
21
26
|
CHECK_FILE:int = 0
|
22
27
|
ANNE_IP:dict = json.load(open(Path(__file__).parent.joinpath(
|
23
28
|
'data/L4D2/l4d2.json'), "r", encoding="utf8"))
|
@@ -28,67 +33,72 @@ ADMINISTRATOR = SUPERUSER | GROUP_ADMIN | GROUP_OWNER | PRIVATE_FRIEND
|
|
28
33
|
# file 填写求生服务器所在路径
|
29
34
|
|
30
35
|
try:
|
31
|
-
l4_file: List[str] =
|
36
|
+
l4_file: List[str] = driver.config.l4_file
|
32
37
|
except:
|
33
38
|
l4_file: List[str] = ['/home/ubuntu/l4d2']
|
34
39
|
|
35
40
|
|
36
41
|
try:
|
37
|
-
l4_image: bool =
|
42
|
+
l4_image: bool = driver.config.l4_image
|
38
43
|
except:
|
39
44
|
l4_image: bool = True
|
40
45
|
|
41
46
|
try:
|
42
|
-
l4_steamid: bool =
|
47
|
+
l4_steamid: bool = driver.config.l4_steamid
|
43
48
|
except:
|
44
49
|
l4_steamid: bool = True
|
45
50
|
|
46
51
|
try:
|
47
|
-
l4_only: bool =
|
52
|
+
l4_only: bool = driver.config.l4_only
|
48
53
|
except:
|
49
54
|
l4_only: bool = False
|
50
55
|
|
51
56
|
try:
|
52
|
-
l4_font: str =
|
57
|
+
l4_font: str = driver.config.l4_font
|
53
58
|
except:
|
54
59
|
l4_font: str = 'simsun.ttf'
|
55
60
|
|
56
61
|
try:
|
57
|
-
l4_host: List[str] =
|
62
|
+
l4_host: List[str] = driver.config.l4_host
|
58
63
|
except:
|
59
64
|
l4_host: List[str] = ['127.0.0.1']
|
60
65
|
|
61
66
|
|
62
67
|
try:
|
63
|
-
l4_port: List[str] =
|
68
|
+
l4_port: List[str] = driver.config.l4_port
|
64
69
|
except:
|
65
70
|
l4_port: List[str] = ['20715']
|
66
71
|
|
67
72
|
|
68
73
|
try:
|
69
|
-
l4_rcon: List[str] =
|
74
|
+
l4_rcon: List[str] = driver.config.l4_rcon
|
70
75
|
except:
|
71
76
|
l4_rcon: List[str] = ['114514']
|
72
77
|
|
73
78
|
|
74
79
|
try:
|
75
|
-
l4_master: List[str] =
|
80
|
+
l4_master: List[str] = driver.config.l4_master
|
76
81
|
except:
|
77
82
|
l4_master: List[str] = ['114514']
|
78
83
|
|
79
84
|
|
80
85
|
try:
|
81
86
|
l4_proxies: set = {
|
82
|
-
'http://':
|
87
|
+
'http://':driver.config.l4_proxies
|
83
88
|
}
|
84
89
|
except:
|
85
90
|
l4_proxies = ''
|
86
91
|
|
87
92
|
try:
|
88
|
-
l4_style:str =
|
93
|
+
l4_style:str = driver.config.l4_style
|
89
94
|
except:
|
90
95
|
l4_style:str = ''
|
91
96
|
|
97
|
+
try:
|
98
|
+
l4_key:str = driver.config.l4_key
|
99
|
+
except:
|
100
|
+
l4_key:str = ""
|
101
|
+
|
92
102
|
l4_list = [l4_file, l4_steamid, l4_host, l4_port, l4_rcon, l4_master]
|
93
103
|
l4_list = [ast.literal_eval(i) if isinstance(i, str) else i for i in l4_list]
|
94
104
|
l4_file, l4_steamid, l4_host, l4_port, l4_rcon, l4_master = l4_list
|
@@ -58,39 +58,59 @@
|
|
58
58
|
{
|
59
59
|
"id": 12,
|
60
60
|
"version": "anne",
|
61
|
-
"ip": "
|
61
|
+
"ip": "103.219.39.254:20676"
|
62
62
|
},
|
63
63
|
{
|
64
64
|
"id": 13,
|
65
65
|
"version": "对抗",
|
66
|
-
"ip": "
|
66
|
+
"ip": "103.219.39.254:20518"
|
67
67
|
},
|
68
68
|
{
|
69
69
|
"id": 14,
|
70
70
|
"version": "对抗",
|
71
|
-
"ip": "
|
71
|
+
"ip": "103.219.39.254:28349"
|
72
72
|
},
|
73
73
|
{
|
74
74
|
"id": 15,
|
75
75
|
"version": "anne",
|
76
|
-
"ip": "
|
76
|
+
"ip": "103.219.39.254:23649"
|
77
77
|
}
|
78
78
|
],
|
79
79
|
"橘":[
|
80
80
|
{
|
81
|
-
"id":1,
|
81
|
+
"id": 1,
|
82
82
|
"version": "战役",
|
83
83
|
"ip":"202.189.7.139:12203"
|
84
84
|
},
|
85
85
|
{
|
86
|
-
"id":2,
|
86
|
+
"id": 2,
|
87
87
|
"version": "多特",
|
88
88
|
"ip":"202.189.7.139:12202"
|
89
89
|
},
|
90
90
|
{
|
91
|
-
"id":3,
|
91
|
+
"id": 3,
|
92
92
|
"version": "多特",
|
93
93
|
"ip":"202.189.7.139:12302"
|
94
|
+
},
|
95
|
+
{
|
96
|
+
"id": 4,
|
97
|
+
"version": "anne",
|
98
|
+
"ip": "g3.kok.wang:40024"
|
99
|
+
},
|
100
|
+
{
|
101
|
+
"id": 5,
|
102
|
+
"version": "anne",
|
103
|
+
"ip": "g3.kok.wang:40025"
|
104
|
+
},
|
105
|
+
{
|
106
|
+
"id": 6,
|
107
|
+
"version": "anne",
|
108
|
+
"ip": "g3.kok.wang:40026"
|
109
|
+
},
|
110
|
+
{
|
111
|
+
"id": 7,
|
112
|
+
"version": "anne",
|
113
|
+
"ip": "g3.kok.wang:40027"
|
94
114
|
}
|
95
115
|
]
|
96
116
|
}
|
@@ -7,7 +7,7 @@ async def queries(ip:str,port:int):
|
|
7
7
|
message = 'ip:' + msg_dict['ip'] + '\n'
|
8
8
|
message += '名称:' + msg_dict['name'] + '\n'
|
9
9
|
message += f"地图:{msg_dict['map_']}\n"
|
10
|
-
message += f"
|
10
|
+
message += f"延迟:{msg_dict['ping']}\n"
|
11
11
|
message += f"玩家:{msg_dict['players']} / {msg_dict['max_players']}\n"
|
12
12
|
return message
|
13
13
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import httpx
|
2
|
+
|
3
|
+
|
4
|
+
async def seach_map(msg:str,qq:str,key:str):
|
5
|
+
url = "http://106.13.207.45:4015/l4d2"
|
6
|
+
json = {
|
7
|
+
"mode":"zh",
|
8
|
+
"map_name":msg,
|
9
|
+
"qq":qq,
|
10
|
+
"key":key
|
11
|
+
}
|
12
|
+
print(json)
|
13
|
+
file = httpx.post(url,json=json)
|
14
|
+
if file.status_code == 200:
|
15
|
+
return file.json()
|
16
|
+
elif file.status_code == 204:
|
17
|
+
return "没有结果"
|
18
|
+
elif file.status_code == 406:
|
19
|
+
return "参数错误"
|
20
|
+
elif file.status_code == 401:
|
21
|
+
return file.json()
|
22
|
+
|
23
|
+
async def map_dict_to_str(data:dict):
|
24
|
+
msg = ""
|
25
|
+
for key,value in data[0].items():
|
26
|
+
msg += f"{key}:{value}\n"
|
27
|
+
return msg
|
@@ -247,10 +247,12 @@ async def write_json(data_str:str):
|
|
247
247
|
return '删除成功喵'
|
248
248
|
return '序号不正确,请输入【求生更新 删除 腐竹 序号】'
|
249
249
|
return '腐竹名不存在,请输入【求生更新 删除 腐竹 序号】'
|
250
|
-
|
251
|
-
|
252
|
-
ips = ALL_HOST['云']
|
253
|
-
ip_anne_list = []
|
254
|
-
for one_ip in ips:
|
255
|
-
|
256
|
-
|
250
|
+
ip_anne_list=[]
|
251
|
+
try:
|
252
|
+
ips = ALL_HOST['云']
|
253
|
+
ip_anne_list = []
|
254
|
+
for one_ip in ips:
|
255
|
+
host,port = split_maohao(one_ip['ip'])
|
256
|
+
ip_anne_list.append((one_ip['id'],host,port))
|
257
|
+
except KeyError:
|
258
|
+
pass
|
@@ -0,0 +1,221 @@
|
|
1
|
+
import datetime
|
2
|
+
from typing import Optional, Union
|
3
|
+
|
4
|
+
from fastapi import FastAPI
|
5
|
+
from fastapi import Header, HTTPException, Depends
|
6
|
+
from fastapi.responses import JSONResponse, HTMLResponse, RedirectResponse
|
7
|
+
from jose import jwt
|
8
|
+
from nonebot import get_bot, get_app
|
9
|
+
from pydantic import BaseModel
|
10
|
+
from typing import List, Dict
|
11
|
+
from pathlib import Path
|
12
|
+
|
13
|
+
from pydantic import BaseModel, Field
|
14
|
+
|
15
|
+
from nonebot import get_driver, logger
|
16
|
+
from ruamel import yaml
|
17
|
+
|
18
|
+
CONFIG_PATH = Path() / 'data' / 'L4D2' / 'l4d2.yml'
|
19
|
+
CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
20
|
+
|
21
|
+
driver = get_driver()
|
22
|
+
|
23
|
+
from .webUI import login_page, admin_app
|
24
|
+
|
25
|
+
requestAdaptor = '''
|
26
|
+
requestAdaptor(api) {
|
27
|
+
api.headers["token"] = localStorage.getItem("token");
|
28
|
+
return api;
|
29
|
+
},
|
30
|
+
'''
|
31
|
+
responseAdaptor = '''
|
32
|
+
responseAdaptor(api, payload, query, request, response) {
|
33
|
+
if (response.data.detail == '登录验证失败或已失效,请重新登录') {
|
34
|
+
window.location.href = '/l4d2/login'
|
35
|
+
window.localStorage.clear()
|
36
|
+
window.sessionStorage.clear()
|
37
|
+
window.alert('登录验证失败或已失效,请重新登录')
|
38
|
+
}
|
39
|
+
return payload
|
40
|
+
},
|
41
|
+
'''
|
42
|
+
|
43
|
+
|
44
|
+
def authentication():
|
45
|
+
def inner(token: Optional[str] = Header(...)):
|
46
|
+
try:
|
47
|
+
payload = jwt.decode(token, config_manager.config.web_secret_key, algorithms='HS256')
|
48
|
+
if not (username := payload.get('username')) or username != config_manager.config.web_username:
|
49
|
+
raise HTTPException(status_code=400, detail='登录验证失败或已失效,请重新登录')
|
50
|
+
except (jwt.JWTError, jwt.ExpiredSignatureError, AttributeError):
|
51
|
+
raise HTTPException(status_code=400, detail='登录验证失败或已失效,请重新登录')
|
52
|
+
|
53
|
+
return Depends(inner)
|
54
|
+
|
55
|
+
|
56
|
+
COMMAND_START = driver.config.command_start.copy()
|
57
|
+
if '' in COMMAND_START:
|
58
|
+
COMMAND_START.remove('')
|
59
|
+
|
60
|
+
|
61
|
+
class ChatGroupConfig(BaseModel):
|
62
|
+
enable: bool = Field(True, alias='群聊学习开关')
|
63
|
+
ban_words: List[str] = Field([], alias='屏蔽词')
|
64
|
+
ban_users: List[int] = Field([], alias='屏蔽用户')
|
65
|
+
answer_threshold: int = Field(4, alias='回复阈值')
|
66
|
+
answer_threshold_weights: List[int] = Field([10, 30, 60], alias='回复阈值权重')
|
67
|
+
repeat_threshold: int = Field(3, alias='复读阈值')
|
68
|
+
break_probability: float = Field(0.25, alias='打断复读概率')
|
69
|
+
speak_enable: bool = Field(True, alias='主动发言开关')
|
70
|
+
speak_threshold: int = Field(5, alias='主动发言阈值')
|
71
|
+
speak_min_interval: int = Field(300, alias='主动发言最小间隔')
|
72
|
+
speak_continuously_probability: float = Field(0.5, alias='连续主动发言概率')
|
73
|
+
speak_continuously_max_len: int = Field(3, alias='最大连续主动发言句数')
|
74
|
+
speak_poke_probability: float = Field(0.5, alias='主动发言附带戳一戳概率')
|
75
|
+
|
76
|
+
def update(self, **kwargs):
|
77
|
+
for key, value in kwargs.items():
|
78
|
+
if key in self.__fields__:
|
79
|
+
self.__setattr__(key, value)
|
80
|
+
|
81
|
+
|
82
|
+
class ChatConfig(BaseModel):
|
83
|
+
total_enable: bool = Field(True, alias='群聊学习总开关')
|
84
|
+
enable_web: bool = Field(True, alias='启用后台管理')
|
85
|
+
web_username: str = Field('chat', alias='后台管理用户名')
|
86
|
+
web_password: str = Field('admin', alias='后台管理密码')
|
87
|
+
web_secret_key: str = Field('49c294d32f69b732ef6447c18379451ce1738922a75cd1d4812ef150318a2ed0',
|
88
|
+
alias='后台管理token密钥')
|
89
|
+
ban_words: List[str] = Field([], alias='全局屏蔽词')
|
90
|
+
ban_users: List[int] = Field([], alias='全局屏蔽用户')
|
91
|
+
KEYWORDS_SIZE: int = Field(3, alias='单句关键词分词数量')
|
92
|
+
cross_group_threshold: int = Field(3, alias='跨群回复阈值')
|
93
|
+
learn_max_count: int = Field(6, alias='最高学习次数')
|
94
|
+
dictionary: List[str] = Field([], alias='自定义词典')
|
95
|
+
group_config: Dict[int, ChatGroupConfig] = Field({}, alias='分群配置')
|
96
|
+
|
97
|
+
def update(self, **kwargs):
|
98
|
+
for key, value in kwargs.items():
|
99
|
+
if key in self.__fields__:
|
100
|
+
self.__setattr__(key, value)
|
101
|
+
|
102
|
+
class ChatConfigManager:
|
103
|
+
|
104
|
+
def __init__(self):
|
105
|
+
self.file_path = CONFIG_PATH
|
106
|
+
if self.file_path.exists():
|
107
|
+
self.config = ChatConfig.parse_obj(
|
108
|
+
yaml.load(self.file_path.read_text(encoding='utf-8'), Loader=yaml.Loader))
|
109
|
+
else:
|
110
|
+
self.config = ChatConfig()
|
111
|
+
self.save()
|
112
|
+
|
113
|
+
def get_group_config(self, group_id: int) -> ChatGroupConfig:
|
114
|
+
if group_id not in self.config.group_config:
|
115
|
+
self.config.group_config[group_id] = ChatGroupConfig()
|
116
|
+
self.save()
|
117
|
+
return self.config.group_config[group_id]
|
118
|
+
|
119
|
+
@property
|
120
|
+
def config_list(self) -> List[str]:
|
121
|
+
return list(self.config.dict(by_alias=True).keys())
|
122
|
+
|
123
|
+
def save(self):
|
124
|
+
with self.file_path.open('w', encoding='utf-8') as f:
|
125
|
+
yaml.dump(
|
126
|
+
self.config.dict(by_alias=True),
|
127
|
+
f,
|
128
|
+
indent=2,
|
129
|
+
Dumper=yaml.RoundTripDumper,
|
130
|
+
allow_unicode=True)
|
131
|
+
|
132
|
+
config_manager = ChatConfigManager()
|
133
|
+
|
134
|
+
class UserModel(BaseModel):
|
135
|
+
username: str
|
136
|
+
password: str
|
137
|
+
|
138
|
+
|
139
|
+
@driver.on_startup
|
140
|
+
async def init_web():
|
141
|
+
if not config_manager.config.enable_web:
|
142
|
+
return
|
143
|
+
app: FastAPI = get_app()
|
144
|
+
|
145
|
+
@app.post('/l4d2/api/login', response_class=JSONResponse)
|
146
|
+
async def login(user: UserModel):
|
147
|
+
if user.username != config_manager.config.web_username or user.password != config_manager.config.web_password:
|
148
|
+
return {
|
149
|
+
'status': -100,
|
150
|
+
'msg': '登录失败,请确认用户ID和密码无误'
|
151
|
+
}
|
152
|
+
token = jwt.encode({'username': user.username,
|
153
|
+
'exp': datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(
|
154
|
+
minutes=30)}, config_manager.config.web_secret_key, algorithm='HS256')
|
155
|
+
return {
|
156
|
+
'status': 0,
|
157
|
+
'msg': '登录成功',
|
158
|
+
'data': {
|
159
|
+
'token': token
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
@app.get('/l4d2/api/get_group_list', response_class=JSONResponse, dependencies=[authentication()])
|
164
|
+
async def get_group_list_api():
|
165
|
+
try:
|
166
|
+
group_list = await get_bot().get_group_list()
|
167
|
+
group_list = [{'label': f'{group["group_name"]}({group["group_id"]})', 'value': group['group_id']} for group
|
168
|
+
in group_list]
|
169
|
+
return {
|
170
|
+
'status': 0,
|
171
|
+
'msg': 'ok',
|
172
|
+
'data': {
|
173
|
+
'group_list': group_list
|
174
|
+
}
|
175
|
+
}
|
176
|
+
except ValueError:
|
177
|
+
return {
|
178
|
+
'status': -100,
|
179
|
+
'msg': '获取群和好友列表失败,请确认已连接GOCQ'
|
180
|
+
}
|
181
|
+
|
182
|
+
@app.get('/l4d2/api/chat_global_config', response_class=JSONResponse, dependencies=[authentication()])
|
183
|
+
async def get_chat_global_config():
|
184
|
+
try:
|
185
|
+
bot = get_bot()
|
186
|
+
groups = await bot.get_group_list()
|
187
|
+
member_list = []
|
188
|
+
for group in groups:
|
189
|
+
members = await bot.get_group_member_list(group_id=group['group_id'])
|
190
|
+
member_list.extend(
|
191
|
+
[{'label': f'{member["nickname"] or member["card"]}({member["user_id"]})',
|
192
|
+
'value': member['user_id']}
|
193
|
+
for
|
194
|
+
member in members])
|
195
|
+
config = config_manager.config.dict(exclude={'group_config'})
|
196
|
+
config['member_list'] = member_list
|
197
|
+
return config
|
198
|
+
except ValueError:
|
199
|
+
return {
|
200
|
+
'status': -100,
|
201
|
+
'msg': '获取群和好友列表失败,请确认已连接GOCQ'
|
202
|
+
}
|
203
|
+
|
204
|
+
|
205
|
+
|
206
|
+
@app.get('/l4d2', response_class=RedirectResponse)
|
207
|
+
async def redirect_page():
|
208
|
+
return RedirectResponse('/l4d2/login')
|
209
|
+
|
210
|
+
@app.get('/l4d2/login', response_class=HTMLResponse)
|
211
|
+
async def login_page_app():
|
212
|
+
return login_page.render(site_title='登录 | Learning-Chat 后台管理',
|
213
|
+
theme='ang')
|
214
|
+
|
215
|
+
@app.get('/l4d2/admin', response_class=HTMLResponse)
|
216
|
+
async def admin_page_app():
|
217
|
+
return admin_app.render(site_title='Learning-Chat 后台管理',
|
218
|
+
theme='ang',
|
219
|
+
requestAdaptor=requestAdaptor,
|
220
|
+
responseAdaptor=responseAdaptor)
|
221
|
+
|
@@ -0,0 +1,353 @@
|
|
1
|
+
from amis import ColumnList, AmisList, ActionType, TableCRUD, TableColumn
|
2
|
+
from amis import Dialog, PageSchema, Switch, InputNumber, InputTag, Action, App
|
3
|
+
from amis import Form, InputText, InputPassword, DisplayModeEnum, Horizontal, Remark, Html, Page, AmisAPI, Wrapper
|
4
|
+
from amis import LevelEnum, Select, InputArray, Alert, Tpl, Flex
|
5
|
+
|
6
|
+
|
7
|
+
from ..config import NICKNAME
|
8
|
+
|
9
|
+
logo = Html(html='''
|
10
|
+
<p align="center">
|
11
|
+
<a href="https://github.com/CMHopeSunshine/nonebot-plugin-learning-chat/">
|
12
|
+
<img src="http://static.cherishmoon.fun/LittlePaimon/readme/logo.png"
|
13
|
+
width="256" height="256" alt="Learning-Chat">
|
14
|
+
</a>
|
15
|
+
</p>
|
16
|
+
<h1 align="center">Nonebot-Plugin-Learning-Chat 控制台</h1>
|
17
|
+
<div align="center">
|
18
|
+
<a href="https://github.com/CMHopeSunshine/nonebot-plugin-learning-chat/" target="_blank">
|
19
|
+
Github仓库</a>
|
20
|
+
</div>
|
21
|
+
<br>
|
22
|
+
<br>
|
23
|
+
''')
|
24
|
+
login_api = AmisAPI(
|
25
|
+
url='/learning_chat/api/login',
|
26
|
+
method='post',
|
27
|
+
adaptor='''
|
28
|
+
if (payload.status == 0) {
|
29
|
+
localStorage.setItem("token", payload.data.token);
|
30
|
+
}
|
31
|
+
return payload;
|
32
|
+
'''
|
33
|
+
)
|
34
|
+
|
35
|
+
login_form = Form(api=login_api, title='', body=[
|
36
|
+
InputText(name='username', label='用户名',
|
37
|
+
labelRemark=Remark(shape='circle', content='后台管理用户名,默认为chat')),
|
38
|
+
InputPassword(name='password', label='密码',
|
39
|
+
labelRemark=Remark(shape='circle', content='后台管理密码,默认为admin')),
|
40
|
+
], mode=DisplayModeEnum.horizontal, horizontal=Horizontal(left=3, right=9, offset=5), redirect='/learning_chat/admin')
|
41
|
+
body = Wrapper(className='w-2/5 mx-auto my-0 m:w-full', body=login_form)
|
42
|
+
login_page = Page(title='', body=[logo, body])
|
43
|
+
|
44
|
+
global_config_form = Form(
|
45
|
+
title='全局配置',
|
46
|
+
name='global_config',
|
47
|
+
initApi='/learning_chat/api/chat_global_config',
|
48
|
+
api='post:/learning_chat/api/chat_global_config',
|
49
|
+
body=[
|
50
|
+
Switch(label='群聊学习总开关', name='total_enable', value='${total_enable}', onText='开启', offText='关闭',
|
51
|
+
labelRemark=Remark(shape='circle',
|
52
|
+
content='关闭后,全局都将不会再学习和回复(但是仍会对收到的消息进行记录)。')),
|
53
|
+
Switch(label='后台管理总开关', name='enable_web', value='${enable_web}', onText='开启', offText='关闭',
|
54
|
+
labelRemark=Remark(shape='circle',
|
55
|
+
content='是否开启本后台管理,若关闭,则无法再访问本页面。')),
|
56
|
+
InputText(label='后台管理用户名', name='web_username', value='${web_username}',
|
57
|
+
labelRemark=Remark(shape='circle',
|
58
|
+
content='登录本后台管理所需要的用户名。')),
|
59
|
+
InputPassword(label='后台管理密码', name='web_password', value='${web_password}',
|
60
|
+
labelRemark=Remark(shape='circle',
|
61
|
+
content='登录本后台管理所需要的密码。')),
|
62
|
+
InputText(label='后台管理token密钥', name='web_secret_key', value='${web_secret_key}',
|
63
|
+
labelRemark=Remark(shape='circle',
|
64
|
+
content='用于本后台管理加密验证token的密钥。')),
|
65
|
+
InputNumber(label='单句关键词数量', name='KEYWORDS_SIZE', value='${KEYWORDS_SIZE}', visibleOn='${total_enable}',
|
66
|
+
min=2,
|
67
|
+
labelRemark=Remark(shape='circle',
|
68
|
+
content='单句语句标签数量,影响对一句话的主题词提取效果,建议保持默认为3。')),
|
69
|
+
InputNumber(label='跨群回复阈值', name='cross_group_threshold', value='${cross_group_threshold}',
|
70
|
+
visibleOn='${total_enable}', min=1,
|
71
|
+
labelRemark=Remark(shape='circle',
|
72
|
+
content='当学习到的一种回复在N个群都有,那么这个回复就会变为全局回复。')),
|
73
|
+
InputNumber(label='最高学习次数', name='learn_max_count', value='${learn_max_count}',
|
74
|
+
visibleOn='${total_enable}', min=2, labelRemark=Remark(shape='circle',
|
75
|
+
content='学习的回复最高能累计到的次数,值越高,这个回复就会学习得越深,越容易进行回复,如果不想每次都大概率固定回复某一句话,可以将该值设低点。')),
|
76
|
+
InputTag(label='全局屏蔽词', name='ban_words', value='${ban_words}', enableBatchAdd=True,
|
77
|
+
placeholder='添加全局屏蔽词', visibleOn='${total_enable}', joinValues=False, extractValue=True,
|
78
|
+
labelRemark=Remark(shape='circle',
|
79
|
+
content='全局屏蔽词,含有这些词的消息不会学习和回复,默认已屏蔽at、分享、语音、和视频等消息。(回车进行添加)')),
|
80
|
+
InputTag(label='全局屏蔽用户', name='ban_users', value='${ban_users}',
|
81
|
+
enableBatchAdd=True,
|
82
|
+
placeholder='添加全局屏蔽用户', visibleOn='${total_enable}', joinValues=False, extractValue=True,
|
83
|
+
labelRemark=Remark(shape='circle',
|
84
|
+
content='全局屏蔽用户,和这些用户有关的消息不会学习和回复。(回车进行添加)')),
|
85
|
+
InputTag(label='自定义词典', name='dictionary', value='${dictionary}',
|
86
|
+
enableBatchAdd=True,
|
87
|
+
placeholder='添加自定义词语', visibleOn='${total_enable}', joinValues=False, extractValue=True,
|
88
|
+
labelRemark=Remark(shape='circle',
|
89
|
+
content='添加自定义词语,让分词能够识别未收录的词汇,提高学习的准确性。你可以添加特殊名词,这样学习时就会将该词看作一个整体,目前词典中已默认添加部分原神相关词汇。(回车进行添加)')),
|
90
|
+
],
|
91
|
+
actions=[Action(label='保存', level=LevelEnum.success, type='submit'),
|
92
|
+
Action(label='重置', level=LevelEnum.warning, type='reset')]
|
93
|
+
)
|
94
|
+
group_select = Select(label='分群配置', name='group_id', source='${group_list}',
|
95
|
+
placeholder='选择群')
|
96
|
+
group_config_form = Form(
|
97
|
+
title='分群配置',
|
98
|
+
visibleOn='group_id != null',
|
99
|
+
initApi='/learning_chat/api/chat_group_config?group_id=${group_id}',
|
100
|
+
api='post:/learning_chat/api/chat_group_config?group_id=${group_id}',
|
101
|
+
body=[
|
102
|
+
Switch(label='群聊学习开关', name='enable', value='${enable}', onText='开启', offText='关闭',
|
103
|
+
labelRemark=Remark(shape='circle', content='针对该群的群聊学习开关,关闭后,仅该群不会学习和回复。')),
|
104
|
+
InputNumber(label='回复阈值', name='answer_threshold', value='${answer_threshold}', visibleOn='${enable}',
|
105
|
+
min=2,
|
106
|
+
labelRemark=Remark(shape='circle', content='可以理解为学习成功所需要的次数,值越低学得越快。')),
|
107
|
+
InputArray(label='回复阈值权重', name='answer_threshold_weights', value='${answer_threshold_weights}',
|
108
|
+
items=InputNumber(min=1, max=100, value=25, suffix='%'), inline=True, visibleOn='${enable}',
|
109
|
+
labelRemark=Remark(shape='circle',
|
110
|
+
content='影响回复阈值的计算方式,以默认的回复阈值4、权重[10, 30, 60]为例,在计算阈值时,60%概率为4,30%概率为3,10%概率为2。')),
|
111
|
+
InputNumber(label='复读阈值', name='repeat_threshold', value='${repeat_threshold}', visibleOn='${enable}',
|
112
|
+
min=2,
|
113
|
+
labelRemark=Remark(shape='circle',
|
114
|
+
content=f'跟随复读所需要的阈值,有N个人复读后,{NICKNAME}就会跟着复读。')),
|
115
|
+
InputNumber(label='打断复读概率', name='break_probability', value='${break_probability}',
|
116
|
+
min=0, max=100, suffix='%', visibleOn='${AND(enable, speak_enable)}',
|
117
|
+
labelRemark=Remark(shape='circle', content='达到复读阈值时,打断复读而不是跟随复读的概率。')),
|
118
|
+
InputTag(label='屏蔽词', name='ban_words', value='${ban_words}', enableBatchAdd=True,
|
119
|
+
placeholder='添加屏蔽词', visibleOn='${enable}', joinValues=False, extractValue=True,
|
120
|
+
labelRemark=Remark(shape='circle', content='含有这些词的消息不会学习和回复。(回车进行添加)')),
|
121
|
+
InputTag(label='屏蔽用户', source='${member_list}', name='ban_users', value='${ban_users}', enableBatchAdd=True,
|
122
|
+
placeholder='添加屏蔽用户', visibleOn='${enable}', joinValues=False, extractValue=True,
|
123
|
+
labelRemark=Remark(shape='circle', content='和该群中这些用户有关的消息不会学习和回复。(回车进行添加)')),
|
124
|
+
Switch(label='主动发言开关', name='speak_enable', value='${speak_enable}', visibleOn='${enable}',
|
125
|
+
labelRemark=Remark(shape='circle',
|
126
|
+
content=f'是否允许{NICKNAME}在该群主动发言,主动发言是指每隔一段时间挑选一个热度较高的群,主动发一些学习过的内容。')),
|
127
|
+
InputNumber(label='主动发言阈值', name='speak_threshold', value='${speak_threshold}',
|
128
|
+
visibleOn='${AND(enable, speak_enable)}', min=0,
|
129
|
+
labelRemark=Remark(shape='circle', content='值越低,主动发言的可能性越高。')),
|
130
|
+
InputNumber(label='主动发言最小间隔', name='speak_min_interval', value='${speak_min_interval}', min=0,
|
131
|
+
visibleOn='${AND(enable, speak_enable)}', suffix='秒',
|
132
|
+
labelRemark=Remark(shape='circle', content='进行主动发言的最小时间间隔。')),
|
133
|
+
InputNumber(label='连续主动发言概率', name='speak_continuously_probability',
|
134
|
+
value='${speak_continuously_probability}', min=0, max=100, suffix='%',
|
135
|
+
visibleOn='${AND(enable, speak_enable)}',
|
136
|
+
labelRemark=Remark(shape='circle', content='触发主动发言时,连续进行发言的概率。')),
|
137
|
+
InputNumber(label='最大连续主动发言句数', name='speak_continuously_max_len',
|
138
|
+
value='${speak_continuously_max_len}', visibleOn='${AND(enable, speak_enable)}', min=1,
|
139
|
+
labelRemark=Remark(shape='circle', content='连续主动发言的最大句数。')),
|
140
|
+
InputNumber(label='主动发言附带戳一戳概率', name='speak_poke_probability', value='${speak_poke_probability}',
|
141
|
+
min=0, max=100, suffix='%', visibleOn='${AND(enable, speak_enable)}',
|
142
|
+
labelRemark=Remark(shape='circle',
|
143
|
+
content='主动发言时附带戳一戳的概率,会在最近5个发言者中随机选一个戳。')),
|
144
|
+
],
|
145
|
+
actions=[Action(label='保存', level=LevelEnum.success, type='submit'),
|
146
|
+
ActionType.Ajax(
|
147
|
+
label='保存至所有群',
|
148
|
+
level=LevelEnum.primary,
|
149
|
+
confirmText='确认将当前配置保存至所有群?',
|
150
|
+
api='post:/learning_chat/api/chat_group_config?group_id=all'
|
151
|
+
),
|
152
|
+
Action(label='重置', level=LevelEnum.warning, type='reset')]
|
153
|
+
)
|
154
|
+
|
155
|
+
blacklist_table = TableCRUD(mode='table',
|
156
|
+
title='',
|
157
|
+
syncLocation=False,
|
158
|
+
api='/learning_chat/api/get_chat_blacklist',
|
159
|
+
interval=15000,
|
160
|
+
headerToolbar=[ActionType.Ajax(label='取消所有禁用',
|
161
|
+
level=LevelEnum.warning,
|
162
|
+
confirmText='确定要取消所有禁用吗?',
|
163
|
+
api='put:/learning_chat/api/delete_all?type=blacklist')],
|
164
|
+
itemActions=[ActionType.Ajax(tooltip='取消禁用',
|
165
|
+
icon='fa fa-check-circle-o text-info',
|
166
|
+
confirmText='取消该被禁用的内容/关键词,但是仍然需要重新学习哦!',
|
167
|
+
api='delete:/learning_chat/api/delete_chat?type=blacklist&id=${id}')
|
168
|
+
],
|
169
|
+
footable=True,
|
170
|
+
columns=[TableColumn(type='tpl', tpl='${keywords|truncate:20}', label='内容/关键词',
|
171
|
+
name='keywords',
|
172
|
+
searchable=True, popOver={'mode': 'dialog', 'title': '全文',
|
173
|
+
'className': 'break-all',
|
174
|
+
'body': {'type': 'tpl',
|
175
|
+
'tpl': '${keywords}'}}),
|
176
|
+
TableColumn(label='已禁用的群', name='bans', searchable=True),
|
177
|
+
])
|
178
|
+
message_table = TableCRUD(mode='table',
|
179
|
+
title='',
|
180
|
+
syncLocation=False,
|
181
|
+
api='/learning_chat/api/get_chat_messages',
|
182
|
+
interval=12000,
|
183
|
+
headerToolbar=[ActionType.Ajax(label='删除所有聊天记录',
|
184
|
+
level=LevelEnum.warning,
|
185
|
+
confirmText='确定要删除所有聊天记录吗?',
|
186
|
+
api='put:/learning_chat/api/delete_all?type=message')],
|
187
|
+
itemActions=[ActionType.Ajax(tooltip='禁用',
|
188
|
+
icon='fa fa-ban text-danger',
|
189
|
+
confirmText='禁用该聊天记录相关的学习内容和回复',
|
190
|
+
api='put:/learning_chat/api/ban_chat?type=message&id=${id}'),
|
191
|
+
ActionType.Ajax(tooltip='删除',
|
192
|
+
icon='fa fa-times text-danger',
|
193
|
+
confirmText='删除该条聊天记录',
|
194
|
+
api='delete:/learning_chat/api/delete_chat?type=message&id=${id}')
|
195
|
+
],
|
196
|
+
footable=True,
|
197
|
+
columns=[TableColumn(label='消息ID', name='message_id'),
|
198
|
+
TableColumn(label='群ID', name='group_id', searchable=True),
|
199
|
+
TableColumn(label='用户ID', name='user_id', searchable=True),
|
200
|
+
TableColumn(type='tpl', tpl='${raw_message|truncate:20}', label='消息',
|
201
|
+
name='message',
|
202
|
+
searchable=True, popOver={'mode': 'dialog', 'title': '消息全文',
|
203
|
+
'className': 'break-all',
|
204
|
+
'body': {'type': 'tpl',
|
205
|
+
'tpl': '${raw_message}'}}),
|
206
|
+
TableColumn(type='tpl', tpl='${time|date:YYYY-MM-DD HH\\:mm\\:ss}', label='时间',
|
207
|
+
name='time', sortable=True)
|
208
|
+
])
|
209
|
+
answer_table = TableCRUD(
|
210
|
+
mode='table',
|
211
|
+
syncLocation=False,
|
212
|
+
footable=True,
|
213
|
+
api='/learning_chat/api/get_chat_answers',
|
214
|
+
interval=12000,
|
215
|
+
headerToolbar=[ActionType.Ajax(label='删除所有已学习的回复',
|
216
|
+
level=LevelEnum.warning,
|
217
|
+
confirmText='确定要删除所有已学习的回复吗?',
|
218
|
+
api='put:/learning_chat/api/delete_all?type=answer')],
|
219
|
+
itemActions=[ActionType.Ajax(tooltip='禁用',
|
220
|
+
icon='fa fa-ban text-danger',
|
221
|
+
confirmText='禁用并删除该已学回复',
|
222
|
+
api='put:/learning_chat/api/ban_chat?type=answer&id=${id}'),
|
223
|
+
ActionType.Ajax(tooltip='删除',
|
224
|
+
icon='fa fa-times text-danger',
|
225
|
+
confirmText='仅删除该已学回复,不会禁用,所以依然能继续学',
|
226
|
+
api='delete:/learning_chat/api/delete_chat?type=answer&id=${id}')],
|
227
|
+
columns=[TableColumn(label='ID', name='id', visible=False),
|
228
|
+
TableColumn(label='群ID', name='group_id', searchable=True),
|
229
|
+
TableColumn(type='tpl', tpl='${keywords|truncate:20}', label='内容/关键词', name='keywords',
|
230
|
+
searchable=True, popOver={'mode': 'dialog', 'title': '内容全文', 'className': 'break-all',
|
231
|
+
'body': {'type': 'tpl', 'tpl': '${keywords}'}}),
|
232
|
+
TableColumn(type='tpl', tpl='${time|date:YYYY-MM-DD HH\\:mm\\:ss}', label='最后学习时间', name='time',
|
233
|
+
sortable=True),
|
234
|
+
TableColumn(label='次数', name='count', sortable=True),
|
235
|
+
ColumnList(label='完整消息', name='messages', breakpoint='*', source='${messages}',
|
236
|
+
listItem=AmisList.Item(body={'name': 'msg'}))
|
237
|
+
])
|
238
|
+
answer_table_on_context = TableCRUD(
|
239
|
+
mode='table',
|
240
|
+
syncLocation=False,
|
241
|
+
footable=True,
|
242
|
+
api='/learning_chat/api/get_chat_answers?context_id=${id}&page=${page}&perPage=${perPage}&orderBy=${orderBy}&orderDir=${orderDir}',
|
243
|
+
interval=12000,
|
244
|
+
headerToolbar=[ActionType.Ajax(label='删除该内容所有回复',
|
245
|
+
level=LevelEnum.warning,
|
246
|
+
confirmText='确定要删除该条内容已学习的回复吗?',
|
247
|
+
api='put:/learning_chat/api/delete_all?type=answer&id=${id}')],
|
248
|
+
itemActions=[ActionType.Ajax(tooltip='禁用',
|
249
|
+
icon='fa fa-ban text-danger',
|
250
|
+
confirmText='禁用并删除该已学回复',
|
251
|
+
api='put:/learning_chat/api/ban_chat?type=answer&id=${id}'),
|
252
|
+
ActionType.Ajax(tooltip='删除',
|
253
|
+
icon='fa fa-times text-danger',
|
254
|
+
confirmText='仅删除该已学回复,但不禁用,依然能继续学',
|
255
|
+
api='delete:/learning_chat/api/delete_chat?type=answer&id=${id}')],
|
256
|
+
columns=[TableColumn(label='ID', name='id', visible=False),
|
257
|
+
TableColumn(label='群ID', name='group_id'),
|
258
|
+
TableColumn(type='tpl', tpl='${keywords|truncate:20}', label='内容/关键词', name='keywords',
|
259
|
+
searchable=True, popOver={'mode': 'dialog', 'title': '内容全文', 'className': 'break-all',
|
260
|
+
'body': {'type': 'tpl', 'tpl': '${keywords}'}}),
|
261
|
+
TableColumn(type='tpl', tpl='${time|date:YYYY-MM-DD HH\\:mm\\:ss}', label='最后学习时间', name='time',
|
262
|
+
sortable=True),
|
263
|
+
TableColumn(label='次数', name='count', sortable=True),
|
264
|
+
ColumnList(label='完整消息', name='messages', breakpoint='*', source='${messages}',
|
265
|
+
listItem=AmisList.Item(body={'name': 'msg'}))
|
266
|
+
])
|
267
|
+
context_table = TableCRUD(mode='table',
|
268
|
+
title='',
|
269
|
+
syncLocation=False,
|
270
|
+
api='/learning_chat/api/get_chat_contexts',
|
271
|
+
interval=12000,
|
272
|
+
headerToolbar=[ActionType.Ajax(label='删除所有学习内容',
|
273
|
+
level=LevelEnum.warning,
|
274
|
+
confirmText='确定要删除所有已学习的内容吗?',
|
275
|
+
api='put:/learning_chat/api/delete_all?type=context')],
|
276
|
+
itemActions=[ActionType.Dialog(tooltip='回复列表',
|
277
|
+
icon='fa fa-book text-info',
|
278
|
+
dialog=Dialog(title='回复列表',
|
279
|
+
size='lg',
|
280
|
+
body=answer_table_on_context)),
|
281
|
+
ActionType.Ajax(tooltip='禁用',
|
282
|
+
icon='fa fa-ban text-danger',
|
283
|
+
confirmText='禁用并删除该学习的内容及其所有回复',
|
284
|
+
api='put:/learning_chat/api/ban_chat?type=context&id=${id}'),
|
285
|
+
ActionType.Ajax(tooltip='删除',
|
286
|
+
icon='fa fa-times text-danger',
|
287
|
+
confirmText='仅删除该学习的内容及其所有回复,但不禁用,依然能继续学',
|
288
|
+
api='delete:/learning_chat/api/delete_chat?type=context&id=${id}')
|
289
|
+
],
|
290
|
+
footable=True,
|
291
|
+
columns=[TableColumn(label='ID', name='id', visible=False),
|
292
|
+
TableColumn(type='tpl', tpl='${keywords|truncate:20}', label='内容/关键词',
|
293
|
+
name='keywords', searchable=True,
|
294
|
+
popOver={'mode': 'dialog', 'title': '内容全文', 'className': 'break-all',
|
295
|
+
'body': {'type': 'tpl', 'tpl': '${keywords}'}}),
|
296
|
+
TableColumn(type='tpl', tpl='${time|date:YYYY-MM-DD HH\\:mm\\:ss}',
|
297
|
+
label='最后学习时间', name='time', sortable=True),
|
298
|
+
TableColumn(label='已学次数', name='count', sortable=True),
|
299
|
+
])
|
300
|
+
|
301
|
+
message_page = PageSchema(url='/messages', icon='fa fa-comments', label='群聊消息',
|
302
|
+
schema=Page(title='群聊消息', body=[
|
303
|
+
Alert(level=LevelEnum.info,
|
304
|
+
className='white-space-pre-wrap',
|
305
|
+
body=(f'此数据库记录了{NICKNAME}收到的聊天记录。\n'
|
306
|
+
'· 点击"禁用"可以将某条聊天记录进行禁用,这样其相关的学习就会列入禁用列表。\n'
|
307
|
+
'· 点击"删除"可以删除某条记录,但不会影响它的学习。\n'
|
308
|
+
f'· 可以通过搜索{NICKNAME}的QQ号,来查看它的回复记录。')),
|
309
|
+
message_table]))
|
310
|
+
context_page = PageSchema(url='/contexts', icon='fa fa-comment', label='学习内容',
|
311
|
+
schema=Page(title='内容',
|
312
|
+
body=[Alert(level=LevelEnum.info,
|
313
|
+
className='white-space-pre-wrap',
|
314
|
+
body=(f'此数据库记录了{NICKNAME}所学习的内容。\n'
|
315
|
+
'· 点击"回复列表"可以查看该条内容已学习到的可能的回复。\n'
|
316
|
+
'· 点击"禁用"可以将该学习进行禁用,以后不会再学。\n'
|
317
|
+
'· 点击"删除"可以删除该学习,让它重新开始学习这句话。')),
|
318
|
+
context_table]))
|
319
|
+
answer_page = PageSchema(url='/answers', icon='fa fa-commenting-o', label='内容回复',
|
320
|
+
schema=Page(title='回复',
|
321
|
+
body=[Alert(level=LevelEnum.info,
|
322
|
+
className='white-space-pre-wrap',
|
323
|
+
body=(
|
324
|
+
f'此数据库记录了{NICKNAME}已学习到的所有回复,但看不到这些回复属于哪些内容,推荐到"学习内容"表进行操作。\n'
|
325
|
+
'· 点击"禁用"可以将该回复进行禁用,以后不会再学。\n'
|
326
|
+
'· 点击"删除"可以删除该回复,让它重新开始学习。')),
|
327
|
+
answer_table]))
|
328
|
+
blacklist_page = PageSchema(url='/blacklist', icon='fa fa-ban', label='禁用列表',
|
329
|
+
schema=Page(title='禁用列表',
|
330
|
+
body=[Alert(level=LevelEnum.info,
|
331
|
+
className='white-space-pre-wrap',
|
332
|
+
body=f'此数据库记录了{NICKNAME}被禁用的内容/关键词。\n'
|
333
|
+
'· 可以取消禁用,使其能够重新继续学习。\n'
|
334
|
+
'· 不能在此添加禁用,只能在群中回复[不可以]或者在<配置>中添加屏蔽词来达到禁用效果。'),
|
335
|
+
blacklist_table]))
|
336
|
+
database_page = PageSchema(label='数据库', icon='fa fa-database',
|
337
|
+
children=[message_page, context_page, answer_page, blacklist_page])
|
338
|
+
config_page = PageSchema(url='/configs', isDefaultPage=True, icon='fa fa-wrench', label='配置',
|
339
|
+
schema=Page(title='配置', initApi='/learning_chat/api/get_group_list',
|
340
|
+
body=[global_config_form, group_select, group_config_form]))
|
341
|
+
chat_page = PageSchema(label='群聊学习', icon='fa fa-wechat (alias)', children=[config_page, database_page])
|
342
|
+
|
343
|
+
github_logo = Tpl(className='w-full',
|
344
|
+
tpl='<div class="flex justify-between"><div></div><div><a href="https://github.com/CMHopeSunshine/nonebot-plugin-learning-chat" target="_blank" title="Copyright"><i class="fa fa-github fa-2x"></i></a></div></div>')
|
345
|
+
header = Flex(className='w-full', justify='flex-end', alignItems='flex-end', items=[github_logo])
|
346
|
+
|
347
|
+
admin_app = App(brandName='Learning-Chat',
|
348
|
+
logo='http://static.cherishmoon.fun/LittlePaimon/readme/logo.png',
|
349
|
+
header=header,
|
350
|
+
pages=[{
|
351
|
+
'children': [config_page, database_page]
|
352
|
+
}],
|
353
|
+
footer='<div class="p-2 text-center bg-blue-100">Copyright © 2021 - 2022 <a href="https://github.com/CMHopeSunshine/nonebot-plugin-learning-chat" target="_blank" class="link-secondary">Learning-Chat</a> X<a target="_blank" href="https://github.com/baidu/amis" class="link-secondary" rel="noopener"> amis v2.2.0</a></div>')
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: nonebot-plugin-l4d2-server
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.5b2
|
4
4
|
Summary: L4D2 server related operations plugin for NoneBot
|
5
5
|
Home-page: https://github.com/Umamusume-Agnes-Digital/nonebot_plugin_l4d2_server
|
6
6
|
License: MIT
|
@@ -22,9 +22,11 @@ Classifier: Programming Language :: Python :: 3.10
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.8
|
23
23
|
Classifier: Programming Language :: Python :: 3.9
|
24
24
|
Requires-Dist: aiohttp (>=3.8.3,<4.0.0)
|
25
|
+
Requires-Dist: amis-python (>=1.0.6,<2.0.0)
|
25
26
|
Requires-Dist: asyncio (>=3.4.3,<4.0.0)
|
26
27
|
Requires-Dist: beautifulsoup4 (>=4.8.0,<5.0.0)
|
27
28
|
Requires-Dist: httpx (>=0.23.3,<0.24.0)
|
29
|
+
Requires-Dist: jieba (>=0.42.1,<0.43.0)
|
28
30
|
Requires-Dist: jinja2 (>=3.0.0,<4.0.0)
|
29
31
|
Requires-Dist: nonebot-adapter-onebot (>=2.1.5)
|
30
32
|
Requires-Dist: nonebot2 (>=2.0.0rc3,<3.0.0)
|
@@ -37,6 +39,7 @@ Requires-Dist: python-a2s (>=1.3.0,<2.0.0)
|
|
37
39
|
Requires-Dist: pyunpack (>=0.3.0,<0.4.0)
|
38
40
|
Requires-Dist: rarfile (>=4.0,<5.0)
|
39
41
|
Requires-Dist: rcon (>=2.1.0,<3.0.0)
|
42
|
+
Requires-Dist: ruamel.yaml (>=0.17.21,<0.18.0)
|
40
43
|
Requires-Dist: srctools (>=2.3.9,<3.0.0)
|
41
44
|
Project-URL: Repository, https://github.com/Umamusume-Agnes-Digital/nonebot_plugin_l4d2_server
|
42
45
|
Description-Content-Type: text/markdown
|
@@ -337,6 +340,20 @@ anne:<br>
|
|
337
340
|
<details>
|
338
341
|
<summary>展开/收起</summary>
|
339
342
|
|
343
|
+
### 0.3.5--2022.3
|
344
|
+
|
345
|
+
- 新增ping查询(在ip里包括)
|
346
|
+
- 新增api查询(未完成)
|
347
|
+
|
348
|
+
### 0.3.4--2022.3.1
|
349
|
+
|
350
|
+
- 新增本地插件smx查询
|
351
|
+
- 增加了三个内置群服
|
352
|
+
- 修改了图片的UI,变好看了
|
353
|
+
- 删减了部分图片和字体,使得轻量化
|
354
|
+
- 修复了海量bug
|
355
|
+
- 修复了python3.8中typing错误
|
356
|
+
|
340
357
|
### 0.3.3--2022.2.26
|
341
358
|
|
342
359
|
- 重写协议,使用a2s库,同时解决win端不同报错无法输出
|
@@ -496,13 +513,13 @@ ubuntu20.04 python3.10
|
|
496
513
|
|
497
514
|
<h2 id="cx">服务器相关 </h2>
|
498
515
|
|
499
|
-
|
516
|
+
目前插件会内置经腐竹同意的服的查询(未来将使用api)
|
500
517
|
|
501
518
|
| 指令 | 服务器 | op | 数量 |
|
502
519
|
|:-----:|:----:|:----:|:----:|
|
503
|
-
| 云 | anne电信服云服 | 东 |
|
520
|
+
| 云 | anne电信服云服(暂时不提供) | 东 | 24
|
504
521
|
| 呆呆 | 呆呆的小窝 | 提莫大魔王 | 15
|
505
|
-
| 橘 | 橘希实香的小窝 | 橘希实香 |
|
522
|
+
| 橘 | 橘希实香的小窝 | 橘希实香 | 7
|
506
523
|
|
507
524
|
如果需要上传自己的ip可以Pr、iss或者进qq群
|
508
525
|
|
{nonebot_plugin_l4d2_server-0.3.5a1.dist-info → nonebot_plugin_l4d2_server-0.3.5b2.dist-info}/RECORD
RENAMED
@@ -1,7 +1,7 @@
|
|
1
1
|
LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
|
2
|
-
nonebot_plugin_l4d2_server/__init__.py,sha256
|
3
|
-
nonebot_plugin_l4d2_server/command.py,sha256=
|
4
|
-
nonebot_plugin_l4d2_server/config.py,sha256=
|
2
|
+
nonebot_plugin_l4d2_server/__init__.py,sha256=7lGkD-LOOEFtSU702utYjQvKhF3Lr-rD1YMmmHsVoV8,17485
|
3
|
+
nonebot_plugin_l4d2_server/command.py,sha256=oyM-j86qLSRUu-8WDRw39SJ33qzW9AqabRDjji_r1SM,5051
|
4
|
+
nonebot_plugin_l4d2_server/config.py,sha256=PrN3VQeEnErz7FOK8lnHeyZzzDmndf09IO-UlQXbfJY,4035
|
5
5
|
nonebot_plugin_l4d2_server/data/L4D2/image/head/head.png,sha256=Z72PEvp7xF1DZcLDeuWlg2_g6JAfHxtisptWn6BYGN8,158357
|
6
6
|
nonebot_plugin_l4d2_server/data/L4D2/image/header/player1.jpg,sha256=2A_llIi9YVhJs9JOMuF36by7Ewc7P7qOgQS8t5jemNw,405369
|
7
7
|
nonebot_plugin_l4d2_server/data/L4D2/image/template/anne.html,sha256=oFpQfCIN0CKoEfjAb8aUOYD7l-kmPd1qCSF8E6bosY8,1567
|
@@ -12,7 +12,7 @@ nonebot_plugin_l4d2_server/data/L4D2/image/template/help.html,sha256=TomooDmqUmq
|
|
12
12
|
nonebot_plugin_l4d2_server/data/L4D2/image/template/help_dack.html,sha256=g7tp8g_ZejiQBQrOti-EvcygJBFICnscU5ckrJ5Lp2A,6417
|
13
13
|
nonebot_plugin_l4d2_server/data/L4D2/image/template/ip.html,sha256=5uNt3wigNdAZX2gNX4nFOJghbXoiBJoceGyV5qcK9Xg,1595
|
14
14
|
nonebot_plugin_l4d2_server/data/L4D2/image/template/vue.css,sha256=2sGjCFrR-3tFMB_x7l4K6k40tZ5JVzhWqD759cagYBA,7874
|
15
|
-
nonebot_plugin_l4d2_server/data/L4D2/l4d2.json,sha256=
|
15
|
+
nonebot_plugin_l4d2_server/data/L4D2/l4d2.json,sha256=_txrDFATQSxiGLENGyXATx1OcAqYDjHIzGzsYssJqwc,2591
|
16
16
|
nonebot_plugin_l4d2_server/l4d2_anne/__init__.py,sha256=QEceM8gXwo6kQn_kO7g7tUqEU1D5v2iWYRZwl8bJm_4,7770
|
17
17
|
nonebot_plugin_l4d2_server/l4d2_anne/anne_telecom.py,sha256=0U1iY4vSY5yyM3vrMWl2wDO_KFKi4KFRxjAuPuFdO3o,2958
|
18
18
|
nonebot_plugin_l4d2_server/l4d2_anne/server.py,sha256=Y1Pss8hU1vkJepKCf9hoSShhbDT_hWrSJknW3AFJDu4,1686
|
@@ -27,18 +27,21 @@ nonebot_plugin_l4d2_server/l4d2_image/htmlimg.py,sha256=bz1oJn-CUoPuBktJxGLrm1Fs
|
|
27
27
|
nonebot_plugin_l4d2_server/l4d2_image/send_image_tool.py,sha256=DKliVudSSeec4Gl5Deji04-P4_bbSIvXWorEIPQpKDc,968
|
28
28
|
nonebot_plugin_l4d2_server/l4d2_image/steam.py,sha256=-N0dcTmnCu5UOjUik0UMWR3pTlCQK7PnkxGuZpju-TU,2481
|
29
29
|
nonebot_plugin_l4d2_server/l4d2_image/vtfs.py,sha256=2WuXE_4_5eVNExzYCTgZnKZrcE6CxqnDpjpKEA_FHCE,1427
|
30
|
-
nonebot_plugin_l4d2_server/l4d2_queries/__init__.py,sha256=
|
30
|
+
nonebot_plugin_l4d2_server/l4d2_queries/__init__.py,sha256=Qv3aIDaqbP2J5zUXiOnfl9eJ1o0WKeGnC1qzOqfDgDo,3468
|
31
|
+
nonebot_plugin_l4d2_server/l4d2_queries/maps.py,sha256=EcyHLVIa801qADz1zO-TZwSdQpr4aHZEGz_M-UeDQQ4,669
|
31
32
|
nonebot_plugin_l4d2_server/l4d2_queries/ohter.py,sha256=HQzsbk10L5nUrPAaN-FvCJO9kmfOyXz8nrnZZezg8Ss,888
|
32
|
-
nonebot_plugin_l4d2_server/l4d2_queries/qqgroup.py,sha256=
|
33
|
+
nonebot_plugin_l4d2_server/l4d2_queries/qqgroup.py,sha256=tbn9i7gY-bZyjOMHfH14Grj6Ue9S9YbYeK3HlttQwJ0,10239
|
33
34
|
nonebot_plugin_l4d2_server/l4d2_server/__init__.py,sha256=mp3Za6jJ-V92ChXRhl3k4D1tMTY4dqHdXgMzdWutccc,1676
|
34
35
|
nonebot_plugin_l4d2_server/l4d2_server/rcon.py,sha256=aP2n-sq_vM-h6UjnNCmKK9_WW8oS9zFySgowPl5FXd4,1160
|
36
|
+
nonebot_plugin_l4d2_server/l4d2_server/web.py,sha256=UanKE3YWvMRCEDqF9wCZKOK2CITgR61Dq6AgwP4zUMY,8727
|
37
|
+
nonebot_plugin_l4d2_server/l4d2_server/webUI.py,sha256=pRZEyTHWOTcoX_U8r2I342M60-g9h59BjaDwZqa_jUk,28187
|
35
38
|
nonebot_plugin_l4d2_server/l4d2_server/workshop.py,sha256=ZpWnWJ7EABNpDu86Rzoqu3tWoABanprIEcmej1zUT1A,1409
|
36
39
|
nonebot_plugin_l4d2_server/message.py,sha256=x_ts0HaW3SNOma-baEG0oaeozKE5Nh_fybnRH6VE8i0,1678
|
37
40
|
nonebot_plugin_l4d2_server/seach.py,sha256=FOtFWYVWNxt-tMFXdVN7_F1vBTKlTDdRljoUWFQzB9w,1021
|
38
41
|
nonebot_plugin_l4d2_server/txt_to_img.py,sha256=ZaxHYNu8aAZUH4fNALyE1Q_ET7KuWytEiMFZ9loZnqc,2188
|
39
42
|
nonebot_plugin_l4d2_server/utils.py,sha256=7hPjQLLhBCjiOCcKA7KAfiLimRx940iWaugD3dnaNCA,8348
|
40
|
-
README.md,sha256=
|
41
|
-
nonebot_plugin_l4d2_server-0.3.
|
42
|
-
nonebot_plugin_l4d2_server-0.3.
|
43
|
-
nonebot_plugin_l4d2_server-0.3.
|
44
|
-
nonebot_plugin_l4d2_server-0.3.
|
43
|
+
README.md,sha256=WwGKulFV_ttxYFJaF8kiP-AytUYYFxp534aAKpn-J3I,16843
|
44
|
+
nonebot_plugin_l4d2_server-0.3.5b2.dist-info/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
|
45
|
+
nonebot_plugin_l4d2_server-0.3.5b2.dist-info/METADATA,sha256=HKZ37JDGtcGRnA4u0seZZNwIBC76jvwqXj2USFzv7VA,18362
|
46
|
+
nonebot_plugin_l4d2_server-0.3.5b2.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
|
47
|
+
nonebot_plugin_l4d2_server-0.3.5b2.dist-info/RECORD,,
|
File without changes
|
{nonebot_plugin_l4d2_server-0.3.5a1.dist-info → nonebot_plugin_l4d2_server-0.3.5b2.dist-info}/WHEEL
RENAMED
File without changes
|