doc:非常清晰的工作流程介绍,你一定看得懂吧
This commit is contained in:
@@ -1,12 +1,71 @@
|
|||||||
# 心流系统 (Heart Flow System)
|
# 心流系统 (Heart Flow System)
|
||||||
|
|
||||||
## 通俗易懂的工作流程介绍
|
## 一条消息是怎么到最终回复的?简明易懂的介绍
|
||||||
|
|
||||||
心流系统就像一个智能聊天管家,它的工作方式可以这样理解:
|
1 接受消息,由HeartHC_processor处理消息,存储消息
|
||||||
|
|
||||||
心流系统由主控中心(Heartflow)作为大脑协调全局,它通过场景管家(SubHeartflowManager)管理各个聊天场景的"小管家"(SubHeartflow)。当收到消息时,系统会先进行过滤和基础分析(如屏蔽词检查和兴趣度计算),然后将处理好的消息分发给对应场景的小管家。每个小管家会根据当前状态决定回复方式:不参与(ABSENT)时完全不看不回,普通模式(CHAT)进行简单回复,专注模式(FOCUSED)则深入交流。系统会根据聊天活跃度和兴趣度自动调整各场景的参与程度,同时主控中心也能手动调整整体参与度(如在离线、轻度参与和专注聊天之间切换)。整个系统就像一个拥有多个聊天助手的智能管家,能够智能地动态调整参与聊天的深度和范围。
|
1.1 process_message()函数,接受消息
|
||||||
|
|
||||||
## 1. 系统架构 (System Architecture)
|
1.2 创建消息对应的聊天流(chat_stream)和子心流(sub_heartflow)
|
||||||
|
|
||||||
|
1.3 进行常规消息处理
|
||||||
|
|
||||||
|
1.4 存储消息 store_message()
|
||||||
|
|
||||||
|
1.5 计算兴趣度Interest
|
||||||
|
|
||||||
|
1.6 将消息连同兴趣度,存储到内存中的interest_dict(SubHeartflow的属性)
|
||||||
|
|
||||||
|
2 根据 sub_heartflow 的聊天状态,决定后续处理流程
|
||||||
|
|
||||||
|
2a ABSENT状态:不做任何处理
|
||||||
|
|
||||||
|
2b CHAT状态:送入NormalChat 实例
|
||||||
|
|
||||||
|
2c FOCUS状态:送入HeartFChatting 实例
|
||||||
|
|
||||||
|
b NormalChat工作方式
|
||||||
|
|
||||||
|
b.1 启动后台任务 _reply_interested_message,持续运行。
|
||||||
|
b.2 该任务轮询 InterestChatting 提供的 interest_dict
|
||||||
|
b.3 对每条消息,结合兴趣度、是否被提及(@)、意愿管理器(WillingManager)计算回复概率。(这部分要改,目前还是用willing计算的,之后要和Interest合并)
|
||||||
|
b.4 若概率通过:
|
||||||
|
b.4.1 创建"思考中"消息 (MessageThinking)。
|
||||||
|
b.4.2 调用 NormalChatGenerator 生成文本回复。
|
||||||
|
b.4.3 通过 message_manager 发送回复 (MessageSending)。
|
||||||
|
b.4.4 可能根据配置和文本内容,额外发送一个匹配的表情包。
|
||||||
|
b.4.5 更新关系值和全局情绪。
|
||||||
|
b.5 处理完成后,从 interest_dict 中移除该消息。
|
||||||
|
|
||||||
|
c HeartFChatting工作方式
|
||||||
|
|
||||||
|
c.1 启动主循环 _hfc_loop
|
||||||
|
c.2 每个循环称为一个周期 (Cycle),执行 think_plan_execute 流程。
|
||||||
|
c.3 Think (思考) 阶段:
|
||||||
|
c.3.1 观察 (Observe): 通过 ChattingObservation,使用 observe() 获取最新的聊天消息。
|
||||||
|
c.3.2 思考 (Think): 调用 SubMind 的 do_thinking_before_reply 方法。
|
||||||
|
c.3.2.1 SubMind 结合观察到的内容、个性、情绪、上周期动作等信息,生成当前的内心想法 (current_mind)。
|
||||||
|
c.3.2.2 在此过程中 SubMind 的LLM可能请求调用工具 (ToolUser) 来获取额外信息或执行操作,结果存储在 structured_info 中。
|
||||||
|
c.4 Plan (规划/决策) 阶段:
|
||||||
|
c.4.1 结合观察到的消息文本、`SubMind` 生成的 `current_mind` 和 `structured_info`、以及 `ActionManager` 提供的可用动作,决定本次周期的行动 (`text_reply`/`emoji_reply`/`no_reply`) 和理由。
|
||||||
|
c.4.2 重新规划检查 (Re-plan Check): 如果在 c.3.1 到 c.4.1 期间检测到新消息,可能(有概率)触发重新执行 c.4.1 决策步骤。
|
||||||
|
c.5 Execute (执行/回复) 阶段:
|
||||||
|
c.5.1 如果决策是 text_reply:
|
||||||
|
c.5.1.1 获取锚点消息。
|
||||||
|
c.5.1.2 通过 HeartFCSender 注册"思考中"状态。
|
||||||
|
c.5.1.3 调用 HeartFCGenerator (gpt_instance) 生成回复文本。
|
||||||
|
c.5.1.4 通过 HeartFCSender 发送回复
|
||||||
|
c.5.1.5 如果规划时指定了表情查询 (emoji_query),随后发送表情。
|
||||||
|
c.5.2 如果决策是 emoji_reply:
|
||||||
|
c.5.2.1 获取锚点消息。
|
||||||
|
c.5.2.2 通过 HeartFCSender 直接发送匹配查询 (emoji_query) 的表情。
|
||||||
|
c.5.3 如果决策是 no_reply:
|
||||||
|
c.5.3.1 进入等待状态,直到检测到新消息或超时。
|
||||||
|
c.6 循环结束后,记录周期信息 (CycleInfo),并根据情况进行短暂休眠,防止CPU空转。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 1. 一条消息是怎么到最终回复的?复杂细致的介绍
|
||||||
|
|
||||||
### 1.1. 主心流 (Heartflow)
|
### 1.1. 主心流 (Heartflow)
|
||||||
- **文件**: `heartflow.py`
|
- **文件**: `heartflow.py`
|
||||||
@@ -24,7 +83,7 @@
|
|||||||
- 维护特定场景下的思维状态和聊天流状态 (`ChatState`)。
|
- 维护特定场景下的思维状态和聊天流状态 (`ChatState`)。
|
||||||
- 通过关联的 `Observation` 实例接收和处理信息。
|
- 通过关联的 `Observation` 实例接收和处理信息。
|
||||||
- 拥有独立的思考 (`SubMind`) 和回复判断能力。
|
- 拥有独立的思考 (`SubMind`) 和回复判断能力。
|
||||||
- **观察者**: 每个子心流可以拥有一个或多个 `Observation` 实例(目前每个子心流仅使用一个 `ChattingObservation`)。
|
- **观察者**: 每个子心流可以拥有一个或多个 `Observation` 实例(目前每个子心流仅使用一个 `ChattingObservation`)。
|
||||||
- **内部结构**:
|
- **内部结构**:
|
||||||
- **聊天流状态 (`ChatState`)**: 标记当前子心流的参与模式 (`ABSENT`, `CHAT`, `FOCUSED`),决定是否观察、回复以及使用何种回复模式。
|
- **聊天流状态 (`ChatState`)**: 标记当前子心流的参与模式 (`ABSENT`, `CHAT`, `FOCUSED`),决定是否观察、回复以及使用何种回复模式。
|
||||||
- **聊天实例 (`NormalChatInstance` / `HeartFlowChatInstance`)**: 根据 `ChatState` 激活对应的实例来处理聊天逻辑。同一时间只有一个实例处于活动状态。
|
- **聊天实例 (`NormalChatInstance` / `HeartFlowChatInstance`)**: 根据 `ChatState` 激活对应的实例来处理聊天逻辑。同一时间只有一个实例处于活动状态。
|
||||||
@@ -84,21 +143,25 @@
|
|||||||
- **状态及含义**:
|
- **状态及含义**:
|
||||||
- `ChatState.ABSENT` (不参与/没在看): 初始或停用状态。子心流不观察新信息,不进行思考,也不回复。
|
- `ChatState.ABSENT` (不参与/没在看): 初始或停用状态。子心流不观察新信息,不进行思考,也不回复。
|
||||||
- `ChatState.CHAT` (随便看看/水群): 普通聊天模式。激活 `NormalChatInstance`。
|
- `ChatState.CHAT` (随便看看/水群): 普通聊天模式。激活 `NormalChatInstance`。
|
||||||
* `ChatState.FOCUSED` (专注/激情水群): 专注聊天模式。激活 `HeartFlowChatInstance`。
|
* `ChatState.FOCUSED` (专注/认真水群): 专注聊天模式。激活 `HeartFlowChatInstance`。
|
||||||
- **选择**: 子心流可以根据外部指令(来自 `SubHeartflowManager`)或内部逻辑(未来的扩展)选择进入 `ABSENT` 状态(不回复不观察),或进入 `CHAT` / `FOCUSED` 中的一种回复模式。
|
- **选择**: 子心流可以根据外部指令(来自 `SubHeartflowManager`)或内部逻辑(未来的扩展)选择进入 `ABSENT` 状态(不回复不观察),或进入 `CHAT` / `FOCUSED` 中的一种回复模式。
|
||||||
- **状态转换机制** (由 `SubHeartflowManager` 驱动):
|
- **状态转换机制** (由 `SubHeartflowManager` 驱动):
|
||||||
- **激活 `CHAT`**: 当 `Heartflow` 状态从 `OFFLINE` 变为允许聊天的状态时,`SubHeartflowManager` 会根据限制,选择部分 `ABSENT` 状态的子心流,调用其 `set_chat_state` 方法将其转换为 `CHAT`。
|
- **激活 `CHAT`**: 当 `Heartflow` 状态从 `OFFLINE` 变为允许聊天的状态时,`SubHeartflowManager` 会根据限制,选择部分 `ABSENT` 状态的子心流,**检查当前 CHAT 状态数量是否达到上限**,如果未达上限,则调用其 `set_chat_state` 方法将其转换为 `CHAT`。
|
||||||
- **激活 `FOCUSED`**: `SubHeartflowManager` 会定期评估处于 `CHAT` 状态的子心流的兴趣度 (`InterestChatting.start_hfc_probability`),若满足条件且未达上限,则调用 `set_chat_state` 将其提升为 `FOCUSED`。
|
- **激活 `FOCUSED`**: `SubHeartflowManager` 会定期评估处于 `CHAT` 状态的子心流的兴趣度 (`InterestChatting.start_hfc_probability`),若满足条件且**检查当前 FOCUSED 状态数量未达上限**,则调用 `set_chat_state` 将其提升为 `FOCUSED`。
|
||||||
- **停用/回退**: `SubHeartflowManager` 可能因 `Heartflow` 状态变化、达到数量限制、长时间不活跃或随机概率等原因,调用 `set_chat_state` 将子心流状态设置为 `ABSENT` 或从 `FOCUSED` 回退到 `CHAT`。
|
- **停用/回退**: `SubHeartflowManager` 可能因 `Heartflow` 状态变化、达到数量限制、长时间不活跃或随机概率等原因,调用 `set_chat_state` 将子心流状态设置为 `ABSENT` 或从 `FOCUSED` 回退到 `CHAT`。
|
||||||
|
- **注意**: `set_chat_state` 方法本身只负责执行状态转换和管理内部聊天实例(`NormalChatInstance`/`HeartFlowChatInstance`),不再进行限额检查。限额检查的责任完全由调用方(即 `SubHeartflowManager` 中的相关方法)承担。
|
||||||
|
|
||||||
## 3. 聊天实例详解 (Chat Instances Explained)
|
## 3. 聊天实例详解 (Chat Instances Explained)
|
||||||
|
|
||||||
### 3.1. NormalChatInstance
|
### 3.1. NormalChatInstance
|
||||||
- **激活条件**: 对应 `SubHeartflow` 的 `ChatState` 为 `CHAT`。
|
- **激活条件**: 对应 `SubHeartflow` 的 `ChatState` 为 `CHAT`。
|
||||||
- **工作流程**:
|
- **工作流程**:
|
||||||
- 按照系统设定的普通聊天规则处理群消息。
|
- 当 `SubHeartflow` 进入 `CHAT` 状态时,`NormalChatInstance` 会被激活。
|
||||||
- 定期检查新消息。
|
- 实例启动后,会创建一个后台任务 (`_reply_interested_message`)。
|
||||||
- 对简单询问、闲聊等进行及时回复。
|
- 该任务持续监控由 `InterestChatting` 传入的、具有一定兴趣度的消息列表 (`interest_dict`)。
|
||||||
|
- 对列表中的每条消息,结合是否被提及 (`@`)、消息本身的兴趣度以及当前的回复意愿 (`WillingManager`),计算出一个回复概率。
|
||||||
|
- 根据计算出的概率随机决定是否对该消息进行回复。
|
||||||
|
- 如果决定回复,则调用 `NormalChatGenerator` 生成回复内容,并可能附带表情包。
|
||||||
- **行为特点**:
|
- **行为特点**:
|
||||||
- 回复相对常规、简单。
|
- 回复相对常规、简单。
|
||||||
- 不投入过多计算资源。
|
- 不投入过多计算资源。
|
||||||
@@ -153,19 +216,4 @@
|
|||||||
- `sub_heart_flow_stop_time`: 子心流停止(标记为可清理)的不活跃时间阈值 (似乎由 `SubHeartflowManager.cleanup_inactive_subheartflows` 的参数 `inactive_threshold_seconds` 控制)。
|
- `sub_heart_flow_stop_time`: 子心流停止(标记为可清理)的不活跃时间阈值 (似乎由 `SubHeartflowManager.cleanup_inactive_subheartflows` 的参数 `inactive_threshold_seconds` 控制)。
|
||||||
- `sub_heart_flow_freeze_time`: 子心流冻结时间 (当前文档未明确体现,可能需要审阅代码确认)。
|
- `sub_heart_flow_freeze_time`: 子心流冻结时间 (当前文档未明确体现,可能需要审阅代码确认)。
|
||||||
- `heart_flow_update_interval`: 主心流更新其状态或执行管理操作的频率 (需要审阅 `Heartflow` 代码确认)。
|
- `heart_flow_update_interval`: 主心流更新其状态或执行管理操作的频率 (需要审阅 `Heartflow` 代码确认)。
|
||||||
- `MaiStateInfo` 内的限制: 定义了不同主状态下 `CHAT` 和 `FOCUSED` 子心流的数量上限。
|
- `
|
||||||
|
|
||||||
## 6. 注意事项 (Important Notes)
|
|
||||||
|
|
||||||
1. **自动清理**: `SubHeartflowManager` 会定期检查并清理长时间不活跃的子心流。
|
|
||||||
2. **性能平衡**: 主心流执行管理操作的频率(如检查状态、清理、评估兴趣)需要合理配置,以平衡系统性能和响应速度。
|
|
||||||
3. **信息过载**: 单个 `ChattingObservation` 会限制一次性从数据库拉取的消息数量 (`max_now_obs_len`)。
|
|
||||||
|
|
||||||
## 7. 待办与未来方向 (TODOs and Future Directions)
|
|
||||||
|
|
||||||
* **更新 "与其他模块的交互" 部分**: 详细说明 `SubHeartflowManager`, `SubHeartflow`, `NormalChatInstance`, `HeartFlowChatInstance` 之间以及与 `MessageManager`, `ResponseGenerator`, `InterestManager` 等外部模块的具体交互。
|
|
||||||
* **明确 `sub_heart_flow_freeze_time`**: 确认该配置项的实际作用和实现位置。
|
|
||||||
* **明确 `heart_flow_update_interval`**: 确认主心流管理循环的实际间隔。
|
|
||||||
* **扩展观察类型**: 实现更多 `Observation` 类型(如私聊、系统事件等)。
|
|
||||||
* **子心流内部状态转换**: 探索允许子心流根据自身思考结果主动请求状态转换的可能性。
|
|
||||||
* **资源管理**: 优化子心流的资源占用和清理策略。
|
|
||||||
@@ -5,7 +5,7 @@ import enum
|
|||||||
class ChatState(enum.Enum):
|
class ChatState(enum.Enum):
|
||||||
ABSENT = "没在看群"
|
ABSENT = "没在看群"
|
||||||
CHAT = "随便水群"
|
CHAT = "随便水群"
|
||||||
FOCUSED = "激情水群"
|
FOCUSED = "认真水群"
|
||||||
|
|
||||||
|
|
||||||
class ChatStateInfo:
|
class ChatStateInfo:
|
||||||
|
|||||||
@@ -118,7 +118,3 @@
|
|||||||
- 是否发生了重新规划 (`replanned`)
|
- 是否发生了重新规划 (`replanned`)
|
||||||
- 详细的响应信息 (`response_info`),包括生成的文本、表情查询、锚点消息 ID、实际发送的消息 ID 列表以及 `SubMind` 的思考内容。
|
- 详细的响应信息 (`response_info`),包括生成的文本、表情查询、锚点消息 ID、实际发送的消息 ID 列表以及 `SubMind` 的思考内容。
|
||||||
- `HeartFChatting` 维护一个 `_cycle_history` 队列来保存最近的循环记录,方便调试和分析。
|
- `HeartFChatting` 维护一个 `_cycle_history` 队列来保存最近的循环记录,方便调试和分析。
|
||||||
|
|
||||||
## 8. 总结
|
|
||||||
|
|
||||||
`HeartFChatting` 通过精密的循环控制、阶段分离(思考、规划、执行)、与 `SubMind` 和 `Observation` 的紧密协作,以及对 `HeartFCSender` 和 `HeartFCGenerator` 等专用组件的依赖,实现了在 FOCUSED 状态下的主动、深入且有状态的对话逻辑。它能够根据上下文和内部思考动态调整回复策略,并通过 `ActionManager` 灵活控制可执行的动作范围。
|
|
||||||
@@ -232,54 +232,68 @@ class SubHeartflow:
|
|||||||
subheartflow_id: 子心流唯一标识符
|
subheartflow_id: 子心流唯一标识符
|
||||||
parent_heartflow: 父级心流实例
|
parent_heartflow: 父级心流实例
|
||||||
"""
|
"""
|
||||||
# 基础属性
|
# 基础属性,两个值是一样的
|
||||||
self.subheartflow_id = subheartflow_id
|
self.subheartflow_id = subheartflow_id
|
||||||
self.chat_id = subheartflow_id
|
self.chat_id = subheartflow_id
|
||||||
|
|
||||||
|
# 麦麦的状态
|
||||||
self.mai_states = mai_states
|
self.mai_states = mai_states
|
||||||
|
|
||||||
# 聊天状态管理
|
# 这个聊天流的状态
|
||||||
self.chat_state: ChatStateInfo = ChatStateInfo() # 该sub_heartflow的聊天状态信息
|
self.chat_state: ChatStateInfo = ChatStateInfo()
|
||||||
self.interest_chatting = None # 将在 initialize 中创建
|
|
||||||
|
# 兴趣检测器
|
||||||
|
self.interest_chatting = None
|
||||||
|
|
||||||
# 活动状态管理
|
# 活动状态管理
|
||||||
self.last_active_time = time.time() # 最后活跃时间
|
self.last_active_time = time.time() # 最后活跃时间
|
||||||
self.should_stop = False # 停止标志
|
self.should_stop = False # 停止标志
|
||||||
self.task: Optional[asyncio.Task] = None # 后台任务
|
self.task: Optional[asyncio.Task] = None # 后台任务
|
||||||
|
|
||||||
|
# 随便水群 normal_chat 和 认真水群 heartFC_chat 实例
|
||||||
|
# CHAT模式激活 随便水群 FOCUS模式激活 认真水群
|
||||||
self.heart_fc_instance: Optional[HeartFChatting] = None # 该sub_heartflow的HeartFChatting实例
|
self.heart_fc_instance: Optional[HeartFChatting] = None # 该sub_heartflow的HeartFChatting实例
|
||||||
self.normal_chat_instance: Optional[NormalChat] = None # 该sub_heartflow的NormalChat实例
|
self.normal_chat_instance: Optional[NormalChat] = None # 该sub_heartflow的NormalChat实例
|
||||||
|
|
||||||
# 观察和知识系统
|
# 观察,目前只有聊天观察,可以载入多个
|
||||||
|
# 负责对处理过的消息进行观察
|
||||||
self.observations: List[ChattingObservation] = [] # 观察列表
|
self.observations: List[ChattingObservation] = [] # 观察列表
|
||||||
self.running_knowledges = [] # 运行中的知识
|
# self.running_knowledges = [] # 运行中的知识,待完善
|
||||||
|
|
||||||
# LLM模型配置
|
# LLM模型配置,负责进行思考
|
||||||
self.sub_mind = SubMind(
|
self.sub_mind = SubMind(
|
||||||
subheartflow_id=self.subheartflow_id, chat_state=self.chat_state, observations=self.observations
|
subheartflow_id=self.subheartflow_id, chat_state=self.chat_state, observations=self.observations
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 日志前缀
|
||||||
self.log_prefix = chat_manager.get_stream_name(self.subheartflow_id) or self.subheartflow_id
|
self.log_prefix = chat_manager.get_stream_name(self.subheartflow_id) or self.subheartflow_id
|
||||||
|
|
||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
"""异步初始化方法"""
|
"""异步初始化方法,创建兴趣检测器"""
|
||||||
self.interest_chatting = await InterestChatting.create(state_change_callback=self.set_chat_state)
|
self.interest_chatting = await InterestChatting.create(state_change_callback=self.set_chat_state)
|
||||||
logger.debug(f"{self.log_prefix} InterestChatting 实例已创建并初始化。")
|
logger.debug(f"{self.log_prefix} InterestChatting 实例已创建并初始化。")
|
||||||
|
|
||||||
async def add_time_current_state(self, add_time: float):
|
async def add_time_current_state(self, add_time: float):
|
||||||
|
"""增加当前状态的时间"""
|
||||||
self.current_state_time += add_time
|
self.current_state_time += add_time
|
||||||
|
|
||||||
async def change_to_state_chat(self):
|
async def change_to_state_chat(self):
|
||||||
|
"""改变到随便水群状态"""
|
||||||
self.current_state_time = 120
|
self.current_state_time = 120
|
||||||
self._start_normal_chat()
|
self._start_normal_chat()
|
||||||
|
|
||||||
async def change_to_state_focused(self):
|
async def change_to_state_focused(self):
|
||||||
|
"""改变到认真水群状态"""
|
||||||
self.current_state_time = 60
|
self.current_state_time = 60
|
||||||
self._start_heart_fc_chat()
|
self._start_heart_fc_chat()
|
||||||
|
|
||||||
async def _stop_normal_chat(self):
|
async def _stop_normal_chat(self):
|
||||||
"""停止 NormalChat 的兴趣监控"""
|
"""
|
||||||
|
停止 NormalChat 实例
|
||||||
|
切出 CHAT 状态时使用
|
||||||
|
"""
|
||||||
if self.normal_chat_instance:
|
if self.normal_chat_instance:
|
||||||
logger.info(f"{self.log_prefix} 停止 NormalChat 兴趣监控...")
|
logger.info(f"{self.log_prefix} 离开CHAT模式,结束 随便水群")
|
||||||
try:
|
try:
|
||||||
await self.normal_chat_instance.stop_chat() # 调用 stop_chat
|
await self.normal_chat_instance.stop_chat() # 调用 stop_chat
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -287,23 +301,21 @@ class SubHeartflow:
|
|||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
|
|
||||||
async def _start_normal_chat(self) -> bool:
|
async def _start_normal_chat(self) -> bool:
|
||||||
"""启动 NormalChat 实例及其兴趣监控,确保 HeartFChatting 已停止"""
|
"""
|
||||||
await self._stop_heart_fc_chat() # 确保专注聊天已停止
|
启动 NormalChat 实例,
|
||||||
|
进入 CHAT 状态时使用
|
||||||
|
|
||||||
|
确保 HeartFChatting 已停止
|
||||||
|
"""
|
||||||
|
await self._stop_heart_fc_chat() # 确保 专注聊天已停止
|
||||||
|
|
||||||
log_prefix = self.log_prefix
|
log_prefix = self.log_prefix
|
||||||
try:
|
try:
|
||||||
# 总是尝试创建或获取最新的 stream 和 interest_dict
|
# 获取聊天流并创建 NormalChat 实例
|
||||||
chat_stream = chat_manager.get_stream(self.chat_id)
|
chat_stream = chat_manager.get_stream(self.chat_id)
|
||||||
if not chat_stream:
|
|
||||||
logger.error(f"{log_prefix} 无法获取 chat_stream,无法启动 NormalChat。")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 如果实例不存在或需要更新,则创建新实例
|
|
||||||
# if not self.normal_chat_instance: # 或者总是重新创建以获取最新的 interest_dict?
|
|
||||||
self.normal_chat_instance = NormalChat(chat_stream=chat_stream, interest_dict=self.get_interest_dict())
|
self.normal_chat_instance = NormalChat(chat_stream=chat_stream, interest_dict=self.get_interest_dict())
|
||||||
logger.info(f"{log_prefix} 创建或更新 NormalChat 实例。")
|
|
||||||
|
|
||||||
logger.info(f"{log_prefix} 启动 NormalChat 兴趣监控...")
|
logger.info(f"{log_prefix} 启动 NormalChat 随便水群...")
|
||||||
await self.normal_chat_instance.start_chat() # <--- 修正:调用 start_chat
|
await self.normal_chat_instance.start_chat() # <--- 修正:调用 start_chat
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -369,7 +381,7 @@ class SubHeartflow:
|
|||||||
self.heart_fc_instance = None # 创建或初始化异常,清理实例
|
self.heart_fc_instance = None # 创建或初始化异常,清理实例
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def set_chat_state(self, new_state: "ChatState", current_states_num: tuple = ()):
|
async def set_chat_state(self, new_state: "ChatState"):
|
||||||
"""更新sub_heartflow的聊天状态,并管理 HeartFChatting 和 NormalChat 实例及任务"""
|
"""更新sub_heartflow的聊天状态,并管理 HeartFChatting 和 NormalChat 实例及任务"""
|
||||||
current_state = self.chat_state.chat_status
|
current_state = self.chat_state.chat_status
|
||||||
if current_state == new_state:
|
if current_state == new_state:
|
||||||
@@ -377,47 +389,30 @@ class SubHeartflow:
|
|||||||
return
|
return
|
||||||
|
|
||||||
log_prefix = self.log_prefix
|
log_prefix = self.log_prefix
|
||||||
current_mai_state = self.mai_states.get_current_state()
|
|
||||||
state_changed = False # 标记状态是否实际发生改变
|
state_changed = False # 标记状态是否实际发生改变
|
||||||
|
|
||||||
# --- 状态转换逻辑 ---
|
# --- 状态转换逻辑 ---
|
||||||
if new_state == ChatState.CHAT:
|
if new_state == ChatState.CHAT:
|
||||||
normal_limit = current_mai_state.get_normal_chat_max_num()
|
# 移除限额检查逻辑
|
||||||
current_chat_count = current_states_num[1] if len(current_states_num) > 1 else 0
|
logger.debug(f"{log_prefix} 准备进入或保持 聊天 状态")
|
||||||
|
if await self._start_normal_chat():
|
||||||
if current_chat_count >= normal_limit and current_state != ChatState.CHAT:
|
logger.info(f"{log_prefix} 成功进入或保持 NormalChat 状态。")
|
||||||
logger.debug(
|
state_changed = True
|
||||||
f"{log_prefix} 无法从 {current_state.value} 转到 聊天。原因:聊不过来了 ({current_chat_count}/{normal_limit})"
|
|
||||||
)
|
|
||||||
return # 阻止状态转换
|
|
||||||
else:
|
else:
|
||||||
logger.debug(f"{log_prefix} 准备进入或保持 聊天 状态 ({current_chat_count}/{normal_limit})")
|
logger.error(f"{log_prefix} 启动 NormalChat 失败,无法进入 CHAT 状态。")
|
||||||
if await self._start_normal_chat():
|
# 考虑是否需要回滚状态或采取其他措施
|
||||||
logger.info(f"{log_prefix} 成功进入或保持 NormalChat 状态。")
|
return # 启动失败,不改变状态
|
||||||
state_changed = True
|
|
||||||
else:
|
|
||||||
logger.error(f"{log_prefix} 启动 NormalChat 失败,无法进入 CHAT 状态。")
|
|
||||||
# 考虑是否需要回滚状态或采取其他措施
|
|
||||||
return # 启动失败,不改变状态
|
|
||||||
|
|
||||||
elif new_state == ChatState.FOCUSED:
|
elif new_state == ChatState.FOCUSED:
|
||||||
focused_limit = current_mai_state.get_focused_chat_max_num()
|
# 移除限额检查逻辑
|
||||||
current_focused_count = current_states_num[2] if len(current_states_num) > 2 else 0
|
logger.debug(f"{log_prefix} 准备进入或保持 专注聊天 状态")
|
||||||
|
if await self._start_heart_fc_chat():
|
||||||
if current_focused_count >= focused_limit and current_state != ChatState.FOCUSED:
|
logger.info(f"{log_prefix} 成功进入或保持 HeartFChatting 状态。")
|
||||||
logger.debug(
|
state_changed = True
|
||||||
f"{log_prefix} 无法从 {current_state.value} 转到 专注。原因:聊不过来了 ({current_focused_count}/{focused_limit})"
|
|
||||||
)
|
|
||||||
return # 阻止状态转换
|
|
||||||
else:
|
else:
|
||||||
logger.debug(f"{log_prefix} 准备进入或保持 专注聊天 状态 ({current_focused_count}/{focused_limit})")
|
logger.error(f"{log_prefix} 启动 HeartFChatting 失败,无法进入 FOCUSED 状态。")
|
||||||
if await self._start_heart_fc_chat():
|
# 启动失败,状态回滚到之前的状态或ABSENT?这里保持不改变
|
||||||
logger.info(f"{log_prefix} 成功进入或保持 HeartFChatting 状态。")
|
return # 启动失败,不改变状态
|
||||||
state_changed = True
|
|
||||||
else:
|
|
||||||
logger.error(f"{log_prefix} 启动 HeartFChatting 失败,无法进入 FOCUSED 状态。")
|
|
||||||
# 启动失败,状态回滚到之前的状态或ABSENT?这里保持不改变
|
|
||||||
return # 启动失败,不改变状态
|
|
||||||
|
|
||||||
elif new_state == ChatState.ABSENT:
|
elif new_state == ChatState.ABSENT:
|
||||||
logger.info(f"{log_prefix} 进入 ABSENT 状态,停止所有聊天活动...")
|
logger.info(f"{log_prefix} 进入 ABSENT 状态,停止所有聊天活动...")
|
||||||
|
|||||||
@@ -74,8 +74,6 @@ class SubHeartflowManager:
|
|||||||
# logger.debug(f"获取到已存在的子心流: {subheartflow_id}")
|
# logger.debug(f"获取到已存在的子心流: {subheartflow_id}")
|
||||||
return subflow
|
return subflow
|
||||||
|
|
||||||
# 创建新的子心流实例
|
|
||||||
# logger.info(f"子心流 {subheartflow_id} 不存在,正在创建...")
|
|
||||||
try:
|
try:
|
||||||
# 初始化子心流
|
# 初始化子心流
|
||||||
new_subflow = SubHeartflow(subheartflow_id, mai_states)
|
new_subflow = SubHeartflow(subheartflow_id, mai_states)
|
||||||
@@ -118,7 +116,7 @@ class SubHeartflowManager:
|
|||||||
self.count_subflows_by_state(ChatState.CHAT),
|
self.count_subflows_by_state(ChatState.CHAT),
|
||||||
self.count_subflows_by_state(ChatState.FOCUSED),
|
self.count_subflows_by_state(ChatState.FOCUSED),
|
||||||
)
|
)
|
||||||
await subheartflow.set_chat_state(ChatState.ABSENT, states_num)
|
await subheartflow.set_chat_state(ChatState.ABSENT)
|
||||||
else:
|
else:
|
||||||
logger.debug(f"[子心流管理] {stream_name} 已是ABSENT状态")
|
logger.debug(f"[子心流管理] {stream_name} 已是ABSENT状态")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -235,13 +233,15 @@ class SubHeartflowManager:
|
|||||||
|
|
||||||
logger.debug(f"[激活] 正在激活子心流{stream_name}")
|
logger.debug(f"[激活] 正在激活子心流{stream_name}")
|
||||||
|
|
||||||
states_num = (
|
# --- 限额检查 --- #
|
||||||
self.count_subflows_by_state(ChatState.ABSENT),
|
current_chat_count = self.count_subflows_by_state(ChatState.CHAT)
|
||||||
self.count_subflows_by_state(ChatState.CHAT),
|
if current_chat_count >= limit:
|
||||||
self.count_subflows_by_state(ChatState.FOCUSED),
|
logger.warning(f"[激活] 跳过{stream_name}, 普通聊天已达上限 ({current_chat_count}/{limit})")
|
||||||
)
|
continue # 跳过此子心流,继续尝试激活下一个
|
||||||
|
# --- 结束限额检查 --- #
|
||||||
|
|
||||||
await flow.set_chat_state(ChatState.CHAT, states_num)
|
# 移除 states_num 参数
|
||||||
|
await flow.set_chat_state(ChatState.CHAT)
|
||||||
|
|
||||||
if flow.chat_state.chat_status == ChatState.CHAT:
|
if flow.chat_state.chat_status == ChatState.CHAT:
|
||||||
activated_count += 1
|
activated_count += 1
|
||||||
@@ -319,11 +319,11 @@ class SubHeartflowManager:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"{log_prefix} [{stream_name}] 触发 激情水群 (概率={current_subflow.interest_chatting.start_hfc_probability:.2f})"
|
f"{log_prefix} [{stream_name}] 触发 认真水群 (概率={current_subflow.interest_chatting.start_hfc_probability:.2f})"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 执行状态提升
|
# 执行状态提升
|
||||||
await current_subflow.set_chat_state(ChatState.FOCUSED, states_num)
|
await current_subflow.set_chat_state(ChatState.FOCUSED)
|
||||||
|
|
||||||
# 验证提升结果
|
# 验证提升结果
|
||||||
if (
|
if (
|
||||||
@@ -372,7 +372,7 @@ class SubHeartflowManager:
|
|||||||
|
|
||||||
# --- 状态设置 --- #
|
# --- 状态设置 --- #
|
||||||
# 注意:这里传递的状态数量是 *停用前* 的状态数量
|
# 注意:这里传递的状态数量是 *停用前* 的状态数量
|
||||||
await current_subflow.set_chat_state(ChatState.ABSENT, states_num_before)
|
await current_subflow.set_chat_state(ChatState.ABSENT)
|
||||||
|
|
||||||
# --- 状态验证 (可选) ---
|
# --- 状态验证 (可选) ---
|
||||||
final_subflow = self.subheartflows.get(flow_id)
|
final_subflow = self.subheartflows.get(flow_id)
|
||||||
@@ -383,7 +383,6 @@ class SubHeartflowManager:
|
|||||||
f"{log_prefix_manager} {log_prefix_flow} 成功从 {current_state.value} 停用到 ABSENT 状态"
|
f"{log_prefix_manager} {log_prefix_flow} 成功从 {current_state.value} 停用到 ABSENT 状态"
|
||||||
)
|
)
|
||||||
deactivated_count += 1
|
deactivated_count += 1
|
||||||
# 注意:停用后不需要更新 states_num_before,因为它只用于 set_chat_state 的限制检查
|
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"{log_prefix_manager} {log_prefix_flow} 尝试停用到 ABSENT 后状态仍为 {final_state.value}"
|
f"{log_prefix_manager} {log_prefix_flow} 尝试停用到 ABSENT 后状态仍为 {final_state.value}"
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ class HeartFChatting:
|
|||||||
self.log_prefix = f"[{chat_manager.get_stream_name(self.stream_id) or self.stream_id}]"
|
self.log_prefix = f"[{chat_manager.get_stream_name(self.stream_id) or self.stream_id}]"
|
||||||
|
|
||||||
self._initialized = True
|
self._initialized = True
|
||||||
logger.info(f"麦麦感觉到了,可以开始激情水群{self.log_prefix} ")
|
logger.info(f"麦麦感觉到了,可以开始认真水群{self.log_prefix} ")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
@@ -224,7 +224,7 @@ class HeartFChatting:
|
|||||||
启动 HeartFChatting 的主循环。
|
启动 HeartFChatting 的主循环。
|
||||||
注意:调用此方法前必须确保已经成功初始化。
|
注意:调用此方法前必须确保已经成功初始化。
|
||||||
"""
|
"""
|
||||||
logger.info(f"{self.log_prefix} 开始激情水群(HFC)...")
|
logger.info(f"{self.log_prefix} 开始认真水群(HFC)...")
|
||||||
await self._start_loop_if_needed()
|
await self._start_loop_if_needed()
|
||||||
|
|
||||||
async def _start_loop_if_needed(self):
|
async def _start_loop_if_needed(self):
|
||||||
@@ -247,7 +247,7 @@ class HeartFChatting:
|
|||||||
pass # 忽略取消或超时错误
|
pass # 忽略取消或超时错误
|
||||||
self._loop_task = None # 清理旧任务引用
|
self._loop_task = None # 清理旧任务引用
|
||||||
|
|
||||||
logger.info(f"{self.log_prefix} 启动激情水群(HFC)主循环...")
|
logger.info(f"{self.log_prefix} 启动认真水群(HFC)主循环...")
|
||||||
# 创建新的循环任务
|
# 创建新的循环任务
|
||||||
self._loop_task = asyncio.create_task(self._hfc_loop())
|
self._loop_task = asyncio.create_task(self._hfc_loop())
|
||||||
# 添加完成回调
|
# 添加完成回调
|
||||||
@@ -320,7 +320,7 @@ class HeartFChatting:
|
|||||||
)
|
)
|
||||||
|
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
logger.info(f"{self.log_prefix} HeartFChatting: 麦麦的激情水群(HFC)被取消了")
|
logger.info(f"{self.log_prefix} HeartFChatting: 麦麦的认真水群(HFC)被取消了")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"{self.log_prefix} HeartFChatting: 意外错误: {e}")
|
logger.error(f"{self.log_prefix} HeartFChatting: 意外错误: {e}")
|
||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
|
|||||||
@@ -164,14 +164,13 @@ class NormalChat:
|
|||||||
)
|
)
|
||||||
self.mood_manager.update_mood_from_emotion(emotion, global_config.mood_intensity_factor)
|
self.mood_manager.update_mood_from_emotion(emotion, global_config.mood_intensity_factor)
|
||||||
|
|
||||||
async def _find_interested_message(self) -> None:
|
async def _reply_interested_message(self) -> None:
|
||||||
"""
|
"""
|
||||||
后台任务方法,轮询当前实例关联chat的兴趣消息
|
后台任务方法,轮询当前实例关联chat的兴趣消息
|
||||||
通常由start_monitoring_interest()启动
|
通常由start_monitoring_interest()启动
|
||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
await asyncio.sleep(1) # 每秒检查一次
|
await asyncio.sleep(0.5) # 每秒检查一次
|
||||||
|
|
||||||
# 检查任务是否已被取消
|
# 检查任务是否已被取消
|
||||||
if self._chat_task is None or self._chat_task.cancelled():
|
if self._chat_task is None or self._chat_task.cancelled():
|
||||||
logger.info(f"[{self.stream_name}] 兴趣监控任务被取消或置空,退出")
|
logger.info(f"[{self.stream_name}] 兴趣监控任务被取消或置空,退出")
|
||||||
@@ -353,36 +352,27 @@ class NormalChat:
|
|||||||
async def start_chat(self):
|
async def start_chat(self):
|
||||||
"""为此 NormalChat 实例关联的 ChatStream 启动聊天任务(如果尚未运行)。"""
|
"""为此 NormalChat 实例关联的 ChatStream 启动聊天任务(如果尚未运行)。"""
|
||||||
if self._chat_task is None or self._chat_task.done():
|
if self._chat_task is None or self._chat_task.done():
|
||||||
logger.info(f"[{self.stream_name}] 启动聊天任务...")
|
task = asyncio.create_task(self._reply_interested_message())
|
||||||
task = asyncio.create_task(self._find_interested_message())
|
|
||||||
task.add_done_callback(lambda t: self._handle_task_completion(t)) # 回调现在是实例方法
|
task.add_done_callback(lambda t: self._handle_task_completion(t)) # 回调现在是实例方法
|
||||||
self._chat_task = task
|
self._chat_task = task
|
||||||
|
|
||||||
# 改为实例方法, 移除 stream_id 参数
|
|
||||||
def _handle_task_completion(self, task: asyncio.Task):
|
def _handle_task_completion(self, task: asyncio.Task):
|
||||||
"""兴趣监控任务完成时的回调函数。"""
|
"""任务完成回调处理"""
|
||||||
# 检查完成的任务是否是当前实例的任务
|
|
||||||
if task is not self._chat_task:
|
if task is not self._chat_task:
|
||||||
logger.warning(f"[{self.stream_name}] 收到一个未知或过时任务的完成回调。")
|
logger.warning(f"[{self.stream_name}] 收到未知任务回调")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 检查任务是否因异常而结束
|
if exc := task.exception():
|
||||||
exception = task.exception()
|
logger.error(f"[{self.stream_name}] 任务异常: {exc}")
|
||||||
if exception:
|
logger.error(traceback.format_exc())
|
||||||
logger.error(f"[{self.stream_name}] 兴趣监控任务因异常结束: {exception}")
|
|
||||||
logger.error(traceback.format_exc()) # 记录完整的 traceback
|
|
||||||
# else: # 减少日志
|
|
||||||
# logger.info(f"[{self.stream_name}] 兴趣监控任务正常结束。")
|
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
logger.info(f"[{self.stream_name}] 兴趣监控任务被取消。")
|
logger.info(f"[{self.stream_name}] 任务已取消")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[{self.stream_name}] 处理任务完成回调时出错: {e}")
|
logger.error(f"[{self.stream_name}] 回调处理错误: {e}")
|
||||||
finally:
|
finally:
|
||||||
# 标记任务已完成/移除
|
if self._chat_task is task:
|
||||||
if self._chat_task is task: # 再次确认是当前任务
|
|
||||||
self._chat_task = None
|
self._chat_task = None
|
||||||
logger.debug(f"[{self.stream_name}] 聊天任务已被标记为完成/移除。")
|
logger.debug(f"[{self.stream_name}] 任务清理完成")
|
||||||
|
|
||||||
# 改为实例方法, 移除 stream_id 参数
|
# 改为实例方法, 移除 stream_id 参数
|
||||||
async def stop_chat(self):
|
async def stop_chat(self):
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ async def build_readable_messages(
|
|||||||
)
|
)
|
||||||
|
|
||||||
readable_read_mark = translate_timestamp_to_human_readable(read_mark, mode=timestamp_mode)
|
readable_read_mark = translate_timestamp_to_human_readable(read_mark, mode=timestamp_mode)
|
||||||
read_mark_line = f"\n--- 以上消息已读 (标记时间: {readable_read_mark}) ---\n--- 以下新消息未读---\n"
|
read_mark_line = f"\n--- 以上消息是你已经思考过的内容已读 (标记时间: {readable_read_mark}) ---\n--- 请关注以下未读的新消息---\n"
|
||||||
|
|
||||||
# 组合结果,确保空部分不引入多余的标记或换行
|
# 组合结果,确保空部分不引入多余的标记或换行
|
||||||
if formatted_before and formatted_after:
|
if formatted_before and formatted_after:
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ provider = "SILICONFLOW"
|
|||||||
pri_in = 0
|
pri_in = 0
|
||||||
pri_out = 0
|
pri_out = 0
|
||||||
|
|
||||||
[model.llm_sub_heartflow] #子心流:激情水群时,生成麦麦的内心想法
|
[model.llm_sub_heartflow] #子心流:认真水群时,生成麦麦的内心想法
|
||||||
name = "Qwen/Qwen2.5-72B-Instruct"
|
name = "Qwen/Qwen2.5-72B-Instruct"
|
||||||
provider = "SILICONFLOW"
|
provider = "SILICONFLOW"
|
||||||
pri_in = 4.13
|
pri_in = 4.13
|
||||||
@@ -260,7 +260,7 @@ pri_out = 4.13
|
|||||||
temp = 0.7 #模型的温度,新V3建议0.1-0.3
|
temp = 0.7 #模型的温度,新V3建议0.1-0.3
|
||||||
|
|
||||||
|
|
||||||
[model.llm_plan] #决策模型:激情水群时,负责决定麦麦该做什么
|
[model.llm_plan] #决策模型:认真水群时,负责决定麦麦该做什么
|
||||||
name = "Qwen/Qwen2.5-32B-Instruct"
|
name = "Qwen/Qwen2.5-32B-Instruct"
|
||||||
provider = "SILICONFLOW"
|
provider = "SILICONFLOW"
|
||||||
pri_in = 1.26
|
pri_in = 1.26
|
||||||
|
|||||||
Reference in New Issue
Block a user