diff --git a/README.md b/README.md index ded2078..0fc0187 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -本readme适用版本 : v1.40-v1.50 +本readme适用版本 : v1.40-v1.51 # 免责声明 ### 本项目禁止用于包括但不限于:违法犯罪、灰色地带等一切有背于社会主义核心价值观的行为。 ### 下载本插件或源码则默认同意以上内容 @@ -10,28 +10,92 @@ **** ## 项目简介 **LoveYou是一个高性能的、可高度自定义的词库+好感度系统插件** -~~**运行本项目,你需要确保你拥有至少300MB的空闲内存** -从v1.42开始,项目需要接近500MB的内存。希望有人可以看一看如何优化(哭)~~ -~~**内存占用可使用虚拟内存代替**~~
-**在v1.50,内存占用降低至150MB左右,常驻内存为100MB** +**在v1.50及以后,内存占用降低至170MB左右**
以下三点是本插件的开发宗旨 * 词库的编辑是简易、高效且可视化的 * 好感度系统是完全兼容词库且高效的 * 项目是灵动的,而非死气沉沉的 +
+本项目release包性能表现:已知2w行的词库可瞬间回复。[测试用词库](https://github.com/hlfzsi/yirimirai_LoveYou/blob/main/example/reply.csv) **** +## 快速上手 +本项目仅支持64位系统
+首先,请正确配置mirai-api-http
+[mirai-api-http参考配置](https://github.com/avilliai/wReply/blob/master/setting.yml),需要注意,本项目仅支持正向ws
+之后,你需要确认config.ini填写无误 +``` +请勿直接复制本config.ini +[bot]如果你按照mirai-api-http参考配置进行部署,则无需修改verify_key、host、port +bot_qq = bot的QQ号 +verify_key = 1234567890 +host = 127.0.0.1 +port = 23456 +[random_CG] +baseline=触发CG的最低好感要求 +rate=0.02触发CG的概率(0-1.00) +[others] +ws=True是否启用LoveYou自带的ws,默认启用 +ws_port=8686 LoveYou的ws端口,默认为8686 +bot_name=bot的名称 +master=bot主人的QQ号 +search_love_reply=查询好感 指令的回复格式 +tank_enable=True是否启用幻影坦克 +[csv] +common_love=-1,1 reply.csv的默认好感变化范围 +[ai] +@_react=True是否启用@对策 +model=调用的模型名称 +;model可填qingyunke或百度大模型(需要自己获取)。若使用百度模型,请填写role、API_Key、Secret_Key、memory +role=ai人设,支持[sender][intlove][time]变量 +API_Key= +Secret_Key= +memory=True是否启用记忆功能 +[lv] +enable=True是否启用好感等级机制 +;通用:\n为换行,[qq]为QQ号,[sender]为群名片,[love]为好感度,[intlove]为数值好感度,[bot]为bot名称 +;对于csv,[vary]为本次回复数值好感度变化 +之后的reply均为不同等级的 我的好感度 指令回复格式 +lv1=-999,-50 +lv1_reply= + + +lv2=-50,50 +lv2_reply= + + +lv3=50,200 +lv3_reply= +lv4=200,1000 +lv4_reply= + +lv5=1000,9999 +lv5_reply= + +``` +1.**Windows**
+ 下载最新的[release](https://github.com/hlfzsi/yirimirai_LoveYou/releases),解压,填写config.ini,编辑你的reply.csv,启动exe即可
+2.**Linux** +下载最新的[release](https://github.com/hlfzsi/yirimirai_LoveYou/releases),解压,填写config.ini,编辑你的reply.csv,尝试使用wine启动exe
+如无法启动,请尝试[Issues#1](https://github.com/hlfzsi/yirimirai_LoveYou/issues/1)中的方法
+欢迎提供Linux上的打包 +**** ## 项目指令 斜体为需输入的变量 ### 用户指令 **群聊** * 我的好感、我的好感度 * 好感排行 + * (v1.51)我的排名 + * (Unknown)好人榜 + * (v1.51)/clear:清理对话记忆 * 本群好感排行 + * (v1.50)/gtank:生成幻影坦克 * /code alias *YourCode* :设置QQ别名。使用被记录在./data/code_users.txt * /code love *YourCode* :设置文本好感。使用被记录在./data/code_users.txt - * v1.42加入/code pic *YourCode* :设置图片好感回复。使用被记录在./data/code_users.txt + * (v1.42)/code pic *YourCode* :设置图片好感回复。使用被记录在./data/code_users.txt ### 主人指令 **群聊** * /set(del) senior *QQ*:设置(取消)本群词库高管,其中*QQ*为高管QQ号 @@ -40,18 +104,18 @@ **私聊** * /encode alias *int_number*:生成QQ别名的code,其中*int_number*为生成数量。可在./data/alias_code.txt查看code * /encode love *int_number*:生成文本好感的code,其中*int_number*为生成数量。可在./data/love_code.txt查看code -* v1.42加入/encode pic *int_number*:生成文本好感的code,其中*int_number*为生成数量。可在./data/pic_code.txt查看code +* (v1.42)/encode pic *int_number*:生成文本好感的code,其中*int_number*为生成数量。可在./data/pic_code.txt查看code ### 词库指令 **高管指令** * /set(del) admin *QQ*:设置(取消)本群词库管理,其中*QQ*为管理QQ号 -* v1.42加入/(un)lock *行号*:解锁/锁定对应行号,支持列表,以空格分隔 +* (v1.42)/(un)lock *行号*:解锁/锁定对应行号,支持列表,以空格分隔 **管理指令** -* v1.42更新精确(模糊)问 *Question* *Answer*:为本群添加一组回复,请注意整个指令中第二个空格是*Question*和*Answer*的切分点 +* (v1.42更新)精确(模糊)问 *Question* *Answer*:为本群添加一组回复,请注意整个指令中第二个空格是*Question*和*Answer*的切分点 * 删除 *Question*:删除对应*Question*,其中*Question*的所有对应项均会被删除 -* v1.42加入查询 *Question*:返回所有对应项的行号 -* v1.42加入/dr *行号*:删除对应行号,支持列表,以空格分隔 -* v1.42加入/info *行号*:返回对应行号回复详细信息 +* (v1.42)查询 *Question*:返回所有对应项的行号 +* (v1.42)/dr *行号*:删除对应行号,支持列表,以空格分隔 +* (v1.42)/info *行号*:返回对应行号回复详细信息 **** ## 词库编辑 #### reply.csv @@ -67,7 +131,7 @@ * 好感范围:本行触发时,从随机范围内随机取一个整数值作为好感变化量。默认值为**config.ini**下common_love所对应的区间。特别地,你可以在回复中使用[vary]来指代好感变化量,这将使得变化量可见 * 触发范围:只有当触发者的好感在本范围内,本行才会触发。默认无范围 * 类型:可不填。1代表精准匹配,2代表模糊匹配,不填默认精准匹配。 -* [pic=' ']:发送图片。请将要发送的图片置于 ./data/pic/ 下。每条消息仅支持一张图片。只要填入文件名即可,包括后缀 +* [pic=]:发送图片。请将要发送的图片置于 ./data/pic/ 下。每条消息仅支持一张图片。只要填入文件名即可,包括后缀 * [cut]:回复切割。将一次回复切分为多次回复。使用本方法可实现一次触发可发送多张图片 * quick_RL行:本行可实现权重选择,使用较为复杂,详见**进阶使用** @@ -89,7 +153,7 @@ **群聊词库是全局词库的阉割** * 好感范围默认值为0,而非common_love * 不支持指令设置 好感范围 和 触发范围,尽管代码支持读取与运算 -* ~~不支持指令添加[pic=' '],尽管代码支持发送~~ 从v1.42开始,图片已默认支持 +* (**v1.42之前**)不支持指令添加[pic=],尽管代码支持发送 * 通过quick_RL方法设置的L值强制变更为0 * 模糊匹配的插件仍然是受到支持的 @@ -102,10 +166,9 @@ **好感度来源** * 词库 * 消息中包含bot_name或@bot时,程序会分析情感偏向并给出一个[-10,10]之间的整数值作为好感变化量 -* 特别地,bot有0.6%的概率进行群聊回复及好感运算 +* 特别地,bot有0.4%的概率进行群聊回复及好感运算 **CG** -这是一个真正可高度自定义的模块
仅当消息包含bot_name时进行判断
每个QQ每日最多触发一次判断,早上9点重置 * 仅支持发送图片,请将图片放置于./data/CG/下(.jpg or .png) @@ -142,7 +205,7 @@ 本项目提供ws方式获得用户好感度、变更用户好感度。
editor.py是一个使用例
要使用LoveYou的ws,请遵循以下简单的规范:
-你应当向LoveYou发送一个json,它的**内容**及**返回**按顺序如下 +你应当向LoveYou发送一个json,它的部分**内容**及**返回**按顺序如下 | type | qq | love | return | | :-: | :-: | :-: |:-: | | 这代表你要调用的函数 | 目标QQ | 好感变化 | 正常返回的格式 | @@ -150,4 +213,39 @@ editor.py是一个使用例
| change_love | Any | int | DONE |
如果调用失败,LoveYou会返回错误的原因。若调用成功而LoveYou内部函数执行失败,LoveYou会返回Fail
-LoveYou的默认ws端口为8686 \ No newline at end of file +LoveYou的默认ws端口为8686
+ +**** +## 基于本项目的Websockets进行开发 +简要的接口介绍(type+所需要的传入变量) +1. get_love : 获得对应QQ好感度
qq:QQ号
+2. change_love : 修改对应QQ好感度(加法)
qq:QQ号
love:变更好感度,要求可转换为int类型
+3. get_lv : 获得对应QQ好感等级
qq:QQ号
+4. get_rank : 获得对应QQ好感排名
qq:QQ号
+5. isAdmin : 检查QQ是否为LoveYou中注册过的特定群管理组成员
groupid:群号
qq:QQ号
+6. silence : 沉默/启用 LoveYou的词库
qq:True沉默或者False解除沉默
+7. love_score : 对文本进行情感分析,返回一个经过处理的好感变化值
text:需要分析的文本
+#### json示例 +变量的存在与否以及存在顺序都是严格的 +``` +{ + "type": "get_love", + "qq": "123456789" +} +``` +``` +{ + "type": "isAdmin", + "groupid":"123456789", + "qq":"123456789" +} +``` +#### 返回示例 +序号与接口介绍序号一一对应
其中,{ }内容为你需要的返回值,{ }在真实返回中不存在
如果调用错误,LoveYou会返回错误原因。若调用成功而LoveYou内部函数错误,会返回Fail +1. {int_love}|||{str_love}
str_love为int_love加上用户好感后缀
+2. DONE +3. {level}
1-5为正常返回结果
0代表好感超出好感等级范围且好感<0,6代表好感超出好感等级范围且好感>=0
若好感等级未启用,则返回-1
+4. {rank}|{total}
rank为用户排名,total为总排名数
+5. {admin?}
权限等级:high > common > False,其中,False代表无权限
+6. Success +7. {intlove}
返回经过处理的好感度变化值,但实际上这一变化值并没有作用于任何QQ \ No newline at end of file diff --git a/main.py b/main.py index b5e470d..9988631 100644 --- a/main.py +++ b/main.py @@ -36,7 +36,7 @@ import websockets # import shutil -py_version = 'v1.50' +py_version = 'v1.51' data_dir = './data/' db_path = os.path.join(data_dir, 'qq.db3') @@ -167,11 +167,16 @@ def loadconfig(): API_Key = config.get('ai', 'API_Key') Secret_Key = config.get('ai', 'Secret_Key') tank_enable = config.get('others', 'tank_enable') + memory = config.get('ai', 'memory') + if memory == 'True': + memory = True + else: + memory = False logger.info('config.ini第一部分已成功加载') - return bot_qq, verify_key, host, port, bot_name, baseline, rate, master, lv_enable, a, b, search_love, ws, react, ws_port, model, role, API_Key, Secret_Key, tank_enable + return bot_qq, verify_key, host, port, bot_name, baseline, rate, master, lv_enable, a, b, search_love, ws, react, ws_port, model, role, API_Key, Secret_Key, tank_enable, memory -bot_qq, verify_key, host, port, bot_name, baseline, rate, master, lv_enable, Ca, Cb, search_love_reply, ws, botreact, ws_port, model, role, API_Key, Secret_Key, tank_enable = loadconfig() +bot_qq, verify_key, host, port, bot_name, baseline, rate, master, lv_enable, Ca, Cb, search_love_reply, ws, botreact, ws_port, model, role, API_Key, Secret_Key, tank_enable, memory = loadconfig() # 初始化ai回复 if botreact != 'True' or model == 'qingyunke': del role, API_Key, Secret_Key @@ -206,6 +211,22 @@ def get_range(value): return None # 返回None表示不属于任何已知范围 +def ws_get_range(qq): + try: + love = read_love(qq) + try: + lv = get_range(int(love)) + except: + lv = -1 + if lv == None and love >= 0: + lv = 6 + elif lv == None and love < 0: + lv = 0 + return lv + except: + return 'Fail' + + def loadconfig_part2(): # 读取配置文件 config_path = os.path.join(os.getcwd(), "config.ini") @@ -296,12 +317,92 @@ def clear_group_not_exist(groupid:str)->None: ''' -async def baidu_ai(msg: str) -> str: +def chat_memory(qq: str, question: str, answer: str): + """处理用户对话 + + 如果answer为空,则只添加question并返回字符串.文件不保留. + + 如果answer非空,无return,保留修改 + + Args: + qq (str): 用户 + question (str): 用户消息 + answer (str): 回复消息 + """ + # 构造文件路径 + file_path = os.path.join('./data/memory', f'{qq}.json') + + # 确保目录存在 + os.makedirs(os.path.dirname(file_path), exist_ok=True) + + # 初始化聊天记录列表,如果文件不存在则为空列表 + try: + with open(file_path, 'r', encoding='utf-8') as file: + records = json.load(file) + except: + records = [] + + # 如果answer不是空字符串,则添加新的聊天记录 + if answer: # 检查answer是否为非空字符串 + records.append({"role": "user", "content": question}) + records.append({"role": "assistant", "content": answer}) + records_json = json.dumps(records, ensure_ascii=False, indent=4) + with open(file_path, 'w', encoding='utf-8') as file: + json.dump(records, file, ensure_ascii=False, indent=4) + return None + else: + records.append({"role": "user", "content": question}) + records_json = json.dumps(records, ensure_ascii=False, indent=4) + records_json = json.loads(records_json) + return records_json + + +def clear_memory(qq: str): + file_path = os.path.join('./data/memory', f'{qq}.json') + try: + os.remove(file_path) + except: + pass + + +def reduce_memory(qq: str): + file_path = f"./data/memory/{qq}.json" + with open(file_path, 'r', encoding='utf-8') as file: + data = json.load(file) + del data[:2] + with open(file_path, 'w', encoding='utf-8') as file: + json.dump(data, file, ensure_ascii=False, indent=4) + + +async def baidu_ai(msg: str, qq: str, intlove, name: str) -> str: ''' 通过百度模型获得ai回复 ''' - resp = qianfan.ChatCompletion().do(endpoint=model, - messages=[{"role": "user", "content": msg}], temperature=0.98, top_p=0.7, penalty_score=1, system=role, max_output_tokens=60) + intlove = str(intlove) + time = datetime.now() + time = time.strftime("%Y-%m-%d.%H:%M") + loacl_role = role + loacl_role = loacl_role.replace( + '[intlove]', intlove).replace('[sender]', name).replace('[time]', time) + if memory == True: + send_msg = chat_memory(qq, msg, '') + while len(send_msg) + len(loacl_role) >= 24000: + reduce_memory(qq) + send_msg = chat_memory(qq, msg, '') + resp = qianfan.ChatCompletion().do(model=model, + messages=send_msg, temperature=0.98, top_p=0.7, penalty_score=1, system=loacl_role) + try: + chat_memory(qq, msg, resp['result']) + if resp['need_clear_history'] == True or resp['need_clear_history'] == 'True': + clear_memory(qq) + logger.debug('清理用户记忆') + except: + pass + + elif memory == False: + resp = qianfan.ChatCompletion().do(model=model, + messages=[{"role": "user", "content": msg}], temperature=0.98, top_p=0.7, penalty_score=1, system=loacl_role) + try: return resp['result'] except: @@ -1146,8 +1247,6 @@ def is_m_in_range(row): except ValueError: # 如果无法转换为整数 return True - # 第四列是字符串形式的范围,如"(1, 5)" - # 或者第四列可能包含空值或无法转换为整数的字符串 valid_matches = matches.apply(is_m_in_range, axis=1) valid_matches = matches[valid_matches] @@ -1218,8 +1317,9 @@ def is_m_in_range(row): # 或者第四列可能包含空值或无法转换为整数的字符串 valid_matches = matches.apply(is_m_in_range, axis=1) valid_matches = matches[valid_matches] + if valid_matches.empty: + return None, None - # 如果没有找到匹配的行,返回None if valid_matches.empty: return None, None @@ -1333,6 +1433,36 @@ def read_love(qq): return 0 +def get_loverank(qq: str) -> Tuple[str, str]: + '''返回用户好感排名与整张表记录数''' + with sqlite3.connect(db_path) as conn: + cursor = conn.cursor() + + cursor.execute("SELECT COUNT(*) FROM qq_love") + total_records = cursor.fetchone()[0] + + cursor.execute(""" + SELECT RANK() OVER (ORDER BY love DESC) AS rn + FROM qq_love + WHERE QQ = ? + """, (qq,)) + rank_result = cursor.fetchone() + + if rank_result: + rank = rank_result[0] + return str(rank), str(total_records) + else: + return 'Unfound', str(total_records) + + +def ws_get_rank(qq): + try: + rank, total = get_loverank(str(qq)) + return f"{rank}|{total}" + except: + return "Fail" + + def read_love_only(qq): # 使用with语句确保连接在函数结束时被关闭 with sqlite3.connect(db_path) as conn: @@ -1551,7 +1681,7 @@ def lock_row(groupid: str, rows: list[str], type: int) -> None: if groupid in groups_df: df = groups_df[groupid] - # 遍历字符串列表并尝试锁定相应的行 + # 遍历字符串列表并尝试锁定相应的行 for row_str in rows: # 尝试将字符串转换为整数 @@ -1702,12 +1832,24 @@ def get_pic(url): new_image.save(buffered, format='PNG') encoded_image = buffered.getvalue() encoded_image = base64.b64encode(encoded_image) - # encoded_image = base64.b64encode(buffer.getvalue()).decode('utf-8') return encoded_image # elif type==1: #彩色图像,效果不好 # 技术尚不成熟,暂不添加 +def isSilence(qq): + try: + global silence + if qq == True or qq == "True": + silence = True + return 'Success' + else: + silence = False + return 'Success' + except: + return 'Fail' + + def mark_achieve(): '''用于标记已经处理的事件''' global isAchieve @@ -1723,7 +1865,8 @@ def mark_achieve(): ) inc = InterruptControl(bot) -isAchieve = False +isAchieve = False # 信号 +silence = False # 词库沉默 @bot.on(MessageEvent, priority=0) @@ -1737,7 +1880,7 @@ async def bhrkhrt(event: GroupMessage): # 词库功能实现 message = str(event.message_chain) # if message.startswith('/') or message.startswith('.') or message.startswith('*') or message.startswith('-') or message.startswith('查询 ') or message.startswith('模糊问 ') or message.startswith('精确问 ') or message.startswith('删除 '): # return None - if isAchieve == True: + if isAchieve == True or silence == True: return None qq = str(event.sender.id) if qq == bot_qq: @@ -1756,7 +1899,6 @@ async def bhrkhrt(event: GroupMessage): # 词库功能实现 # reply = reply.replace('RL', '') reply, love = RL_support(reply) logger.debug('RL '+reply) - if '[pos]' in reply: s = snownlp.SnowNLP(message) sentiment_score = s.sentiments @@ -1773,6 +1915,7 @@ async def bhrkhrt(event: GroupMessage): # 词库功能实现 return None else: reply = reply.replace('[nag]', '') + try: love = int(love) except: @@ -1821,11 +1964,10 @@ async def bhrkhrt(event: GroupMessage): # 词库功能实现 reply, love = RL_support(reply) love = 0 logger.debug('RL '+reply) - if '[pos]' in reply: s = snownlp.SnowNLP(message) sentiment_score = s.sentiments - if sentiment_score <= 0.7: + if sentiment_score <= 0.75: logger.debug('拒绝发送') return None else: @@ -1833,11 +1975,12 @@ async def bhrkhrt(event: GroupMessage): # 词库功能实现 if '[nag]' in reply: s = snownlp.SnowNLP(message) sentiment_score = s.sentiments - if sentiment_score >= 0.3: + if sentiment_score >= 0.25: logger.debug('拒绝发送') return None else: reply = reply.replace('[nag]', '') + try: love = int(love) except: @@ -1891,6 +2034,11 @@ def find_images(path, filename): if files: return os.path.basename(files[0]) return None + if msg == '/clear' and botreact == 'True': + clear_memory(qq) + await bot.send(event, '刚刚我们说什么了喵~') + mark_achieve() + logger.debug(f'{qq}记忆清除') if msg.startswith('/set senior '): if qq == master: msg = msg.replace('/set senior ', '') @@ -1919,6 +2067,8 @@ def find_images(path, filename): await bot.send(event, '成功取消高管喵~') logger.debug('取消'+msg+'为'+groupid+'高管') mark_achieve() + elif silence == True: + return None elif msg.startswith('删除 '): if qq == master or a != False: question = msg.replace('删除 ', '') @@ -2034,7 +2184,7 @@ async def sadxchjw(event: GroupMessage): qq = str(event.sender.id) int_love, str_love = get_both_love(qq) if str_love != '' or None: - if lv_enable == 'False': + if lv_enable != 'True': await bot.send(event, '你的好感度是:\n'+str_love+'\n————————\n(ˉ▽ ̄~) 切~~') mark_achieve() elif lv_enable == "True": @@ -2080,11 +2230,13 @@ async def sadxchjw(event: GroupMessage): else: await bot.send(event, bot_name+'很中意你\n'+str_love) mark_achieve() - else: - logger.error('enable参数填写错误,应为True或False') - logger.error('程序将在5秒后退出') - time.sleep(5) - sys.exit + elif str(event.message_chain) == '我的排名': + qq = str(event.sender.id) + name = event.sender.get_name() + rank, total = get_loverank(qq) + await bot.send(event, [At(int(qq)), f'\n{name}的好感排名为[{rank}/{total}]']) + logger.debug('完成个人排名') + mark_achieve() @bot.on(GroupMessage, priority=1) @@ -2402,32 +2554,40 @@ def del_face(text: str) -> str: # sentiment_score = float(s.sentiments) reply = None isSend = False + name = str(event.sender.get_name()) + qq = str(event.sender.id) + if memory != False: + intlove = read_love(qq) + else: + intlove = 0 if bot_name in message or At(bot.qq) in event.message_chain: isSend = True if At(bot.qq) in event.message_chain and botreact == 'True': s = snownlp.SnowNLP(message) sentiment_score = float(s.sentiments) a = new_msg_judge(message) - if a == True: - if sentiment_score <= 0.1 or model == 'qingyunke': - message = message.replace(bot_name, '菲菲') - reply = await qingyunke(message) - else: - reply = await baidu_ai(message) - qq = str(event.sender.id) - message = message.replace('菲菲', '') - love = love_score(message) - logger.debug('情感运算') - if love != 0: - updata_love(qq, love) - logger.debug(qq+'情感运算'+str(love)) - if reply != None: - reply = str(reply) - reply = reply.replace('菲菲', bot_name) - reply = del_face(reply) - await bot.send(event, reply, True) + # if a == True: + if sentiment_score <= 0.1 or model == 'qingyunke': + message = message.replace(bot_name, '菲菲') + reply = await qingyunke(message) else: + reply = await baidu_ai(message, qq, intlove, name) + message = message.replace('菲菲', '') + love = love_score(message) + logger.debug('情感运算') + if love != 0 and a == True: + updata_love(qq, love) + logger.debug(qq+'情感运算'+str(love)) + elif a == False: + updata_love(qq, -3) logger.debug('重复消息') + if reply != None: + reply = str(reply) + reply = reply.replace('菲菲', bot_name) + reply = del_face(reply) + await bot.send(event, reply, True) + # else: + # logger.debug('重复消息') mark_achieve() m = random.random() if m <= 0.004 and botreact == 'True' and isSend == False: @@ -2437,10 +2597,9 @@ def del_face(text: str) -> str: message = message.replace(bot_name, '菲菲') reply = await qingyunke(message) else: - reply = await baidu_ai(message) + reply = await baidu_ai(message, qq, intlove, name) s2 = SnowNLP(message) key = s2.keywords(1) - qq = str(event.sender.id) message = message.replace('菲菲', '') love = love_score(message) if love >= 5: @@ -2461,10 +2620,16 @@ def del_face(text: str) -> str: await bot.send(event, [At(int(qq)), ' '+reply]) mark_achieve() + # 函数注册表 function_registry = { "get_love": ws_load_love, # 需要qq - "change_love": ws_change_love # 需要qq和love + "change_love": ws_change_love, # 需要qq和love + "get_lv": ws_get_range, # 需要qq + 'get_rank': ws_get_rank, + "isAdmin": check_admin, + "silence": isSilence, + 'love_score': love_score } # 辅助函数,用于检查参数并调用函数 @@ -2522,7 +2687,7 @@ def real_start_server(): ws_thread.start() else: logger.info('ws服务被禁用') -del ws +del ws, ws_thread retry = False try: logger.info('Ciallo~(∠・ω< )⌒★')