更多events
This commit is contained in:
@@ -389,7 +389,10 @@ class HeartFChatting:
|
|||||||
chat_target_info=planner_info[1],
|
chat_target_info=planner_info[1],
|
||||||
current_available_actions=planner_info[2],
|
current_available_actions=planner_info[2],
|
||||||
)
|
)
|
||||||
await events_manager.handle_mai_events(EventType.ON_PLAN, None, prompt_info[0], None, self.chat_stream.stream_id)
|
if not await events_manager.handle_mai_events(
|
||||||
|
EventType.ON_PLAN, None, prompt_info[0], None, self.chat_stream.stream_id
|
||||||
|
):
|
||||||
|
return False
|
||||||
with Timer("规划器", cycle_timers):
|
with Timer("规划器", cycle_timers):
|
||||||
plan_result, target_message = await self.action_planner.plan(mode=self.loop_mode)
|
plan_result, target_message = await self.action_planner.plan(mode=self.loop_mode)
|
||||||
|
|
||||||
@@ -761,6 +764,7 @@ class HeartFChatting:
|
|||||||
available_actions=available_actions,
|
available_actions=available_actions,
|
||||||
enable_tool=global_config.tool.enable_tool,
|
enable_tool=global_config.tool.enable_tool,
|
||||||
request_type=request_type,
|
request_type=request_type,
|
||||||
|
from_plugin=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not success or not reply_set:
|
if not success or not reply_set:
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ from src.chat.memory_system.instant_memory import InstantMemory
|
|||||||
from src.mood.mood_manager import mood_manager
|
from src.mood.mood_manager import mood_manager
|
||||||
from src.person_info.relationship_fetcher import relationship_fetcher_manager
|
from src.person_info.relationship_fetcher import relationship_fetcher_manager
|
||||||
from src.person_info.person_info import get_person_info_manager
|
from src.person_info.person_info import get_person_info_manager
|
||||||
from src.plugin_system.base.component_types import ActionInfo
|
from src.plugin_system.base.component_types import ActionInfo, EventType
|
||||||
from src.plugin_system.apis import llm_api
|
from src.plugin_system.apis import llm_api
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger("replyer")
|
logger = get_logger("replyer")
|
||||||
|
|
||||||
|
|
||||||
@@ -179,7 +180,10 @@ class DefaultReplyer:
|
|||||||
extra_info: str = "",
|
extra_info: str = "",
|
||||||
available_actions: Optional[Dict[str, ActionInfo]] = None,
|
available_actions: Optional[Dict[str, ActionInfo]] = None,
|
||||||
enable_tool: bool = True,
|
enable_tool: bool = True,
|
||||||
) -> Tuple[bool, Optional[str], Optional[str]]:
|
from_plugin: bool = True,
|
||||||
|
stream_id: Optional[str] = None,
|
||||||
|
) -> Tuple[bool, Optional[Dict[str, Any]], Optional[str]]:
|
||||||
|
# sourcery skip: merge-nested-ifs
|
||||||
"""
|
"""
|
||||||
回复器 (Replier): 负责生成回复文本的核心逻辑。
|
回复器 (Replier): 负责生成回复文本的核心逻辑。
|
||||||
|
|
||||||
@@ -188,9 +192,10 @@ class DefaultReplyer:
|
|||||||
extra_info: 额外信息,用于补充上下文
|
extra_info: 额外信息,用于补充上下文
|
||||||
available_actions: 可用的动作信息字典
|
available_actions: 可用的动作信息字典
|
||||||
enable_tool: 是否启用工具调用
|
enable_tool: 是否启用工具调用
|
||||||
|
from_plugin: 是否来自插件
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuple[bool, Optional[str], Optional[str]]: (是否成功, 生成的回复内容, 使用的prompt)
|
Tuple[bool, Optional[Dict[str, Any]], Optional[str]]: (是否成功, 生成的回复, 使用的prompt)
|
||||||
"""
|
"""
|
||||||
prompt = None
|
prompt = None
|
||||||
if available_actions is None:
|
if available_actions is None:
|
||||||
@@ -208,6 +213,13 @@ class DefaultReplyer:
|
|||||||
if not prompt:
|
if not prompt:
|
||||||
logger.warning("构建prompt失败,跳过回复生成")
|
logger.warning("构建prompt失败,跳过回复生成")
|
||||||
return False, None, None
|
return False, None, None
|
||||||
|
from src.plugin_system.core.events_manager import events_manager
|
||||||
|
|
||||||
|
if not from_plugin:
|
||||||
|
if not await events_manager.handle_mai_events(
|
||||||
|
EventType.POST_LLM, None, prompt, None, stream_id=stream_id
|
||||||
|
):
|
||||||
|
raise UserWarning("插件于请求前中断了内容生成")
|
||||||
|
|
||||||
# 4. 调用 LLM 生成回复
|
# 4. 调用 LLM 生成回复
|
||||||
content = None
|
content = None
|
||||||
@@ -215,16 +227,29 @@ class DefaultReplyer:
|
|||||||
model_name = "unknown_model"
|
model_name = "unknown_model"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
content, reasoning_content, model_name, _ = await self.llm_generate_content(prompt)
|
content, reasoning_content, model_name, tool_call = await self.llm_generate_content(prompt)
|
||||||
logger.debug(f"replyer生成内容: {content}")
|
logger.debug(f"replyer生成内容: {content}")
|
||||||
|
llm_response = {
|
||||||
|
"content": content,
|
||||||
|
"reasoning": reasoning_content,
|
||||||
|
"model": model_name,
|
||||||
|
"tool_calls": tool_call,
|
||||||
|
}
|
||||||
|
if not from_plugin and not await events_manager.handle_mai_events(
|
||||||
|
EventType.AFTER_LLM, None, prompt, llm_response, stream_id=stream_id
|
||||||
|
):
|
||||||
|
raise UserWarning("插件于请求后取消了内容生成")
|
||||||
|
except UserWarning as e:
|
||||||
|
raise e
|
||||||
except Exception as llm_e:
|
except Exception as llm_e:
|
||||||
# 精简报错信息
|
# 精简报错信息
|
||||||
logger.error(f"LLM 生成失败: {llm_e}")
|
logger.error(f"LLM 生成失败: {llm_e}")
|
||||||
return False, None, prompt # LLM 调用失败则无法生成回复
|
return False, None, prompt # LLM 调用失败则无法生成回复
|
||||||
|
|
||||||
return True, content, prompt
|
return True, llm_response, prompt
|
||||||
|
|
||||||
|
except UserWarning as uw:
|
||||||
|
raise uw
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"回复生成意外失败: {e}")
|
logger.error(f"回复生成意外失败: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
@@ -1022,6 +1047,7 @@ class DefaultReplyer:
|
|||||||
related_info = ""
|
related_info = ""
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
from src.plugins.built_in.knowledge.lpmm_get_knowledge import SearchKnowledgeFromLPMMTool
|
from src.plugins.built_in.knowledge.lpmm_get_knowledge import SearchKnowledgeFromLPMMTool
|
||||||
|
|
||||||
if not reply_to:
|
if not reply_to:
|
||||||
logger.debug("没有回复对象,跳过获取知识库内容")
|
logger.debug("没有回复对象,跳过获取知识库内容")
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -53,9 +53,6 @@ class LLMRequest:
|
|||||||
}
|
}
|
||||||
"""模型使用量记录,用于进行负载均衡,对应为(total_tokens, penalty, usage_penalty),惩罚值是为了能在某个模型请求不给力或正在被使用的时候进行调整"""
|
"""模型使用量记录,用于进行负载均衡,对应为(total_tokens, penalty, usage_penalty),惩罚值是为了能在某个模型请求不给力或正在被使用的时候进行调整"""
|
||||||
|
|
||||||
self.pri_in = 0
|
|
||||||
self.pri_out = 0
|
|
||||||
|
|
||||||
async def generate_response_for_image(
|
async def generate_response_for_image(
|
||||||
self,
|
self,
|
||||||
prompt: str,
|
prompt: str,
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ async def generate_reply(
|
|||||||
return_prompt: bool = False,
|
return_prompt: bool = False,
|
||||||
model_set_with_weight: Optional[List[Tuple[TaskConfig, float]]] = None,
|
model_set_with_weight: Optional[List[Tuple[TaskConfig, float]]] = None,
|
||||||
request_type: str = "generator_api",
|
request_type: str = "generator_api",
|
||||||
|
from_plugin: bool = True,
|
||||||
) -> Tuple[bool, List[Tuple[str, Any]], Optional[str]]:
|
) -> Tuple[bool, List[Tuple[str, Any]], Optional[str]]:
|
||||||
"""生成回复
|
"""生成回复
|
||||||
|
|
||||||
@@ -102,12 +103,15 @@ async def generate_reply(
|
|||||||
return_prompt: 是否返回提示词
|
return_prompt: 是否返回提示词
|
||||||
model_set_with_weight: 模型配置列表,每个元素为 (TaskConfig, weight) 元组
|
model_set_with_weight: 模型配置列表,每个元素为 (TaskConfig, weight) 元组
|
||||||
request_type: 请求类型(可选,记录LLM使用)
|
request_type: 请求类型(可选,记录LLM使用)
|
||||||
|
from_plugin: 是否来自插件
|
||||||
Returns:
|
Returns:
|
||||||
Tuple[bool, List[Tuple[str, Any]], Optional[str]]: (是否成功, 回复集合, 提示词)
|
Tuple[bool, List[Tuple[str, Any]], Optional[str]]: (是否成功, 回复集合, 提示词)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# 获取回复器
|
# 获取回复器
|
||||||
replyer = get_replyer(chat_stream, chat_id, model_set_with_weight=model_set_with_weight, request_type=request_type)
|
replyer = get_replyer(
|
||||||
|
chat_stream, chat_id, model_set_with_weight=model_set_with_weight, request_type=request_type
|
||||||
|
)
|
||||||
if not replyer:
|
if not replyer:
|
||||||
logger.error("[GeneratorAPI] 无法获取回复器")
|
logger.error("[GeneratorAPI] 无法获取回复器")
|
||||||
return False, [], None
|
return False, [], None
|
||||||
@@ -120,20 +124,23 @@ async def generate_reply(
|
|||||||
extra_info = action_data.get("extra_info", "")
|
extra_info = action_data.get("extra_info", "")
|
||||||
|
|
||||||
# 调用回复器生成回复
|
# 调用回复器生成回复
|
||||||
success, content, prompt = await replyer.generate_reply_with_context(
|
success, llm_response_dict, prompt = await replyer.generate_reply_with_context(
|
||||||
reply_to=reply_to,
|
reply_to=reply_to,
|
||||||
extra_info=extra_info,
|
extra_info=extra_info,
|
||||||
available_actions=available_actions,
|
available_actions=available_actions,
|
||||||
enable_tool=enable_tool,
|
enable_tool=enable_tool,
|
||||||
|
from_plugin=from_plugin,
|
||||||
|
stream_id=chat_stream.stream_id if chat_stream else chat_id,
|
||||||
)
|
)
|
||||||
reply_set = []
|
if not success:
|
||||||
if content:
|
|
||||||
reply_set = await process_human_text(content, enable_splitter, enable_chinese_typo)
|
|
||||||
|
|
||||||
if success:
|
|
||||||
logger.debug(f"[GeneratorAPI] 回复生成成功,生成了 {len(reply_set)} 个回复项")
|
|
||||||
else:
|
|
||||||
logger.warning("[GeneratorAPI] 回复生成失败")
|
logger.warning("[GeneratorAPI] 回复生成失败")
|
||||||
|
return False, [], None
|
||||||
|
assert llm_response_dict is not None, "llm_response_dict不应为None" # 虽然说不会出现llm_response为空的情况
|
||||||
|
if content := llm_response_dict.get("content", ""):
|
||||||
|
reply_set = process_human_text(content, enable_splitter, enable_chinese_typo)
|
||||||
|
else:
|
||||||
|
reply_set = []
|
||||||
|
logger.debug(f"[GeneratorAPI] 回复生成成功,生成了 {len(reply_set)} 个回复项")
|
||||||
|
|
||||||
if return_prompt:
|
if return_prompt:
|
||||||
return success, reply_set, prompt
|
return success, reply_set, prompt
|
||||||
@@ -143,6 +150,10 @@ async def generate_reply(
|
|||||||
except ValueError as ve:
|
except ValueError as ve:
|
||||||
raise ve
|
raise ve
|
||||||
|
|
||||||
|
except UserWarning as uw:
|
||||||
|
logger.warning(f"[GeneratorAPI] 中断了生成: {uw}")
|
||||||
|
return False, [], None
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[GeneratorAPI] 生成回复时出错: {e}")
|
logger.error(f"[GeneratorAPI] 生成回复时出错: {e}")
|
||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
@@ -202,7 +213,7 @@ async def rewrite_reply(
|
|||||||
)
|
)
|
||||||
reply_set = []
|
reply_set = []
|
||||||
if content:
|
if content:
|
||||||
reply_set = await process_human_text(content, enable_splitter, enable_chinese_typo)
|
reply_set = process_human_text(content, enable_splitter, enable_chinese_typo)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
logger.info(f"[GeneratorAPI] 重写回复成功,生成了 {len(reply_set)} 个回复项")
|
logger.info(f"[GeneratorAPI] 重写回复成功,生成了 {len(reply_set)} 个回复项")
|
||||||
@@ -219,7 +230,7 @@ async def rewrite_reply(
|
|||||||
return False, [], None
|
return False, [], None
|
||||||
|
|
||||||
|
|
||||||
async def process_human_text(content: str, enable_splitter: bool, enable_chinese_typo: bool) -> List[Tuple[str, Any]]:
|
def process_human_text(content: str, enable_splitter: bool, enable_chinese_typo: bool) -> List[Tuple[str, Any]]:
|
||||||
"""将文本处理为更拟人化的文本
|
"""将文本处理为更拟人化的文本
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -243,6 +254,7 @@ async def process_human_text(content: str, enable_splitter: bool, enable_chinese
|
|||||||
logger.error(f"[GeneratorAPI] 处理人形文本时出错: {e}")
|
logger.error(f"[GeneratorAPI] 处理人形文本时出错: {e}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
async def generate_response_custom(
|
async def generate_response_custom(
|
||||||
chat_stream: Optional[ChatStream] = None,
|
chat_stream: Optional[ChatStream] = None,
|
||||||
chat_id: Optional[str] = None,
|
chat_id: Optional[str] = None,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from dataclasses import dataclass, field
|
|||||||
from maim_message import Seg
|
from maim_message import Seg
|
||||||
|
|
||||||
from src.llm_models.payload_content.tool_option import ToolParamType as ToolParamType
|
from src.llm_models.payload_content.tool_option import ToolParamType as ToolParamType
|
||||||
|
from src.llm_models.payload_content.tool_option import ToolCall as ToolCall
|
||||||
|
|
||||||
# 组件类型枚举
|
# 组件类型枚举
|
||||||
class ComponentType(Enum):
|
class ComponentType(Enum):
|
||||||
@@ -259,9 +260,21 @@ class MaiMessages:
|
|||||||
llm_prompt: Optional[str] = None
|
llm_prompt: Optional[str] = None
|
||||||
"""LLM提示词"""
|
"""LLM提示词"""
|
||||||
|
|
||||||
llm_response: Optional[str] = None
|
llm_response_content: Optional[str] = None
|
||||||
"""LLM响应内容"""
|
"""LLM响应内容"""
|
||||||
|
|
||||||
|
llm_response_reasoning: Optional[str] = None
|
||||||
|
"""LLM响应推理内容"""
|
||||||
|
|
||||||
|
llm_response_model: Optional[str] = None
|
||||||
|
"""LLM响应模型名称"""
|
||||||
|
|
||||||
|
llm_response_tool_call: Optional[List[ToolCall]] = None
|
||||||
|
"""LLM使用的工具调用"""
|
||||||
|
|
||||||
|
action_usage: Optional[List[str]] = None
|
||||||
|
"""使用的Action"""
|
||||||
|
|
||||||
additional_data: Dict[Any, Any] = field(default_factory=dict)
|
additional_data: Dict[Any, Any] = field(default_factory=dict)
|
||||||
"""附加数据,可以存储额外信息"""
|
"""附加数据,可以存储额外信息"""
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import contextlib
|
import contextlib
|
||||||
from typing import List, Dict, Optional, Type, Tuple
|
from typing import List, Dict, Optional, Type, Tuple, Any
|
||||||
|
|
||||||
from src.chat.message_receive.message import MessageRecv
|
from src.chat.message_receive.message import MessageRecv
|
||||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||||
@@ -47,8 +47,9 @@ class EventsManager:
|
|||||||
event_type: EventType,
|
event_type: EventType,
|
||||||
message: Optional[MessageRecv] = None,
|
message: Optional[MessageRecv] = None,
|
||||||
llm_prompt: Optional[str] = None,
|
llm_prompt: Optional[str] = None,
|
||||||
llm_response: Optional[str] = None,
|
llm_response: Optional[Dict[str, Any]] = None,
|
||||||
stream_id: Optional[str] = None,
|
stream_id: Optional[str] = None,
|
||||||
|
action_usage: Optional[List[str]] = None,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""处理 events"""
|
"""处理 events"""
|
||||||
from src.plugin_system.core import component_registry
|
from src.plugin_system.core import component_registry
|
||||||
@@ -57,7 +58,12 @@ class EventsManager:
|
|||||||
transformed_message: Optional[MaiMessages] = None
|
transformed_message: Optional[MaiMessages] = None
|
||||||
if not message:
|
if not message:
|
||||||
assert stream_id, "如果没有消息,必须提供流ID"
|
assert stream_id, "如果没有消息,必须提供流ID"
|
||||||
|
if event_type in [EventType.ON_MESSAGE, EventType.ON_PLAN, EventType.POST_LLM, EventType.AFTER_LLM]:
|
||||||
transformed_message = self._build_message_from_stream(stream_id, llm_prompt, llm_response)
|
transformed_message = self._build_message_from_stream(stream_id, llm_prompt, llm_response)
|
||||||
|
else:
|
||||||
|
transformed_message = self._transform_event_without_message(
|
||||||
|
stream_id, llm_prompt, llm_response, action_usage
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
transformed_message = self._transform_event_message(message, llm_prompt, llm_response)
|
transformed_message = self._transform_event_message(message, llm_prompt, llm_response)
|
||||||
for handler in self._events_subscribers.get(event_type, []):
|
for handler in self._events_subscribers.get(event_type, []):
|
||||||
@@ -121,13 +127,16 @@ class EventsManager:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def _transform_event_message(
|
def _transform_event_message(
|
||||||
self, message: MessageRecv, llm_prompt: Optional[str] = None, llm_response: Optional[str] = None
|
self, message: MessageRecv, llm_prompt: Optional[str] = None, llm_response: Optional[Dict[str, Any]] = None
|
||||||
) -> MaiMessages:
|
) -> MaiMessages:
|
||||||
"""转换事件消息格式"""
|
"""转换事件消息格式"""
|
||||||
# 直接赋值部分内容
|
# 直接赋值部分内容
|
||||||
transformed_message = MaiMessages(
|
transformed_message = MaiMessages(
|
||||||
llm_prompt=llm_prompt,
|
llm_prompt=llm_prompt,
|
||||||
llm_response=llm_response,
|
llm_response_content=llm_response.get("content") if llm_response else None,
|
||||||
|
llm_response_reasoning=llm_response.get("reasoning") if llm_response else None,
|
||||||
|
llm_response_model=llm_response.get("model") if llm_response else None,
|
||||||
|
llm_response_tool_call=llm_response.get("tool_calls") if llm_response else None,
|
||||||
raw_message=message.raw_message,
|
raw_message=message.raw_message,
|
||||||
additional_data=message.message_info.additional_config or {},
|
additional_data=message.message_info.additional_config or {},
|
||||||
)
|
)
|
||||||
@@ -171,7 +180,7 @@ class EventsManager:
|
|||||||
return transformed_message
|
return transformed_message
|
||||||
|
|
||||||
def _build_message_from_stream(
|
def _build_message_from_stream(
|
||||||
self, stream_id: str, llm_prompt: Optional[str] = None, llm_response: Optional[str] = None
|
self, stream_id: str, llm_prompt: Optional[str] = None, llm_response: Optional[Dict[str, Any]] = None
|
||||||
) -> MaiMessages:
|
) -> MaiMessages:
|
||||||
"""从流ID构建消息"""
|
"""从流ID构建消息"""
|
||||||
chat_stream = get_chat_manager().get_stream(stream_id)
|
chat_stream = get_chat_manager().get_stream(stream_id)
|
||||||
@@ -179,6 +188,29 @@ class EventsManager:
|
|||||||
message = chat_stream.context.get_last_message()
|
message = chat_stream.context.get_last_message()
|
||||||
return self._transform_event_message(message, llm_prompt, llm_response)
|
return self._transform_event_message(message, llm_prompt, llm_response)
|
||||||
|
|
||||||
|
def _transform_event_without_message(
|
||||||
|
self,
|
||||||
|
stream_id: str,
|
||||||
|
llm_prompt: Optional[str] = None,
|
||||||
|
llm_response: Optional[Dict[str, Any]] = None,
|
||||||
|
action_usage: Optional[List[str]] = None,
|
||||||
|
) -> MaiMessages:
|
||||||
|
"""没有message对象时进行转换"""
|
||||||
|
chat_stream = get_chat_manager().get_stream(stream_id)
|
||||||
|
assert chat_stream, f"未找到流ID为 {stream_id} 的聊天流"
|
||||||
|
return MaiMessages(
|
||||||
|
stream_id=stream_id,
|
||||||
|
llm_prompt=llm_prompt,
|
||||||
|
llm_response_content=(llm_response.get("content") if llm_response else None),
|
||||||
|
llm_response_reasoning=(llm_response.get("reasoning") if llm_response else None),
|
||||||
|
llm_response_model=llm_response.get("model") if llm_response else None,
|
||||||
|
llm_response_tool_call=(llm_response.get("tool_calls") if llm_response else None),
|
||||||
|
is_group_message=(not (not chat_stream.group_info)),
|
||||||
|
is_private_message=(not chat_stream.group_info),
|
||||||
|
action_usage=action_usage,
|
||||||
|
additional_data={"response_is_processed": True},
|
||||||
|
)
|
||||||
|
|
||||||
def _task_done_callback(self, task: asyncio.Task[Tuple[bool, bool, str | None]]):
|
def _task_done_callback(self, task: asyncio.Task[Tuple[bool, bool, str | None]]):
|
||||||
"""任务完成回调"""
|
"""任务完成回调"""
|
||||||
task_name = task.get_name() or "Unknown Task"
|
task_name = task.get_name() or "Unknown Task"
|
||||||
|
|||||||
Reference in New Issue
Block a user