nonebot-plugin-llmchat/nonebot_plugin_llmchat/__init__.py
FuQuan233 0d6771eca6
Some checks failed
Pyright Lint / Pyright Lint (push) Has been cancelled
Ruff Lint / Ruff Lint (push) Has been cancelled
♻️ 大幅重构,拆分模块,增加一些MCP相关限制
2026-07-29 17:00:22 +08:00

106 lines
3.5 KiB
Python
Executable file

import random
from nonebot import get_driver, get_plugin_config, logger, on_message, require
from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent
from nonebot.plugin import PluginMetadata
from nonebot.rule import Rule
from .commands import register_commands
from .config import Config
from .conversation import ConversationService
from .dispatcher import MessageDispatcher
from .mcpclient import MCPClient
from .persistence import StatePersistence
from .state import StateStore
require("nonebot_plugin_localstore")
import nonebot_plugin_localstore as store
require("nonebot_plugin_apscheduler")
from nonebot_plugin_apscheduler import scheduler
__plugin_meta__ = PluginMetadata(
name="llmchat",
description="支持多API预设、MCP协议、联网搜索、视觉模型的AI群聊插件",
usage="@机器人 + 消息 开启对话",
type="application",
homepage="https://github.com/FuQuan233/nonebot-plugin-llmchat",
config=Config,
supported_adapters={"~onebot.v11"},
)
plugin_config = get_plugin_config(Config).llmchat
driver = get_driver()
states = StateStore(plugin_config)
# 保留旧版公开名称,避免依赖插件内部状态的代码立即失效。
group_states = states.group_states
private_chat_states = states.private_states
async def is_triggered(event: GroupMessageEvent | PrivateMessageEvent) -> bool:
is_group = isinstance(event, GroupMessageEvent)
if not is_group and not plugin_config.enable_private_chat:
return False
state = states.get(event.group_id if is_group else event.user_id, is_group)
if state.preset_name == "off" or event.user_id in plugin_config.blacklist_user_ids:
return False
text = event.get_plaintext().strip()
if any(text.startswith(prefix) for prefix in plugin_config.ignore_prefixes):
return False
state.pending_events.append(event)
if not is_group:
return True
return event.is_tome() or random.random() < state.random_trigger_prob
handler = on_message(rule=Rule(is_triggered), priority=99, block=False)
conversation = ConversationService(
config=plugin_config,
states=states,
bot_names=set(driver.config.nickname),
sender=handler.send,
)
message_dispatcher = MessageDispatcher(conversation.process_event)
@handler.handle()
async def handle_message(event: GroupMessageEvent | PrivateMessageEvent) -> None:
is_group = isinstance(event, GroupMessageEvent)
context_id = event.group_id if is_group else event.user_id
state = states.get(context_id, is_group)
logger.debug(
f"收到{'群聊' if is_group else '私聊'}消息 " f"会话:{context_id} 用户:{event.user_id} 内容:{event.get_plaintext()}"
)
await message_dispatcher.enqueue(context_id, is_group, state, event)
register_commands(plugin_config, states)
state_persistence = StatePersistence(
plugin_config,
states,
store.get_plugin_data_file("llmchat_state.json"),
store.get_plugin_data_file("llmchat_private_state.json"),
)
@driver.on_startup
async def init_plugin() -> None:
logger.info("llmchat插件启动初始化")
await state_persistence.load()
scheduler.add_job(
state_persistence.save,
"interval",
minutes=5,
id="llmchat_save_state",
replace_existing=True,
)
@driver.on_shutdown
async def cleanup_plugin() -> None:
logger.info("llmchat插件关闭清理")
await message_dispatcher.shutdown()
await state_persistence.save()
await MCPClient.destroy_instance()