Files
Mofox-Core/plugins/hello_world_plugin/plugin.py
Windpicker-owo 071a160da9 feat(plugin): 禁用 hello_world_plugin 插件
refactor(prompt): 将日志级别从 info 调整为 debug
fix(mem_monitor): 启用内存监控并调整监控间隔至 2400s
feat(llm_models): 添加系统提示支持,优化请求策略
refactor(main): 更新内存监控启动日志信息
refactor(user_profile_tool): 将用户画像更新日志级别调整为 debug
refactor(exa_engine): 移除搜索引擎请求中的高亮片段选项
feat(system_prompt): 添加系统提示内容
2025-12-08 12:02:44 +08:00

262 lines
9.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import random
from typing import Any, ClassVar
from src.common.logger import get_logger
from src.common.security import VerifiedDep
# 修正导入路径让Pylance不再抱怨
from src.plugin_system import (
BaseAction,
BaseEventHandler,
BasePlugin,
BasePrompt,
BaseTool,
ChatType,
CommandArgs,
ComponentInfo,
ConfigField,
EventType,
PlusCommand,
ToolParamType,
register_plugin,
)
from src.plugin_system.base.base_event import HandlerResult
from src.plugin_system.base.base_http_component import BaseRouterComponent
from src.plugin_system.base.component_types import InjectionRule, InjectionType
logger = get_logger("hello_world_plugin")
class StartupMessageHandler(BaseEventHandler):
"""启动时打印消息的事件处理器。"""
handler_name = "hello_world_startup_handler"
handler_description = "在机器人启动时打印一条日志。"
init_subscribe: ClassVar[list[EventType]] = [EventType.ON_START]
async def execute(self, params: dict) -> HandlerResult:
logger.info("🎉 Hello World 插件已启动,准备就绪!")
return HandlerResult(success=True, continue_process=True)
class GetSystemInfoTool(BaseTool):
"""一个提供系统信息的示例工具。"""
name = "get_system_info"
description = "获取当前系统的模拟版本和状态信息。"
available_for_llm = True
parameters: ClassVar = [
("query", ToolParamType.STRING, "要搜索的关键词或问题。", True, None),
("num_results", ToolParamType.INTEGER, "期望每个搜索引擎返回的搜索结果数量默认为5。", False, None),
(
"time_range",
ToolParamType.STRING,
"指定搜索的时间范围,可以是 'any', 'week', 'month'。默认为 'any'",
False,
["any", "week", "month"],
),
] # type: ignore
async def execute(self, function_args: dict[str, Any]) -> dict[str, Any]:
return {"name": self.name, "content": "系统版本: 1.0.1, 状态: 运行正常"}
class HelloCommand(PlusCommand):
"""一个简单的 /hello 命令,使用配置文件中的问候语。"""
command_name = "hello"
command_description = "向机器人发送一个简单的问候。"
command_aliases: ClassVar[list[str]] = ["hi", "你好"]
chat_type_allow = ChatType.ALL
async def execute(self, args: CommandArgs) -> tuple[bool, str | None, bool]:
greeting = str(self.get_config("greeting.message", "Hello, World! 我是一个由 MoFox_Bot 驱动的插件。"))
await self.send_text(greeting)
return True, "成功发送问候", True
# ==================================================================================
# 新的激活方式示例 Actions
# ==================================================================================
class KeywordActivationExampleAction(BaseAction):
"""关键词激活示例
此示例展示如何使用关键词匹配来激活 Action。
"""
action_name = "keyword_example"
action_description = "当检测到特定关键词时发送回应"
action_require: ClassVar[list[str]] = ["用户提到了问候语"]
associated_types: ClassVar[list[str]] = ["text"]
async def go_activate(self, chat_content: str = "", llm_judge_model=None) -> bool:
"""关键词激活:检测到"你好""hello""hi"时激活"""
return await self._keyword_match(
chat_content,
keywords=["你好", "hello", "hi", ""],
case_sensitive=False # 不区分大小写
)
async def execute(self) -> tuple[bool, str]:
await self.send_text("检测到问候语,我也向你问好!👋")
return True, "发送了问候回应"
class LLMJudgeExampleAction(BaseAction):
"""LLM 判断激活示例
此示例展示如何使用 LLM 来智能判断是否激活 Action。
"""
action_name = "llm_judge_example"
action_description = "当用户表达情绪低落时提供安慰"
action_require: ClassVar[list[str]] = ["用户情绪低落", "需要情感支持"]
associated_types: ClassVar[list[str]] = ["text"]
async def go_activate(self, chat_content: str = "", llm_judge_model=None) -> bool:
"""LLM 判断激活:判断用户是否情绪低落"""
return await self._llm_judge_activation(
judge_prompt="""
判断用户是否表达了以下情绪或需求:
1. 感到难过、沮丧或失落
2. 表达了负面情绪
3. 需要安慰或鼓励
如果用户表达了上述情绪或需求,回答"",否则回答""
""",
llm_judge_model=llm_judge_model
)
async def execute(self) -> tuple[bool, str]:
await self.send_text("看起来你心情不太好,希望能让你开心一点!🤗💕")
return True, "发送了安慰消息"
class CombinedActivationExampleAction(BaseAction):
"""组合激活条件示例
此示例展示如何组合多种激活条件。
"""
action_name = "combined_example"
action_description = "展示如何组合多种激活条件"
action_require: ClassVar[list[str]] = ["展示灵活的激活逻辑"]
associated_types: ClassVar[list[str]] = ["text"]
async def go_activate(self, chat_content: str = "", llm_judge_model=None) -> bool:
"""组合激活:随机 20% 概率,或者匹配特定关键词"""
# 先尝试随机激活
if await self._random_activation(0.2):
return True
# 如果随机未激活,尝试关键词匹配
if await self._keyword_match(chat_content, ["表情", "emoji", "😊"], case_sensitive=False):
return True
# 都不满足则不激活
return False
async def execute(self) -> tuple[bool, str]:
await self.send_text("这是一个组合激活条件的示例!✨")
return True, "发送了示例消息"
class RandomEmojiAction(BaseAction):
"""一个随机发送表情的动作。
此示例展示了如何使用新的 go_activate() 方法来实现随机激活。
"""
action_name = "random_emoji"
action_description = "随机发送一个表情符号,增加聊天的趣味性。"
action_require: ClassVar[list[str]] = ["当对话气氛轻松时", "可以用来回应简单的情感表达"]
associated_types: ClassVar[list[str]] = ["text"]
async def go_activate(self, llm_judge_model=None) -> bool:
"""使用新的激活方式10% 的概率激活
注意:不需要传入 chat_content会自动从实例属性中获取
"""
return await self._random_activation(0.1)
async def execute(self) -> tuple[bool, str]:
emojis = ["😊", "😂", "👍", "🎉", "🤔", "🤖"]
await self.send_text(random.choice(emojis))
return True, "成功发送了一个随机表情"
class WeatherPrompt(BasePrompt):
"""一个简单的Prompt组件用于向Planner注入天气信息。"""
prompt_name = "weather_info_prompt"
prompt_description = "向Planner注入当前天气信息以丰富对话上下文。"
injection_rules: ClassVar[list[InjectionRule]] = [InjectionRule(target_prompt="planner_prompt", injection_type=InjectionType.REPLACE, target_content="## 可用动作列表")]
async def execute(self) -> str:
# 在实际应用中这里可以调用天气API
# 为了演示,我们返回一个固定的天气信息
logger.info(self.target_prompt_name)
return "当前天气晴朗温度25°C。"
class HelloWorldRouter(BaseRouterComponent):
"""一个简单的HTTP端点示例。"""
component_name = "hello_world_router"
component_description = "提供一个简单的 /greet HTTP GET 端点。"
def register_endpoints(self) -> None:
@self.router.get("/greet", summary="返回一个问候消息")
def greet(_=VerifiedDep):
"""这个端点返回一个固定的问候语。"""
return {"message": "Hello from your new API endpoint!"}
@register_plugin
class HelloWorldPlugin(BasePlugin):
"""一个包含四大核心组件和高级配置功能的入门示例插件。"""
plugin_name = "hello_world_plugin"
enable_plugin: bool = False
dependencies: ClassVar = []
python_dependencies: ClassVar = []
config_file_name = "config.toml"
config_schema: ClassVar = {
"meta": {
"config_version": ConfigField(type=int, default=1, description="配置文件版本,请勿手动修改。"),
},
"greeting": {
"message": ConfigField(
type=str, default="这是来自配置文件的问候!👋", description="HelloCommand 使用的问候语。"
),
},
"components": {
"hello_command_enabled": ConfigField(type=bool, default=True, description="是否启用 /hello 命令。"),
"random_emoji_action_enabled": ConfigField(type=bool, default=True, description="是否启用随机表情动作。"),
},
}
def get_plugin_components(self) -> list[tuple[ComponentInfo, type]]:
"""根据配置文件动态注册插件的功能组件。"""
components: list[tuple[ComponentInfo, type]] = []
components.append((StartupMessageHandler.get_handler_info(), StartupMessageHandler))
components.append((GetSystemInfoTool.get_tool_info(), GetSystemInfoTool))
if self.get_config("components.hello_command_enabled", True):
components.append((HelloCommand.get_plus_command_info(), HelloCommand))
if self.get_config("components.random_emoji_action_enabled", True):
components.append((RandomEmojiAction.get_action_info(), RandomEmojiAction))
# 注册新的Prompt组件
components.append((WeatherPrompt.get_prompt_info(), WeatherPrompt))
# 注册新的Router组件
components.append((HelloWorldRouter.get_router_info(), HelloWorldRouter))
return components