v0.2,支持保存/读取上下文

This commit is contained in:
Asankilp 2024-10-03 15:16:32 +08:00
parent aa605afc9e
commit e4facb65f7
6 changed files with 57 additions and 24 deletions

View File

@ -1,5 +1,5 @@
<div align="center"> <div align="center">
<a href="https://v2.nonebot.dev/store"><img src="https://github.com/LiteyukiStudio/nonebot-plugin-marshoai/blob/main/resources/marsho.svg" width="820" height="310" alt="NoneBotPluginLogo"></a> <a href="https://v2.nonebot.dev/store"><img src="https://raw.githubusercontent.com/LiteyukiStudio/nonebot-plugin-marshoai/refs/heads/main/resources/marsho.svg" width="820" height="310" alt="NoneBotPluginLogo"></a>
<br> <br>
</div> </div>

View File

@ -15,6 +15,8 @@ usage = """MarshoAI Alpha by Asankilp
praises : 返回夸赞名单的提示词 praises : 返回夸赞名单的提示词
usermsg <消息> : 往当前会话添加用户消息(UserMessage) usermsg <消息> : 往当前会话添加用户消息(UserMessage)
assistantmsg <消息> : 往当前会话添加助手消息(AssistantMessage) assistantmsg <消息> : 往当前会话添加助手消息(AssistantMessage)
savecontext <文件名> : 保存当前会话的上下文至插件数据目录下的contexts/<文件名>.json里
loadcontext <文件名> : 从插件数据目录下的contexts/<文件名>.json里读取上下文并覆盖到当前会话
注意事项 注意事项
- Marsho 回复消息为None或以content_filter开头的错误信息时表示该消息被内容过滤器过滤请调整你的聊天内容确保其合规 - Marsho 回复消息为None或以content_filter开头的错误信息时表示该消息被内容过滤器过滤请调整你的聊天内容确保其合规
- 当回复以RateLimitReached开头的错误信息时 AI 模型的次数配额已用尽请联系Bot管理员 - 当回复以RateLimitReached开头的错误信息时 AI 模型的次数配额已用尽请联系Bot管理员

View File

@ -20,6 +20,8 @@ praises_cmd = on_command("praises",permission=SUPERUSER)
add_usermsg_cmd = on_command("usermsg",permission=SUPERUSER) add_usermsg_cmd = on_command("usermsg",permission=SUPERUSER)
add_assistantmsg_cmd = on_command("assistantmsg",permission=SUPERUSER) add_assistantmsg_cmd = on_command("assistantmsg",permission=SUPERUSER)
contexts_cmd = on_command("contexts",permission=SUPERUSER) contexts_cmd = on_command("contexts",permission=SUPERUSER)
save_context_cmd = on_command("savecontext",permission=SUPERUSER)
load_context_cmd = on_command("loadcontext",permission=SUPERUSER)
marsho_cmd = on_alconna( marsho_cmd = on_alconna(
Alconna( Alconna(
"marsho", "marsho",
@ -32,14 +34,14 @@ context = MarshoContext()
@add_usermsg_cmd.handle() @add_usermsg_cmd.handle()
async def add_usermsg(target: MsgTarget, arg: Message = CommandArg()): async def add_usermsg(target: MsgTarget, arg: Message = CommandArg()):
if msg := arg.extract_plain_text(): if msg := arg.extract_plain_text():
context.append(UserMessage(content=msg), target.id, target.private) context.append(UserMessage(content=msg).as_dict(), target.id, target.private)
await UniMessage("已添加用户消息").send() await add_usermsg_cmd.finish("已添加用户消息")
@add_assistantmsg_cmd.handle() @add_assistantmsg_cmd.handle()
async def add_assistantmsg(target: MsgTarget, arg: Message = CommandArg()): async def add_assistantmsg(target: MsgTarget, arg: Message = CommandArg()):
if msg := arg.extract_plain_text(): if msg := arg.extract_plain_text():
context.append(AssistantMessage(content=msg), target.id, target.private) context.append(AssistantMessage(content=msg).as_dict(), target.id, target.private)
await UniMessage("已添加助手消息").send() await add_assistantmsg_cmd.finish("已添加助手消息")
@praises_cmd.handle() @praises_cmd.handle()
async def praises(): async def praises():
@ -49,17 +51,18 @@ async def praises():
async def contexts(target: MsgTarget): async def contexts(target: MsgTarget):
await UniMessage(str(context.build(target.id, target.private)[1:])).send() await UniMessage(str(context.build(target.id, target.private)[1:])).send()
# @setprompt_cmd.handle() #用不了了 @save_context_cmd.handle()
# async def setprompt(arg: Message = CommandArg()): async def save_context(target: MsgTarget, arg: Message = CommandArg()):
# global spell, context contexts = context.build(target.id, target.private)[1:]
# if prompt := arg.extract_plain_text(): if msg := arg.extract_plain_text():
# spell = SystemMessage(content=prompt) await save_context_to_json(msg, contexts)
# await setprompt_cmd.finish("已设置提示词") await save_context_cmd.finish("已保存上下文")
# else:
# spell = SystemMessage(content="")
# context = []
# await setprompt_cmd.finish("已清除提示词")
@load_context_cmd.handle()
async def load_context(target: MsgTarget, arg: Message = CommandArg()):
if msg := arg.extract_plain_text():
context.set_context(await load_context_from_json(msg), target.id, target.private)
await load_context_cmd.finish("已加载并覆盖上下文")
@resetmem_cmd.handle() @resetmem_cmd.handle()
async def resetmem(target: MsgTarget): async def resetmem(target: MsgTarget):
@ -72,6 +75,7 @@ async def changemodel(arg : Message = CommandArg()):
if model := arg.extract_plain_text(): if model := arg.extract_plain_text():
model_name = model model_name = model
await changemodel_cmd.finish("已切换") await changemodel_cmd.finish("已切换")
@marsho_cmd.handle() @marsho_cmd.handle()
async def marsho( async def marsho(
target: MsgTarget, target: MsgTarget,
@ -121,9 +125,9 @@ async def marsho(
) )
#await UniMessage(str(response)).send() #await UniMessage(str(response)).send()
choice = response.choices[0] choice = response.choices[0]
if choice["finish_reason"] == CompletionsFinishReason.STOPPED: if choice["finish_reason"] == CompletionsFinishReason.STOPPED: # 当对话成功时将dict的上下文添加到上下文类中
context.append(UserMessage(content=usermsg), target.id, target.private) context.append(UserMessage(content=usermsg).as_dict(), target.id, target.private)
context.append(choice.message, target.id, target.private) context.append(choice.message.as_dict(), target.id, target.private)
elif choice["finish_reason"] == CompletionsFinishReason.CONTENT_FILTERED: elif choice["finish_reason"] == CompletionsFinishReason.CONTENT_FILTERED:
await UniMessage("*已被内容过滤器过滤。*").send() await UniMessage("*已被内容过滤器过滤。*").send()
#await UniMessage(str(choice)).send() #await UniMessage(str(choice)).send()

View File

@ -13,7 +13,7 @@ class MarshoContext:
def _get_target_dict(self, is_private): def _get_target_dict(self, is_private):
return self.contents["private"] if is_private else self.contents["non-private"] return self.contents["private"] if is_private else self.contents["non-private"]
def append(self, content, target_id, is_private): def append(self, content, target_id: str, is_private: bool):
""" """
往上下文中添加消息 往上下文中添加消息
""" """
@ -22,14 +22,21 @@ class MarshoContext:
target_dict[target_id] = [] target_dict[target_id] = []
target_dict[target_id].append(content) target_dict[target_id].append(content)
def reset(self, target_id, is_private): def set_context(self, contexts, target_id: str, is_private: bool):
"""
设置上下文
"""
target_dict = self._get_target_dict(is_private)
target_dict[target_id] = contexts
def reset(self, target_id: str, is_private: bool):
""" """
重置上下文 重置上下文
""" """
target_dict = self._get_target_dict(is_private) target_dict = self._get_target_dict(is_private)
target_dict[target_id].clear() target_dict[target_id].clear()
def build(self, target_id, is_private): def build(self, target_id: str, is_private: bool) -> list:
""" """
构建返回的上下文其中包括系统消息 构建返回的上下文其中包括系统消息
""" """

View File

@ -6,6 +6,7 @@ import httpx
import nonebot_plugin_localstore as store import nonebot_plugin_localstore as store
from datetime import datetime from datetime import datetime
from zhDateTime import DateTime from zhDateTime import DateTime
from pathlib import Path
from azure.ai.inference.models import SystemMessage from azure.ai.inference.models import SystemMessage
from .config import config from .config import config
async def get_image_b64(url): async def get_image_b64(url):
@ -49,6 +50,23 @@ def build_praises():
result.append(f"名字:{item['name']},优点:{item['advantages']}") result.append(f"名字:{item['name']},优点:{item['advantages']}")
return "\n".join(result) return "\n".join(result)
async def save_context_to_json(name: str, context: str):
context_dir = store.get_plugin_data_dir() / "contexts"
os.makedirs(context_dir, exist_ok=True)
file_path = os.path.join(context_dir, f"{name}.json")
with open(file_path, 'w', encoding='utf-8') as json_file:
json.dump(context, json_file, ensure_ascii=False, indent=4)
async def load_context_from_json(name: str):
context_dir = store.get_plugin_data_dir() / "contexts"
os.makedirs(context_dir, exist_ok=True)
file_path = os.path.join(context_dir, f"{name}.json")
try:
with open(file_path, 'r', encoding='utf-8') as json_file:
return json.load(json_file)
except FileNotFoundError:
return []
def get_prompt(): def get_prompt():
prompts = "" prompts = ""
prompts += config.marshoai_additional_prompt prompts += config.marshoai_additional_prompt
@ -61,7 +79,7 @@ def get_prompt():
time_prompt = f"现在的时间是{current_time},农历{current_lunar_date}" time_prompt = f"现在的时间是{current_time},农历{current_lunar_date}"
prompts += time_prompt prompts += time_prompt
marsho_prompt = config.marshoai_prompt marsho_prompt = config.marshoai_prompt
spell = SystemMessage(content=marsho_prompt+prompts) spell = SystemMessage(content=marsho_prompt+prompts).as_dict()
return spell return spell
def suggest_solution(errinfo: str) -> str: def suggest_solution(errinfo: str) -> str:
@ -70,7 +88,8 @@ def suggest_solution(errinfo: str) -> str:
"RateLimitReached": "模型达到调用速率限制。请稍等一段时间或联系Bot管理员。", "RateLimitReached": "模型达到调用速率限制。请稍等一段时间或联系Bot管理员。",
"tokens_limit_reached": "请求token达到上限。请重置上下文。", "tokens_limit_reached": "请求token达到上限。请重置上下文。",
"content_length_limit": "请求体过大。请重置上下文。", "content_length_limit": "请求体过大。请重置上下文。",
"unauthorized": "Azure凭据无效。请联系Bot管理员。" "unauthorized": "Azure凭据无效。请联系Bot管理员。",
"invalid type: parameter messages.content is of type array but should be of type string.": "请重置上下文。"
} }
for key, suggestion in suggestions.items(): for key, suggestion in suggestions.items():

View File

@ -1,6 +1,6 @@
[project] [project]
name = "nonebot-plugin-marshoai" name = "nonebot-plugin-marshoai"
version = "0.1.4" version = "0.2"
description = "Nonebot2插件调用Azure OpenAI服务实现猫娘聊天" description = "Nonebot2插件调用Azure OpenAI服务实现猫娘聊天"
readme = "README.md" readme = "README.md"
requires-python = "<4.0,>=3.9" requires-python = "<4.0,>=3.9"
@ -22,6 +22,7 @@ Homepage = "https://github.com/LiteyukiStudio/nonebot-plugin-marshoai"
[tool.nonebot] [tool.nonebot]
plugins = ["nonebot_plugin_marshoai"] plugins = ["nonebot_plugin_marshoai"]
adapters = [{name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11"}]
[tool.pdm] [tool.pdm]