mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-04 12:56:02 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c246fb6d8e | ||
|
|
ec6c041bcf | ||
|
|
2da5a9f3c7 | ||
|
|
4e0df52d7c | ||
|
|
71b8bf13e4 | ||
|
|
a8b1e6ce91 | ||
|
|
1419d7611d | ||
|
|
89c83ebf20 | ||
|
|
76d7db88ea | ||
|
|
67a208bc90 | ||
|
|
acbd55ded2 | ||
|
|
11a240a6d1 | ||
|
|
97c85abbe7 | ||
|
|
06a0cd2a3d | ||
|
|
572b215df8 | ||
|
|
2c542bf412 | ||
|
|
1576ba7a01 |
@@ -21,12 +21,12 @@ jobs:
|
|||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.x
|
python-version: 3.10.13
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade yiri-mirai openai>=1.0.0 colorlog func_timeout dulwich Pillow CallingGPT tiktoken
|
||||||
python -m pip install --upgrade yiri-mirai openai colorlog func_timeout dulwich Pillow CallingGPT tiktoken
|
python -m pip install -U openai>=1.0.0
|
||||||
|
|
||||||
- name: Copy Scripts
|
- name: Copy Scripts
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
1
.github/workflows/update-override-all.yml
vendored
1
.github/workflows/update-override-all.yml
vendored
@@ -29,7 +29,6 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
# 在此处添加您的项目所需的其他依赖
|
|
||||||
|
|
||||||
- name: Copy Scripts
|
- name: Copy Scripts
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
FROM python:3.10.13-alpine3.18
|
FROM python:3.10.13-bullseye
|
||||||
WORKDIR /QChatGPT
|
WORKDIR /QChatGPT
|
||||||
|
|
||||||
COPY . /QChatGPT/
|
COPY . /QChatGPT/
|
||||||
|
|
||||||
RUN ls
|
RUN ls
|
||||||
|
|
||||||
RUN pip install -r requirements.txt
|
RUN python -m pip install -r requirements.txt && \
|
||||||
RUN pip install -U websockets==10.0
|
python -m pip install -U websockets==10.0 && \
|
||||||
|
python -m pip install -U httpcore httpx openai
|
||||||
|
|
||||||
# 生成配置文件
|
# 生成配置文件
|
||||||
RUN python main.py
|
RUN python main.py
|
||||||
|
|||||||
@@ -208,29 +208,52 @@ auto_reset = True
|
|||||||
|
|
||||||
# OpenAI补全API的参数
|
# OpenAI补全API的参数
|
||||||
# 请在下方填写模型,程序自动选择接口
|
# 请在下方填写模型,程序自动选择接口
|
||||||
|
# 模型文档:https://platform.openai.com/docs/models
|
||||||
# 现已支持的模型有:
|
# 现已支持的模型有:
|
||||||
#
|
#
|
||||||
# 'gpt-4'
|
# ChatCompletions 接口:
|
||||||
# 'gpt-4-0613'
|
# # GPT 4 系列
|
||||||
# 'gpt-4-32k'
|
# "gpt-4-1106-preview",
|
||||||
# 'gpt-4-32k-0613'
|
# "gpt-4-vision-preview",
|
||||||
# 'gpt-3.5-turbo'
|
# "gpt-4",
|
||||||
# 'gpt-3.5-turbo-16k'
|
# "gpt-4-32k",
|
||||||
# 'gpt-3.5-turbo-0613'
|
# "gpt-4-0613",
|
||||||
# 'gpt-3.5-turbo-16k-0613'
|
# "gpt-4-32k-0613",
|
||||||
# 'text-davinci-003'
|
# "gpt-4-0314", # legacy
|
||||||
# 'text-davinci-002'
|
# "gpt-4-32k-0314", # legacy
|
||||||
# 'code-davinci-002'
|
# # GPT 3.5 系列
|
||||||
# 'code-cushman-001'
|
# "gpt-3.5-turbo-1106",
|
||||||
# 'text-curie-001'
|
# "gpt-3.5-turbo",
|
||||||
# 'text-babbage-001'
|
# "gpt-3.5-turbo-16k",
|
||||||
# 'text-ada-001'
|
# "gpt-3.5-turbo-0613", # legacy
|
||||||
|
# "gpt-3.5-turbo-16k-0613", # legacy
|
||||||
|
# "gpt-3.5-turbo-0301", # legacy
|
||||||
|
#
|
||||||
|
# Completions接口:
|
||||||
|
# "text-davinci-003", # legacy
|
||||||
|
# "text-davinci-002", # legacy
|
||||||
|
# "code-davinci-002", # legacy
|
||||||
|
# "code-cushman-001", # legacy
|
||||||
|
# "text-curie-001", # legacy
|
||||||
|
# "text-babbage-001", # legacy
|
||||||
|
# "text-ada-001", # legacy
|
||||||
|
# "gpt-3.5-turbo-instruct",
|
||||||
#
|
#
|
||||||
# 具体请查看OpenAI的文档: https://beta.openai.com/docs/api-reference/completions/create
|
# 具体请查看OpenAI的文档: https://beta.openai.com/docs/api-reference/completions/create
|
||||||
# 请将内容修改到config.py中,请勿修改config-template.py
|
# 请将内容修改到config.py中,请勿修改config-template.py
|
||||||
#
|
#
|
||||||
# 支持通过 One API 接入多种模型,请在上方的openai_config中设置One API的代理地址,
|
# 支持通过 One API 接入多种模型,请在上方的openai_config中设置One API的代理地址,
|
||||||
# 并在此填写您要使用的模型名称,详细请参考:https://github.com/songquanpeng/one-api
|
# 并在此填写您要使用的模型名称,详细请参考:https://github.com/songquanpeng/one-api
|
||||||
|
#
|
||||||
|
# 支持的 One API 模型:
|
||||||
|
# "SparkDesk",
|
||||||
|
# "chatglm_pro",
|
||||||
|
# "chatglm_std",
|
||||||
|
# "chatglm_lite",
|
||||||
|
# "qwen-v1",
|
||||||
|
# "qwen-plus-v1",
|
||||||
|
# "ERNIE-Bot",
|
||||||
|
# "ERNIE-Bot-turbo",
|
||||||
completion_api_params = {
|
completion_api_params = {
|
||||||
"model": "gpt-3.5-turbo",
|
"model": "gpt-3.5-turbo",
|
||||||
"temperature": 0.9, # 数值越低得到的回答越理性,取值范围[0, 1]
|
"temperature": 0.9, # 数值越低得到的回答越理性,取值范围[0, 1]
|
||||||
@@ -351,7 +374,7 @@ rate_limitation = {
|
|||||||
rate_limit_strategy = "drop"
|
rate_limit_strategy = "drop"
|
||||||
|
|
||||||
# 是否在启动时进行依赖库更新
|
# 是否在启动时进行依赖库更新
|
||||||
upgrade_dependencies = True
|
upgrade_dependencies = False
|
||||||
|
|
||||||
# 是否上报统计信息
|
# 是否上报统计信息
|
||||||
# 用于统计机器人的使用情况,不会收集任何用户信息
|
# 用于统计机器人的使用情况,不会收集任何用户信息
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
"default": 60
|
"default": 60
|
||||||
},
|
},
|
||||||
"rate_limit_strategy": "drop",
|
"rate_limit_strategy": "drop",
|
||||||
"upgrade_dependencies": true,
|
"upgrade_dependencies": false,
|
||||||
"report_usage": true,
|
"report_usage": true,
|
||||||
"logging_level": 20
|
"logging_level": 20
|
||||||
}
|
}
|
||||||
@@ -13,34 +13,42 @@ from pkg.openai.api.completion import CompletionRequest
|
|||||||
from pkg.openai.api.chat_completion import ChatCompletionRequest
|
from pkg.openai.api.chat_completion import ChatCompletionRequest
|
||||||
|
|
||||||
COMPLETION_MODELS = {
|
COMPLETION_MODELS = {
|
||||||
'text-davinci-003',
|
"text-davinci-003", # legacy
|
||||||
'text-davinci-002',
|
"text-davinci-002", # legacy
|
||||||
'code-davinci-002',
|
"code-davinci-002", # legacy
|
||||||
'code-cushman-001',
|
"code-cushman-001", # legacy
|
||||||
'text-curie-001',
|
"text-curie-001", # legacy
|
||||||
'text-babbage-001',
|
"text-babbage-001", # legacy
|
||||||
'text-ada-001',
|
"text-ada-001", # legacy
|
||||||
|
"gpt-3.5-turbo-instruct",
|
||||||
}
|
}
|
||||||
|
|
||||||
CHAT_COMPLETION_MODELS = {
|
CHAT_COMPLETION_MODELS = {
|
||||||
'gpt-3.5-turbo',
|
# GPT 4 系列
|
||||||
'gpt-3.5-turbo-16k',
|
"gpt-4-1106-preview",
|
||||||
'gpt-3.5-turbo-0613',
|
"gpt-4-vision-preview",
|
||||||
'gpt-3.5-turbo-16k-0613',
|
"gpt-4",
|
||||||
# 'gpt-3.5-turbo-0301',
|
"gpt-4-32k",
|
||||||
'gpt-4',
|
"gpt-4-0613",
|
||||||
'gpt-4-0613',
|
"gpt-4-32k-0613",
|
||||||
'gpt-4-32k',
|
"gpt-4-0314", # legacy
|
||||||
'gpt-4-32k-0613',
|
"gpt-4-32k-0314", # legacy
|
||||||
|
# GPT 3.5 系列
|
||||||
|
"gpt-3.5-turbo-1106",
|
||||||
|
"gpt-3.5-turbo",
|
||||||
|
"gpt-3.5-turbo-16k",
|
||||||
|
"gpt-3.5-turbo-0613", # legacy
|
||||||
|
"gpt-3.5-turbo-16k-0613", # legacy
|
||||||
|
"gpt-3.5-turbo-0301", # legacy
|
||||||
# One-API 接入
|
# One-API 接入
|
||||||
'SparkDesk',
|
"SparkDesk",
|
||||||
'chatglm_pro',
|
"chatglm_pro",
|
||||||
'chatglm_std',
|
"chatglm_std",
|
||||||
'chatglm_lite',
|
"chatglm_lite",
|
||||||
'qwen-v1',
|
"qwen-v1",
|
||||||
'qwen-plus-v1',
|
"qwen-plus-v1",
|
||||||
'ERNIE-Bot',
|
"ERNIE-Bot",
|
||||||
'ERNIE-Bot-turbo',
|
"ERNIE-Bot-turbo",
|
||||||
}
|
}
|
||||||
|
|
||||||
EDIT_MODELS = {
|
EDIT_MODELS = {
|
||||||
|
|||||||
@@ -7,14 +7,19 @@ import pkgutil
|
|||||||
import sys
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
import traceback
|
import traceback
|
||||||
|
import time
|
||||||
|
import re
|
||||||
|
|
||||||
import pkg.utils.updater as updater
|
import pkg.utils.updater as updater
|
||||||
import pkg.utils.context as context
|
import pkg.utils.context as context
|
||||||
import pkg.plugin.switch as switch
|
import pkg.plugin.switch as switch
|
||||||
import pkg.plugin.settings as settings
|
import pkg.plugin.settings as settings
|
||||||
import pkg.qqbot.adapter as msadapter
|
import pkg.qqbot.adapter as msadapter
|
||||||
|
import pkg.utils.network as network
|
||||||
|
import pkg.plugin.metadata as metadata
|
||||||
|
|
||||||
from mirai import Mirai
|
from mirai import Mirai
|
||||||
|
import requests
|
||||||
|
|
||||||
from CallingGPT.session.session import Session
|
from CallingGPT.session.session import Session
|
||||||
|
|
||||||
@@ -65,6 +70,8 @@ def generate_plugin_order():
|
|||||||
def iter_plugins():
|
def iter_plugins():
|
||||||
"""按照顺序迭代插件"""
|
"""按照顺序迭代插件"""
|
||||||
for plugin_name in __plugins_order__:
|
for plugin_name in __plugins_order__:
|
||||||
|
if plugin_name not in __plugins__:
|
||||||
|
continue
|
||||||
yield __plugins__[plugin_name]
|
yield __plugins__[plugin_name]
|
||||||
|
|
||||||
|
|
||||||
@@ -113,10 +120,15 @@ def load_plugins():
|
|||||||
# 加载插件顺序
|
# 加载插件顺序
|
||||||
settings.load_settings()
|
settings.load_settings()
|
||||||
|
|
||||||
|
logging.debug("registered plugins: {}".format(__plugins__))
|
||||||
|
|
||||||
# 输出已注册的内容函数列表
|
# 输出已注册的内容函数列表
|
||||||
logging.debug("registered content functions: {}".format(__callable_functions__))
|
logging.debug("registered content functions: {}".format(__callable_functions__))
|
||||||
logging.debug("function instance map: {}".format(__function_inst_map__))
|
logging.debug("function instance map: {}".format(__function_inst_map__))
|
||||||
|
|
||||||
|
# 迁移插件源地址记录
|
||||||
|
metadata.do_plugin_git_repo_migrate()
|
||||||
|
|
||||||
|
|
||||||
def initialize_plugins():
|
def initialize_plugins():
|
||||||
"""初始化插件"""
|
"""初始化插件"""
|
||||||
@@ -155,34 +167,100 @@ def unload_plugins():
|
|||||||
# logging.error("插件{}卸载时发生错误: {}".format(plugin['name'], sys.exc_info()))
|
# logging.error("插件{}卸载时发生错误: {}".format(plugin['name'], sys.exc_info()))
|
||||||
|
|
||||||
|
|
||||||
def install_plugin(repo_url: str):
|
def get_github_plugin_repo_label(repo_url: str) -> list[str]:
|
||||||
"""安装插件,从git储存库获取并解决依赖"""
|
"""获取username, repo"""
|
||||||
try:
|
|
||||||
import pkg.utils.pkgmgr
|
|
||||||
pkg.utils.pkgmgr.ensure_dulwich()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
# 提取 username/repo , 正则表达式
|
||||||
import dulwich
|
repo = re.findall(r'(?:https?://github\.com/|git@github\.com:)([^/]+/[^/]+?)(?:\.git|/|$)', repo_url)
|
||||||
except ModuleNotFoundError:
|
|
||||||
raise Exception("dulwich模块未安装,请查看 https://github.com/RockChinQ/QChatGPT/issues/77")
|
|
||||||
|
|
||||||
from dulwich import porcelain
|
if len(repo) > 0: # github
|
||||||
|
return repo[0].split("/")
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
logging.info("克隆插件储存库: {}".format(repo_url))
|
|
||||||
repo = porcelain.clone(repo_url, "plugins/"+repo_url.split(".git")[0].split("/")[-1]+"/", checkout=True)
|
|
||||||
|
|
||||||
|
def download_plugin_source_code(repo_url: str, target_path: str) -> str:
|
||||||
|
"""下载插件源码"""
|
||||||
|
# 检查源类型
|
||||||
|
|
||||||
|
# 提取 username/repo , 正则表达式
|
||||||
|
repo = get_github_plugin_repo_label(repo_url)
|
||||||
|
|
||||||
|
target_path += repo[1]
|
||||||
|
|
||||||
|
if repo is not None: # github
|
||||||
|
logging.info("从 GitHub 下载插件源码...")
|
||||||
|
|
||||||
|
zipball_url = f"https://api.github.com/repos/{'/'.join(repo)}/zipball/HEAD"
|
||||||
|
|
||||||
|
zip_resp = requests.get(
|
||||||
|
url=zipball_url,
|
||||||
|
proxies=network.wrapper_proxies(),
|
||||||
|
stream=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if zip_resp.status_code != 200:
|
||||||
|
raise Exception("下载源码失败: {}".format(zip_resp.text))
|
||||||
|
|
||||||
|
if os.path.exists("temp/"+target_path):
|
||||||
|
shutil.rmtree("temp/"+target_path)
|
||||||
|
|
||||||
|
if os.path.exists(target_path):
|
||||||
|
shutil.rmtree(target_path)
|
||||||
|
|
||||||
|
os.makedirs("temp/"+target_path)
|
||||||
|
|
||||||
|
with open("temp/"+target_path+"/source.zip", "wb") as f:
|
||||||
|
for chunk in zip_resp.iter_content(chunk_size=1024):
|
||||||
|
if chunk:
|
||||||
|
f.write(chunk)
|
||||||
|
|
||||||
|
logging.info("下载完成, 解压...")
|
||||||
|
import zipfile
|
||||||
|
with zipfile.ZipFile("temp/"+target_path+"/source.zip", 'r') as zip_ref:
|
||||||
|
zip_ref.extractall("temp/"+target_path)
|
||||||
|
os.remove("temp/"+target_path+"/source.zip")
|
||||||
|
|
||||||
|
# 目标是 username-repo-hash , 用正则表达式提取完整的文件夹名,复制到 plugins/repo
|
||||||
|
import glob
|
||||||
|
|
||||||
|
# 获取解压后的文件夹名
|
||||||
|
unzip_dir = glob.glob("temp/"+target_path+"/*")[0]
|
||||||
|
|
||||||
|
# 复制到 plugins/repo
|
||||||
|
shutil.copytree(unzip_dir, target_path+"/")
|
||||||
|
|
||||||
|
# 删除解压后的文件夹
|
||||||
|
shutil.rmtree(unzip_dir)
|
||||||
|
|
||||||
|
logging.info("解压完成")
|
||||||
|
else:
|
||||||
|
raise Exception("暂不支持的源类型,请使用 GitHub 仓库发行插件。")
|
||||||
|
|
||||||
|
return repo[1]
|
||||||
|
|
||||||
|
|
||||||
|
def check_requirements(path: str):
|
||||||
# 检查此目录是否包含requirements.txt
|
# 检查此目录是否包含requirements.txt
|
||||||
if os.path.exists("plugins/"+repo_url.split(".git")[0].split("/")[-1]+"/requirements.txt"):
|
if os.path.exists(path+"/requirements.txt"):
|
||||||
logging.info("检测到requirements.txt,正在安装依赖")
|
logging.info("检测到requirements.txt,正在安装依赖")
|
||||||
import pkg.utils.pkgmgr
|
import pkg.utils.pkgmgr
|
||||||
pkg.utils.pkgmgr.install_requirements("plugins/"+repo_url.split(".git")[0].split("/")[-1]+"/requirements.txt")
|
pkg.utils.pkgmgr.install_requirements(path+"/requirements.txt")
|
||||||
|
|
||||||
import pkg.utils.log as log
|
import pkg.utils.log as log
|
||||||
log.reset_logging()
|
log.reset_logging()
|
||||||
|
|
||||||
|
|
||||||
|
def install_plugin(repo_url: str):
|
||||||
|
"""安装插件,从git储存库获取并解决依赖"""
|
||||||
|
|
||||||
|
repo_label = download_plugin_source_code(repo_url, "plugins/")
|
||||||
|
|
||||||
|
check_requirements("plugins/"+repo_label)
|
||||||
|
|
||||||
|
metadata.set_plugin_metadata(repo_label, repo_url, int(time.time()), "HEAD")
|
||||||
|
|
||||||
|
|
||||||
def uninstall_plugin(plugin_name: str) -> str:
|
def uninstall_plugin(plugin_name: str) -> str:
|
||||||
"""卸载插件"""
|
"""卸载插件"""
|
||||||
if plugin_name not in __plugins__:
|
if plugin_name not in __plugins__:
|
||||||
@@ -202,39 +280,43 @@ def uninstall_plugin(plugin_name: str) -> str:
|
|||||||
def update_plugin(plugin_name: str):
|
def update_plugin(plugin_name: str):
|
||||||
"""更新插件"""
|
"""更新插件"""
|
||||||
# 检查是否有远程地址记录
|
# 检查是否有远程地址记录
|
||||||
target_plugin_dir = "plugins/" + __plugins__[plugin_name]['path'].replace("\\", "/").split("plugins/")[1].split("/")[0]
|
plugin_path_name = get_plugin_path_name_by_plugin_name(plugin_name)
|
||||||
|
|
||||||
remote_url = updater.get_remote_url(target_plugin_dir)
|
meta = metadata.get_plugin_metadata(plugin_path_name)
|
||||||
|
|
||||||
|
if meta == {}:
|
||||||
|
raise Exception("没有此插件元数据信息,无法更新")
|
||||||
|
|
||||||
|
remote_url = meta['source']
|
||||||
if remote_url == "https://github.com/RockChinQ/QChatGPT" or remote_url == "https://gitee.com/RockChin/QChatGPT" \
|
if remote_url == "https://github.com/RockChinQ/QChatGPT" or remote_url == "https://gitee.com/RockChin/QChatGPT" \
|
||||||
or remote_url == "" or remote_url is None or remote_url == "http://github.com/RockChinQ/QChatGPT" or remote_url == "http://gitee.com/RockChin/QChatGPT":
|
or remote_url == "" or remote_url is None or remote_url == "http://github.com/RockChinQ/QChatGPT" or remote_url == "http://gitee.com/RockChin/QChatGPT":
|
||||||
raise Exception("插件没有远程地址记录,无法更新")
|
raise Exception("插件没有远程地址记录,无法更新")
|
||||||
|
|
||||||
# 把远程clone到temp/plugins/update/插件名
|
# 重新安装插件
|
||||||
logging.info("克隆插件储存库: {}".format(remote_url))
|
logging.info("正在重新安装插件以进行更新...")
|
||||||
|
|
||||||
from dulwich import porcelain
|
install_plugin(remote_url)
|
||||||
clone_target_dir = "temp/plugins/update/"+target_plugin_dir.split("/")[-1]+"/"
|
|
||||||
|
|
||||||
if os.path.exists(clone_target_dir):
|
|
||||||
shutil.rmtree(clone_target_dir)
|
|
||||||
|
|
||||||
if not os.path.exists(clone_target_dir):
|
def get_plugin_name_by_path_name(plugin_path_name: str) -> str:
|
||||||
os.makedirs(clone_target_dir)
|
for k, v in __plugins__.items():
|
||||||
repo = porcelain.clone(remote_url, clone_target_dir, checkout=True)
|
if v['path'] == "plugins/"+plugin_path_name+"/main.py":
|
||||||
|
return k
|
||||||
|
return None
|
||||||
|
|
||||||
# 检查此目录是否包含requirements.txt
|
|
||||||
if os.path.exists(clone_target_dir+"requirements.txt"):
|
|
||||||
logging.info("检测到requirements.txt,正在安装依赖")
|
|
||||||
import pkg.utils.pkgmgr
|
|
||||||
pkg.utils.pkgmgr.install_requirements(clone_target_dir+"requirements.txt")
|
|
||||||
|
|
||||||
import pkg.utils.log as log
|
def get_plugin_path_name_by_plugin_name(plugin_name: str) -> str:
|
||||||
log.reset_logging()
|
if plugin_name not in __plugins__:
|
||||||
|
return None
|
||||||
|
|
||||||
# 将temp/plugins/update/插件名 覆盖到 plugins/插件名
|
plugin_main_module_path = __plugins__[plugin_name]['path']
|
||||||
shutil.rmtree(target_plugin_dir)
|
|
||||||
|
plugin_main_module_path = plugin_main_module_path.replace("\\", "/")
|
||||||
|
|
||||||
|
spt = plugin_main_module_path.split("/")
|
||||||
|
|
||||||
|
return spt[1]
|
||||||
|
|
||||||
shutil.copytree(clone_target_dir, target_plugin_dir)
|
|
||||||
|
|
||||||
class EventContext:
|
class EventContext:
|
||||||
"""事件上下文"""
|
"""事件上下文"""
|
||||||
|
|||||||
87
pkg/plugin/metadata.py
Normal file
87
pkg/plugin/metadata.py
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
|
||||||
|
import dulwich.errors as dulwich_err
|
||||||
|
|
||||||
|
from ..utils import updater
|
||||||
|
|
||||||
|
|
||||||
|
def read_metadata_file() -> dict:
|
||||||
|
# 读取 plugins/metadata.json 文件
|
||||||
|
if not os.path.exists('plugins/metadata.json'):
|
||||||
|
return {}
|
||||||
|
with open('plugins/metadata.json', 'r') as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
def write_metadata_file(metadata: dict):
|
||||||
|
if not os.path.exists('plugins'):
|
||||||
|
os.mkdir('plugins')
|
||||||
|
|
||||||
|
with open('plugins/metadata.json', 'w') as f:
|
||||||
|
json.dump(metadata, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
|
def do_plugin_git_repo_migrate():
|
||||||
|
# 仅在 plugins/metadata.json 不存在时执行
|
||||||
|
if os.path.exists('plugins/metadata.json'):
|
||||||
|
return
|
||||||
|
|
||||||
|
metadata = read_metadata_file()
|
||||||
|
|
||||||
|
# 遍历 plugins 下所有目录,获取目录的git远程地址
|
||||||
|
for plugin_name in os.listdir('plugins'):
|
||||||
|
plugin_path = os.path.join('plugins', plugin_name)
|
||||||
|
if not os.path.isdir(plugin_path):
|
||||||
|
continue
|
||||||
|
|
||||||
|
remote_url = None
|
||||||
|
try:
|
||||||
|
remote_url = updater.get_remote_url(plugin_path)
|
||||||
|
except dulwich_err.NotGitRepository:
|
||||||
|
continue
|
||||||
|
if remote_url == "https://github.com/RockChinQ/QChatGPT" or remote_url == "https://gitee.com/RockChin/QChatGPT" \
|
||||||
|
or remote_url == "" or remote_url is None or remote_url == "http://github.com/RockChinQ/QChatGPT" or remote_url == "http://gitee.com/RockChin/QChatGPT":
|
||||||
|
continue
|
||||||
|
|
||||||
|
from . import host
|
||||||
|
|
||||||
|
if plugin_name not in metadata:
|
||||||
|
metadata[plugin_name] = {
|
||||||
|
'source': remote_url,
|
||||||
|
'install_timestamp': int(time.time()),
|
||||||
|
'ref': 'HEAD',
|
||||||
|
}
|
||||||
|
|
||||||
|
write_metadata_file(metadata)
|
||||||
|
|
||||||
|
|
||||||
|
def set_plugin_metadata(
|
||||||
|
plugin_name: str,
|
||||||
|
source: str,
|
||||||
|
install_timestamp: int,
|
||||||
|
ref: str,
|
||||||
|
):
|
||||||
|
metadata = read_metadata_file()
|
||||||
|
metadata[plugin_name] = {
|
||||||
|
'source': source,
|
||||||
|
'install_timestamp': install_timestamp,
|
||||||
|
'ref': ref,
|
||||||
|
}
|
||||||
|
write_metadata_file(metadata)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_plugin_metadata(plugin_name: str):
|
||||||
|
metadata = read_metadata_file()
|
||||||
|
if plugin_name in metadata:
|
||||||
|
del metadata[plugin_name]
|
||||||
|
write_metadata_file(metadata)
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugin_metadata(plugin_name: str) -> dict:
|
||||||
|
metadata = read_metadata_file()
|
||||||
|
if plugin_name in metadata:
|
||||||
|
return metadata[plugin_name]
|
||||||
|
return {}
|
||||||
@@ -84,7 +84,7 @@ class PluginGetCommand(AbstractCommandNode):
|
|||||||
@AbstractCommandNode.register(
|
@AbstractCommandNode.register(
|
||||||
parent=PluginCommand,
|
parent=PluginCommand,
|
||||||
name="update",
|
name="update",
|
||||||
description="更新所有插件",
|
description="更新指定插件或全部插件",
|
||||||
usage="!plugin update",
|
usage="!plugin update",
|
||||||
aliases=[],
|
aliases=[],
|
||||||
privilege=2
|
privilege=2
|
||||||
@@ -110,7 +110,9 @@ class PluginUpdateCommand(AbstractCommandNode):
|
|||||||
plugin_host.update_plugin(key)
|
plugin_host.update_plugin(key)
|
||||||
updated.append(key)
|
updated.append(key)
|
||||||
else:
|
else:
|
||||||
if ctx.crt_params[0] in plugin_list:
|
plugin_path_name = plugin_host.get_plugin_path_name_by_plugin_name(ctx.crt_params[0])
|
||||||
|
|
||||||
|
if plugin_path_name is not None:
|
||||||
plugin_host.update_plugin(ctx.crt_params[0])
|
plugin_host.update_plugin(ctx.crt_params[0])
|
||||||
updated.append(ctx.crt_params[0])
|
updated.append(ctx.crt_params[0])
|
||||||
else:
|
else:
|
||||||
@@ -119,7 +121,7 @@ class PluginUpdateCommand(AbstractCommandNode):
|
|||||||
pkg.utils.context.get_qqbot_manager().notify_admin("已更新插件: {}, 请发送 !reload 重载插件".format(", ".join(updated)))
|
pkg.utils.context.get_qqbot_manager().notify_admin("已更新插件: {}, 请发送 !reload 重载插件".format(", ".join(updated)))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("插件更新失败:{}".format(e))
|
logging.error("插件更新失败:{}".format(e))
|
||||||
pkg.utils.context.get_qqbot_manager().notify_admin("插件更新失败:{} 请尝试手动更新插件".format(e))
|
pkg.utils.context.get_qqbot_manager().notify_admin("插件更新失败:{} 请使用 !plugin 命令确认插件名称或尝试手动更新插件".format(e))
|
||||||
|
|
||||||
reply = ["[bot]正在更新插件,请勿重复发起..."]
|
reply = ["[bot]正在更新插件,请勿重复发起..."]
|
||||||
threading.Thread(target=closure).start()
|
threading.Thread(target=closure).start()
|
||||||
|
|||||||
@@ -185,7 +185,11 @@ class NakuruProjectAdapter(MessageSourceAdapter):
|
|||||||
if resp.status_code == 403:
|
if resp.status_code == 403:
|
||||||
logging.error("go-cqhttp拒绝访问,请检查config.py中nakuru_config的token是否与go-cqhttp设置的access-token匹配")
|
logging.error("go-cqhttp拒绝访问,请检查config.py中nakuru_config的token是否与go-cqhttp设置的access-token匹配")
|
||||||
raise Exception("go-cqhttp拒绝访问,请检查config.py中nakuru_config的token是否与go-cqhttp设置的access-token匹配")
|
raise Exception("go-cqhttp拒绝访问,请检查config.py中nakuru_config的token是否与go-cqhttp设置的access-token匹配")
|
||||||
self.bot_account_id = int(resp.json()['data']['user_id'])
|
try:
|
||||||
|
self.bot_account_id = int(resp.json()['data']['user_id'])
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("获取go-cqhttp账号信息失败: {}, 请检查是否已启动go-cqhttp并配置正确".format(e))
|
||||||
|
raise Exception("获取go-cqhttp账号信息失败: {}, 请检查是否已启动go-cqhttp并配置正确".format(e))
|
||||||
|
|
||||||
def send_message(
|
def send_message(
|
||||||
self,
|
self,
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -4,5 +4,11 @@
|
|||||||
"time": "2023-08-01 10:49:26",
|
"time": "2023-08-01 10:49:26",
|
||||||
"timestamp": 1690858166,
|
"timestamp": 1690858166,
|
||||||
"content": "现已支持GPT函数调用功能,欢迎了解:https://github.com/RockChinQ/QChatGPT/wiki/%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8-%E5%86%85%E5%AE%B9%E5%87%BD%E6%95%B0"
|
"content": "现已支持GPT函数调用功能,欢迎了解:https://github.com/RockChinQ/QChatGPT/wiki/%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8-%E5%86%85%E5%AE%B9%E5%87%BD%E6%95%B0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"time": "2023-11-10 12:20:09",
|
||||||
|
"timestamp": 1699590009,
|
||||||
|
"content": "OpenAI 库1.0版本已发行,若出现 OpenAI 调用问题,请更新 QChatGPT 版本。详见项目主页:https://github.com/RockChinQ/QChatGPT"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
7
tests/repo_regexp_test.py
Normal file
7
tests/repo_regexp_test.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
repo_url = "git@github.com:RockChinQ/WebwlkrPlugin.git"
|
||||||
|
|
||||||
|
repo = re.findall(r'(?:https?://github\.com/|git@github\.com:)([^/]+/[^/]+?)(?:\.git|/|$)', repo_url)
|
||||||
|
|
||||||
|
print(repo)
|
||||||
Reference in New Issue
Block a user