feat: 支持在命令行操作bot

fix: 修复 windows 下 ctrl+c 不能退出程序的问题
This commit is contained in:
Soulter
2023-11-30 12:06:37 +08:00
parent d602041ad0
commit be1f8e7075
7 changed files with 134 additions and 85 deletions
+5
View File
@@ -50,6 +50,11 @@ class HelloWorldPlugin:
return True, tuple([True, "Hello World!!", "helloworld"])
else:
return False, None
else:
"""
其他平台处理逻辑
"""
return False, None
"""
帮助函数,当用户输入 plugin v 插件名称 时,会调用此函数,返回帮助信息
返回参数要求(必填)dict{
+109 -73
View File
@@ -96,28 +96,32 @@ client = None
# QQ群机器人
PLATFROM_QQBOT = 'qqbot'
# 配置
cc.init_attributes(["qq_forward_threshold"], 200)
cc.init_attributes(["qq_welcome"], "欢迎加入本群!\n欢迎给https://github.com/Soulter/QQChannelChatGPT项目一个Star😊~\n输入help查看帮助~\n")
cc.init_attributes(["bing_proxy"], "")
cc.init_attributes(["qq_pic_mode"], False)
cc.init_attributes(["rev_chatgpt_model"], "")
cc.init_attributes(["rev_chatgpt_plugin_ids"], [])
cc.init_attributes(["rev_chatgpt_PUID"], "")
cc.init_attributes(["rev_chatgpt_unverified_plugin_domains"], [])
cc.init_attributes(["gocq_host"], "127.0.0.1")
cc.init_attributes(["gocq_http_port"], 5700)
cc.init_attributes(["gocq_websocket_port"], 6700)
cc.init_attributes(["gocq_react_group"], True)
cc.init_attributes(["gocq_react_guild"], True)
cc.init_attributes(["gocq_react_friend"], True)
cc.init_attributes(["gocq_react_group_increase"], True)
cc.init_attributes(["gocq_qqchan_admin"], "")
cc.init_attributes(["other_admins"], [])
cc.init_attributes(["CHATGPT_BASE_URL"], "")
cc.init_attributes(["qqbot_appid"], "")
cc.init_attributes(["qqbot_secret"], "")
cc.init_attributes(["llm_env_prompt"], "> hint: 末尾根据内容和心情添加 1-2 个emoji")
# CLI
PLATFORM_CLI = 'cli'
# 加载默认配置
cc.init_attributes("qq_forward_threshold", 200)
cc.init_attributes("qq_welcome", "欢迎加入本群!\n欢迎给https://github.com/Soulter/QQChannelChatGPT项目一个Star😊~\n输入help查看帮助~\n")
cc.init_attributes("bing_proxy", "")
cc.init_attributes("qq_pic_mode", False)
cc.init_attributes("rev_chatgpt_model", "")
cc.init_attributes("rev_chatgpt_plugin_ids", [])
cc.init_attributes("rev_chatgpt_PUID", "")
cc.init_attributes("rev_chatgpt_unverified_plugin_domains", [])
cc.init_attributes("gocq_host", "127.0.0.1")
cc.init_attributes("gocq_http_port", 5700)
cc.init_attributes("gocq_websocket_port", 6700)
cc.init_attributes("gocq_react_group", True)
cc.init_attributes("gocq_react_guild", True)
cc.init_attributes("gocq_react_friend", True)
cc.init_attributes("gocq_react_group_increase", True)
cc.init_attributes("gocq_qqchan_admin", "")
cc.init_attributes("other_admins", [])
cc.init_attributes("CHATGPT_BASE_URL", "")
cc.init_attributes("qqbot_appid", "")
cc.init_attributes("qqbot_secret", "")
cc.init_attributes("llm_env_prompt", "> hint: 末尾根据内容和心情添加 1-2 个emoji")
cc.init_attributes("default_personality_name", "")
# cc.init_attributes(["qq_forward_mode"], False)
# QQ机器人
@@ -219,6 +223,9 @@ def initBot(cfg, prov):
global frequency_count, frequency_time, announcement, direct_message_mode, version
global keywords, _global_object
_event_loop = asyncio.new_event_loop()
asyncio.set_event_loop(_event_loop)
# 初始化 global_object
_global_object = GlobalObject()
_global_object.base_config = cfg
@@ -374,7 +381,7 @@ def initBot(cfg, prov):
qqbot_loop = asyncio.new_event_loop()
if cc.get("qqbot_appid", '') != '' and cc.get("qqbot_secret", '') != '':
gu.log("- 启用QQ群机器人 -", gu.LEVEL_INFO)
thread_inst = threading.Thread(target=run_qqbot, args=(qqbot_loop, qq_bot,), daemon=False)
thread_inst = threading.Thread(target=run_qqbot, args=(qqbot_loop, qq_bot,), daemon=True)
thread_inst.start()
@@ -386,7 +393,7 @@ def initBot(cfg, prov):
global gocq_app, gocq_loop
gocq_loop = asyncio.new_event_loop()
gocq_bot = QQ(True, cc, gocq_loop)
thread_inst = threading.Thread(target=run_gocq_bot, args=(gocq_loop, gocq_bot, gocq_app), daemon=False)
thread_inst = threading.Thread(target=run_gocq_bot, args=(gocq_loop, gocq_bot, gocq_app), daemon=True)
thread_inst.start()
else:
gocq_bot = QQ(False)
@@ -404,7 +411,7 @@ def initBot(cfg, prov):
qqchannel_bot = QQChan()
qqchan_loop = asyncio.new_event_loop()
_global_object.platform_qqchan = qqchannel_bot
thread_inst = threading.Thread(target=run_qqchan_bot, args=(cfg, qqchan_loop, qqchannel_bot), daemon=False)
thread_inst = threading.Thread(target=run_qqchan_bot, args=(cfg, qqchan_loop, qqchannel_bot), daemon=True)
thread_inst.start()
# thread.join()
@@ -412,7 +419,31 @@ def initBot(cfg, prov):
input("[System-Error] 没有启用/成功启用任何机器人,程序退出")
exit()
thread_inst.join()
gu.log("🎉 项目启动完成。")
# thread_inst.join()
asyncio.get_event_loop().run_until_complete(cli())
async def cli():
time.sleep(1)
while True:
prompt = input(">>> ")
if prompt == "":
continue
ngm = NakuruGuildMessage()
ngm.channel_id = 6180
ngm.user_id = 6180
ngm.message = [Plain(prompt)]
ngm.type = "GuildMessage"
ngm.self_id = 6180
ngm.self_tiny_id = 6180
ngm.guild_id = 6180
ngm.sender = NakuruGuildMember()
ngm.sender.tiny_id = 6180
ngm.sender.user_id = 6180
ngm.sender.nickname = "CLI"
ngm.sender.role = 0
await oper_msg(ngm, True, PLATFORM_CLI)
'''
运行QQ频道机器人
@@ -443,9 +474,12 @@ def run_qqchan_bot(cfg, loop, qqchannel_bot: QQChan):
def run_gocq_bot(loop, gocq_bot, gocq_app):
asyncio.set_event_loop(loop)
gu.log("正在检查本地GO-CQHTTP连接...端口5700, 6700", tag="QQ")
noticed = False
while True:
if not gu.port_checker(5700, cc.get("gocq_host", "127.0.0.1")) or not gu.port_checker(6700, cc.get("gocq_host", "127.0.0.1")):
gu.log("与GO-CQHTTP通信失败, 请检查GO-CQHTTP是否启动并正确配置。5秒后自动重试。", gu.LEVEL_CRITICAL, tag="QQ")
if not noticed:
noticed = True
gu.log("与GO-CQHTTP通信失败, 请检查GO-CQHTTP是否启动并正确配置。程序会每隔 5s 自动重试。", gu.LEVEL_CRITICAL, tag="QQ")
time.sleep(5)
else:
gu.log("检查完毕,未发现问题。", tag="QQ")
@@ -509,6 +543,8 @@ async def send_message(platform, message, res, session_id = None):
message_chain = MessageChain()
message_chain.parse_from_nakuru(res)
await qq_bot.send(message, message_chain)
if platform == PLATFORM_CLI:
print(res)
async def oper_msg(message: Union[GroupMessage, FriendMessage, GuildMessage, NakuruGuildMessage],
group: bool=False,
@@ -533,59 +569,59 @@ async def oper_msg(message: Union[GroupMessage, FriendMessage, GuildMessage, Nak
with_tag = False # 是否带有昵称
if platform == PLATFORM_QQCHAN or platform == PLATFROM_QQBOT:
if platform == PLATFORM_QQCHAN or platform == PLATFROM_QQBOT or platform == PLATFORM_CLI:
with_tag = True
if platform == PLATFORM_GOCQ or platform == PLATFORM_QQCHAN or platform == PLATFROM_QQBOT:
_len = 0
for i in message.message:
if isinstance(i, Plain) or isinstance(i, PlainText):
qq_msg += str(i.text).strip()
if isinstance(i, At):
if message.type == "GuildMessage":
if i.qq == message.user_id or i.qq == message.self_tiny_id:
with_tag = True
if message.type == "FriendMessage":
if i.qq == message.self_id:
with_tag = True
if message.type == "GroupMessage":
if i.qq == message.self_id:
with_tag = True
for i in _global_object.nick:
if i != '' and qq_msg.startswith(i):
_len = len(i)
with_tag = True
break
qq_msg = qq_msg[_len:].strip()
gu.log(f"收到消息:{qq_msg}", gu.LEVEL_INFO, tag="QQ")
user_id = message.user_id
if group:
# 适配GO-CQHTTP的频道功能
_len = 0
for i in message.message:
if isinstance(i, Plain) or isinstance(i, PlainText):
qq_msg += str(i.text).strip()
if isinstance(i, At):
if message.type == "GuildMessage":
session_id = message.channel_id
else:
session_id = message.group_id
else:
if i.qq == message.user_id or i.qq == message.self_tiny_id:
with_tag = True
if message.type == "FriendMessage":
if i.qq == message.self_id:
with_tag = True
if message.type == "GroupMessage":
if i.qq == message.self_id:
with_tag = True
for i in _global_object.nick:
if i != '' and qq_msg.startswith(i):
_len = len(i)
with_tag = True
session_id = message.user_id
role = "member"
break
qq_msg = qq_msg[_len:].strip()
gu.log(f"收到消息:{qq_msg}", gu.LEVEL_INFO, tag="QQ")
user_id = message.user_id
if group:
# 适配GO-CQHTTP的频道功能
if message.type == "GuildMessage":
sender_id = str(message.sender.tiny_id)
session_id = message.channel_id
else:
sender_id = str(message.sender.user_id)
if sender_id == _global_object.admin_qq or \
sender_id == _global_object.admin_qqchan or \
sender_id in cc.get("other_admins", []) or \
sender_id == cc.get("gocq_qqchan_admin", ""):
# gu.log("检测到管理员身份", gu.LEVEL_INFO, tag="GOCQ")
role = "admin"
if _global_object.uniqueSession:
# 独立会话时,一个用户一个session
session_id = sender_id
session_id = message.group_id
else:
with_tag = True
session_id = message.user_id
if message.type == "GuildMessage":
sender_id = str(message.sender.tiny_id)
else:
sender_id = str(message.sender.user_id)
if sender_id == _global_object.admin_qq or \
sender_id == _global_object.admin_qqchan or \
sender_id in cc.get("other_admins", []) or \
sender_id == cc.get("gocq_qqchan_admin", "") or \
platform == PLATFORM_CLI:
role = "admin"
if _global_object.uniqueSession:
# 独立会话时,一个用户一个 session
session_id = sender_id
if qq_msg == "":
await send_message(platform, message, f"Hi~", session_id=session_id)
+5 -1
View File
@@ -2,6 +2,7 @@ import os, sys
from pip._internal import main as pipmain
import warnings
import traceback
import threading
warnings.filterwarnings("ignore")
abs_path = os.path.dirname(os.path.realpath(sys.argv[0])) + '/'
@@ -128,4 +129,7 @@ if __name__ == "__main__":
except BaseException as e:
print(e)
print(f"[System-err] Replit Web保活服务启动失败:{str(e)}")
main()
t = threading.Thread(target=main, daemon=False)
t.start()
t.join()
-2
View File
@@ -126,8 +126,6 @@ class Command:
fail_rec = ""
if plugins is None:
return False, "未找到任何插件模块"
print(plugins)
for plugin in plugins:
try:
+1 -1
View File
@@ -35,7 +35,7 @@ class ProviderOpenAIOfficial(Provider):
self.api_base = None
if 'api_base' in cfg and cfg['api_base'] != 'none' and cfg['api_base'] != '':
self.api_base = cfg['api_base']
print(f"设置 api_base 为: {self.api_base}")
gu.log(f"设置 api_base 为: {self.api_base}")
# openai client
self.client = OpenAI(
api_key=self.key_list[0],
+3 -3
View File
@@ -1,15 +1,15 @@
from model.provider.provider import Provider
# from EdgeGPT import Chatbot, ConversationStyle
from EdgeGPT import Chatbot, ConversationStyle
import json
import os
from util import general_utils as gu
from util.cmd_config import CmdConfig as cc
import time
from EdgeGPT.EdgeUtils import Query, Cookie
from EdgeGPT.EdgeGPT import Chatbot as EdgeChatbot, ConversationStyle, NotAllowedToAccess
class ProviderRevEdgeGPT(Provider):
def __init__(self):
raise Exception("Bing 逆向已停止维护,不可用,请使用 ChatGPT 官方 API。")
self.busy = False
self.wait_stack = []
with open('./cookies.json', 'r') as f:
+11 -5
View File
@@ -1,5 +1,6 @@
import os
import json
from typing import Union
cpath = "cmd_config.json"
@@ -38,7 +39,7 @@ class CmdConfig():
f.flush()
@staticmethod
def init_attributes(keys: list, init_val = ""):
def init_attributes(key: Union[str, list], init_val = ""):
check_exist()
conf_str = ''
with open(cpath, "r", encoding="utf-8-sig") as f:
@@ -47,10 +48,15 @@ class CmdConfig():
conf_str = conf_str.encode('utf8')[3:].decode('utf8')
d = json.loads(conf_str)
_tag = False
for k in keys:
if k not in d:
d[k] = init_val
_tag = True
if isinstance(key, str):
d[key] = init_val
_tag = True
elif isinstance(key, list):
for k in key:
if k not in d:
d[k] = init_val
_tag = True
if _tag:
with open(cpath, "w", encoding="utf-8-sig") as f:
json.dump(d, f, indent=4, ensure_ascii=False)