perf: 优化项目更新逻辑

This commit is contained in:
Soulter
2024-02-06 17:45:02 +08:00
parent 680593d636
commit e14dece206
5 changed files with 164 additions and 82 deletions
+1
View File
@@ -7,3 +7,4 @@ configs/config.yaml
**/.DS_Store
temp
cmd_config.json
addons/plugins/
+21 -66
View File
@@ -14,6 +14,7 @@ import json
import util.plugin_util as putil
from util.cmd_config import CmdConfig as cc
from util.general_utils import Logger
import util.updator
from nakuru.entities.components import (
Plain,
Image
@@ -112,8 +113,8 @@ class Command:
elif platform == PLATFORM_GOCQ:
user_id = str(message_obj.user_id)
return True, f"你的ID{user_id}", "plugin"
return True, f"在此平台上的ID{user_id}", "plugin"
def get_new_conf(self, message, role):
if role != "admin":
return False, f"你的身份组{role}没有权限使用此指令。", "newconf"
@@ -200,14 +201,12 @@ class Command:
return {
"help": "帮助",
"keyword": "设置关键词/关键指令回复",
"update": "更新面板",
"update latest": "更新到最新版本",
"update r": "重启机器人",
"reset": "重置会话",
"update": "更新项目",
"nick": "设置机器人昵称",
"plugin": "插件安装、卸载和重载",
"web on/off": "启动或关闭网页搜索能力",
"/gpt": "切换到OpenAI ChatGPT API",
"web on/off": "LLM 网页搜索能力",
"reset": "重置 LLM 对话",
"/gpt": "切换到 OpenAI 官方接口",
"/revgpt": "切换到网页版ChatGPT",
}
@@ -238,8 +237,10 @@ class Command:
finally:
return msg
# 接受可变参数
def command_start_with(self, message: str, *args):
'''
当消息以指定的指令开头时返回True
'''
for arg in args:
if message.startswith(arg) or message.startswith('/'+arg):
return True
@@ -273,8 +274,7 @@ class Command:
3. keyword d hi
删除hi关键词的回复
4. keyword hi <图片>
当发送hi时会回复图片
""", "keyword"
当发送hi时会回复图片""", "keyword"
del_mode = False
if l[1] == "d":
@@ -321,68 +321,23 @@ class Command:
if role != "admin":
return True, "你没有权限使用该指令", "keyword"
l = message.split(" ")
try:
repo = Repo()
except git.exc.InvalidGitRepositoryError:
try:
repo = Repo(path="QQChannelChatGPT")
except git.exc.InvalidGitRepositoryError:
repo = Repo(path="AstrBot")
if len(l) == 1:
curr_branch = repo.active_branch.name
# 得到本地版本号和最新版本号
now_commit = repo.head.commit
# 得到远程3条commit列表, 包含commit信息
origin = repo.remotes.origin
origin.fetch()
commits = list(repo.iter_commits(curr_branch, max_count=3))
commits_log = ''
index = 1
for commit in commits:
if commit.message.endswith("\n"):
commits_log += f"[{index}] {commit.message}-----------\n"
else:
commits_log += f"[{index}] {commit.message}\n-----------\n"
index+=1
# remote_commit_hash = origin.refs.master.commit.hexsha[:6]
remote_commit_hash = origin.refs[curr_branch].commit.hexsha[:6]
return True, f"当前分支: {curr_branch}\n当前版本: {now_commit.hexsha[:6]}\n最新版本: {remote_commit_hash}\n\n3条commit(非最新):\n{str(commits_log)}\nTips:\n1. 使用 update latest 更新至最新版本;\n2. 使用 update checkout <分支名> 切换代码分支。", "update"
try:
update_info = util.updator.check_update()
update_info += "\nTips:\n输入「update latest」更新到最新版本\n输入「update r」重启机器人\n"
return True, update_info, "update"
except BaseException as e:
return False, "检查更新失败: "+str(e), "update"
else:
if l[1] == "latest":
try:
curr_branch = repo.active_branch.name
origin = repo.remotes.origin
repo.git.pull("origin", curr_branch, "-f")
commits = list(repo.iter_commits(curr_branch, max_count=1))
commit_log = commits[0].message
tag = "update"
if len(l) == 3 and l[2] == "r":
tag = "update latest r"
return True, f"更新成功。新版本内容: \n{commit_log}\nps:重启后生效。输入update r重启(重启指令不返回任何确认信息)。", tag
release_data = util.updator.request_release_info()
util.updator.update_project(release_data)
return True, "更新成功,重启生效。可输入「update r」重启", "update"
except BaseException as e:
return False, "更新失败: "+str(e), "update"
if l[1] == "r":
py = sys.executable
os.execl(py, py, *sys.argv)
if l[1] == 'checkout':
# 切换分支
if len(l) < 3:
return False, "请提供分支名,如 /update checkout dev_dashboard", "update"
try:
origin = repo.remotes.origin
origin.fetch()
repo.git.checkout(l[2])
# 更新分支(强制)
repo.git.pull("origin", l[2], "-f")
# 获得最新的 commit
commits = list(repo.iter_commits(max_count=1))
commit_log = commits[0].message
return True, f"切换分支成功,机器人将在 5 秒内重新启动以应用新的功能。\n当前分支: {l[2]}\n此分支最近更新: \n{commit_log}", "update latest r"
except BaseException as e:
return False, f"切换分支失败。原因: {str(e)}", "update"
util.updator._reboot()
def reset(self):
return False
+10 -15
View File
@@ -68,7 +68,7 @@ class CommandOpenAIOfficial(Command):
def reset(self, session_id: str, message: str = "reset"):
if self.provider is None:
return False, "未启OpenAI ChatGPT语言模型.", "reset"
return False, "未启OpenAI 官方 API", "reset"
l = message.split(" ")
if len(l) == 1:
self.provider.forget(session_id)
@@ -81,7 +81,7 @@ class CommandOpenAIOfficial(Command):
def his(self, message: str, session_id: str):
if self.provider is None:
return False, "未启OpenAI ChatGPT语言模型.", "his"
return False, "未启OpenAI 官方 API", "his"
#分页,每页5条
msg = ''
size_per_page = 3
@@ -99,17 +99,17 @@ class CommandOpenAIOfficial(Command):
def token(self, session_id: str):
if self.provider is None:
return False, "未启OpenAI ChatGPT语言模型.", "token"
return False, "未启OpenAI 官方 API", "token"
return True, f"会话的token数: {self.provider.get_user_usage_tokens(self.provider.session_dict[session_id])}\n系统最大缓存token数: {self.provider.max_tokens}", "token"
def gpt(self):
if self.provider is None:
return False, "未启OpenAI ChatGPT语言模型.", "gpt"
return False, "未启OpenAI 官方 API", "gpt"
return True, f"OpenAI GPT配置:\n {self.provider.chatGPT_configs}", "gpt"
def status(self):
if self.provider is None:
return False, "未启OpenAI ChatGPT语言模型.", "status"
return False, "未启OpenAI 官方 API", "status"
chatgpt_cfg_str = ""
key_stat = self.provider.get_key_stat()
index = 1
@@ -131,7 +131,7 @@ class CommandOpenAIOfficial(Command):
def key(self, message: str):
if self.provider is None:
return False, "未启OpenAI ChatGPT语言模型.", "reset"
return False, "未启OpenAI 官方 API", "reset"
l = message.split(" ")
if len(l) == 1:
msg = "感谢您赞助key,key为官方API使用,请以以下格式赞助:\n/key xxxxx"
@@ -177,14 +177,14 @@ class CommandOpenAIOfficial(Command):
def unset(self, session_id: str):
if self.provider is None:
return False, "未启OpenAI ChatGPT语言模型.", "unset"
return False, "未启OpenAI 官方 API", "unset"
self.provider.curr_personality = {}
self.provider.forget(session_id)
return True, "已清除人格并重置历史记录。", "unset"
def set(self, message: str, session_id: str):
if self.provider is None:
return False, "未启OpenAI ChatGPT语言模型.", "set"
return False, "未启OpenAI 官方 API", "set"
l = message.split(" ")
if len(l) == 1:
return True, f"【人格文本由PlexPt开源项目awesome-chatgpt-pr \
@@ -256,7 +256,7 @@ class CommandOpenAIOfficial(Command):
def draw(self, message):
if self.provider is None:
return False, "未启OpenAI ChatGPT语言模型.", "draw"
return False, "未启OpenAI 官方 API", "draw"
if message.startswith("/画"):
message = message[2:]
elif message.startswith(""):
@@ -268,9 +268,4 @@ class CommandOpenAIOfficial(Command):
except Exception as e:
if 'exceeded' in str(e):
return f"OpenAI API错误。原因:\n{str(e)} \n超额了。可自己搭建一个机器人(Github仓库:QQChannelChatGPT)"
return False, f"图片生成失败: {e}", "draw"
return False, f"图片生成失败: {e}", "draw"
-1
View File
@@ -207,7 +207,6 @@ class QQOfficial(Platform):
self._send_wrapper(**data)
def _send_wrapper(self, **kwargs):
print(kwargs)
if 'channel_id' in kwargs:
asyncio.run_coroutine_threadsafe(self.client.api.post_message(**kwargs), self.loop).result()
else:
+132
View File
@@ -0,0 +1,132 @@
has_git = True
try:
import git.exc
from git.repo import Repo
except BaseException as e:
has_git = False
import sys, os
import requests
def _reboot():
py = sys.executable
os.execl(py, py, *sys.argv)
def find_repo() -> Repo:
if not has_git:
raise Exception("未安装 GitPython 库,无法进行更新。")
repo = None
# 由于项目更名过,因此这里需要多次尝试。
try:
repo = Repo()
except git.exc.InvalidGitRepositoryError:
try:
repo = Repo(path="QQChannelChatGPT")
except git.exc.InvalidGitRepositoryError:
repo = Repo(path="AstrBot")
if not repo:
raise Exception("在已知的目录下未找到项目位置。请联系项目维护者。")
return repo
def request_release_info(latest: bool = True) -> list:
'''
请求版本信息。
返回一个列表,每个元素是一个字典,包含版本号、发布时间、更新内容、commit hash等信息。
'''
api_url = "https://api.github.com/repos/Soulter/AstrBot/releases"
result = requests.get(api_url).json()
if latest:
ret = github_api_release_parser([result[0]])
else:
ret = github_api_release_parser(result)
return ret
def github_api_release_parser(releases: list) -> list:
'''
解析 GitHub API 返回的 releases 信息。
返回一个列表,每个元素是一个字典,包含版本号、发布时间、更新内容、commit hash等信息。
'''
ret = []
for release in releases:
version = release['tag_name']
commit_hash = ''
# 规范是: v3.0.7.xxxxxx,其中xxxxxx为 commit hash
_t = version.split(".")
if len(_t) == 4:
commit_hash = _t[3]
ret.append({
"version": release['name'],
"published_at": release['published_at'],
"body": release['body'],
"commit_hash": commit_hash
})
return ret
def check_update() -> str:
repo = find_repo()
curr_commit = repo.head.commit.hexsha[:6]
update_data = request_release_info()
new_commit = update_data[0]['commit_hash']
if curr_commit == new_commit:
return "当前已经是最新版本。"
else:
update_info = f"""有新版本可用。
=== 新版本 ===
{update_data[0]['version']}
=== 发布时间 ===
{update_data[0]['published_at']}
=== 更新内容 ===
{update_data[0]['body']}"""
return update_info
def update_project(update_data: list,
reboot: bool = False,
latest: bool = True,
version: str = ''):
repo = find_repo()
# update_data = request_release_info(latest)
if latest:
# 检查本地commit和最新commit是否一致
curr_commit = repo.head.commit.hexsha[:6]
new_commit = update_data[0]['commit_hash']
if curr_commit == '':
raise Exception("无法获取当前版本号对应的版本位置。请联系项目维护者。")
if curr_commit == new_commit:
raise Exception("当前已经是最新版本。")
else:
# 更新到最新版本对应的commit
try:
repo.remotes.origin.fetch()
repo.git.checkout(new_commit)
if reboot: _reboot()
except BaseException as e:
raise e
else:
# 更新到指定版本
flag = False
for data in update_data:
if data['version'] == version:
try:
repo.remotes.origin.fetch()
repo.git.checkout(data['commit_hash'])
flag = True
if reboot: _reboot()
except BaseException as e:
raise e
else:
continue
if not flag:
raise Exception("未找到指定版本。")
def checkout_branch(branch_name: str):
repo = find_repo()
try:
origin = repo.remotes.origin
origin.fetch()
repo.git.checkout(branch_name)
repo.git.pull("origin", branch_name, "-f")
return True
except BaseException as e:
raise e