mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-07-20 21:57:14 +08:00
feat: add installp/uninstallp command
This commit is contained in:
15
common/package_manager.py
Normal file
15
common/package_manager.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import pip
|
||||||
|
|
||||||
|
def install(package):
|
||||||
|
pip.main(['install', package])
|
||||||
|
|
||||||
|
def install_requirements(file):
|
||||||
|
pip.main(['install', '-r', file, "--upgrade"])
|
||||||
|
|
||||||
|
def check_dulwich():
|
||||||
|
try:
|
||||||
|
import dulwich
|
||||||
|
return
|
||||||
|
except ImportError:
|
||||||
|
install('dulwich')
|
||||||
|
raise ImportError("Unable to import dulwich")
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .banwords import *
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .bdunit import *
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .dungeon import *
|
||||||
1
plugins/finish/__init__.py
Normal file
1
plugins/finish/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .finish import *
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .godcmd import *
|
||||||
@@ -37,10 +37,10 @@ COMMANDS = {
|
|||||||
"alias": ["reset_openai_api_key"],
|
"alias": ["reset_openai_api_key"],
|
||||||
"desc": "重置为默认的api_key",
|
"desc": "重置为默认的api_key",
|
||||||
},
|
},
|
||||||
# "id": {
|
"id": {
|
||||||
# "alias": ["id", "用户"],
|
"alias": ["id", "用户"],
|
||||||
# "desc": "获取用户id", #目前无实际意义
|
"desc": "获取用户id", # wechaty和wechatmp的用户id不会变化,可用于绑定管理员
|
||||||
# },
|
},
|
||||||
"reset": {
|
"reset": {
|
||||||
"alias": ["reset", "重置会话"],
|
"alias": ["reset", "重置会话"],
|
||||||
"desc": "重置会话",
|
"desc": "重置会话",
|
||||||
@@ -92,6 +92,16 @@ ADMIN_COMMANDS = {
|
|||||||
"args": ["插件名"],
|
"args": ["插件名"],
|
||||||
"desc": "禁用指定插件",
|
"desc": "禁用指定插件",
|
||||||
},
|
},
|
||||||
|
"installp": {
|
||||||
|
"alias": ["installp", "安装插件"],
|
||||||
|
"args": ["仓库地址或插件名"],
|
||||||
|
"desc": "安装指定插件",
|
||||||
|
},
|
||||||
|
"uninstallp": {
|
||||||
|
"alias": ["uninstallp", "卸载插件"],
|
||||||
|
"args": ["插件名"],
|
||||||
|
"desc": "卸载指定插件",
|
||||||
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"alias": ["debug", "调试模式", "DEBUG"],
|
"alias": ["debug", "调试模式", "DEBUG"],
|
||||||
"desc": "开启机器调试日志",
|
"desc": "开启机器调试日志",
|
||||||
@@ -103,7 +113,9 @@ def get_help_text(isadmin, isgroup):
|
|||||||
for cmd, info in COMMANDS.items():
|
for cmd, info in COMMANDS.items():
|
||||||
if cmd=="auth": #不提示认证指令
|
if cmd=="auth": #不提示认证指令
|
||||||
continue
|
continue
|
||||||
alias=["#"+a for a in info['alias']]
|
if cmd=="id" and conf().get("channel_type","wx") not in ["wxy","wechatmp"]:
|
||||||
|
continue
|
||||||
|
alias=["#"+a for a in info['alias'][:1]]
|
||||||
help_text += f"{','.join(alias)} "
|
help_text += f"{','.join(alias)} "
|
||||||
if 'args' in info:
|
if 'args' in info:
|
||||||
args=[a for a in info['args']]
|
args=[a for a in info['args']]
|
||||||
@@ -122,7 +134,7 @@ def get_help_text(isadmin, isgroup):
|
|||||||
if ADMIN_COMMANDS and isadmin:
|
if ADMIN_COMMANDS and isadmin:
|
||||||
help_text += "\n\n管理员指令:\n"
|
help_text += "\n\n管理员指令:\n"
|
||||||
for cmd, info in ADMIN_COMMANDS.items():
|
for cmd, info in ADMIN_COMMANDS.items():
|
||||||
alias=["#"+a for a in info['alias']]
|
alias=["#"+a for a in info['alias'][:1]]
|
||||||
help_text += f"{','.join(alias)} "
|
help_text += f"{','.join(alias)} "
|
||||||
if 'args' in info:
|
if 'args' in info:
|
||||||
args=[a for a in info['args']]
|
args=[a for a in info['args']]
|
||||||
@@ -208,6 +220,8 @@ class Godcmd(Plugin):
|
|||||||
break
|
break
|
||||||
if not ok:
|
if not ok:
|
||||||
result = "插件不存在或未启用"
|
result = "插件不存在或未启用"
|
||||||
|
elif cmd == "id":
|
||||||
|
ok, result = True, user
|
||||||
elif cmd == "set_openai_api_key":
|
elif cmd == "set_openai_api_key":
|
||||||
if len(args) == 1:
|
if len(args) == 1:
|
||||||
user_data = conf().get_user_data(user)
|
user_data = conf().get_user_data(user)
|
||||||
@@ -310,7 +324,16 @@ class Godcmd(Plugin):
|
|||||||
result = "插件已禁用"
|
result = "插件已禁用"
|
||||||
else:
|
else:
|
||||||
result = "插件不存在"
|
result = "插件不存在"
|
||||||
|
elif cmd == "installp":
|
||||||
|
if len(args) != 1:
|
||||||
|
ok, result = False, "请提供插件名或.git结尾的仓库地址"
|
||||||
|
else:
|
||||||
|
ok, result = PluginManager().install_plugin(args[0])
|
||||||
|
elif cmd == "uninstallp":
|
||||||
|
if len(args) != 1:
|
||||||
|
ok, result = False, "请提供插件名"
|
||||||
|
else:
|
||||||
|
ok, result = PluginManager().uninstall_plugin(args[0])
|
||||||
logger.debug("[Godcmd] admin command: %s by %s" % (cmd, user))
|
logger.debug("[Godcmd] admin command: %s by %s" % (cmd, user))
|
||||||
else:
|
else:
|
||||||
ok, result = False, "需要管理员权限才能执行该指令"
|
ok, result = False, "需要管理员权限才能执行该指令"
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
from .hello import *
|
||||||
@@ -17,6 +17,7 @@ class PluginManager:
|
|||||||
self.listening_plugins = {}
|
self.listening_plugins = {}
|
||||||
self.instances = {}
|
self.instances = {}
|
||||||
self.pconf = {}
|
self.pconf = {}
|
||||||
|
self.current_plugin_path = None
|
||||||
|
|
||||||
def register(self, name: str, desire_priority: int = 0, **kwargs):
|
def register(self, name: str, desire_priority: int = 0, **kwargs):
|
||||||
def wrapper(plugincls):
|
def wrapper(plugincls):
|
||||||
@@ -24,12 +25,13 @@ class PluginManager:
|
|||||||
plugincls.priority = desire_priority
|
plugincls.priority = desire_priority
|
||||||
plugincls.desc = kwargs.get('desc')
|
plugincls.desc = kwargs.get('desc')
|
||||||
plugincls.author = kwargs.get('author')
|
plugincls.author = kwargs.get('author')
|
||||||
|
plugincls.path = self.current_plugin_path
|
||||||
plugincls.version = kwargs.get('version') if kwargs.get('version') != None else "1.0"
|
plugincls.version = kwargs.get('version') if kwargs.get('version') != None else "1.0"
|
||||||
plugincls.namecn = kwargs.get('namecn') if kwargs.get('namecn') != None else name
|
plugincls.namecn = kwargs.get('namecn') if kwargs.get('namecn') != None else name
|
||||||
plugincls.hidden = kwargs.get('hidden') if kwargs.get('hidden') != None else False
|
plugincls.hidden = kwargs.get('hidden') if kwargs.get('hidden') != None else False
|
||||||
plugincls.enabled = True
|
plugincls.enabled = True
|
||||||
self.plugins[name.upper()] = plugincls
|
self.plugins[name.upper()] = plugincls
|
||||||
logger.info("Plugin %s_v%s registered" % (name, plugincls.version))
|
logger.info("Plugin %s_v%s registered, path=%s" % (name, plugincls.version, plugincls.path))
|
||||||
return plugincls
|
return plugincls
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
@@ -59,12 +61,13 @@ class PluginManager:
|
|||||||
for plugin_name in os.listdir(plugins_dir):
|
for plugin_name in os.listdir(plugins_dir):
|
||||||
plugin_path = os.path.join(plugins_dir, plugin_name)
|
plugin_path = os.path.join(plugins_dir, plugin_name)
|
||||||
if os.path.isdir(plugin_path):
|
if os.path.isdir(plugin_path):
|
||||||
# 判断插件是否包含同名.py文件
|
# 判断插件是否包含同名__init__.py文件
|
||||||
main_module_path = os.path.join(plugin_path, plugin_name+".py")
|
main_module_path = os.path.join(plugin_path,"__init__.py")
|
||||||
if os.path.isfile(main_module_path):
|
if os.path.isfile(main_module_path):
|
||||||
# 导入插件
|
# 导入插件
|
||||||
import_path = "plugins.{}.{}".format(plugin_name, plugin_name)
|
import_path = "plugins.{}".format(plugin_name)
|
||||||
try:
|
try:
|
||||||
|
self.current_plugin_path = plugin_path
|
||||||
main_module = importlib.import_module(import_path)
|
main_module = importlib.import_module(import_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn("Failed to import plugin %s: %s" % (plugin_name, e))
|
logger.warn("Failed to import plugin %s: %s" % (plugin_name, e))
|
||||||
@@ -179,4 +182,59 @@ class PluginManager:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def list_plugins(self):
|
def list_plugins(self):
|
||||||
return self.plugins
|
return self.plugins
|
||||||
|
|
||||||
|
def install_plugin(self, repo:str):
|
||||||
|
try:
|
||||||
|
import common.package_manager as pkgmgr
|
||||||
|
pkgmgr.check_dulwich()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Failed to install plugin, {}".format(e))
|
||||||
|
return False, "无法导入dulwich,安装插件失败"
|
||||||
|
import re
|
||||||
|
from dulwich import porcelain
|
||||||
|
|
||||||
|
logger.info("clone git repo: {}".format(repo))
|
||||||
|
|
||||||
|
match = re.match(r"^(https?:\/\/|git@)([^\/:]+)[\/:]([^\/:]+)\/(.+).git$", repo)
|
||||||
|
|
||||||
|
if not match:
|
||||||
|
try:
|
||||||
|
with open("./plugins/source.json","r") as f:
|
||||||
|
source = json.load(f)
|
||||||
|
if repo in source["repo"]:
|
||||||
|
repo = source["repo"][repo]["url"]
|
||||||
|
match = re.match(r"^(https?:\/\/|git@)([^\/:]+)[\/:]([^\/:]+)\/(.+).git$", repo)
|
||||||
|
if not match:
|
||||||
|
return False, "source中的仓库地址不合法"
|
||||||
|
else:
|
||||||
|
return False, "仓库地址不合法"
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Failed to install plugin, {}".format(e))
|
||||||
|
return False, "安装插件失败"
|
||||||
|
dirname = os.path.join("./plugins",match.group(4))
|
||||||
|
try:
|
||||||
|
repo = porcelain.clone(repo, dirname, checkout=True)
|
||||||
|
if os.path.exists(os.path.join(dirname,"requirements.txt")):
|
||||||
|
logger.info("detect requirements.txt,installing...")
|
||||||
|
pkgmgr.install_requirements(os.path.join(dirname,"requirements.txt"))
|
||||||
|
return True, "安装插件成功,请扫描插件或重启程序"
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Failed to install plugin, {}".format(e))
|
||||||
|
return False, "安装插件失败"
|
||||||
|
|
||||||
|
def uninstall_plugin(self, name:str):
|
||||||
|
name = name.upper()
|
||||||
|
if name not in self.plugins:
|
||||||
|
return False, "插件不存在"
|
||||||
|
if name in self.instances:
|
||||||
|
self.disable_plugin(name)
|
||||||
|
dirname = self.plugins[name].path
|
||||||
|
try:
|
||||||
|
import shutil
|
||||||
|
shutil.rmtree(dirname)
|
||||||
|
del self.plugins[name]
|
||||||
|
return True, "卸载插件成功"
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Failed to uninstall plugin, {}".format(e))
|
||||||
|
return False, "卸载插件失败"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .role import *
|
||||||
7
plugins/source.json
Normal file
7
plugins/source.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"repo": {
|
||||||
|
"sdwebui": {
|
||||||
|
"url": "https://github.com/lanvent/plugin_sdwebui.git"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .tool import *
|
||||||
@@ -8,6 +8,9 @@ pyttsx3>=2.90 # pytsx text to speech
|
|||||||
baidu_aip>=4.16.10 # baidu voice
|
baidu_aip>=4.16.10 # baidu voice
|
||||||
# azure-cognitiveservices-speech # azure voice
|
# azure-cognitiveservices-speech # azure voice
|
||||||
|
|
||||||
|
#install plugin
|
||||||
|
dulwich
|
||||||
|
|
||||||
# wechaty
|
# wechaty
|
||||||
wechaty>=0.10.7
|
wechaty>=0.10.7
|
||||||
wechaty_puppet>=0.4.23
|
wechaty_puppet>=0.4.23
|
||||||
|
|||||||
Reference in New Issue
Block a user