Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 853ac4c104 | |||
| ed053acad6 | |||
| f147634e51 | |||
| e3b2a68341 | |||
| 84c450aef9 | |||
| f52a0eb43a |
@@ -10,3 +10,4 @@ cmd_config.json
|
||||
data/*
|
||||
cookies.json
|
||||
logs/
|
||||
addons/plugins
|
||||
@@ -101,10 +101,14 @@ class AstrBotBootstrap():
|
||||
self.openai_command_handler = OpenAIOfficialCommandHandler(self.command_manager)
|
||||
self.llm_instance = ProviderOpenAIOfficial(self.context)
|
||||
self.openai_command_handler.set_provider(self.llm_instance)
|
||||
self.context.register_provider("internal_openai", self.llm_instance)
|
||||
logger.info("已启用 OpenAI API 支持。")
|
||||
|
||||
def load_plugins(self):
|
||||
self.plugin_manager.plugin_reload()
|
||||
|
||||
def load_platform(self):
|
||||
return self.platfrom_manager.load_platforms()
|
||||
platforms = self.platfrom_manager.load_platforms()
|
||||
if not platforms:
|
||||
logger.warn("未启用任何消息平台。")
|
||||
return platforms
|
||||
@@ -115,6 +115,9 @@ class MessageHandler():
|
||||
self.nicks = self.context.nick
|
||||
self.provider = provider
|
||||
self.reply_prefix = self.context.reply_prefix
|
||||
|
||||
def set_provider(self, provider: Provider):
|
||||
self.provider = provider
|
||||
|
||||
async def handle(self, message: AstrMessageEvent, llm_provider: Provider = None) -> MessageResult:
|
||||
'''
|
||||
@@ -148,7 +151,8 @@ class MessageHandler():
|
||||
assert(isinstance(cmd_res, CommandResult))
|
||||
return MessageResult(
|
||||
cmd_res.message_chain,
|
||||
is_command_call=True
|
||||
is_command_call=True,
|
||||
use_t2i=cmd_res.is_use_t2i
|
||||
)
|
||||
|
||||
# check if the message is a llm-wake-up command
|
||||
@@ -178,7 +182,9 @@ class MessageHandler():
|
||||
llm_result = await web_searcher.web_search(msg_plain, provider, message.session_id, inner_provider)
|
||||
else:
|
||||
llm_result = await provider.text_chat(
|
||||
msg_plain, message.session_id, image_url
|
||||
prompt=msg_plain,
|
||||
session_id=message.session_id,
|
||||
image_url=image_url
|
||||
)
|
||||
except BaseException as e:
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
# 如果你不知道怎么部署,请查看https://soulter.top/posts/qpdg.html
|
||||
# 不一定需要key了,如果你没有key但有openAI账号或者必应账号,可以考虑使用下面的逆向库
|
||||
|
||||
|
||||
###############平台设置#################
|
||||
|
||||
# QQ频道机器人
|
||||
# QQ开放平台的appid和令牌
|
||||
# q.qq.com
|
||||
# enable为true则启用,false则不启用
|
||||
qqbot:
|
||||
enable: true
|
||||
appid:
|
||||
token:
|
||||
|
||||
# QQ机器人
|
||||
# enable为true则启用,false则不启用
|
||||
# 需要安装GO-CQHTTP配合使用。
|
||||
# 文档:https://docs.go-cqhttp.org/
|
||||
# 请将go-cqhttp的配置文件的sever部分粘贴为以下内容,否则无法使用
|
||||
# 请先启动go-cqhttp再启动本程序
|
||||
#
|
||||
# servers:
|
||||
# - http:
|
||||
# host: 127.0.0.1
|
||||
# version: 0
|
||||
# port: 5700
|
||||
# timeout: 5
|
||||
# - ws:
|
||||
# address: 127.0.0.1:6700
|
||||
# middlewares:
|
||||
# <<: *default
|
||||
gocqbot:
|
||||
enable: false
|
||||
|
||||
# 设置是否一个人一个会话
|
||||
uniqueSessionMode: false
|
||||
# QChannelBot 的版本,请勿修改此字段,否则可能产生一些bug
|
||||
version: 3.0
|
||||
# [Beta] 转储历史记录时间间隔(分钟)
|
||||
dump_history_interval: 10
|
||||
# 一个用户只能在time秒内发送count条消息
|
||||
limit:
|
||||
time: 60
|
||||
count: 5
|
||||
# 公告
|
||||
notice: "此机器人由Github项目QQChannelChatGPT驱动。"
|
||||
# 是否打开私信功能
|
||||
# 设置为true则频道成员可以私聊机器人。
|
||||
# 设置为false则频道成员不能私聊机器人。
|
||||
direct_message_mode: true
|
||||
|
||||
# 系统代理
|
||||
# http_proxy: http://localhost:7890
|
||||
# https_proxy: http://localhost:7890
|
||||
|
||||
# 自定义回复前缀,如[Rev]或其他,务必加引号以防止不必要的bug。
|
||||
reply_prefix:
|
||||
openai_official: "[GPT]"
|
||||
rev_chatgpt: "[Rev]"
|
||||
rev_edgegpt: "[RevBing]"
|
||||
|
||||
# 百度内容审核服务
|
||||
# 新用户免费5万次调用。https://cloud.baidu.com/doc/ANTIPORN/index.html
|
||||
baidu_aip:
|
||||
enable: false
|
||||
app_id:
|
||||
api_key:
|
||||
secret_key:
|
||||
|
||||
|
||||
|
||||
|
||||
###############语言模型设置#################
|
||||
|
||||
|
||||
# OpenAI官方API
|
||||
# 注意:已支持多key自动切换,方法:
|
||||
# key:
|
||||
# - sk-xxxxxx
|
||||
# - sk-xxxxxx
|
||||
# 在下方非注释的地方使用以上格式
|
||||
# 关于api_base:可以使用一些云函数(如腾讯、阿里)来避免国内被墙的问题。
|
||||
# 详见:
|
||||
# https://github.com/Ice-Hazymoon/openai-scf-proxy
|
||||
# https://github.com/Soulter/QQChannelChatGPT/issues/42
|
||||
# 设置为none则表示使用官方默认api地址
|
||||
openai:
|
||||
key:
|
||||
-
|
||||
api_base: none
|
||||
# 这里是GPT配置,语言模型默认使用gpt-3.5-turbo
|
||||
chatGPTConfigs:
|
||||
model: gpt-3.5-turbo
|
||||
max_tokens: 3000
|
||||
temperature: 0.9
|
||||
top_p: 1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
|
||||
total_tokens_limit: 5000
|
||||
|
||||
# 逆向文心一言【暂时不可用,请勿使用】
|
||||
rev_ernie:
|
||||
enable: false
|
||||
|
||||
# 逆向New Bing
|
||||
# 需要在项目根目录下创建cookies.json并粘贴cookies进去。
|
||||
# 详见:https://soulter.top/posts/qpdg.html
|
||||
rev_edgegpt:
|
||||
enable: false
|
||||
|
||||
# 逆向ChatGPT库
|
||||
# https://github.com/acheong08/ChatGPT
|
||||
# 优点:免费(无免费额度限制);
|
||||
# 缺点:速度相对慢。OpenAI 速率限制:免费帐户每小时 50 个请求。您可以通过多帐户循环来绕过它
|
||||
# enable设置为true后,将会停止使用上面正常的官方API调用而使用本逆向项目
|
||||
#
|
||||
# 多账户可以保证每个请求都能得到及时的回复。
|
||||
# 关于account的格式
|
||||
# account:
|
||||
# - email: 第1个账户
|
||||
# password: 第1个账户密码
|
||||
# - email: 第2个账户
|
||||
# password: 第2个账户密码
|
||||
# - ....
|
||||
# 支持使用access_token登录
|
||||
# 例:
|
||||
# - session_token: xxxxx
|
||||
# - access_token: xxxx
|
||||
# 请严格按照上面这个格式填写。
|
||||
# 逆向ChatGPT库的email-password登录方式不工作,建议使用access_token登录
|
||||
# 获取access_token的方法,详见:https://soulter.top/posts/qpdg.html
|
||||
rev_ChatGPT:
|
||||
enable: false
|
||||
account:
|
||||
- access_token:
|
||||
+1
-1
@@ -285,7 +285,7 @@ class AstrBotDashBoard():
|
||||
ret = self.astrbot_updator.check_update(None, None)
|
||||
return Response(
|
||||
status="success",
|
||||
message=str(ret),
|
||||
message=str(ret) if ret is not None else "已经是最新版本了。",
|
||||
data={
|
||||
"has_new_version": ret is not None
|
||||
}
|
||||
|
||||
@@ -26,7 +26,36 @@ class InternalCommandHandler:
|
||||
self.manager.register("websearch", "网页搜索开关", 10, self.web_search)
|
||||
self.manager.register("t2i", "文本转图片开关", 10, self.t2i_toggle)
|
||||
self.manager.register("myid", "获取你在此平台上的ID", 10, self.myid)
|
||||
|
||||
self.manager.register("provider", "查看和切换当前使用的 LLM 资源来源", 10, self.provider)
|
||||
|
||||
def provider(self, message: AstrMessageEvent, context: Context):
|
||||
if len(context.llms) == 0:
|
||||
return CommandResult().message("当前没有加载任何 LLM 资源。")
|
||||
|
||||
tokens = self.manager.command_parser.parse(message.message_str)
|
||||
|
||||
if tokens.len == 1:
|
||||
ret = "## 当前载入的 LLM 资源\n"
|
||||
for idx, llm in enumerate(context.llms):
|
||||
ret += f"{idx}. {llm.llm_name}"
|
||||
if llm.origin:
|
||||
ret += f" (来源: {llm.origin})"
|
||||
if context.message_handler.provider == llm.llm_instance:
|
||||
ret += " (当前使用)"
|
||||
ret += "\n"
|
||||
|
||||
ret += "\n使用 provider <序号> 切换 LLM 资源。"
|
||||
return CommandResult().message(ret)
|
||||
else:
|
||||
try:
|
||||
idx = int(tokens.get(1))
|
||||
if idx >= len(context.llms):
|
||||
return CommandResult().message("provider: 无效的序号。")
|
||||
context.message_handler.set_provider(context.llms[idx].llm_instance)
|
||||
return CommandResult().message(f"已经成功切换到 LLM 资源 {context.llms[idx].llm_name}。")
|
||||
except BaseException as e:
|
||||
return CommandResult().message("provider: 参数错误。")
|
||||
|
||||
def set_nick(self, message: AstrMessageEvent, context: Context):
|
||||
message_str = message.message_str
|
||||
if message.role != "admin":
|
||||
|
||||
@@ -73,7 +73,8 @@ class CommandManager():
|
||||
if message_str.startswith(command):
|
||||
logger.info(f"触发 {command} 指令。")
|
||||
command_result = await self.execute_handler(command, message_event, context)
|
||||
return command_result
|
||||
if command_result.hit:
|
||||
return command_result
|
||||
|
||||
async def execute_handler(self,
|
||||
command: str,
|
||||
|
||||
@@ -24,6 +24,7 @@ class CommandResult():
|
||||
self.success = success
|
||||
self.message_chain = message_chain
|
||||
self.command_name = command_name
|
||||
self.is_use_t2i = None # default
|
||||
|
||||
def message(self, message: str):
|
||||
'''
|
||||
@@ -61,6 +62,15 @@ class CommandResult():
|
||||
'''
|
||||
self.message_chain = [Image.fromFileSystem(path), ]
|
||||
return self
|
||||
|
||||
# def use_t2i(self, use_t2i: bool):
|
||||
# '''
|
||||
# 设置是否使用文本转图片服务。如果不设置,则跟随用户的设置。
|
||||
|
||||
# CommandResult().use_t2i(False)
|
||||
# '''
|
||||
# self.is_use_t2i = use_t2i
|
||||
# return self
|
||||
|
||||
def _result_tuple(self):
|
||||
return (self.success, self.message_chain, self.command_name)
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
VERSION = '3.3.0'
|
||||
VERSION = '3.3.2'
|
||||
@@ -43,13 +43,10 @@ class AstrMessageEvent():
|
||||
context,
|
||||
session_id)
|
||||
return ame
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class MessageResult():
|
||||
result_message: Union[str, list]
|
||||
is_command_call: Optional[bool] = False
|
||||
use_t2i: Optional[bool] = None # None 为跟随用户设置
|
||||
callback: Optional[callable] = None
|
||||
|
||||
@@ -9,6 +9,7 @@ from util.updator.astrbot_updator import AstrBotUpdator
|
||||
from util.image_uploader import ImageUploader
|
||||
from util.updator.plugin_updator import PluginUpdator
|
||||
from model.plugin.command import PluginCommandBridge
|
||||
from model.provider.provider import Provider
|
||||
|
||||
|
||||
class Context:
|
||||
@@ -68,6 +69,14 @@ class Context:
|
||||
'''
|
||||
task = asyncio.create_task(coro, name=task_name)
|
||||
self.ext_tasks.append(task)
|
||||
|
||||
def register_provider(self, llm_name: str, provider: Provider, origin: str = ''):
|
||||
'''
|
||||
注册一个提供 LLM 资源的 Provider。
|
||||
|
||||
`provider`: Provider 对象。即你的实现需要继承 Provider 类。至少应该实现 text_chat() 方法。
|
||||
'''
|
||||
self.llms.append(RegisteredLLM(llm_name, provider, origin))
|
||||
|
||||
def find_platform(self, platform_name: str) -> RegisteredPlatform:
|
||||
for platform in self.platforms:
|
||||
|
||||
@@ -122,7 +122,7 @@ class FuncCall():
|
||||
_c = 0
|
||||
while _c < 3:
|
||||
try:
|
||||
res = self.provider.text_chat(prompt, session_id)
|
||||
res = self.provider.text_chat(prompt=prompt, session_id=session_id)
|
||||
if res.find('```') != -1:
|
||||
res = res[res.find('```json') + 7: res.rfind('```')]
|
||||
gu.log("REVGPT func_call json result",
|
||||
@@ -187,7 +187,7 @@ class FuncCall():
|
||||
_c = 0
|
||||
while _c < 5:
|
||||
try:
|
||||
res = self.provider.text_chat(after_prompt, session_id)
|
||||
res = self.provider.text_chat(prompt=after_prompt, session_id=session_id)
|
||||
# 截取```之间的内容
|
||||
gu.log(
|
||||
"DEBUG BEGIN", bg=gu.BG_COLORS["yellow"], fg=gu.FG_COLORS["white"])
|
||||
|
||||
@@ -127,7 +127,7 @@ async def web_search(prompt, provider: Provider, session_id, official_fc=False):
|
||||
function_invoked_ret = ""
|
||||
if official_fc:
|
||||
# we use official function-calling
|
||||
result = await provider.text_chat(prompt, session_id, tools=new_func_call.get_func())
|
||||
result = await provider.text_chat(prompt=prompt, session_id=session_id, tools=new_func_call.get_func())
|
||||
if isinstance(result, Function):
|
||||
logger.debug(f"web_searcher - function-calling: {result}")
|
||||
func_obj = None
|
||||
@@ -136,14 +136,14 @@ async def web_search(prompt, provider: Provider, session_id, official_fc=False):
|
||||
func_obj = i["func_obj"]
|
||||
break
|
||||
if not func_obj:
|
||||
return await provider.text_chat(prompt, session_id) + "\n(网页搜索失败, 此为默认回复)"
|
||||
return await provider.text_chat(prompt=prompt, session_id=session_id, ) + "\n(网页搜索失败, 此为默认回复)"
|
||||
try:
|
||||
args = json.loads(result.arguments)
|
||||
function_invoked_ret = await func_obj(**args)
|
||||
has_func = True
|
||||
except BaseException as e:
|
||||
traceback.print_exc()
|
||||
return await provider.text_chat(prompt, session_id) + "\n(网页搜索失败, 此为默认回复)"
|
||||
return await provider.text_chat(prompt=prompt, session_id=session_id, ) + "\n(网页搜索失败, 此为默认回复)"
|
||||
else:
|
||||
return result
|
||||
else:
|
||||
@@ -162,7 +162,7 @@ async def web_search(prompt, provider: Provider, session_id, official_fc=False):
|
||||
has_func = True
|
||||
|
||||
if has_func:
|
||||
await provider.forget(session_id)
|
||||
await provider.forget(session_id=session_id, )
|
||||
summary_prompt = f"""
|
||||
你是一个专业且高效的助手,你的任务是
|
||||
1. 根据下面的相关材料对用户的问题 `{prompt}` 进行总结;
|
||||
@@ -178,6 +178,6 @@ async def web_search(prompt, provider: Provider, session_id, official_fc=False):
|
||||
|
||||
# 相关材料
|
||||
{function_invoked_ret}"""
|
||||
ret = await provider.text_chat(summary_prompt, session_id)
|
||||
ret = await provider.text_chat(prompt=summary_prompt, session_id=session_id)
|
||||
return ret
|
||||
return function_invoked_ret
|
||||
|
||||
@@ -9,6 +9,44 @@ def init_configs():
|
||||
'''
|
||||
cc = CmdConfig()
|
||||
|
||||
cc.init_attributes("qqbot", {
|
||||
"enable": False,
|
||||
"appid": "",
|
||||
"token": "",
|
||||
})
|
||||
cc.init_attributes("gocqbot", {
|
||||
"enable": False,
|
||||
})
|
||||
cc.init_attributes("uniqueSessionMode", False)
|
||||
cc.init_attributes("dump_history_interval", 10)
|
||||
cc.init_attributes("limit", {
|
||||
"time": 60,
|
||||
"count": 30,
|
||||
})
|
||||
cc.init_attributes("notice", "")
|
||||
cc.init_attributes("direct_message_mode", True)
|
||||
cc.init_attributes("reply_prefix", "")
|
||||
cc.init_attributes("baidu_aip", {
|
||||
"enable": False,
|
||||
"app_id": "",
|
||||
"api_key": "",
|
||||
"secret_key": ""
|
||||
})
|
||||
cc.init_attributes("openai", {
|
||||
"key": [],
|
||||
"api_base": "",
|
||||
"chatGPTConfigs": {
|
||||
"model": "gpt-4o",
|
||||
"max_tokens": 6000,
|
||||
"temperature": 0.9,
|
||||
"top_p": 1,
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0,
|
||||
},
|
||||
"total_tokens_limit": 10000,
|
||||
})
|
||||
|
||||
|
||||
cc.init_attributes("qq_forward_threshold", 200)
|
||||
cc.init_attributes("qq_welcome", "")
|
||||
cc.init_attributes("qq_pic_mode", True)
|
||||
|
||||
@@ -32,7 +32,7 @@ class NetworkRenderStrategy(RenderStrategy):
|
||||
"options": {
|
||||
"full_page": True,
|
||||
"type": "jpeg",
|
||||
"quality": 25,
|
||||
"quality": 40,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from util.updator.zip_updator import ReleaseInfo, RepoZipUpdator
|
||||
from SparkleLogging.utils.core import LogManager
|
||||
from logging import Logger
|
||||
from type.config import VERSION
|
||||
from util.io import on_error
|
||||
from util.io import on_error, download_file
|
||||
|
||||
logger: Logger = LogManager.GetLogger(log_name='astrbot')
|
||||
|
||||
@@ -58,7 +58,8 @@ class AstrBotUpdator(RepoZipUpdator):
|
||||
raise Exception(f"未找到版本号为 {version} 的更新文件。")
|
||||
|
||||
try:
|
||||
self.download_from_repo_url("temp", data['zipball_url'])
|
||||
# self.download_from_repo_url("temp", file_url)
|
||||
download_file(file_url, "temp.zip")
|
||||
self.unzip_file("temp.zip", self.MAIN_PATH)
|
||||
except BaseException as e:
|
||||
raise e
|
||||
|
||||
Reference in New Issue
Block a user