Compare commits

...

6 Commits

Author SHA1 Message Date
887bf808a7 修改元数据和gitignore 2025-01-31 16:35:59 +08:00
金羿ELS
2afe3c48ce 增设版权声明,更新授权年份,主题色! (#2)
* 优化更新

* 代码不够黑,新增一个空行

* ?

* 空格?

* 新年新气象,莫生气

* 又是空格

* 附和:zhDateTime1.1.1 修复过于愚蠢导致的问题

* 增设版权声明,更新授权年份,主题色!

* ?怎么没删

* 更新 zhDateTime 库版本,主题色往文档里塞

* 我愚蠢了
2025-01-31 16:11:07 +08:00
23ca88b93a 修复上下文重置逻辑;增加调试和信息日志 2025-01-30 15:43:51 +08:00
b28e6921c5 优化OpenAI请求参数,默认传入NotGiven 2025-01-30 15:24:49 +08:00
17f18fa56a 修复语法错误 2025-01-29 00:53:33 +08:00
金羿ELS
4f5cb89365 Merge pull request #1 from LiteyukiStudio/eilles-main
🌟优化部分内容
2025-01-29 00:36:53 +08:00
23 changed files with 212 additions and 134 deletions

2
.gitignore vendored
View File

@@ -173,7 +173,7 @@ bot.py
pdm.lock
praises.json
*.bak
./config/
config/
# dev
.vscode/

View File

@@ -15,6 +15,7 @@ def is_valid_filename(filename: str) -> bool:
bool: _description_
"""
# 检查文件名是否仅包含小写字母,数字,下划线
# 啊?文件名还不能有大写啊……
if not re.match(r"^[a-z0-9_]+\.py$", filename):
return False
else:

View File

@@ -3,7 +3,7 @@ LiteyukiStudio Opensource license
---
Copyright © 2024 <copyright holders>
Copyright © 2025 Asankilp & LiteyukiStudio
---

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2024 LiteyukiStudio
Copyright (c) 2025 Asankilp & LiteyukiStudio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,4 +1,4 @@
Copyright (c) 2024 EillesWan
Copyright (c) 2025 EillesWan
nonebot-plugin-latex & other specified codes is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:

View File

@@ -10,38 +10,38 @@
_✨ 使用 OpenAI 标准格式 API 的聊天机器人插件 ✨_
[![NoneBot Registry](https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin%2Fnonebot-plugin-marshoai)](https://registry.nonebot.dev/plugin/nonebot-plugin-marshoai:nonebot_plugin_marshoai)
[![NoneBot Registry](https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin%2Fnonebot-plugin-marshoai&style=flat-square)](https://registry.nonebot.dev/plugin/nonebot-plugin-marshoai:nonebot_plugin_marshoai)
<a href="https://registry.nonebot.dev/plugin/nonebot-plugin-marshoai:nonebot_plugin_marshoai">
<img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin-adapters%2Fnonebot-plugin-marshoai" alt="Supported Adapters">
<img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin-adapters%2Fnonebot-plugin-marshoai&style=flat-square" alt="Supported Adapters">
</a>
<a href="https://pypi.python.org/pypi/nonebot-plugin-marshoai">
<img src="https://img.shields.io/pypi/v/nonebot-plugin-marshoai.svg" alt="pypi">
<img src="https://img.shields.io/pypi/v/nonebot-plugin-marshoai.svg?style=flat-square" alt="pypi">
</a>
<img src="https://img.shields.io/badge/python-3.10+-blue.svg" alt="python">
<img src="https://img.shields.io/badge/python-3.10+-blue.svg?style=flat-square" alt="python">
<img src="https://img.shields.io/badge/Code%20Style-Black-121110.svg?style=flat-square" alt="codestyle">
</div>
## 📖 介绍
通过调用 OpenAI 标准格式 API(例如 GitHub Models API) 来实现聊天的插件。
插件内置了猫娘小棉(Marsho)的人物设定,可以进行可爱的聊天!
*谁不喜欢回复消息快又可爱的猫娘呢?*
**对 OneBot 以外的适配器与非 GitHub Models API的支持未经过完全验证。**
[Melobot 实现](https://github.com/LiteyukiStudio/marshoai-melo)
_谁不喜欢回复消息快又可爱的猫娘呢?_
**对 OneBot 以外的适配器与非 GitHub Models API 的支持未经过完全验证。**
[Melobot 实现](https://github.com/LiteyukiStudio/marshoai-melo)
## 🐱 设定
#### 基本信息
- 名字:小棉(Marsho)
- 生日9月6
- 名字:小棉(Marsho)
- 生日9 月 6
#### 喜好
- 🌞 晒太阳晒到融化
- 🤱 撒娇啊~谁不喜欢呢~
- 🍫 吃零食!肉肉好吃!
- 🐾 玩!我喜欢和朋友们一起玩!
- 🌞 晒太阳晒到融化
- 🤱 撒娇啊~谁不喜欢呢~
- 🍫 吃零食!肉肉好吃!
- 🐾 玩!我喜欢和朋友们一起玩!
## 😼 使用
@@ -49,13 +49,15 @@ _✨ 使用 OpenAI 标准格式 API 的聊天机器人插件 ✨_
## ❤ 鸣谢&版权说明
本项目使用了以下项目的代码:
> Copyright (c) 2025 Asankilp & LiteyukiStudio
- [nonebot-plugin-latex](https://github.com/EillesWan/nonebot-plugin-latex)
本项目使用了以下项目的代码:
- [nonebot-plugin-latex](https://github.com/EillesWan/nonebot-plugin-latex)
"Marsho" logo 由 [@Asankilp](https://github.com/Asankilp)绘制,基于 [CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 许可下提供。
"nonebot-plugin-marshoai" 基于 [MIT](./LICENSE-MIT) 许可下提供。
部分指定的代码基于 [Mulan PSL v2](./LICENSE-MULAN) 许可下提供。
部分指定的代码基于 [Mulan PSL v2](./LICENSE-MULAN) 许可下提供。
<div>
<a href="https://github.com/LiteyukiStudio/nonebot-plugin-marshoai/graphs/contributors">
@@ -67,4 +69,4 @@ _✨ 使用 OpenAI 标准格式 API 的聊天机器人插件 ✨_
## 开发
- 请阅读[开发规范](./README_DEV.md)
- 请阅读[开发规范](./README_DEV.md)

View File

@@ -20,4 +20,5 @@ pre-commit install
## 其他提示
- 请勿在大小写不敏感的文件系统或操作系统中开发,否则可能会导致文件名大小写问题(例如Windows APFS(不区分大小写)等)
-西文大小写不敏感的文件系统或操作系统中开发时请注意文件名的西文大小写情况,点名批评 APFS 文件系统和视窗操作系统
- 请在提交的文件中尽可能使用相对路径

View File

@@ -14,7 +14,7 @@ title: config
#### ***attr*** `marshoai_aliases: set[str] = {'小棉'}`
#### ***attr*** `marshoai_main_colour: str = 'FFAAAA'`
#### ***attr*** `marshoai_main_colour: str = 'FEABA9'`
#### ***attr*** `marshoai_default_model: str = 'gpt-4o-mini'`

View File

@@ -109,7 +109,7 @@ Add options in the `.env` file from the diagram below in nonebot2 project.
| MARSHOAI_DEFAULT_NAME | `str` | `marsho` | Command to call Marsho |
| MARSHOAI_ALIASES | `set[str]` | `list["小棉"]` | Other name(Alias) to call Marsho |
| MARSHOAI_AT | `bool` | `false` | Call by @ or not |
| MARSHOAI_MAIN_COLOUR | `str` | `FFAAAA` | Theme color, used by some tools and features |
| MARSHOAI_MAIN_COLOUR | `str` | `FEABA9` | Theme color, used by some tools and features |
#### AI call

View File

@@ -14,7 +14,7 @@ title: config
#### ***attr*** `marshoai_aliases: set[str] = {'小棉'}`
#### ***attr*** `marshoai_main_colour: str = 'FFAAAA'`
#### ***attr*** `marshoai_main_colour: str = 'FEABA9'`
#### ***attr*** `marshoai_default_model: str = 'gpt-4o-mini'`

View File

@@ -103,7 +103,7 @@ title: 安装
| MARSHOAI_DEFAULT_NAME | `str` | `marsho` | 调用 Marsho 默认的命令前缀 |
| MARSHOAI_ALIASES | `set[str]` | `set{"小棉"}` | 调用 Marsho 的命令别名 |
| MARSHOAI_AT | `bool` | `false` | 决定是否使用at触发 |
| MARSHOAI_MAIN_COLOUR | `str` | `FFAAAA` | 主题色,部分工具和功能可用 |
| MARSHOAI_MAIN_COLOUR | `str` | `FEABA9` | 主题色,部分工具和功能可用 |
#### AI 调用

View File

@@ -111,7 +111,7 @@ GitHub Models API 的限制较多,不建议使用,建议通过修改`MARSHOA
| MARSHOAI_DEFAULT_NAME | `str` | `marsho` | 调用 Marsho 默认的命令前缀 |
| MARSHOAI_ALIASES | `set[str]` | `list["小棉"]` | 调用 Marsho 的命令别名 |
| MARSHOAI_AT | `bool` | `false` | 决定是否使用at触发 |
| MARSHOAI_MAIN_COLOUR | `str` | `FFAAAA` | 主题色,部分工具和功能可用 |
| MARSHOAI_MAIN_COLOUR | `str` | `FEABA9` | 主题色,部分工具和功能可用 |
#### AI 调用

View File

@@ -1,3 +1,27 @@
"""
MIT License
Copyright (c) 2025 Asankilp & LiteyukiStudio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
from nonebot.plugin import require
require("nonebot_plugin_alconna")

View File

@@ -16,7 +16,7 @@ class ConfigModel(BaseModel):
marshoai_aliases: list[str] = [
"小棉",
]
marshoai_main_colour: str = "FFAAAA"
marshoai_main_colour: str = "FEABA9"
marshoai_default_model: str = "gpt-4o-mini"
marshoai_prompt: str = (
"你是一只可爱的猫娘你的生日是9月6日你喜欢晒太阳撒娇吃零食玩耍等等可爱的事情偶尔会调皮一下"
@@ -31,8 +31,17 @@ class ConfigModel(BaseModel):
marshoai_additional_prompt: str = ""
marshoai_poke_suffix: str = "揉了揉你的猫耳"
marshoai_enable_richtext_parse: bool = True
"""
是否启用自动消息富文本解析 即若包含图片链接则发送图片、若包含LaTeX公式则发送公式图。
"""
marshoai_single_latex_parse: bool = False
"""
单行公式是否渲染(当消息富文本解析启用时可用)
"""
marshoai_enable_time_prompt: bool = True
"""
是否启用实时更新的日期与时间(精确到秒)与农历日期系统提示词
"""
marshoai_enable_nickname_tip: bool = True
marshoai_enable_support_image_tip: bool = True
marshoai_enforce_nickname: bool = True

View File

@@ -8,7 +8,7 @@ marshoai_aliases:
marshoai_at: false # 决定是否开启at响应
marshoai_main_colour: "FFAAAA" # 默认主色,部分插件和功能使用
marshoai_main_colour: "FEABA9" # 默认主色,部分插件和功能使用
marshoai_default_model: "gpt-4o-mini" # 默认模型设定为gpt-4o-mini。
# 主提示词定义了Marsho的性格和行为包含多语言名字翻译规则和对特定问题的回答约束。

View File

@@ -281,8 +281,7 @@ class ConvertLatex:
"""
LaTeX 在线渲染
参数
====
参数:
latex: str
LaTeX 代码
@@ -294,8 +293,7 @@ class ConvertLatex:
超时时间
retry_: int
重试次数
返回
====
返回:
bytes
图片
"""
@@ -305,6 +303,15 @@ class ConvertLatex:
@staticmethod
async def auto_choose_channel() -> ConvertChannel:
"""
依据访问延迟,自动选择 LaTeX 转换服务频道
返回
====
ConvertChannel
LaTeX 转换服务实例
"""
async def channel_test_wrapper(
channel: type[ConvertChannel],
) -> Tuple[int, type[ConvertChannel]]:

View File

@@ -58,7 +58,7 @@ marsho_cmd = on_alconna(
config.marshoai_default_name,
Args["text?", AllParam],
),
aliases=config.marshoai_aliases,
aliases=tuple(config.marshoai_aliases),
priority=10,
block=True,
)
@@ -147,6 +147,9 @@ async def load_context(target: MsgTarget, arg: Message = CommandArg()):
async def resetmem(target: MsgTarget):
if [target.id, target.private] not in target_list:
target_list.append([target.id, target.private])
backup_context = await get_backup_context(target.id, target.private)
if backup_context:
context.set_context(backup_context, target.id, target.private)
context.reset(target.id, target.private)
await resetmem_cmd.finish("上下文已重置")
@@ -284,6 +287,7 @@ async def marsho(
tools_lists = tools.tools_list + list(
map(lambda v: v.data(), get_function_calls().values())
)
logger.debug(f"正在获取回答,模型:{model_name}")
response = await make_chat_openai(
client=client,
model_name=model_name,
@@ -296,6 +300,7 @@ async def marsho(
# 当tool_calls非空时将finish_reason设置为TOOL_CALLS
if choice.message.tool_calls != None and config.marshoai_fix_toolcalls:
choice.finish_reason = CompletionsFinishReason.TOOL_CALLS
logger.info(f"完成原因:{choice.finish_reason}")
if choice.finish_reason == CompletionsFinishReason.STOPPED:
# 当对话成功时将dict的上下文添加到上下文类中
context.append(
@@ -445,11 +450,16 @@ with contextlib.suppress(ImportError): # 优化先不做()
user_nickname = nicknames.get(user_id, "")
try:
if config.marshoai_poke_suffix != "":
logger.info(f"收到戳一戳,用户昵称:{user_nickname}用户ID{user_id}")
response = await make_chat_openai(
client=client,
model_name=model_name,
msg=[
get_prompt(),
(
get_prompt()
if model_name.lower() not in NO_SYSPROMPT_MODELS
else None
),
UserMessage(
content=f"*{user_nickname}{config.marshoai_poke_suffix}"
),

View File

@@ -4,8 +4,8 @@ from .config import ConfigModel
from .constants import USAGE
metadata = PluginMetadata(
name="Marsho AI插件",
description="接入Azure服务或其他API的AI猫娘聊天插件,支持图片处理,外部函数调用,兼容多个AI模型可解析AI回复的富文本信息",
name="Marsho AI 插件",
description="接入 Azure API 或其他 API 的 AI 聊天插件,支持图片处理,外部函数调用,兼容包括 DeepSeek-R1 在内的多个模型",
usage=USAGE,
type="application",
config=ConfigModel,

View File

@@ -13,15 +13,17 @@ __marsho_meta__ = PluginMetadata(
)
weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
@on_function_call(description="获取当前时间,日期和星期")
async def get_current_time() -> str:
"""获取当前的时间和日期"""
current_time = DateTime.now().strftime("%Y.%m.%d %H:%M:%S")
current_weekday = DateTime.now().weekday()
current_time = DateTime.now()
weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
current_weekday_name = weekdays[current_weekday]
current_lunar_date = DateTime.now().to_lunar().date_hanzify()[5:]
time_prompt = f"现在的时间是 {current_time}{current_weekday_name},农历 {current_lunar_date}"
time_prompt = "现在的时间是 {}{}{}".format(
current_time.strftime("%Y.%m.%d %H:%M:%S"),
weekdays[current_time.weekday()],
current_time.chinesize.date_hanzify("农历{干支年}{生肖}{月份}{数序日}"),
)
return time_prompt

View File

@@ -2,6 +2,9 @@ import os
from zhDateTime import DateTime
weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
time_prompt = "现在的时间是{date_time}{weekday_name},农历{lunar_date}"
async def get_weather(location: str):
return f"{location}的温度是114514℃。"
@@ -13,12 +16,12 @@ async def get_current_env():
async def get_current_time():
current_time = DateTime.now().strftime("%Y.%m.%d %H:%M:%S")
current_weekday = DateTime.now().weekday()
current_time = DateTime.now()
weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
current_weekday_name = weekdays[current_weekday]
current_lunar_date = DateTime.now().to_lunar().date_hanzify()[5:]
time_prompt = f"现在的时间是{current_time}{current_weekday_name},农历{current_lunar_date}"
return time_prompt
return time_prompt.format(
date_time=current_time.strftime("%Y年%m月%d%H:%M:%S"),
weekday_name=weekdays[current_time.weekday()],
lunar_date=current_time.to_lunar().date_hanzify(
"{干支年}{生肖}{月份}{日期}"
),
)

View File

@@ -1,14 +1,12 @@
import base64
import json
import mimetypes
import os
import uuid
from typing import Any, Optional
import aiofiles # type: ignore
import httpx
import nonebot_plugin_localstore as store
# from zhDateTime import DateTime
from azure.ai.inference.aio import ChatCompletionsClient
from azure.ai.inference.models import SystemMessage
from nonebot import get_driver
@@ -16,7 +14,7 @@ from nonebot.log import logger
from nonebot_plugin_alconna import Image as ImageMsg
from nonebot_plugin_alconna import Text as TextMsg
from nonebot_plugin_alconna import UniMessage
from openai import AsyncOpenAI
from openai import AsyncOpenAI, NotGiven
from zhDateTime import DateTime
from .config import config
@@ -27,10 +25,35 @@ nickname_json = None # 记录昵称
praises_json = None # 记录夸赞名单
loaded_target_list = [] # 记录已恢复备份的上下文的列表
NOT_GIVEN = NotGiven()
# 时间参数相关
if config.marshoai_enable_time_prompt:
_weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
_time_prompt = "现在的时间是{date_time}{weekday_name}{lunar_date}"
# noinspection LongLine
chromium_headers = {
_chromium_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0"
}
"""
最新的火狐用户代理头
"""
# noinspection LongLine
_praises_init_data = {
"like": [
{
"name": "Asankilp",
"advantages": "赋予了Marsho猫娘人格使用手机在vim与vscode的加持下为Marsho写了许多代码使Marsho更加可爱",
}
]
}
"""
初始夸赞名单之数据
"""
async def get_image_raw_and_type(
@@ -45,11 +68,10 @@ async def get_image_raw_and_type(
return:
tuple[bytes, str]: 图片二进制数据, 图片MIME格式
"""
async with httpx.AsyncClient() as client:
response = await client.get(url, headers=chromium_headers, timeout=timeout)
response = await client.get(url, headers=_chromium_headers, timeout=timeout)
if response.status_code == 200:
# 获取图片数据
content_type = response.headers.get("Content-Type")
@@ -87,13 +109,15 @@ async def make_chat(
model_name: str,
tools: Optional[list] = None,
):
"""调用ai获取回复
"""
调用ai获取回复
参数:
client: 用于与AI模型进行通信
msg: 消息内容
model_name: 指定AI模型名
tools: 工具列表"""
tools: 工具列表
"""
return await client.complete(
messages=msg,
model=model_name,
@@ -110,20 +134,22 @@ async def make_chat_openai(
model_name: str,
tools: Optional[list] = None,
):
"""使用 Openai SDK 调用ai获取回复
"""
使用 Openai SDK 调用ai获取回复
参数:
client: 用于与AI模型进行通信
msg: 消息内容
model_name: 指定AI模型名
tools: 工具列表"""
return await client.chat.completions.create(
tools: 工具列表
"""
return await client.chat.completions.create( # type: ignore
messages=msg,
model=model_name,
tools=tools,
temperature=config.marshoai_temperature,
max_tokens=config.marshoai_max_tokens,
top_p=config.marshoai_top_p,
tools=tools or NOT_GIVEN,
temperature=config.marshoai_temperature or NOT_GIVEN,
max_tokens=config.marshoai_max_tokens or NOT_GIVEN,
top_p=config.marshoai_top_p or NOT_GIVEN,
timeout=config.marshoai_timeout,
)
@@ -134,17 +160,9 @@ def get_praises():
praises_file = store.get_plugin_data_file(
"praises.json"
) # 夸赞名单文件使用localstore存储
if not os.path.exists(praises_file):
init_data = {
"like": [
{
"name": "Asankilp",
"advantages": "赋予了Marsho猫娘人格使用vim与vscode为Marsho写了许多代码使Marsho更加可爱",
}
]
}
if not praises_file.exists():
with open(praises_file, "w", encoding="utf-8") as f:
json.dump(init_data, f, ensure_ascii=False, indent=4)
json.dump(_praises_init_data, f, ensure_ascii=False, indent=4)
with open(praises_file, "r", encoding="utf-8") as f:
data = json.load(f)
praises_json = data
@@ -154,19 +172,11 @@ def get_praises():
async def refresh_praises_json():
global praises_json
praises_file = store.get_plugin_data_file("praises.json")
if not os.path.exists(praises_file):
init_data = {
"like": [
{
"name": "Asankilp",
"advantages": "赋予了Marsho猫娘人格使用vim与vscode为Marsho写了许多代码使Marsho更加可爱",
}
]
}
if not praises_file.exists():
with open(praises_file, "w", encoding="utf-8") as f:
json.dump(init_data, f, ensure_ascii=False, indent=4)
with open(praises_file, "r", encoding="utf-8") as f:
data = json.load(f)
json.dump(_praises_init_data, f, ensure_ascii=False, indent=4) # 异步?
async with aiofiles.open(praises_file, "r", encoding="utf-8") as f:
data = json.loads(await f.read())
praises_json = data
@@ -179,33 +189,48 @@ def build_praises():
async def save_context_to_json(name: str, context: Any, path: str):
context_dir = store.get_plugin_data_dir() / path
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:
(context_dir := store.get_plugin_data_dir() / path).mkdir(
parents=True, exist_ok=True
)
# os.makedirs(context_dir, exist_ok=True)
with open(context_dir / f"{name}.json", "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, path: str) -> list:
"""从指定路径加载历史记录"""
context_dir = store.get_plugin_data_dir() / path
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:
(context_dir := store.get_plugin_data_dir() / path).mkdir(
parents=True, exist_ok=True
)
if (file_path := context_dir / f"{name}.json").exists():
async with aiofiles.open(file_path, "r", encoding="utf-8") as json_file:
return json.loads(await json_file.read())
else:
return []
async def get_nicknames():
"""获取nickname_json, 优先来源于全局变量"""
global nickname_json
if nickname_json is None:
filename = store.get_plugin_data_file("nickname.json")
# noinspection PyBroadException
try:
async with aiofiles.open(filename, "r", encoding="utf-8") as f:
nickname_json = json.loads(await f.read())
except Exception:
nickname_json = {}
return nickname_json
async def set_nickname(user_id: str, name: str):
global nickname_json
filename = store.get_plugin_data_file("nickname.json")
if not os.path.exists(filename):
if not filename.exists():
data = {}
else:
with open(filename, "r", encoding="utf-8") as f:
data = json.load(f)
async with aiofiles.open(filename, "r", encoding="utf-8") as f:
data = json.loads(await f.read())
data[user_id] = name
if name == "" and user_id in data:
del data[user_id]
@@ -214,46 +239,37 @@ async def set_nickname(user_id: str, name: str):
nickname_json = data
# noinspection PyBroadException
async def get_nicknames():
"""获取nickname_json, 优先来源于全局变量"""
global nickname_json
if nickname_json is None:
filename = store.get_plugin_data_file("nickname.json")
try:
with open(filename, "r", encoding="utf-8") as f:
nickname_json = json.load(f)
except Exception:
nickname_json = {}
return nickname_json
async def refresh_nickname_json():
"""强制刷新nickname_json, 刷新全局变量"""
global nickname_json
filename = store.get_plugin_data_file("nickname.json")
# noinspection PyBroadException
try:
with open(filename, "r", encoding="utf-8") as f:
nickname_json = json.load(f)
async with aiofiles.open(
store.get_plugin_data_file("nickname.json"), "r", encoding="utf-8"
) as f:
nickname_json = json.loads(await f.read())
except Exception:
logger.error("Error loading nickname.json")
logger.error("刷新 nickname_json 表错误:无法载入 nickname.json 文件")
def get_prompt():
"""获取系统提示词"""
prompts = ""
prompts += config.marshoai_additional_prompt
prompts = config.marshoai_additional_prompt
if config.marshoai_enable_praises:
praises_prompt = build_praises()
prompts += praises_prompt
if config.marshoai_enable_time_prompt:
current_time = DateTime.now().strftime("%Y.%m.%d %H:%M:%S")
current_lunar_date = (
DateTime.now().to_lunar().date_hanzify()[5:]
) # 库更新之前使用切片
time_prompt = f"现在的时间是{current_time},农历{current_lunar_date}"
prompts += time_prompt
prompts += _time_prompt.format(
date_time=(current_time := DateTime.now()).strftime(
"%Y年%m月%d%H:%M:%S"
),
weekday_name=_weekdays[current_time.weekday()],
lunar_date=current_time.chinesize.date_hanzify(
"农历{干支年}{生肖}{月份}{日期}"
),
)
marsho_prompt = config.marshoai_prompt
spell = SystemMessage(content=marsho_prompt + prompts).as_dict()
return spell

View File

@@ -12,7 +12,7 @@ dependencies = [
"nonebot2>=2.4.0",
"nonebot-plugin-alconna>=0.48.0",
"nonebot-plugin-localstore>=0.7.1",
"zhDatetime>=1.1.1",
"zhDatetime>=2.0.0",
"aiohttp>=3.9",
"httpx>=0.27.0",
"ruamel.yaml>=0.18.6",
@@ -74,6 +74,7 @@ dev = [
"black>=24.10.0",
"litedoc>=0.1.0.dev20240906203154",
"viztracer>=1.0.0",
"types-aiofiles"
]
test = [
"nonebug>=0.4.3",

View File

@@ -1,4 +1,6 @@
# Marsho Resources
本目录存放 Marsho 的图像资源logo,icon由[Asankilp](https://github.com/Asankilp)绘制。
所有资源均在[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)许可下提供。
> Copyright (c) 2025 [@Asankilp](https://github.com/Asankilp)
本目录存放 Marsho 的图像资源logo, icon均由[Asankilp](https://github.com/Asankilp)绘制。\
上述所有资源均在[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)许可下提供。