fix:添加新插件API
This commit is contained in:
@@ -1,16 +1,29 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [0.7.1] -2025-6-2
|
## [0.7.1] -2025-6-3
|
||||||
- 修复关键词功能,并且在focus中可用
|
重点优化
|
||||||
- 更新planner架构,大大加快速度和表现效果,建议使用simple规划器
|
|
||||||
- 为normal加入使用action的能力
|
加入了人物侧写!麦麦认得群友
|
||||||
- 修复emoji配置项无效问题
|
更新planner架构,大大加快速度和表现效果!
|
||||||
|
为normal_chat加入动作执行!
|
||||||
|
新增关系处理器
|
||||||
|
修复关键词功能,并且在focus中可用!
|
||||||
|
|
||||||
|
|
||||||
- 修复log出错问题
|
|
||||||
- 修复focus吞第一条消息问题
|
修复了:
|
||||||
- 可关闭聊天规划处理器(建议关闭)
|
群名称导致log保存失败
|
||||||
- 优化记忆同步速度,修复记忆构建缺少chat_id的问题
|
focus吞掉首条消息
|
||||||
|
表达方式的多样性
|
||||||
|
可关闭思考处理器(建议默认关闭)
|
||||||
|
focus没有时间信息的问题
|
||||||
|
修复了表情包action
|
||||||
|
优化聊天记录构建方式
|
||||||
|
优化记忆同步速度和记忆构建缺少chat_id的问题
|
||||||
|
优化工作记忆处理器
|
||||||
|
优化人格表达
|
||||||
|
删除无效字段防止数据库报错
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ from src.chat.focus_chat.planners.actions.base_action import BaseAction, registe
|
|||||||
from src.chat.heart_flow.observation.chatting_observation import ChattingObservation
|
from src.chat.heart_flow.observation.chatting_observation import ChattingObservation
|
||||||
from src.chat.focus_chat.hfc_utils import create_empty_anchor_message
|
from src.chat.focus_chat.hfc_utils import create_empty_anchor_message
|
||||||
from src.common.logger_manager import get_logger
|
from src.common.logger_manager import get_logger
|
||||||
|
from src.llm_models.utils_model import LLMRequest
|
||||||
from src.person_info.person_info import person_info_manager
|
from src.person_info.person_info import person_info_manager
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
from src.config.config import global_config
|
||||||
import os
|
import os
|
||||||
import inspect
|
import inspect
|
||||||
import toml # 导入 toml 库
|
import toml # 导入 toml 库
|
||||||
@@ -35,7 +37,6 @@ class PluginAction(BaseAction):
|
|||||||
|
|
||||||
# 存储内部服务和对象引用
|
# 存储内部服务和对象引用
|
||||||
self._services = {}
|
self._services = {}
|
||||||
self._global_config = global_config # 存储全局配置的只读引用
|
|
||||||
self.config: Dict[str, Any] = {} # 用于存储插件自身的配置
|
self.config: Dict[str, Any] = {} # 用于存储插件自身的配置
|
||||||
|
|
||||||
# 从kwargs提取必要的内部服务
|
# 从kwargs提取必要的内部服务
|
||||||
@@ -100,10 +101,8 @@ class PluginAction(BaseAction):
|
|||||||
安全地从全局配置中获取一个值。
|
安全地从全局配置中获取一个值。
|
||||||
插件应使用此方法读取全局配置,以保证只读和隔离性。
|
插件应使用此方法读取全局配置,以保证只读和隔离性。
|
||||||
"""
|
"""
|
||||||
if self._global_config:
|
|
||||||
return self._global_config.get(key, default)
|
return global_config.get(key, default)
|
||||||
logger.debug(f"{self.log_prefix} 尝试访问全局配置项 '{key}',但全局配置未提供。")
|
|
||||||
return default
|
|
||||||
|
|
||||||
async def get_user_id_by_person_name(self, person_name: str) -> Tuple[str, str]:
|
async def get_user_id_by_person_name(self, person_name: str) -> Tuple[str, str]:
|
||||||
"""根据用户名获取用户ID"""
|
"""根据用户名获取用户ID"""
|
||||||
@@ -228,6 +227,62 @@ class PluginAction(BaseAction):
|
|||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
||||||
|
async def send_message_by_replyer(self, target: Optional[str] = None, extra_info_block: Optional[str] = None) -> bool:
|
||||||
|
"""通过 replyer 发送消息的简化方法
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: 要发送的消息文本
|
||||||
|
target: 目标消息(可选)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 是否发送成功
|
||||||
|
"""
|
||||||
|
replyer = self._services.get("replyer")
|
||||||
|
chat_stream = self._services.get("chat_stream")
|
||||||
|
|
||||||
|
if not replyer or not chat_stream:
|
||||||
|
logger.error(f"{self.log_prefix} 无法发送消息:缺少必要的内部服务")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 构造简化的动作数据
|
||||||
|
reply_data = {"target": target or "", "extra_info_block": extra_info_block}
|
||||||
|
|
||||||
|
# 获取锚定消息(如果有)
|
||||||
|
observations = self._services.get("observations", [])
|
||||||
|
|
||||||
|
# 查找 ChattingObservation 实例
|
||||||
|
chatting_observation = None
|
||||||
|
for obs in observations:
|
||||||
|
if isinstance(obs, ChattingObservation):
|
||||||
|
chatting_observation = obs
|
||||||
|
break
|
||||||
|
|
||||||
|
if not chatting_observation:
|
||||||
|
logger.warning(f"{self.log_prefix} 未找到 ChattingObservation 实例,创建占位符")
|
||||||
|
anchor_message = await create_empty_anchor_message(
|
||||||
|
chat_stream.platform, chat_stream.group_info, chat_stream
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
anchor_message = chatting_observation.search_message_by_text(reply_data["target"])
|
||||||
|
if not anchor_message:
|
||||||
|
logger.info(f"{self.log_prefix} 未找到锚点消息,创建占位符")
|
||||||
|
anchor_message = await create_empty_anchor_message(
|
||||||
|
chat_stream.platform, chat_stream.group_info, chat_stream
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
anchor_message.update_chat_stream(chat_stream)
|
||||||
|
|
||||||
|
# 调用内部方法发送消息
|
||||||
|
success, _ = await replyer.deal_reply(
|
||||||
|
cycle_timers=self.cycle_timers,
|
||||||
|
action_data=reply_data,
|
||||||
|
anchor_message=anchor_message,
|
||||||
|
reasoning=self.reasoning,
|
||||||
|
thinking_id=self.thinking_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
return success
|
||||||
|
|
||||||
def get_chat_type(self) -> str:
|
def get_chat_type(self) -> str:
|
||||||
"""获取当前聊天类型
|
"""获取当前聊天类型
|
||||||
|
|
||||||
@@ -266,6 +321,60 @@ class PluginAction(BaseAction):
|
|||||||
|
|
||||||
return messages
|
return messages
|
||||||
|
|
||||||
|
def get_available_models(self) -> Dict[str, Any]:
|
||||||
|
"""获取所有可用的模型配置
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, Any]: 模型配置字典,key为模型名称,value为模型配置
|
||||||
|
"""
|
||||||
|
if not hasattr(global_config, "model"):
|
||||||
|
logger.error(f"{self.log_prefix} 无法获取模型列表:全局配置中未找到 model 配置")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
models = global_config.model
|
||||||
|
|
||||||
|
return models
|
||||||
|
|
||||||
|
async def generate_with_model(
|
||||||
|
self,
|
||||||
|
prompt: str,
|
||||||
|
model_config: Dict[str, Any],
|
||||||
|
max_tokens: int = 2000,
|
||||||
|
request_type: str = "plugin.generate",
|
||||||
|
**kwargs
|
||||||
|
) -> Tuple[bool, str]:
|
||||||
|
"""使用指定模型生成内容
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prompt: 提示词
|
||||||
|
model_config: 模型配置(从 get_available_models 获取的模型配置)
|
||||||
|
temperature: 温度参数,控制随机性 (0-1)
|
||||||
|
max_tokens: 最大生成token数
|
||||||
|
request_type: 请求类型标识
|
||||||
|
**kwargs: 其他模型特定参数
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple[bool, str]: (是否成功, 生成的内容或错误信息)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
|
||||||
|
|
||||||
|
logger.info(f"prompt: {prompt}")
|
||||||
|
|
||||||
|
llm_request = LLMRequest(
|
||||||
|
model=model_config,
|
||||||
|
max_tokens=max_tokens,
|
||||||
|
request_type=request_type,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
response,(resoning , model_name) = await llm_request.generate_response_async(prompt)
|
||||||
|
return True, response, resoning, model_name
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = f"生成内容时出错: {str(e)}"
|
||||||
|
logger.error(f"{self.log_prefix} {error_msg}")
|
||||||
|
return False, error_msg
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def process(self) -> Tuple[bool, str]:
|
async def process(self) -> Tuple[bool, str]:
|
||||||
"""插件处理逻辑,子类必须实现此方法
|
"""插件处理逻辑,子类必须实现此方法
|
||||||
|
|||||||
@@ -190,11 +190,10 @@ class ActionPlanner(BasePlanner):
|
|||||||
prompt = f"{prompt}"
|
prompt = f"{prompt}"
|
||||||
llm_content, (reasoning_content, _) = await self.planner_llm.generate_response_async(prompt=prompt)
|
llm_content, (reasoning_content, _) = await self.planner_llm.generate_response_async(prompt=prompt)
|
||||||
|
|
||||||
logger.debug(
|
logger.info(
|
||||||
f"{self.log_prefix}规划器Prompt:\n{prompt}\n\n决策动作:{action},\n动作信息: '{action_data}'\n理由: {reasoning}"
|
f"{self.log_prefix}规划器Prompt:\n{prompt}\n\nLLM 原始响应: {llm_content}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.debug(f"{self.log_prefix}LLM 原始响应: {llm_content}")
|
|
||||||
logger.debug(f"{self.log_prefix}LLM 原始理由响应: {reasoning_content}")
|
logger.debug(f"{self.log_prefix}LLM 原始理由响应: {reasoning_content}")
|
||||||
except Exception as req_e:
|
except Exception as req_e:
|
||||||
logger.error(f"{self.log_prefix}LLM 请求执行失败: {req_e}")
|
logger.error(f"{self.log_prefix}LLM 请求执行失败: {req_e}")
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import random
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import re
|
import re
|
||||||
|
|
||||||
logger = get_logger("expressor")
|
logger = get_logger("replyer")
|
||||||
|
|
||||||
|
|
||||||
def init_prompt():
|
def init_prompt():
|
||||||
@@ -295,7 +295,7 @@ class DefaultReplyer:
|
|||||||
# logger.info(f"{self.log_prefix}[Replier-{thinking_id}]\nPrompt:\n{prompt}\n")
|
# logger.info(f"{self.log_prefix}[Replier-{thinking_id}]\nPrompt:\n{prompt}\n")
|
||||||
content, (reasoning_content, model_name) = await self.express_model.generate_response_async(prompt)
|
content, (reasoning_content, model_name) = await self.express_model.generate_response_async(prompt)
|
||||||
|
|
||||||
logger.debug(f"prompt: {prompt}")
|
logger.info(f"prompt: {prompt}")
|
||||||
logger.info(f"最终回复: {content}")
|
logger.info(f"最终回复: {content}")
|
||||||
|
|
||||||
info_catcher.catch_after_llm_generated(
|
info_catcher.catch_after_llm_generated(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[inner]
|
[inner]
|
||||||
version = "2.12.0"
|
version = "2.12.1"
|
||||||
|
|
||||||
#----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读----
|
#----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读----
|
||||||
#如果你想要修改配置文件,请在修改后将version的值进行变更
|
#如果你想要修改配置文件,请在修改后将version的值进行变更
|
||||||
|
|||||||
Reference in New Issue
Block a user