Repository: SengokuCola/MaiMBot
Pull request #274: 让回复意愿更加拟人，增加高低回复意愿周期，且增加了一个简单的追问回复功能
Author: login: Pocketfans
Created: 2025-03-12T10:11:36Z | Merged: 2025-03-13T07:02:11Z

1. - [x] `main` 分支 **禁止修改**，请确认本次提交的分支 **不是 `main` 分支**
2. - [x] 本次更新 **包含破坏性变更**（如数据库结构变更、配置文件修改等）
3. - [x] 本次更新是否经过测试
4. 请填写破坏性更新的具体内容（如有）:修改了willing_manager里的大部分代码
5. 请简要说明本次更新的内容和目的：
1.让回复更加拟人，增加了高低回复意愿周期，几分钟高强度回复意愿之后是5-20分钟的低回复意愿。但也有10%的可能从低回复医院回到高回复意愿。（不过为了拟人，也让被提及的回复率调到了30%，会出现叫名字不理人的情况）
2.避免回复意愿太高而增加了保底功能。在高回复意愿周期，别人发出4-8句话才会有65%概率回复，而低意愿期需要15句话才有50%概率回复。同时在高回复周期时，每发言一次会降低0.3的回复意愿，未能回答则增加0.1的回复意愿。在低回复周期则每发言一次会降低0.4的回复意愿，未能回答则增加0.1的回复意愿
3.如果5分钟内有人追问你跟你聊天，则增加回复几率，高意愿期75%，低意愿期50%。这样能保证被追问时不想说话了

好的，这是将给定的 pull request 总结翻译成中文的结果：

## Sourcery 总结

通过增加回复意愿高低期，并引入简单的后续问题回复功能，改进了机器人的个性。现在，机器人将在回复意愿高和低的时期之间交替，即使在低意愿时期，也有机会切换回高意愿。此外，它还增加了在短时间内回复后续问题的可能性。

增强功能：

- 实现交替的高低回复意愿期，以模拟更像人类的行为。
- 增加回复后续问题的可能性，以保持对话流程。
- 根据机器人是否被提及以及对主题的兴趣程度调整回复概率。
- 通过跟踪最后发送者和回复时间，提高机器人在对话中保持上下文的能力。
- 重构回复意愿逻辑，使其更具动态性并能响应用户互动。
- 增加一种随时间衰减回复意愿的机制，确保机器人不会变得过于健谈。
- 改进日志记录，以便调试和监控回复意愿。
- 确保在创建新的聊天流时初始化聊天数据。
- 根据消息是否包含表情符号调整回复意愿。
- 根据群组配置调整回复意愿。
- 在发送或不发送消息后调整回复意愿。
- 根据对话上下文调整回复意愿。
- 根据主题兴趣调整回复意愿。
- 根据提及情况调整回复意愿。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

Improves the bot's personality by adding high and low reply willingness periods, and introduces a simple follow-up question reply function. The bot will now alternate between periods of high and low willingness to reply, with a chance to switch back to high willingness even during a low willingness period. It also increases the likelihood of replying to follow-up questions within a short time frame.

Enhancements:
- Implement alternating high and low reply willingness periods to simulate more human-like behavior.
- Increase the likelihood of replying to follow-up questions to maintain conversation flow.
- Adjust reply probability based on whether the bot is mentioned and the level of interest in the topic.
- Improve the bot's ability to maintain context in a conversation by tracking the last sender and reply time.
- Refactor the reply willingness logic to be more dynamic and responsive to user interactions.
- Add a mechanism to decay reply willingness over time, ensuring the bot doesn't become overly talkative.
- Improve logging for debugging and monitoring reply willingness.
- Ensure chat data is initialized when a new chat stream is created.
- Adjust reply willingness based on whether the message contains emoji.
- Adjust reply willingness based on group configuration.
- Adjust reply willingness after sending or not sending a message.
- Adjust reply willingness based on conversation context.
- Adjust reply willingness based on topic interest.
- Adjust reply willingness based on mentions.

</details>


Diff:
diff --git a/src/plugins/chat/bot.py b/src/plugins/chat/bot.py
index 1db38477c7..53266fccf2 100644
--- a/src/plugins/chat/bot.py
+++ b/src/plugins/chat/bot.py
@@ -159,6 +159,7 @@ async def handle_message(self, event: MessageEvent, bot: Bot) -> None:
             config=global_config,
             is_emoji=message.is_emoji,
             interested_rate=interested_rate,
+            sender_id=str(message.message_info.user_info.user_id),
         )
         current_willing = willing_manager.get_willing(chat_stream=chat)
 
@@ -189,6 +190,9 @@ async def handle_message(self, event: MessageEvent, bot: Bot) -> None:
             willing_manager.change_reply_willing_sent(chat)
 
             response, raw_content = await self.gpt.generate_response(message)
+        else:
+            # 决定不回复时，也更新回复意愿
+            willing_manager.change_reply_willing_not_sent(chat)
 
         # print(f"response: {response}")
         if response:
diff --git a/src/plugins/chat/willing_manager.py b/src/plugins/chat/willing_manager.py
index 773d40c6ea..6df27f3a49 100644
--- a/src/plugins/chat/willing_manager.py
+++ b/src/plugins/chat/willing_manager.py
@@ -1,109 +1,259 @@
 import asyncio
+import random
+import time
 from typing import Dict
+from loguru import logger
 
 
 from .config import global_config
 from .chat_stream import ChatStream
 
-from loguru import logger
-
 
 class WillingManager:
     def __init__(self):
         self.chat_reply_willing: Dict[str, float] = {}  # 存储每个聊天流的回复意愿
+        self.chat_high_willing_mode: Dict[str, bool] = {}  # 存储每个聊天流是否处于高回复意愿期
+        self.chat_msg_count: Dict[str, int] = {}  # 存储每个聊天流接收到的消息数量
+        self.chat_last_mode_change: Dict[str, float] = {}  # 存储每个聊天流上次模式切换的时间
+        self.chat_high_willing_duration: Dict[str, int] = {}  # 高意愿期持续时间(秒)
+        self.chat_low_willing_duration: Dict[str, int] = {}  # 低意愿期持续时间(秒)
+        self.chat_last_reply_time: Dict[str, float] = {}  # 存储每个聊天流上次回复的时间
+        self.chat_last_sender_id: Dict[str, str] = {}  # 存储每个聊天流上次回复的用户ID
+        self.chat_conversation_context: Dict[str, bool] = {}  # 标记是否处于对话上下文中
         self._decay_task = None
+        self._mode_switch_task = None
         self._started = False
-
+        
     async def _decay_reply_willing(self):
         """定期衰减回复意愿"""
         while True:
             await asyncio.sleep(5)
             for chat_id in self.chat_reply_willing:
-                self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.6)
-
+                is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+                if is_high_mode:
+                    # 高回复意愿期内轻微衰减
+                    self.chat_reply_willing[chat_id] = max(0.5, self.chat_reply_willing[chat_id] * 0.95)
+                else:
+                    # 低回复意愿期内正常衰减
+                    self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.8)
+                
+    async def _mode_switch_check(self):
+        """定期检查是否需要切换回复意愿模式"""
+        while True:
+            current_time = time.time()
+            await asyncio.sleep(10)  # 每10秒检查一次
+            
+            for chat_id in self.chat_high_willing_mode:
+                last_change_time = self.chat_last_mode_change.get(chat_id, 0)
+                is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+                
+                # 获取当前模式的持续时间
+                duration = 0
+                if is_high_mode:
+                    duration = self.chat_high_willing_duration.get(chat_id, 180)  # 默认3分钟
+                else:
+                    duration = self.chat_low_willing_duration.get(chat_id, random.randint(300, 1200))  # 默认5-20分钟
+                
+                # 检查是否需要切换模式
+                if current_time - last_change_time > duration:
+                    self._switch_willing_mode(chat_id)
+                elif not is_high_mode and random.random() < 0.1:
+                    # 低回复意愿期有10%概率随机切换到高回复期
+                    self._switch_willing_mode(chat_id)
+                
+                # 检查对话上下文状态是否需要重置
+                last_reply_time = self.chat_last_reply_time.get(chat_id, 0)
+                if current_time - last_reply_time > 300:  # 5分钟无交互，重置对话上下文
+                    self.chat_conversation_context[chat_id] = False
+    
+    def _switch_willing_mode(self, chat_id: str):
+        """切换聊天流的回复意愿模式"""
+        is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+        
+        if is_high_mode:
+            # 从高回复期切换到低回复期
+            self.chat_high_willing_mode[chat_id] = False
+            self.chat_reply_willing[chat_id] = 0.1  # 设置为最低回复意愿
+            self.chat_low_willing_duration[chat_id] = random.randint(600, 1200)  # 10-20分钟
+            logger.debug(f"聊天流 {chat_id} 切换到低回复意愿期，持续 {self.chat_low_willing_duration[chat_id]} 秒")
+        else:
+            # 从低回复期切换到高回复期
+            self.chat_high_willing_mode[chat_id] = True
+            self.chat_reply_willing[chat_id] = 1.0  # 设置为较高回复意愿
+            self.chat_high_willing_duration[chat_id] = random.randint(180, 240)  # 3-4分钟
+            logger.debug(f"聊天流 {chat_id} 切换到高回复意愿期，持续 {self.chat_high_willing_duration[chat_id]} 秒")
+        
+        self.chat_last_mode_change[chat_id] = time.time()
+        self.chat_msg_count[chat_id] = 0  # 重置消息计数
+                
     def get_willing(self, chat_stream: ChatStream) -> float:
         """获取指定聊天流的回复意愿"""
         stream = chat_stream
         if stream:
             return self.chat_reply_willing.get(stream.stream_id, 0)
         return 0
-
+    
     def set_willing(self, chat_id: str, willing: float):
         """设置指定聊天流的回复意愿"""
         self.chat_reply_willing[chat_id] = willing
-
-    async def change_reply_willing_received(
-        self,
-        chat_stream: ChatStream,
-        topic: str = None,
-        is_mentioned_bot: bool = False,
-        config=None,
-        is_emoji: bool = False,
-        interested_rate: float = 0,
-    ) -> float:
+        
+    def _ensure_chat_initialized(self, chat_id: str):
+        """确保聊天流的所有数据已初始化"""
+        if chat_id not in self.chat_reply_willing:
+            self.chat_reply_willing[chat_id] = 0.1
+        
+        if chat_id not in self.chat_high_willing_mode:
+            self.chat_high_willing_mode[chat_id] = False
+            self.chat_last_mode_change[chat_id] = time.time()
+            self.chat_low_willing_duration[chat_id] = random.randint(300, 1200)  # 5-20分钟
+        
+        if chat_id not in self.chat_msg_count:
+            self.chat_msg_count[chat_id] = 0
+            
+        if chat_id not in self.chat_conversation_context:
+            self.chat_conversation_context[chat_id] = False
+        
+    async def change_reply_willing_received(self, 
+                                          chat_stream: ChatStream,
+                                          topic: str = None,
+                                          is_mentioned_bot: bool = False,
+                                          config = None,
+                                          is_emoji: bool = False,
+                                          interested_rate: float = 0,
+                                          sender_id: str = None) -> float:
         """改变指定聊天流的回复意愿并返回回复概率"""
         # 获取或创建聊天流
         stream = chat_stream
         chat_id = stream.stream_id
-
+        current_time = time.time()
+        
+        self._ensure_chat_initialized(chat_id)
+        
+        # 增加消息计数
+        self.chat_msg_count[chat_id] = self.chat_msg_count.get(chat_id, 0) + 1
+        
         current_willing = self.chat_reply_willing.get(chat_id, 0)
-
-        if is_mentioned_bot and current_willing < 1.0:
-            current_willing += 0.9
+        is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+        msg_count = self.chat_msg_count.get(chat_id, 0)
+        in_conversation_context = self.chat_conversation_context.get(chat_id, False)
+        
+        # 检查是否是对话上下文中的追问
+        last_reply_time = self.chat_last_reply_time.get(chat_id, 0)
+        last_sender = self.chat_last_sender_id.get(chat_id, "")
+        is_follow_up_question = False
+        
+        # 如果是同一个人在短时间内（2分钟内）发送消息，且消息数量较少（<=5条），视为追问
+        if sender_id and sender_id == last_sender and current_time - last_reply_time < 120 and msg_count <= 5:
+            is_follow_up_question = True
+            in_conversation_context = True
+            self.chat_conversation_context[chat_id] = True
+            logger.debug(f"检测到追问 (同一用户), 提高回复意愿")
+            current_willing += 0.3
+        
+        # 特殊情况处理
+        if is_mentioned_bot:
+            current_willing += 0.5
+            in_conversation_context = True
+            self.chat_conversation_context[chat_id] = True
             logger.debug(f"被提及, 当前意愿: {current_willing}")
-        elif is_mentioned_bot:
-            current_willing += 0.05
-            logger.debug(f"被重复提及, 当前意愿: {current_willing}")
-
+        
         if is_emoji:
             current_willing *= 0.1
             logger.debug(f"表情包, 当前意愿: {current_willing}")
-
-        logger.debug(f"放大系数_interested_rate: {global_config.response_interested_rate_amplifier}")
-        interested_rate *= global_config.response_interested_rate_amplifier  # 放大回复兴趣度
-        if interested_rate > 0.4:
-            # print(f"兴趣度: {interested_rate}, 当前意愿: {current_willing}")
-            current_willing += interested_rate - 0.4
-
-        current_willing *= global_config.response_willing_amplifier  # 放大回复意愿
-        # print(f"放大系数_willing: {global_config.response_willing_amplifier}, 当前意愿: {current_willing}")
-
-        reply_probability = max((current_willing - 0.45) * 2, 0)
-
+        
+        # 根据话题兴趣度适当调整
+        if interested_rate > 0.5:
+            current_willing += (interested_rate - 0.5) * 0.5
+            
+        # 根据当前模式计算回复概率
+        base_probability = 0.0
+        
+        if in_conversation_context:
+            # 在对话上下文中，降低基础回复概率
+            base_probability = 0.5 if is_high_mode else 0.25
+            logger.debug(f"处于对话上下文中，基础回复概率: {base_probability}")
+        elif is_high_mode:
+            # 高回复周期：4-8句话有50%的概率会回复一次
+            base_probability = 0.50 if 4 <= msg_count <= 8 else 0.2
+        else:
+            # 低回复周期：需要最少15句才有30%的概率会回一句
+            base_probability = 0.30 if msg_count >= 15 else 0.03 * min(msg_count, 10)
+            
+        # 考虑回复意愿的影响
+        reply_probability = base_probability * current_willing
+        
         # 检查群组权限（如果是群聊）
-        if chat_stream.group_info:
+        if chat_stream.group_info and config:               
             if chat_stream.group_info.group_id in config.talk_frequency_down_groups:
                 reply_probability = reply_probability / global_config.down_frequency_rate
 
-        reply_probability = min(reply_probability, 1)
+        # 限制最大回复概率
+        reply_probability = min(reply_probability, 0.75)  # 设置最大回复概率为75%
         if reply_probability < 0:
             reply_probability = 0
-
+        
+        # 记录当前发送者ID以便后续追踪
+        if sender_id:
+            self.chat_last_sender_id[chat_id] = sender_id
+            
         self.chat_reply_willing[chat_id] = min(current_willing, 3.0)
         return reply_probability
-
+    
     def change_reply_willing_sent(self, chat_stream: ChatStream):
         """开始思考后降低聊天流的回复意愿"""
         stream = chat_stream
         if stream:
-            current_willing = self.chat_reply_willing.get(stream.stream_id, 0)
-            self.chat_reply_willing[stream.stream_id] = max(0, current_willing - 2)
-
-    def change_reply_willing_after_sent(self, chat_stream: ChatStream):
-        """发送消息后提高聊天流的回复意愿"""
+            chat_id = stream.stream_id
+            self._ensure_chat_initialized(chat_id)
+            is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+            current_willing = self.chat_reply_willing.get(chat_id, 0)
+            
+            # 回复后减少回复意愿
+            self.chat_reply_willing[chat_id] = max(0, current_willing - 0.3)
+            
+            # 标记为对话上下文中
+            self.chat_conversation_context[chat_id] = True
+            
+            # 记录最后回复时间
+            self.chat_last_reply_time[chat_id] = time.time()
+            
+            # 重置消息计数
+            self.chat_msg_count[chat_id] = 0
+        
+    def change_reply_willing_not_sent(self, chat_stream: ChatStream):
+        """决定不回复后提高聊天流的回复意愿"""
         stream = chat_stream
         if stream:
-            current_willing = self.chat_reply_willing.get(stream.stream_id, 0)
-            if current_willing < 1:
-                self.chat_reply_willing[stream.stream_id] = min(1, current_willing + 0.2)
-
+            chat_id = stream.stream_id
+            self._ensure_chat_initialized(chat_id)
+            is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+            current_willing = self.chat_reply_willing.get(chat_id, 0)
+            in_conversation_context = self.chat_conversation_context.get(chat_id, False)
+            
+            # 根据当前模式调整不回复后的意愿增加
+            if is_high_mode:
+                willing_increase = 0.1
+            elif in_conversation_context:
+                # 在对话上下文中但决定不回复，小幅增加回复意愿
+                willing_increase = 0.15
+            else:
+                willing_increase = random.uniform(0.05, 0.1)
+                
+            self.chat_reply_willing[chat_id] = min(2.0, current_willing + willing_increase)
+        
+    def change_reply_willing_after_sent(self, chat_stream: ChatStream):
+        """发送消息后提高聊天流的回复意愿"""
+        # 由于已经在sent中处理，这个方法保留但不再需要额外调整
+        pass
+        
     async def ensure_started(self):
-        """确保衰减任务已启动"""
+        """确保所有任务已启动"""
         if not self._started:
             if self._decay_task is None:
                 self._decay_task = asyncio.create_task(self._decay_reply_willing())
+            if self._mode_switch_task is None:
+                self._mode_switch_task = asyncio.create_task(self._mode_switch_check())
             self._started = True
 
-
 # 创建全局实例
-willing_manager = WillingManager()
+willing_manager = WillingManager() 
\ No newline at end of file


Reviews:
user: login: sourcery-ai[bot]
body: Hey @Pocketfans - I've reviewed your changes - here's some feedback:

**Overall Comments**:
- Consider adding more comments to explain the logic behind the formulas used to calculate reply probability.
- The `ensure_started` function should probably be called at the start of the program, not when the first message is received.

<details>
<summary>Here's what I looked at during the review</summary>

- 🟡 **General issues**: 5 issues found
- 🟢 **Security**: all looks good
- 🟢 **Testing**: all looks good
- 🟡 **Complexity**: 1 issue found
- 🟢 **Documentation**: all looks good
</details>

***

<details>
<summary>Sourcery is free for open source - if you like our reviews please consider sharing them ✨</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https://sourcery.ai)
- [Facebook](https://www.facebook.com/sharer/sharer.php?u=https://sourcery.ai)

</details>

<sub>
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
</sub>
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T10:12:57Z
user: login: BBleae
body: > 以下结果由 Claude Code 生成

1. 竞态条件与并发问题

  - 字典修改问题: `_decay_reply_willing` 和 `_mode_switch_check` 方法中，在遍历字典的同时修改字典内容，可能会引发`RuntimeError: dictionary changed size during iteration` 。建议使用字典副本进行遍历：
```python
for chat_id in list(self.chat_reply_willing.keys()):
      # 修改操作
```

  - 无锁保护：多个异步任务同时修改共享状态，缺乏同步机制

  2. 初始化与空值处理

  - 不完整的初始化: `_ensure_chat_initialized` 方法未初始化所有使用的字典键，特别是：
    - `chat_last_reply_time`
    - `chat_last_sender_id`
    - `chat_high_willing_duration`
  - 未处理空值：多处使用 `.get(key, default)` 获取值，但不保证这些键之后会被初始化

  3. 逻辑错误

  - 切换模式时间计算：在 `_mode_switch_check` 中使用随机生成的持续时间，而后在 `_switch_willing_mode` 再次覆盖，导致持续时间计算不一致
  - 追问检测逻辑过于简化：
    - 仅基于用户ID、时间窗口和消息数量判断
    - 无法识别不同用户间的对话连续性
    - 固定的时间窗口(120秒)和消息限制(5条)不适应不同场景

  4. 资源管理问题

  - 无任务清理机制：缺少停止和清理异步任务的方法，可能导致协程泄漏
  - 持续增长的字典：所有字典都只添加不删除，对长期运行可能造成内存压力

  5. 回复概率计算

  - 可能的极端值：
    - `reply_probability = base_probability * current_willing` 中，如果 `current_willing` 接近0，回复概率会非常低
    - 低概率情况下可能导致聊天完全停止响应
  - 高频率切换：低回复期有10%概率随机切换到高回复期，可能导致行为不稳定

  总结

  虽然本PR改进了机器人的拟人程度，但存在多个潜在问题，特别是在并发安全、初始化完整性和逻辑一致性方面。建议在合并前修复这些问题
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-13T06:33:30Z

Review comments:
diff_hunk: @@ -1,109 +1,257 @@
 import asyncio
+import random
+import time
 from typing import Dict
 
 
 from .config import global_config
 from .chat_stream import ChatStream
 
-from loguru import logger
-
 
 class WillingManager:
     def __init__(self):
         self.chat_reply_willing: Dict[str, float] = {}  # 存储每个聊天流的回复意愿
+        self.chat_high_willing_mode: Dict[str, bool] = {}  # 存储每个聊天流是否处于高回复意愿期
+        self.chat_msg_count: Dict[str, int] = {}  # 存储每个聊天流接收到的消息数量
+        self.chat_last_mode_change: Dict[str, float] = {}  # 存储每个聊天流上次模式切换的时间
+        self.chat_high_willing_duration: Dict[str, int] = {}  # 高意愿期持续时间(秒)
+        self.chat_low_willing_duration: Dict[str, int] = {}  # 低意愿期持续时间(秒)
+        self.chat_last_reply_time: Dict[str, float] = {}  # 存储每个聊天流上次回复的时间
+        self.chat_last_sender_id: Dict[str, str] = {}  # 存储每个聊天流上次回复的用户ID
+        self.chat_conversation_context: Dict[str, bool] = {}  # 标记是否处于对话上下文中
         self._decay_task = None
+        self._mode_switch_task = None
         self._started = False
-
+        
     async def _decay_reply_willing(self):
         """定期衰减回复意愿"""
         while True:
             await asyncio.sleep(5)
-            for chat_id in self.chat_reply_willing:
-                self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.6)
-
+            for chat_id in list(self.chat_reply_willing.keys()):
+                is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+                if is_high_mode:
+                    # 高回复意愿期内轻微衰减
+                    self.chat_reply_willing[chat_id] = max(0.5, self.chat_reply_willing[chat_id] * 0.95)
+                else:
+                    # 低回复意愿期内正常衰减
+                    self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.8)
+                
+    async def _mode_switch_check(self):
+        """定期检查是否需要切换回复意愿模式"""
+        while True:
+            current_time = time.time()
+            await asyncio.sleep(10)  # 每10秒检查一次
+            
+            for chat_id in list(self.chat_high_willing_mode.keys()):
+                last_change_time = self.chat_last_mode_change.get(chat_id, 0)
+                is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+                
+                # 获取当前模式的持续时间
+                duration = 0
+                if is_high_mode:
+                    duration = self.chat_high_willing_duration.get(chat_id, 180)  # 默认3分钟
+                else:
+                    duration = self.chat_low_willing_duration.get(chat_id, random.randint(300, 1200))  # 默认5-20分钟
+                
+                # 检查是否需要切换模式
+                if current_time - last_change_time > duration:
+                    self._switch_willing_mode(chat_id)
+                elif not is_high_mode and random.random() < 0.1:
+                    # 低回复意愿期有10%概率随机切换到高回复期
+                    self._switch_willing_mode(chat_id)
+                
+                # 检查对话上下文状态是否需要重置
+                last_reply_time = self.chat_last_reply_time.get(chat_id, 0)
+                if current_time - last_reply_time > 300:  # 5分钟无交互，重置对话上下文
+                    self.chat_conversation_context[chat_id] = False
+    
+    def _switch_willing_mode(self, chat_id: str):
+        """切换聊天流的回复意愿模式"""
+        is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+        
+        if is_high_mode:
+            # 从高回复期切换到低回复期
+            self.chat_high_willing_mode[chat_id] = False
+            self.chat_reply_willing[chat_id] = 0.1  # 设置为最低回复意愿
+            self.chat_low_willing_duration[chat_id] = random.randint(600, 1200)  # 10-20分钟
+            print(f"聊天流 {chat_id} 切换到低回复意愿期，持续 {self.chat_low_willing_duration[chat_id]} 秒")
path: src/plugins/chat/willing_manager.py
user: login: sourcery-ai[bot]
body: **suggestion:** Avoid using print statements for logging mode switches.

Since this module previously used a logging framework, it would be preferable to maintain that approach here for consistency and configurability in production.

Suggested implementation:

```python
import logging
logger = logging.getLogger(__name__)

```

```python
            logger.info(f"聊天流 {chat_id} 切换到低回复意愿期，持续 {self.chat_low_willing_duration[chat_id]} 秒")

```

```python
            logger.info(f"聊天流 {chat_id} 切换到高回复意愿期，持续 {self.chat_high_willing_duration[chat_id]} 秒")

```

Make sure that logging is properly configured in your application. If logging is already configured elsewhere in the project, this change will integrate seamlessly with your production logging setup.
created_at: 2025-03-12T10:12:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,109 +1,257 @@
 import asyncio
+import random
+import time
 from typing import Dict
 
 
 from .config import global_config
 from .chat_stream import ChatStream
 
-from loguru import logger
-
 
 class WillingManager:
     def __init__(self):
         self.chat_reply_willing: Dict[str, float] = {}  # 存储每个聊天流的回复意愿
+        self.chat_high_willing_mode: Dict[str, bool] = {}  # 存储每个聊天流是否处于高回复意愿期
+        self.chat_msg_count: Dict[str, int] = {}  # 存储每个聊天流接收到的消息数量
+        self.chat_last_mode_change: Dict[str, float] = {}  # 存储每个聊天流上次模式切换的时间
+        self.chat_high_willing_duration: Dict[str, int] = {}  # 高意愿期持续时间(秒)
+        self.chat_low_willing_duration: Dict[str, int] = {}  # 低意愿期持续时间(秒)
+        self.chat_last_reply_time: Dict[str, float] = {}  # 存储每个聊天流上次回复的时间
+        self.chat_last_sender_id: Dict[str, str] = {}  # 存储每个聊天流上次回复的用户ID
+        self.chat_conversation_context: Dict[str, bool] = {}  # 标记是否处于对话上下文中
         self._decay_task = None
+        self._mode_switch_task = None
         self._started = False
-
+        
     async def _decay_reply_willing(self):
         """定期衰减回复意愿"""
         while True:
             await asyncio.sleep(5)
-            for chat_id in self.chat_reply_willing:
-                self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.6)
-
+            for chat_id in list(self.chat_reply_willing.keys()):
+                is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+                if is_high_mode:
+                    # 高回复意愿期内轻微衰减
+                    self.chat_reply_willing[chat_id] = max(0.5, self.chat_reply_willing[chat_id] * 0.95)
+                else:
+                    # 低回复意愿期内正常衰减
+                    self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.8)
+                
+    async def _mode_switch_check(self):
+        """定期检查是否需要切换回复意愿模式"""
+        while True:
+            current_time = time.time()
+            await asyncio.sleep(10)  # 每10秒检查一次
+            
+            for chat_id in list(self.chat_high_willing_mode.keys()):
+                last_change_time = self.chat_last_mode_change.get(chat_id, 0)
+                is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+                
+                # 获取当前模式的持续时间
+                duration = 0
+                if is_high_mode:
+                    duration = self.chat_high_willing_duration.get(chat_id, 180)  # 默认3分钟
+                else:
+                    duration = self.chat_low_willing_duration.get(chat_id, random.randint(300, 1200))  # 默认5-20分钟
+                
+                # 检查是否需要切换模式
+                if current_time - last_change_time > duration:
+                    self._switch_willing_mode(chat_id)
+                elif not is_high_mode and random.random() < 0.1:
+                    # 低回复意愿期有10%概率随机切换到高回复期
+                    self._switch_willing_mode(chat_id)
+                
+                # 检查对话上下文状态是否需要重置
+                last_reply_time = self.chat_last_reply_time.get(chat_id, 0)
+                if current_time - last_reply_time > 300:  # 5分钟无交互，重置对话上下文
+                    self.chat_conversation_context[chat_id] = False
+    
+    def _switch_willing_mode(self, chat_id: str):
+        """切换聊天流的回复意愿模式"""
+        is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+        
+        if is_high_mode:
+            # 从高回复期切换到低回复期
+            self.chat_high_willing_mode[chat_id] = False
+            self.chat_reply_willing[chat_id] = 0.1  # 设置为最低回复意愿
+            self.chat_low_willing_duration[chat_id] = random.randint(600, 1200)  # 10-20分钟
+            print(f"聊天流 {chat_id} 切换到低回复意愿期，持续 {self.chat_low_willing_duration[chat_id]} 秒")
+        else:
+            # 从低回复期切换到高回复期
+            self.chat_high_willing_mode[chat_id] = True
+            self.chat_reply_willing[chat_id] = 1.0  # 设置为较高回复意愿
+            self.chat_high_willing_duration[chat_id] = random.randint(180, 240)  # 3-4分钟
+            print(f"聊天流 {chat_id} 切换到高回复意愿期，持续 {self.chat_high_willing_duration[chat_id]} 秒")
+        
+        self.chat_last_mode_change[chat_id] = time.time()
+        self.chat_msg_count[chat_id] = 0  # 重置消息计数
+                
     def get_willing(self, chat_stream: ChatStream) -> float:
         """获取指定聊天流的回复意愿"""
         stream = chat_stream
         if stream:
             return self.chat_reply_willing.get(stream.stream_id, 0)
         return 0
-
+    
     def set_willing(self, chat_id: str, willing: float):
         """设置指定聊天流的回复意愿"""
         self.chat_reply_willing[chat_id] = willing
-
-    async def change_reply_willing_received(
-        self,
-        chat_stream: ChatStream,
-        topic: str = None,
-        is_mentioned_bot: bool = False,
-        config=None,
-        is_emoji: bool = False,
-        interested_rate: float = 0,
-    ) -> float:
+        
+    def _ensure_chat_initialized(self, chat_id: str):
+        """确保聊天流的所有数据已初始化"""
+        if chat_id not in self.chat_reply_willing:
+            self.chat_reply_willing[chat_id] = 0.1
+        
+        if chat_id not in self.chat_high_willing_mode:
+            self.chat_high_willing_mode[chat_id] = False
+            self.chat_last_mode_change[chat_id] = time.time()
+            self.chat_low_willing_duration[chat_id] = random.randint(300, 1200)  # 5-20分钟
+        
+        if chat_id not in self.chat_msg_count:
+            self.chat_msg_count[chat_id] = 0
+            
+        if chat_id not in self.chat_conversation_context:
+            self.chat_conversation_context[chat_id] = False
+        
+    async def change_reply_willing_received(self, 
+                                          chat_stream: ChatStream,
+                                          topic: str = None,
+                                          is_mentioned_bot: bool = False,
+                                          config = None,
+                                          is_emoji: bool = False,
+                                          interested_rate: float = 0,
+                                          sender_id: str = None) -> float:
         """改变指定聊天流的回复意愿并返回回复概率"""
         # 获取或创建聊天流
         stream = chat_stream
         chat_id = stream.stream_id
-
+        current_time = time.time()
+        
+        self._ensure_chat_initialized(chat_id)
+        
+        # 增加消息计数
+        self.chat_msg_count[chat_id] = self.chat_msg_count.get(chat_id, 0) + 1
+        
         current_willing = self.chat_reply_willing.get(chat_id, 0)
-
-        if is_mentioned_bot and current_willing < 1.0:
-            current_willing += 0.9
-            logger.debug(f"被提及, 当前意愿: {current_willing}")
-        elif is_mentioned_bot:
-            current_willing += 0.05
-            logger.debug(f"被重复提及, 当前意愿: {current_willing}")
-
+        is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+        msg_count = self.chat_msg_count.get(chat_id, 0)
+        in_conversation_context = self.chat_conversation_context.get(chat_id, False)
+        
+        # 检查是否是对话上下文中的追问
+        last_reply_time = self.chat_last_reply_time.get(chat_id, 0)
+        last_sender = self.chat_last_sender_id.get(chat_id, "")
+        is_follow_up_question = False
+        
+        # 如果是同一个人在短时间内（2分钟内）发送消息，且消息数量较少（<=5条），视为追问
+        if sender_id and sender_id == last_sender and current_time - last_reply_time < 120 and msg_count <= 5:
+            is_follow_up_question = True
+            in_conversation_context = True
+            self.chat_conversation_context[chat_id] = True
+            print(f"检测到追问 (同一用户), 提高回复意愿")
path: src/plugins/chat/willing_manager.py
user: login: sourcery-ai[bot]
body: **suggestion:** Prefer using a logging method over print() for debugging output.

Replacing print calls with controlled logging improves consistency and enables log level management across the codebase.

Suggested implementation:

```python
import logging
from .config import global_config

```

```python
            logging.debug("检测到追问 (同一用户), 提高回复意愿")

```
created_at: 2025-03-12T10:12:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,109 +1,257 @@
 import asyncio
+import random
+import time
 from typing import Dict
 
 
 from .config import global_config
 from .chat_stream import ChatStream
 
-from loguru import logger
-
 
 class WillingManager:
     def __init__(self):
         self.chat_reply_willing: Dict[str, float] = {}  # 存储每个聊天流的回复意愿
+        self.chat_high_willing_mode: Dict[str, bool] = {}  # 存储每个聊天流是否处于高回复意愿期
+        self.chat_msg_count: Dict[str, int] = {}  # 存储每个聊天流接收到的消息数量
+        self.chat_last_mode_change: Dict[str, float] = {}  # 存储每个聊天流上次模式切换的时间
+        self.chat_high_willing_duration: Dict[str, int] = {}  # 高意愿期持续时间(秒)
+        self.chat_low_willing_duration: Dict[str, int] = {}  # 低意愿期持续时间(秒)
+        self.chat_last_reply_time: Dict[str, float] = {}  # 存储每个聊天流上次回复的时间
+        self.chat_last_sender_id: Dict[str, str] = {}  # 存储每个聊天流上次回复的用户ID
+        self.chat_conversation_context: Dict[str, bool] = {}  # 标记是否处于对话上下文中
         self._decay_task = None
+        self._mode_switch_task = None
         self._started = False
-
+        
     async def _decay_reply_willing(self):
         """定期衰减回复意愿"""
         while True:
             await asyncio.sleep(5)
-            for chat_id in self.chat_reply_willing:
-                self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.6)
-
+            for chat_id in list(self.chat_reply_willing.keys()):
+                is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+                if is_high_mode:
+                    # 高回复意愿期内轻微衰减
+                    self.chat_reply_willing[chat_id] = max(0.5, self.chat_reply_willing[chat_id] * 0.95)
+                else:
+                    # 低回复意愿期内正常衰减
+                    self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.8)
+                
+    async def _mode_switch_check(self):
+        """定期检查是否需要切换回复意愿模式"""
+        while True:
+            current_time = time.time()
+            await asyncio.sleep(10)  # 每10秒检查一次
+            
+            for chat_id in list(self.chat_high_willing_mode.keys()):
+                last_change_time = self.chat_last_mode_change.get(chat_id, 0)
+                is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+                
+                # 获取当前模式的持续时间
+                duration = 0
+                if is_high_mode:
+                    duration = self.chat_high_willing_duration.get(chat_id, 180)  # 默认3分钟
+                else:
+                    duration = self.chat_low_willing_duration.get(chat_id, random.randint(300, 1200))  # 默认5-20分钟
+                
+                # 检查是否需要切换模式
+                if current_time - last_change_time > duration:
+                    self._switch_willing_mode(chat_id)
+                elif not is_high_mode and random.random() < 0.1:
+                    # 低回复意愿期有10%概率随机切换到高回复期
+                    self._switch_willing_mode(chat_id)
+                
+                # 检查对话上下文状态是否需要重置
+                last_reply_time = self.chat_last_reply_time.get(chat_id, 0)
+                if current_time - last_reply_time > 300:  # 5分钟无交互，重置对话上下文
+                    self.chat_conversation_context[chat_id] = False
+    
+    def _switch_willing_mode(self, chat_id: str):
+        """切换聊天流的回复意愿模式"""
+        is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+        
+        if is_high_mode:
+            # 从高回复期切换到低回复期
+            self.chat_high_willing_mode[chat_id] = False
+            self.chat_reply_willing[chat_id] = 0.1  # 设置为最低回复意愿
+            self.chat_low_willing_duration[chat_id] = random.randint(600, 1200)  # 10-20分钟
+            print(f"聊天流 {chat_id} 切换到低回复意愿期，持续 {self.chat_low_willing_duration[chat_id]} 秒")
+        else:
+            # 从低回复期切换到高回复期
+            self.chat_high_willing_mode[chat_id] = True
+            self.chat_reply_willing[chat_id] = 1.0  # 设置为较高回复意愿
+            self.chat_high_willing_duration[chat_id] = random.randint(180, 240)  # 3-4分钟
+            print(f"聊天流 {chat_id} 切换到高回复意愿期，持续 {self.chat_high_willing_duration[chat_id]} 秒")
+        
+        self.chat_last_mode_change[chat_id] = time.time()
+        self.chat_msg_count[chat_id] = 0  # 重置消息计数
+                
     def get_willing(self, chat_stream: ChatStream) -> float:
         """获取指定聊天流的回复意愿"""
         stream = chat_stream
         if stream:
             return self.chat_reply_willing.get(stream.stream_id, 0)
         return 0
-
+    
     def set_willing(self, chat_id: str, willing: float):
         """设置指定聊天流的回复意愿"""
         self.chat_reply_willing[chat_id] = willing
-
-    async def change_reply_willing_received(
-        self,
-        chat_stream: ChatStream,
-        topic: str = None,
-        is_mentioned_bot: bool = False,
-        config=None,
-        is_emoji: bool = False,
-        interested_rate: float = 0,
-    ) -> float:
+        
+    def _ensure_chat_initialized(self, chat_id: str):
+        """确保聊天流的所有数据已初始化"""
+        if chat_id not in self.chat_reply_willing:
+            self.chat_reply_willing[chat_id] = 0.1
+        
+        if chat_id not in self.chat_high_willing_mode:
+            self.chat_high_willing_mode[chat_id] = False
+            self.chat_last_mode_change[chat_id] = time.time()
+            self.chat_low_willing_duration[chat_id] = random.randint(300, 1200)  # 5-20分钟
+        
+        if chat_id not in self.chat_msg_count:
+            self.chat_msg_count[chat_id] = 0
+            
+        if chat_id not in self.chat_conversation_context:
+            self.chat_conversation_context[chat_id] = False
+        
+    async def change_reply_willing_received(self, 
+                                          chat_stream: ChatStream,
+                                          topic: str = None,
+                                          is_mentioned_bot: bool = False,
+                                          config = None,
+                                          is_emoji: bool = False,
+                                          interested_rate: float = 0,
+                                          sender_id: str = None) -> float:
         """改变指定聊天流的回复意愿并返回回复概率"""
         # 获取或创建聊天流
         stream = chat_stream
         chat_id = stream.stream_id
-
+        current_time = time.time()
+        
+        self._ensure_chat_initialized(chat_id)
+        
+        # 增加消息计数
+        self.chat_msg_count[chat_id] = self.chat_msg_count.get(chat_id, 0) + 1
+        
         current_willing = self.chat_reply_willing.get(chat_id, 0)
-
-        if is_mentioned_bot and current_willing < 1.0:
-            current_willing += 0.9
-            logger.debug(f"被提及, 当前意愿: {current_willing}")
-        elif is_mentioned_bot:
-            current_willing += 0.05
-            logger.debug(f"被重复提及, 当前意愿: {current_willing}")
-
+        is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+        msg_count = self.chat_msg_count.get(chat_id, 0)
+        in_conversation_context = self.chat_conversation_context.get(chat_id, False)
+        
+        # 检查是否是对话上下文中的追问
+        last_reply_time = self.chat_last_reply_time.get(chat_id, 0)
+        last_sender = self.chat_last_sender_id.get(chat_id, "")
+        is_follow_up_question = False
+        
+        # 如果是同一个人在短时间内（2分钟内）发送消息，且消息数量较少（<=5条），视为追问
+        if sender_id and sender_id == last_sender and current_time - last_reply_time < 120 and msg_count <= 5:
+            is_follow_up_question = True
+            in_conversation_context = True
+            self.chat_conversation_context[chat_id] = True
+            print(f"检测到追问 (同一用户), 提高回复意愿")
+            current_willing += 0.3
+        
+        # 特殊情况处理
+        if is_mentioned_bot:
+            current_willing += 0.3
+            in_conversation_context = True
+            self.chat_conversation_context[chat_id] = True
+            print(f"被提及, 当前意愿: {current_willing}")
+        
         if is_emoji:
             current_willing *= 0.1
-            logger.debug(f"表情包, 当前意愿: {current_willing}")
-
-        logger.debug(f"放大系数_interested_rate: {global_config.response_interested_rate_amplifier}")
-        interested_rate *= global_config.response_interested_rate_amplifier  # 放大回复兴趣度
-        if interested_rate > 0.4:
-            # print(f"兴趣度: {interested_rate}, 当前意愿: {current_willing}")
-            current_willing += interested_rate - 0.4
-
-        current_willing *= global_config.response_willing_amplifier  # 放大回复意愿
-        # print(f"放大系数_willing: {global_config.response_willing_amplifier}, 当前意愿: {current_willing}")
-
-        reply_probability = max((current_willing - 0.45) * 2, 0)
-
+            print(f"表情包, 当前意愿: {current_willing}")
path: src/plugins/chat/willing_manager.py
user: login: sourcery-ai[bot]
body: **suggestion:** Consider substituting print with logger for reporting emoji adjustments.

A consistent logging approach allows for managing output in production; this change would align the debug reporting with other parts of the system.

Suggested implementation:

```python
            logger.debug(f"表情包, 当前意愿: {current_willing}")

```

```python
            logger.debug(f"处于对话上下文中，基础回复概率: {base_probability}")

```

Ensure that the logger is correctly configured and imported in this file. If not already imported, add a statement such as "import logging" and "logger = logging.getLogger(__name__)" at the top of the file.
created_at: 2025-03-12T10:12:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -235,10 +239,10 @@ async def handle_message(self, event: MessageEvent, bot: Bot) -> None:
                     is_head=not mark_head,
                     is_emoji=False,
                 )
-                logger.debug(f"bot_message: {bot_message}")
+                print(f"bot_message: {bot_message}")
path: src/plugins/chat/bot.py
user: login: sourcery-ai[bot]
body: **suggestion:** Maintain consistent logging usage instead of print in bot handling.

The rest of the code utilizes logging (or previously did); switching back to a logging framework helps in controlling the verbosity and log levels effectively.

Suggested implementation:

```python
                logger.debug(f"bot_message: {bot_message}")

```

```python
                logger.debug(f"添加消息到message_set: {bot_message}")

```
created_at: 2025-03-12T10:12:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -235,10 +239,10 @@ async def handle_message(self, event: MessageEvent, bot: Bot) -> None:
                     is_head=not mark_head,
                     is_emoji=False,
                 )
-                logger.debug(f"bot_message: {bot_message}")
+                print(f"bot_message: {bot_message}")
                 if not mark_head:
                     mark_head = True
-                logger.debug(f"添加消息到message_set: {bot_message}")
+                print(f"添加消息到message_set: {bot_message}")
path: src/plugins/chat/bot.py
user: login: sourcery-ai[bot]
body: **suggestion:** Replace print statements with logging for consistency in debug messaging.

Consistent use of a logging mechanism rather than print will offer more flexibility in managing output and is generally preferable in production-quality code.

Suggested implementation:

```python
                logger.debug(f"添加消息到message_set: {bot_message}")

```

```python
                logger.debug(f"bot_message: {bot_message}")

```
created_at: 2025-03-12T10:12:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,109 +1,257 @@
 import asyncio
+import random
+import time
 from typing import Dict
 
 
 from .config import global_config
 from .chat_stream import ChatStream
 
-from loguru import logger
-
 
 class WillingManager:
     def __init__(self):
         self.chat_reply_willing: Dict[str, float] = {}  # 存储每个聊天流的回复意愿
+        self.chat_high_willing_mode: Dict[str, bool] = {}  # 存储每个聊天流是否处于高回复意愿期
+        self.chat_msg_count: Dict[str, int] = {}  # 存储每个聊天流接收到的消息数量
+        self.chat_last_mode_change: Dict[str, float] = {}  # 存储每个聊天流上次模式切换的时间
+        self.chat_high_willing_duration: Dict[str, int] = {}  # 高意愿期持续时间(秒)
+        self.chat_low_willing_duration: Dict[str, int] = {}  # 低意愿期持续时间(秒)
+        self.chat_last_reply_time: Dict[str, float] = {}  # 存储每个聊天流上次回复的时间
+        self.chat_last_sender_id: Dict[str, str] = {}  # 存储每个聊天流上次回复的用户ID
+        self.chat_conversation_context: Dict[str, bool] = {}  # 标记是否处于对话上下文中
         self._decay_task = None
+        self._mode_switch_task = None
         self._started = False
-
+        
     async def _decay_reply_willing(self):
         """定期衰减回复意愿"""
         while True:
             await asyncio.sleep(5)
-            for chat_id in self.chat_reply_willing:
-                self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.6)
-
+            for chat_id in list(self.chat_reply_willing.keys()):
+                is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+                if is_high_mode:
+                    # 高回复意愿期内轻微衰减
+                    self.chat_reply_willing[chat_id] = max(0.5, self.chat_reply_willing[chat_id] * 0.95)
+                else:
+                    # 低回复意愿期内正常衰减
+                    self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.8)
+                
+    async def _mode_switch_check(self):
+        """定期检查是否需要切换回复意愿模式"""
+        while True:
+            current_time = time.time()
+            await asyncio.sleep(10)  # 每10秒检查一次
+            
+            for chat_id in list(self.chat_high_willing_mode.keys()):
+                last_change_time = self.chat_last_mode_change.get(chat_id, 0)
+                is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+                
+                # 获取当前模式的持续时间
+                duration = 0
+                if is_high_mode:
+                    duration = self.chat_high_willing_duration.get(chat_id, 180)  # 默认3分钟
+                else:
+                    duration = self.chat_low_willing_duration.get(chat_id, random.randint(300, 1200))  # 默认5-20分钟
+                
+                # 检查是否需要切换模式
+                if current_time - last_change_time > duration:
+                    self._switch_willing_mode(chat_id)
+                elif not is_high_mode and random.random() < 0.1:
+                    # 低回复意愿期有10%概率随机切换到高回复期
+                    self._switch_willing_mode(chat_id)
+                
+                # 检查对话上下文状态是否需要重置
+                last_reply_time = self.chat_last_reply_time.get(chat_id, 0)
+                if current_time - last_reply_time > 300:  # 5分钟无交互，重置对话上下文
+                    self.chat_conversation_context[chat_id] = False
+    
+    def _switch_willing_mode(self, chat_id: str):
+        """切换聊天流的回复意愿模式"""
+        is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
+        
+        if is_high_mode:
+            # 从高回复期切换到低回复期
+            self.chat_high_willing_mode[chat_id] = False
+            self.chat_reply_willing[chat_id] = 0.1  # 设置为最低回复意愿
+            self.chat_low_willing_duration[chat_id] = random.randint(600, 1200)  # 10-20分钟
+            print(f"聊天流 {chat_id} 切换到低回复意愿期，持续 {self.chat_low_willing_duration[chat_id]} 秒")
+        else:
+            # 从低回复期切换到高回复期
+            self.chat_high_willing_mode[chat_id] = True
+            self.chat_reply_willing[chat_id] = 1.0  # 设置为较高回复意愿
+            self.chat_high_willing_duration[chat_id] = random.randint(180, 240)  # 3-4分钟
+            print(f"聊天流 {chat_id} 切换到高回复意愿期，持续 {self.chat_high_willing_duration[chat_id]} 秒")
+        
+        self.chat_last_mode_change[chat_id] = time.time()
+        self.chat_msg_count[chat_id] = 0  # 重置消息计数
+                
     def get_willing(self, chat_stream: ChatStream) -> float:
         """获取指定聊天流的回复意愿"""
         stream = chat_stream
         if stream:
             return self.chat_reply_willing.get(stream.stream_id, 0)
         return 0
-
+    
     def set_willing(self, chat_id: str, willing: float):
         """设置指定聊天流的回复意愿"""
         self.chat_reply_willing[chat_id] = willing
-
-    async def change_reply_willing_received(
-        self,
-        chat_stream: ChatStream,
-        topic: str = None,
-        is_mentioned_bot: bool = False,
-        config=None,
-        is_emoji: bool = False,
-        interested_rate: float = 0,
-    ) -> float:
+        
+    def _ensure_chat_initialized(self, chat_id: str):
+        """确保聊天流的所有数据已初始化"""
+        if chat_id not in self.chat_reply_willing:
+            self.chat_reply_willing[chat_id] = 0.1
+        
+        if chat_id not in self.chat_high_willing_mode:
+            self.chat_high_willing_mode[chat_id] = False
+            self.chat_last_mode_change[chat_id] = time.time()
+            self.chat_low_willing_duration[chat_id] = random.randint(300, 1200)  # 5-20分钟
+        
+        if chat_id not in self.chat_msg_count:
+            self.chat_msg_count[chat_id] = 0
+            
+        if chat_id not in self.chat_conversation_context:
+            self.chat_conversation_context[chat_id] = False
+        
+    async def change_reply_willing_received(self, 
+                                          chat_stream: ChatStream,
+                                          topic: str = None,
+                                          is_mentioned_bot: bool = False,
+                                          config = None,
+                                          is_emoji: bool = False,
+                                          interested_rate: float = 0,
+                                          sender_id: str = None) -> float:
path: src/plugins/chat/willing_manager.py
user: login: sourcery-ai[bot]
body: **issue (complexity):** Consider refactoring complex functions like `change_reply_willing_received` and `_mode_switch_check` into smaller helper functions to improve code readability and maintainability by isolating distinct concerns such as conversation context handling and probability calculation..

Below is an actionable suggestion to break down the complex logic inside functions like `change_reply_willing_received` and `_mode_switch_check` into smaller, more focused helper functions. This keeps the overall control flow easier to follow without removing any features.

### Suggested Steps

1. **Extract Conversation Context Handling**  
   Move the logic that determines if the message is a follow-up or part of a conversation context into a separate helper function.

   ```python
   def _is_follow_up(self, chat_id: str, sender_id: str, current_time: float) -> bool:
       last_reply_time = self.chat_last_reply_time.get(chat_id, 0)
       last_sender = self.chat_last_sender_id.get(chat_id, "")
       msg_count = self.chat_msg_count.get(chat_id, 0)
       return sender_id and sender_id == last_sender and current_time - last_reply_time < 120 and msg_count <= 5
   ```

2. **Refactor Probability Calculation**  
   Isolate the parts that calculate the base reply probability according to the chat's context and mode. For example:

   ```python
   def _compute_base_probability(self, chat_id: str, in_context: bool, is_high_mode: bool) -> float:
       msg_count = self.chat_msg_count.get(chat_id, 0)
       if in_context:
           return 0.75 if is_high_mode else 0.5
       elif is_high_mode:
           return 0.65 if 4 <= msg_count <= 8 else 0.3
       else:
           return 0.5 if msg_count >= 15 else 0.05 * min(msg_count, 10)
   ```

   Then update `change_reply_willing_received` to use these helpers:

   ```python
   async def change_reply_willing_received(self, chat_stream: ChatStream, 
                                             topic: str = None, is_mentioned_bot: bool = False,
                                             config = None, is_emoji: bool = False,
                                             interested_rate: float = 0, sender_id: str = None) -> float:
       chat_id = chat_stream.stream_id
       current_time = time.time()
       self._ensure_chat_initialized(chat_id)
       self.chat_msg_count[chat_id] += 1

       current_willing = self.chat_reply_willing.get(chat_id, 0)
       is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
       in_context = self.chat_conversation_context.get(chat_id, False)

       if self._is_follow_up(chat_id, sender_id, current_time):
           in_context = True
           self.chat_conversation_context[chat_id] = True
           current_willing += 0.3

       if is_mentioned_bot:
           current_willing += 0.3
           in_context = True
           self.chat_conversation_context[chat_id] = True

       if is_emoji:
           current_willing *= 0.1

       if interested_rate > 0.5:
           current_willing += (interested_rate - 0.5) * 0.5

       base_probability = self._compute_base_probability(chat_id, in_context, is_high_mode)
       reply_probability = min(base_probability * current_willing, 1)
       # ... remaining group check logic and logging

       if sender_id:
           self.chat_last_sender_id[chat_id] = sender_id

       self.chat_reply_willing[chat_id] = min(current_willing, 3.0)
       return reply_probability
   ```

3. **Decouple Mode Switch Logic**  
   Similarly, extract parts of `_mode_switch_check` that determine the duration for updating the mode into helper functions.

   ```python
   def _mode_duration(self, chat_id: str, is_high_mode: bool) -> int:
       if is_high_mode:
           return self.chat_high_willing_duration.get(chat_id, 180)
       else:
           return self.chat_low_willing_duration.get(chat_id, random.randint(300, 1200))
   ```

   Then, within `_mode_switch_check`, simply use this helper:

   ```python
   async def _mode_switch_check(self):
       while True:
           current_time = time.time()
           await asyncio.sleep(10)
           for chat_id in list(self.chat_high_willing_mode.keys()):
               last_change = self.chat_last_mode_change.get(chat_id, 0)
               is_high_mode = self.chat_high_willing_mode.get(chat_id, False)
               duration = self._mode_duration(chat_id, is_high_mode)
               if current_time - last_change > duration or (not is_high_mode and random.random() < 0.1):
                   self._switch_willing_mode(chat_id)
               if current_time - self.chat_last_reply_time.get(chat_id, 0) > 300:
                   self.chat_conversation_context[chat_id] = False
   ```

### Summary

By extracting distinct concerns into helper functions, you reduce the complexity of your main methods while keeping all existing functionality intact. This will make the code easier to test and maintain.
created_at: 2025-03-12T10:12:57Z
author_association: CONTRIBUTOR

PR comments:
user: login: sourcery-ai[bot]
created_at: 2025-03-12T10:11:44Z
body: <!-- Generated by sourcery-ai[bot]: start review_guide -->

```reviewlanguage
## Sourcery 评审者指南

此拉取请求通过引入更像人类的意愿系统（具有高意愿和低意愿时期）以及一个简单的后续问题回复功能，增强了机器人的回复行为。该实现涉及修改 `WillingManager` 类来管理回复意愿、跟踪高/低意愿时期以及处理后续问题。还修改了 `bot.py` 中的 `handle_message` 函数，以整合新的意愿系统。

#### 使用意愿管理处理消息的序列图

```mermaid
sequenceDiagram
    participant User
    participant Bot
    participant WillingManager
    participant GPT

    User->>Bot: Sends a message
    activate Bot
    Bot->>WillingManager: change_reply_willing_received(message, is_mentioned_bot, interested_rate, sender_id)
    activate WillingManager
    WillingManager->>WillingManager: _ensure_chat_initialized(chat_id)
    WillingManager->>WillingManager: Checks high/low willingness mode, follow-up question, etc.
    WillingManager-->>Bot: reply_probability
    deactivate WillingManager
    alt reply_probability > threshold
        Bot->>GPT: generate_response(message)
        activate GPT
        GPT-->>Bot: response, raw_content
        deactivate GPT
        Bot->>WillingManager: change_reply_willing_sent(chat)
        activate WillingManager
        WillingManager->>WillingManager: Updates reply willingness
        deactivate WillingManager
        Bot->>User: Sends response
    else reply_probability <= threshold
        Bot->>WillingManager: change_reply_willing_not_sent(chat)
        activate WillingManager
        WillingManager->>WillingManager: Updates reply willingness
        deactivate WillingManager
    end
    deactivate Bot
```

### 文件级别更改

| 变更 | 详情 | 文件 |
| ------ | ------- | ----- |
| 实现了更像人类的回复意愿系统，具有高意愿和低意愿时期。 | <ul><li>添加了 `chat_high_willing_mode` 来跟踪每个聊天的高/低意愿时期。</li><li>引入了 `chat_msg_count` 来跟踪每个聊天中收到的消息数量。</li><li>添加了 `chat_last_mode_change` 来跟踪上次切换意愿模式的时间。</li><li>实现了 `_decay_reply_willing` 以随时间衰减回复意愿，高意愿和低意愿时期具有不同的衰减率。</li><li>实现了 `_mode_switch_check` 以基于持续时间和随机性定期在高意愿和低意愿模式之间切换。</li><li>添加了 `_switch_willing_mode` 来处理意愿模式的切换。</li><li>修改了 `change_reply_willing_received` 以整合新的意愿系统，包括处理提及、表情符号和兴趣率。</li><li>添加了 `change_reply_willing_not_sent` 以在未发送消息时增加回复意愿。</li><li>确保所有任务都在 `ensure_started` 中启动。</li></ul> | `src/plugins/chat/willing_manager.py` |
| 添加了一个简单的后续问题回复功能。 | <ul><li>修改了 `change_reply_willing_received` 以在有人在 5 分钟内提出后续问题时增加回复概率。</li><li>添加了 `chat_last_reply_time` 来跟踪每个聊天的上次回复时间。</li><li>添加了 `chat_last_sender_id` 来跟踪每个聊天的上次发送者 ID。</li><li>添加了 `chat_conversation_context` 来标记机器人是否处于对话上下文中。</li></ul> | `src/plugins/chat/willing_manager.py` |
| 修改了机器人消息处理以整合新的意愿系统。 | <ul><li>将 `sender_id` 传递给 `change_reply_willing_received`。</li><li>当机器人决定不回复时，调用 `willing_manager.change_reply_willing_not_sent`。</li><li>删除了冗余的 `logger.debug` 调用，并将其替换为 `print` 语句。</li></ul> | `src/plugins/chat/bot.py` |

---

<details>
<summary>提示和命令</summary>

#### 与 Sourcery 交互

- **触发新的审查：** 在拉取请求上评论 `@sourcery-ai review`。
- **继续讨论：** 直接回复 Sourcery 的审查评论。
- **从审查评论生成 GitHub issue：** 通过回复审查评论，要求 Sourcery 从审查评论创建一个 issue。您也可以回复审查评论并使用 `@sourcery-ai issue` 从中创建一个 issue。
- **生成拉取请求标题：** 在拉取请求标题中的任何位置写入 `@sourcery-ai` 以随时生成标题。您也可以在拉取请求上评论 `@sourcery-ai title` 以随时（重新）生成标题。
- **生成拉取请求摘要：** 在拉取请求正文中的任何位置写入 `@sourcery-ai summary` 以随时在您想要的位置生成 PR 摘要。您也可以在拉取请求上评论 `@sourcery-ai summary` 以随时（重新）生成摘要。
- **生成评审者指南：** 在拉取请求上评论 `@sourcery-ai guide` 以随时（重新）生成评审者指南。
- **解决所有 Sourcery 评论：** 在拉取请求上评论 `@sourcery-ai resolve` 以解决所有 Sourcery 评论。如果您已经解决了所有评论并且不想再看到它们，这将非常有用。
- **驳回所有 Sourcery 审查：** 在拉取请求上评论 `@sourcery-ai dismiss` 以驳回所有现有的 Sourcery 审查。如果您想重新开始新的审查，这将特别有用 - 不要忘记评论 `@sourcery-ai review` 以触发新的审查！
- **为 issue 生成行动计划：** 在 issue 上评论 `@sourcery-ai plan` 以为其生成行动计划。

#### 自定义您的体验

访问您的 [仪表板](https://app.sourcery.ai) 以：
- 启用或禁用审查功能，例如 Sourcery 生成的拉取请求摘要、评审者指南等。
- 更改审查语言。
- 添加、删除或编辑自定义审查说明。
- 调整其他审查设置。

#### 获取帮助

- [联系我们的支持团队](mailto:support@sourcery.ai) 提出问题或反馈。
- 访问我们的 [文档](https://docs.sourcery.ai) 获取详细指南和信息。
- 通过在 [X/Twitter](https://x.com/SourceryAI)、[LinkedIn](https://www.linkedin.com/company/sourcery-ai/) 或 [GitHub](https://github.com/sourcery-ai) 上关注我们，与 Sourcery 团队保持联系。

</details>
```

<details>
<summary>Original review guide in English</summary>

## Reviewer's Guide by Sourcery

This pull request enhances the bot's reply behavior by introducing a more human-like willingness system with high and low willingness periods, and a simple follow-up question reply feature. The implementation involves modifying the `WillingManager` class to manage reply willingness, track high/low willingness periods, and handle follow-up questions. The `handle_message` function in `bot.py` was also modified to incorporate the new willingness system.

#### Sequence diagram for handling a message with willingness management

```mermaid
sequenceDiagram
    participant User
    participant Bot
    participant WillingManager
    participant GPT

    User->>Bot: Sends a message
    activate Bot
    Bot->>WillingManager: change_reply_willing_received(message, is_mentioned_bot, interested_rate, sender_id)
    activate WillingManager
    WillingManager->>WillingManager: _ensure_chat_initialized(chat_id)
    WillingManager->>WillingManager: Checks high/low willingness mode, follow-up question, etc.
    WillingManager-->>Bot: reply_probability
    deactivate WillingManager
    alt reply_probability > threshold
        Bot->>GPT: generate_response(message)
        activate GPT
        GPT-->>Bot: response, raw_content
        deactivate GPT
        Bot->>WillingManager: change_reply_willing_sent(chat)
        activate WillingManager
        WillingManager->>WillingManager: Updates reply willingness
        deactivate WillingManager
        Bot->>User: Sends response
    else reply_probability <= threshold
        Bot->>WillingManager: change_reply_willing_not_sent(chat)
        activate WillingManager
        WillingManager->>WillingManager: Updates reply willingness
        deactivate WillingManager
    end
    deactivate Bot
```

### File-Level Changes

| Change | Details | Files |
| ------ | ------- | ----- |
| Implemented a more human-like reply willingness system with high and low willingness periods. | <ul><li>Added `chat_high_willing_mode` to track high/low willingness periods for each chat.</li><li>Introduced `chat_msg_count` to track the number of messages received in each chat.</li><li>Added `chat_last_mode_change` to track the last time the willingness mode was switched.</li><li>Implemented `_decay_reply_willing` to decay reply willingness over time, with different decay rates for high and low willingness periods.</li><li>Implemented `_mode_switch_check` to periodically switch between high and low willingness modes based on duration and randomness.</li><li>Added `_switch_willing_mode` to handle the switching of willingness modes.</li><li>Modified `change_reply_willing_received` to incorporate the new willingness system, including handling mentions, emojis, and interest rates.</li><li>Added `change_reply_willing_not_sent` to increase reply willingness when a message is not sent.</li><li>Ensured all tasks are started in `ensure_started`.</li></ul> | `src/plugins/chat/willing_manager.py` |
| Added a simple follow-up question reply feature. | <ul><li>Modified `change_reply_willing_received` to increase reply probability if someone asks a follow-up question within 5 minutes.</li><li>Added `chat_last_reply_time` to track the last reply time for each chat.</li><li>Added `chat_last_sender_id` to track the last sender ID for each chat.</li><li>Added `chat_conversation_context` to mark if the bot is in a conversation context.</li></ul> | `src/plugins/chat/willing_manager.py` |
| Modified bot message handling to incorporate the new willingness system. | <ul><li>Pass `sender_id` to `change_reply_willing_received`.</li><li>Call `willing_manager.change_reply_willing_not_sent` when the bot decides not to reply.</li><li>Removed redundant `logger.debug` calls and replaced them with `print` statements.</li></ul> | `src/plugins/chat/bot.py` |

---

<details>
<summary>Tips and commands</summary>

#### Interacting with Sourcery

- **Trigger a new review:** Comment `@sourcery-ai review` on the pull request.
- **Continue discussions:** Reply directly to Sourcery's review comments.
- **Generate a GitHub issue from a review comment:** Ask Sourcery to create an
  issue from a review comment by replying to it. You can also reply to a
  review comment with `@sourcery-ai issue` to create an issue from it.
- **Generate a pull request title:** Write `@sourcery-ai` anywhere in the pull
  request title to generate a title at any time. You can also comment
  `@sourcery-ai title` on the pull request to (re-)generate the title at any time.
- **Generate a pull request summary:** Write `@sourcery-ai summary` anywhere in
  the pull request body to generate a PR summary at any time exactly where you
  want it. You can also comment `@sourcery-ai summary` on the pull request to
  (re-)generate the summary at any time.
- **Generate reviewer's guide:** Comment `@sourcery-ai guide` on the pull
  request to (re-)generate the reviewer's guide at any time.
- **Resolve all Sourcery comments:** Comment `@sourcery-ai resolve` on the
  pull request to resolve all Sourcery comments. Useful if you've already
  addressed all the comments and don't want to see them anymore.
- **Dismiss all Sourcery reviews:** Comment `@sourcery-ai dismiss` on the pull
  request to dismiss all existing Sourcery reviews. Especially useful if you
  want to start fresh with a new review - don't forget to comment
  `@sourcery-ai review` to trigger a new review!
- **Generate a plan of action for an issue:** Comment `@sourcery-ai plan` on
  an issue to generate a plan of action for it.

#### Customizing Your Experience

Access your [dashboard](https://app.sourcery.ai) to:
- Enable or disable review features such as the Sourcery-generated pull request
  summary, the reviewer's guide, and others.
- Change the review language.
- Add, remove or edit custom review instructions.
- Adjust other review settings.

#### Getting Help

- [Contact our support team](mailto:support@sourcery.ai) for questions or feedback.
- Visit our [documentation](https://docs.sourcery.ai) for detailed guides and information.
- Keep in touch with the Sourcery team by following us on [X/Twitter](https://x.com/SourceryAI), [LinkedIn](https://www.linkedin.com/company/sourcery-ai/) or [GitHub](https://github.com/sourcery-ai).

</details>

</details>

<!-- Generated by sourcery-ai[bot]: end review_guide -->
author_association: CONTRIBUTOR
user: login: SengokuCola
created_at: 2025-03-12T13:25:06Z
body: 谢谢！改动有些多，等我抽时间review一下！
author_association: COLLABORATOR