better:整理config
This commit is contained in:
@@ -33,7 +33,7 @@
|
|||||||
- 调整了部分配置项的默认值
|
- 调整了部分配置项的默认值
|
||||||
- 调整了配置项的顺序,将 `groups` 配置项移到了更靠前的位置
|
- 调整了配置项的顺序,将 `groups` 配置项移到了更靠前的位置
|
||||||
- 在 `message` 配置项中:
|
- 在 `message` 配置项中:
|
||||||
- 新增了 `max_response_length` 参数
|
- 新增了 `model_max_output_length` 参数
|
||||||
- 在 `willing` 配置项中新增了 `emoji_response_penalty` 参数
|
- 在 `willing` 配置项中新增了 `emoji_response_penalty` 参数
|
||||||
- 将 `personality` 配置项中的 `prompt_schedule` 重命名为 `prompt_schedule_gen`
|
- 将 `personality` 配置项中的 `prompt_schedule` 重命名为 `prompt_schedule_gen`
|
||||||
|
|
||||||
|
|||||||
@@ -344,9 +344,6 @@ class InterestMonitorApp:
|
|||||||
self.stream_last_active[stream_id] = subflow_entry.get(
|
self.stream_last_active[stream_id] = subflow_entry.get(
|
||||||
"chat_state_changed_time"
|
"chat_state_changed_time"
|
||||||
) # 存储原始时间戳
|
) # 存储原始时间戳
|
||||||
self.stream_last_interaction[stream_id] = subflow_entry.get(
|
|
||||||
"last_interaction_time"
|
|
||||||
) # 存储原始时间戳
|
|
||||||
|
|
||||||
# 添加数据点 (使用顶层时间戳)
|
# 添加数据点 (使用顶层时间戳)
|
||||||
new_stream_history[stream_id].append((entry_timestamp, interest_level_float))
|
new_stream_history[stream_id].append((entry_timestamp, interest_level_float))
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class BotConfig:
|
|||||||
MAX_CONTEXT_SIZE: int # 上下文最大消息数
|
MAX_CONTEXT_SIZE: int # 上下文最大消息数
|
||||||
emoji_chance: float # 发送表情包的基础概率
|
emoji_chance: float # 发送表情包的基础概率
|
||||||
thinking_timeout: int # 思考时间
|
thinking_timeout: int # 思考时间
|
||||||
max_response_length: int # 最大回复长度
|
model_max_output_length: int # 最大回复长度
|
||||||
message_buffer: bool # 消息缓冲器
|
message_buffer: bool # 消息缓冲器
|
||||||
|
|
||||||
ban_words: set
|
ban_words: set
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ from src.common.logger_manager import get_logger
|
|||||||
logger = get_logger("config")
|
logger = get_logger("config")
|
||||||
|
|
||||||
# 考虑到,实际上配置文件中的mai_version是不会自动更新的,所以采用硬编码
|
# 考虑到,实际上配置文件中的mai_version是不会自动更新的,所以采用硬编码
|
||||||
is_test = True
|
is_test = False
|
||||||
mai_version_main = "0.6.3"
|
mai_version_main = "0.6.3"
|
||||||
mai_version_fix = "snapshot-5"
|
mai_version_fix = ""
|
||||||
|
|
||||||
if mai_version_fix:
|
if mai_version_fix:
|
||||||
if is_test:
|
if is_test:
|
||||||
@@ -170,32 +170,38 @@ class BotConfig:
|
|||||||
SCHEDULE_TEMPERATURE: float = 0.5 # 日程表温度,建议0.5-1.0
|
SCHEDULE_TEMPERATURE: float = 0.5 # 日程表温度,建议0.5-1.0
|
||||||
TIME_ZONE: str = "Asia/Shanghai" # 时区
|
TIME_ZONE: str = "Asia/Shanghai" # 时区
|
||||||
|
|
||||||
# message
|
|
||||||
MAX_CONTEXT_SIZE: int = 15 # 上下文最大消息数
|
# chat
|
||||||
emoji_chance: float = 0.2 # 发送表情包的基础概率
|
allow_focus_mode: bool = True # 是否允许专注聊天状态
|
||||||
thinking_timeout: int = 120 # 思考时间
|
|
||||||
max_response_length: int = 1024 # 最大回复长度
|
base_normal_chat_num: int = 3 # 最多允许多少个群进行普通聊天
|
||||||
|
base_focused_chat_num: int = 2 # 最多允许多少个群进行专注聊天
|
||||||
|
|
||||||
|
observation_context_size: int = 12 # 心流观察到的最长上下文大小,超过这个值的上下文会被压缩
|
||||||
|
|
||||||
message_buffer: bool = True # 消息缓冲器
|
message_buffer: bool = True # 消息缓冲器
|
||||||
|
|
||||||
|
|
||||||
ban_words = set()
|
ban_words = set()
|
||||||
ban_msgs_regex = set()
|
ban_msgs_regex = set()
|
||||||
|
|
||||||
# [heartflow] # 启用启用heart_flowC(心流聊天)模式时生效, 需要填写token消耗量巨大的相关模型
|
# focus_chat
|
||||||
# 启用后麦麦会自主选择进入heart_flowC模式(持续一段时间), 进行长时间高质量的聊天
|
|
||||||
reply_trigger_threshold: float = 3.0 # 心流聊天触发阈值,越低越容易触发
|
reply_trigger_threshold: float = 3.0 # 心流聊天触发阈值,越低越容易触发
|
||||||
probability_decay_factor_per_second: float = 0.2 # 概率衰减因子,越大衰减越快
|
|
||||||
default_decay_rate_per_second: float = 0.98 # 默认衰减率,越大衰减越慢
|
default_decay_rate_per_second: float = 0.98 # 默认衰减率,越大衰减越慢
|
||||||
allow_focus_mode: bool = True # 是否允许子心流进入 FOCUSED 状态
|
consecutive_no_reply_threshold = 3
|
||||||
|
|
||||||
|
|
||||||
# sub_heart_flow_update_interval: int = 60 # 子心流更新频率,间隔 单位秒
|
|
||||||
# sub_heart_flow_freeze_time: int = 120 # 子心流冻结时间,超过这个时间没有回复,子心流会冻结,间隔 单位秒
|
|
||||||
sub_heart_flow_stop_time: int = 600 # 子心流停止时间,超过这个时间没有回复,子心流会停止,间隔 单位秒
|
|
||||||
# heart_flow_update_interval: int = 300 # 心流更新频率,间隔 单位秒
|
|
||||||
observation_context_size: int = 20 # 心流观察到的最长上下文大小,超过这个值的上下文会被压缩
|
|
||||||
compressed_length: int = 5 # 不能大于observation_context_size,心流上下文压缩的最短压缩长度,超过心流观察到的上下文长度,会压缩,最短压缩长度为5
|
compressed_length: int = 5 # 不能大于observation_context_size,心流上下文压缩的最短压缩长度,超过心流观察到的上下文长度,会压缩,最短压缩长度为5
|
||||||
compress_length_limit: int = 5 # 最多压缩份数,超过该数值的压缩上下文会被删除
|
compress_length_limit: int = 5 # 最多压缩份数,超过该数值的压缩上下文会被删除
|
||||||
|
|
||||||
# willing
|
|
||||||
|
# normal_chat
|
||||||
|
model_reasoning_probability: float = 0.7 # 麦麦回答时选择推理模型(主要)模型概率
|
||||||
|
model_normal_probability: float = 0.3 # 麦麦回答时选择一般模型(次要)模型概率
|
||||||
|
|
||||||
|
emoji_chance: float = 0.2 # 发送表情包的基础概率
|
||||||
|
thinking_timeout: int = 120 # 思考时间
|
||||||
|
|
||||||
willing_mode: str = "classical" # 意愿模式
|
willing_mode: str = "classical" # 意愿模式
|
||||||
response_willing_amplifier: float = 1.0 # 回复意愿放大系数
|
response_willing_amplifier: float = 1.0 # 回复意愿放大系数
|
||||||
response_interested_rate_amplifier: float = 1.0 # 回复兴趣度放大系数
|
response_interested_rate_amplifier: float = 1.0 # 回复兴趣度放大系数
|
||||||
@@ -204,12 +210,6 @@ class BotConfig:
|
|||||||
mentioned_bot_inevitable_reply: bool = False # 提及 bot 必然回复
|
mentioned_bot_inevitable_reply: bool = False # 提及 bot 必然回复
|
||||||
at_bot_inevitable_reply: bool = False # @bot 必然回复
|
at_bot_inevitable_reply: bool = False # @bot 必然回复
|
||||||
|
|
||||||
# response
|
|
||||||
response_mode: str = "heart_flow" # 回复策略
|
|
||||||
model_reasoning_probability: float = 0.7 # 麦麦回答时选择推理模型(主要)模型概率
|
|
||||||
model_normal_probability: float = 0.3 # 麦麦回答时选择一般模型(次要)模型概率
|
|
||||||
# MODEL_R1_DISTILL_PROBABILITY: float = 0.1 # R1蒸馏模型概率
|
|
||||||
|
|
||||||
# emoji
|
# emoji
|
||||||
max_emoji_num: int = 200 # 表情包最大数量
|
max_emoji_num: int = 200 # 表情包最大数量
|
||||||
max_reach_deletion: bool = True # 开启则在达到最大数量时删除表情包,关闭则不会继续收集表情包
|
max_reach_deletion: bool = True # 开启则在达到最大数量时删除表情包,关闭则不会继续收集表情包
|
||||||
@@ -264,6 +264,8 @@ class BotConfig:
|
|||||||
response_max_length = 100 # 回复允许的最大长度
|
response_max_length = 100 # 回复允许的最大长度
|
||||||
response_max_sentence_num = 3 # 回复允许的最大句子数
|
response_max_sentence_num = 3 # 回复允许的最大句子数
|
||||||
|
|
||||||
|
model_max_output_length: int = 800 # 最大回复长度
|
||||||
|
|
||||||
# remote
|
# remote
|
||||||
remote_enable: bool = True # 是否启用远程控制
|
remote_enable: bool = True # 是否启用远程控制
|
||||||
|
|
||||||
@@ -409,64 +411,67 @@ class BotConfig:
|
|||||||
config.BOT_NICKNAME = bot_config.get("nickname", config.BOT_NICKNAME)
|
config.BOT_NICKNAME = bot_config.get("nickname", config.BOT_NICKNAME)
|
||||||
config.BOT_ALIAS_NAMES = bot_config.get("alias_names", config.BOT_ALIAS_NAMES)
|
config.BOT_ALIAS_NAMES = bot_config.get("alias_names", config.BOT_ALIAS_NAMES)
|
||||||
|
|
||||||
def response(parent: dict):
|
def chat(parent: dict):
|
||||||
response_config = parent["response"]
|
chat_config = parent["chat"]
|
||||||
config.model_reasoning_probability = response_config.get(
|
config.allow_focus_mode = chat_config.get("allow_focus_mode", config.allow_focus_mode)
|
||||||
"model_reasoning_probability", config.model_reasoning_probability
|
config.base_normal_chat_num = chat_config.get("base_normal_chat_num", config.base_normal_chat_num)
|
||||||
)
|
config.base_focused_chat_num = chat_config.get("base_focused_chat_num", config.base_focused_chat_num)
|
||||||
config.model_normal_probability = response_config.get(
|
config.observation_context_size = chat_config.get(
|
||||||
"model_normal_probability", config.model_normal_probability
|
|
||||||
)
|
|
||||||
|
|
||||||
def heartflow(parent: dict):
|
|
||||||
heartflow_config = parent["heartflow"]
|
|
||||||
config.sub_heart_flow_stop_time = heartflow_config.get(
|
|
||||||
"sub_heart_flow_stop_time", config.sub_heart_flow_stop_time
|
|
||||||
)
|
|
||||||
if config.INNER_VERSION in SpecifierSet(">=1.3.0"):
|
|
||||||
config.observation_context_size = heartflow_config.get(
|
|
||||||
"observation_context_size", config.observation_context_size
|
"observation_context_size", config.observation_context_size
|
||||||
)
|
)
|
||||||
config.compressed_length = heartflow_config.get("compressed_length", config.compressed_length)
|
config.message_buffer = chat_config.get("message_buffer", config.message_buffer)
|
||||||
config.compress_length_limit = heartflow_config.get(
|
config.ban_words = chat_config.get("ban_words", config.ban_words)
|
||||||
"compress_length_limit", config.compress_length_limit
|
for r in chat_config.get("ban_msgs_regex", config.ban_msgs_regex):
|
||||||
)
|
config.ban_msgs_regex.add(re.compile(r))
|
||||||
if config.INNER_VERSION in SpecifierSet(">=1.4.0"):
|
|
||||||
config.reply_trigger_threshold = heartflow_config.get(
|
|
||||||
"reply_trigger_threshold", config.reply_trigger_threshold
|
|
||||||
)
|
|
||||||
config.probability_decay_factor_per_second = heartflow_config.get(
|
|
||||||
"probability_decay_factor_per_second", config.probability_decay_factor_per_second
|
|
||||||
)
|
|
||||||
config.default_decay_rate_per_second = heartflow_config.get(
|
|
||||||
"default_decay_rate_per_second", config.default_decay_rate_per_second
|
|
||||||
)
|
|
||||||
if config.INNER_VERSION in SpecifierSet(">=1.5.1"):
|
|
||||||
config.allow_focus_mode = heartflow_config.get("allow_focus_mode", config.allow_focus_mode)
|
|
||||||
|
|
||||||
def willing(parent: dict):
|
def normal_chat(parent: dict):
|
||||||
willing_config = parent["willing"]
|
normal_chat_config = parent["normal_chat"]
|
||||||
config.willing_mode = willing_config.get("willing_mode", config.willing_mode)
|
config.model_reasoning_probability = normal_chat_config.get(
|
||||||
|
"model_reasoning_probability", config.model_reasoning_probability
|
||||||
|
)
|
||||||
|
config.model_normal_probability = normal_chat_config.get(
|
||||||
|
"model_normal_probability", config.model_normal_probability
|
||||||
|
)
|
||||||
|
config.emoji_chance = normal_chat_config.get("emoji_chance", config.emoji_chance)
|
||||||
|
config.thinking_timeout = normal_chat_config.get("thinking_timeout", config.thinking_timeout)
|
||||||
|
|
||||||
if config.INNER_VERSION in SpecifierSet(">=0.0.11"):
|
|
||||||
config.response_willing_amplifier = willing_config.get(
|
config.willing_mode = normal_chat_config.get("willing_mode", config.willing_mode)
|
||||||
|
config.response_willing_amplifier = normal_chat_config.get(
|
||||||
"response_willing_amplifier", config.response_willing_amplifier
|
"response_willing_amplifier", config.response_willing_amplifier
|
||||||
)
|
)
|
||||||
config.response_interested_rate_amplifier = willing_config.get(
|
config.response_interested_rate_amplifier = normal_chat_config.get(
|
||||||
"response_interested_rate_amplifier", config.response_interested_rate_amplifier
|
"response_interested_rate_amplifier", config.response_interested_rate_amplifier
|
||||||
)
|
)
|
||||||
config.down_frequency_rate = willing_config.get("down_frequency_rate", config.down_frequency_rate)
|
config.down_frequency_rate = normal_chat_config.get("down_frequency_rate", config.down_frequency_rate)
|
||||||
config.emoji_response_penalty = willing_config.get(
|
config.emoji_response_penalty = normal_chat_config.get(
|
||||||
"emoji_response_penalty", config.emoji_response_penalty
|
"emoji_response_penalty", config.emoji_response_penalty
|
||||||
)
|
)
|
||||||
if config.INNER_VERSION in SpecifierSet(">=1.2.5"):
|
|
||||||
config.mentioned_bot_inevitable_reply = willing_config.get(
|
config.mentioned_bot_inevitable_reply = normal_chat_config.get(
|
||||||
"mentioned_bot_inevitable_reply", config.mentioned_bot_inevitable_reply
|
"mentioned_bot_inevitable_reply", config.mentioned_bot_inevitable_reply
|
||||||
)
|
)
|
||||||
config.at_bot_inevitable_reply = willing_config.get(
|
config.at_bot_inevitable_reply = normal_chat_config.get(
|
||||||
"at_bot_inevitable_reply", config.at_bot_inevitable_reply
|
"at_bot_inevitable_reply", config.at_bot_inevitable_reply
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def focus_chat(parent: dict):
|
||||||
|
focus_chat_config = parent["focus_chat"]
|
||||||
|
config.compressed_length = focus_chat_config.get("compressed_length", config.compressed_length)
|
||||||
|
config.compress_length_limit = focus_chat_config.get(
|
||||||
|
"compress_length_limit", config.compress_length_limit
|
||||||
|
)
|
||||||
|
config.reply_trigger_threshold = focus_chat_config.get(
|
||||||
|
"reply_trigger_threshold", config.reply_trigger_threshold
|
||||||
|
)
|
||||||
|
config.default_decay_rate_per_second = focus_chat_config.get(
|
||||||
|
"default_decay_rate_per_second", config.default_decay_rate_per_second
|
||||||
|
)
|
||||||
|
config.consecutive_no_reply_threshold = focus_chat_config.get(
|
||||||
|
"consecutive_no_reply_threshold", config.consecutive_no_reply_threshold
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def model(parent: dict):
|
def model(parent: dict):
|
||||||
# 加载模型配置
|
# 加载模型配置
|
||||||
model_config: dict = parent["model"]
|
model_config: dict = parent["model"]
|
||||||
@@ -556,26 +561,6 @@ class BotConfig:
|
|||||||
logger.error(f"模型 {item} 在config中不存在,请检查,或尝试更新配置文件")
|
logger.error(f"模型 {item} 在config中不存在,请检查,或尝试更新配置文件")
|
||||||
raise KeyError(f"模型 {item} 在config中不存在,请检查,或尝试更新配置文件")
|
raise KeyError(f"模型 {item} 在config中不存在,请检查,或尝试更新配置文件")
|
||||||
|
|
||||||
def message(parent: dict):
|
|
||||||
msg_config = parent["message"]
|
|
||||||
config.MAX_CONTEXT_SIZE = msg_config.get("max_context_size", config.MAX_CONTEXT_SIZE)
|
|
||||||
config.emoji_chance = msg_config.get("emoji_chance", config.emoji_chance)
|
|
||||||
config.ban_words = msg_config.get("ban_words", config.ban_words)
|
|
||||||
config.thinking_timeout = msg_config.get("thinking_timeout", config.thinking_timeout)
|
|
||||||
config.response_willing_amplifier = msg_config.get(
|
|
||||||
"response_willing_amplifier", config.response_willing_amplifier
|
|
||||||
)
|
|
||||||
config.response_interested_rate_amplifier = msg_config.get(
|
|
||||||
"response_interested_rate_amplifier", config.response_interested_rate_amplifier
|
|
||||||
)
|
|
||||||
config.down_frequency_rate = msg_config.get("down_frequency_rate", config.down_frequency_rate)
|
|
||||||
for r in msg_config.get("ban_msgs_regex", config.ban_msgs_regex):
|
|
||||||
config.ban_msgs_regex.add(re.compile(r))
|
|
||||||
if config.INNER_VERSION in SpecifierSet(">=0.0.11"):
|
|
||||||
config.max_response_length = msg_config.get("max_response_length", config.max_response_length)
|
|
||||||
if config.INNER_VERSION in SpecifierSet(">=1.1.4"):
|
|
||||||
config.message_buffer = msg_config.get("message_buffer", config.message_buffer)
|
|
||||||
|
|
||||||
def memory(parent: dict):
|
def memory(parent: dict):
|
||||||
memory_config = parent["memory"]
|
memory_config = parent["memory"]
|
||||||
config.build_memory_interval = memory_config.get("build_memory_interval", config.build_memory_interval)
|
config.build_memory_interval = memory_config.get("build_memory_interval", config.build_memory_interval)
|
||||||
@@ -650,6 +635,8 @@ class BotConfig:
|
|||||||
config.enable_kaomoji_protection = response_splitter_config.get(
|
config.enable_kaomoji_protection = response_splitter_config.get(
|
||||||
"enable_kaomoji_protection", config.enable_kaomoji_protection
|
"enable_kaomoji_protection", config.enable_kaomoji_protection
|
||||||
)
|
)
|
||||||
|
if config.INNER_VERSION in SpecifierSet(">=1.6.0"):
|
||||||
|
config.model_max_output_length = response_splitter_config.get("model_max_output_length", config.model_max_output_length)
|
||||||
|
|
||||||
def groups(parent: dict):
|
def groups(parent: dict):
|
||||||
groups_config = parent["groups"]
|
groups_config = parent["groups"]
|
||||||
@@ -695,10 +682,7 @@ class BotConfig:
|
|||||||
"personality": {"func": personality, "support": ">=0.0.0"},
|
"personality": {"func": personality, "support": ">=0.0.0"},
|
||||||
"identity": {"func": identity, "support": ">=1.2.4"},
|
"identity": {"func": identity, "support": ">=1.2.4"},
|
||||||
"schedule": {"func": schedule, "support": ">=0.0.11", "necessary": False},
|
"schedule": {"func": schedule, "support": ">=0.0.11", "necessary": False},
|
||||||
"message": {"func": message, "support": ">=0.0.0"},
|
|
||||||
"willing": {"func": willing, "support": ">=0.0.9", "necessary": False},
|
|
||||||
"emoji": {"func": emoji, "support": ">=0.0.0"},
|
"emoji": {"func": emoji, "support": ">=0.0.0"},
|
||||||
"response": {"func": response, "support": ">=0.0.0"},
|
|
||||||
"model": {"func": model, "support": ">=0.0.0"},
|
"model": {"func": model, "support": ">=0.0.0"},
|
||||||
"memory": {"func": memory, "support": ">=0.0.0", "necessary": False},
|
"memory": {"func": memory, "support": ">=0.0.0", "necessary": False},
|
||||||
"mood": {"func": mood, "support": ">=0.0.0"},
|
"mood": {"func": mood, "support": ">=0.0.0"},
|
||||||
@@ -708,7 +692,9 @@ class BotConfig:
|
|||||||
"platforms": {"func": platforms, "support": ">=1.0.0"},
|
"platforms": {"func": platforms, "support": ">=1.0.0"},
|
||||||
"response_splitter": {"func": response_splitter, "support": ">=0.0.11", "necessary": False},
|
"response_splitter": {"func": response_splitter, "support": ">=0.0.11", "necessary": False},
|
||||||
"experimental": {"func": experimental, "support": ">=0.0.11", "necessary": False},
|
"experimental": {"func": experimental, "support": ">=0.0.11", "necessary": False},
|
||||||
"heartflow": {"func": heartflow, "support": ">=1.0.2", "necessary": False},
|
"chat": {"func": chat, "support": ">=1.6.0", "necessary": False},
|
||||||
|
"normal_chat": {"func": normal_chat, "support": ">=1.6.0", "necessary": False},
|
||||||
|
"focus_chat": {"func": focus_chat, "support": ">=1.6.0", "necessary": False},
|
||||||
}
|
}
|
||||||
|
|
||||||
# 原地修改,将 字符串版本表达式 转换成 版本对象
|
# 原地修改,将 字符串版本表达式 转换成 版本对象
|
||||||
|
|||||||
@@ -129,7 +129,6 @@ class ToolUser:
|
|||||||
payload = {
|
payload = {
|
||||||
"model": self.llm_model_tool.model_name,
|
"model": self.llm_model_tool.model_name,
|
||||||
"messages": [{"role": "user", "content": prompt}],
|
"messages": [{"role": "user", "content": prompt}],
|
||||||
"max_tokens": global_config.max_response_length,
|
|
||||||
"tools": tools,
|
"tools": tools,
|
||||||
"temperature": 0.2,
|
"temperature": 0.2,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
# 0.6.3 版本发布前待办事项
|
|
||||||
|
|
||||||
- [0.6.3]**统一化人格配置:**
|
|
||||||
- 检查代码中是否存在硬编码的人格相关配置。
|
|
||||||
- 将所有硬编码的人格配置替换为使用 `individual` 模块进行管理。
|
|
||||||
|
|
||||||
- [0.6.3]**在 Planner 中添加回复计数信息:**
|
|
||||||
- 修改 `HeartFlowChatInstance` 的 `Plan` 阶段逻辑。
|
|
||||||
- 将当前周期的回复计数(或其他相关统计信息)作为输入提供给 Planner。
|
|
||||||
- 目的是为 Planner 提供负反馈,减少连续回复或不当回复的可能性。
|
|
||||||
|
|
||||||
- [0.6.3]**恢复/检查被停止的功能:**
|
|
||||||
- 全面审查代码,特别是对比之前的版本或设计文档。
|
|
||||||
- 识别并重新启用那些暂时被禁用但应该恢复的功能。
|
|
||||||
- 确认没有核心功能意外丢失。
|
|
||||||
|
|
||||||
- [0.6.3]**参数提取与配置化:**
|
|
||||||
- 识别代码中散落的各种可调参数(例如:概率阈值、时间间隔、次数限制、LLM 模型名称等)。
|
|
||||||
- 将这些参数统一提取到模块或类的顶部。
|
|
||||||
- 最终将这些参数移至外部配置文件(如 YAML 或 JSON 文件),方便用户自定义。
|
|
||||||
|
|
||||||
- **[0.6.3]提供 HFC (HeartFlowChatInstance) 开启/关闭选项:**
|
|
||||||
- 增加一个全局或针对特定子心流的配置选项。
|
|
||||||
- 允许用户控制是否启用 `FOCUSED` 状态以及关联的 `HeartFlowChatInstance`。
|
|
||||||
- 如果禁用 HFC,子心流可能只会在 `ABSENT` 和 `CHAT` 状态间切换。
|
|
||||||
|
|
||||||
- [0.6.3]**添加防破线机制 (针对接收消息):**
|
|
||||||
- 在消息处理流程的早期阶段 (例如 `HeartHC_processor` 或类似模块),增加对接收到的消息文本长度的检查。
|
|
||||||
- 对超过预设长度阈值的*接收*消息进行截断处理。
|
|
||||||
- 目的是防止过长的输入(可能包含"破限"提示词)影响后续的兴趣计算、LLM 回复生成等环节。
|
|
||||||
|
|
||||||
- [0.6.3]**NormalChat 模式下的记忆与 Prompt 优化:**
|
|
||||||
- 重点审视 `NormalChatInstance` (闲聊/推理模式) 中记忆调用 (例如 `HippocampusManager` 的使用) 的方式。
|
|
||||||
- 评估在该模式下引入工具调用 (Tool Calling) 机制以更结构化访问记忆的必要性。
|
|
||||||
- 优化 `NormalChatInstance` 中与记忆检索、应用相关的 Prompt。
|
|
||||||
|
|
||||||
- [0.6.3]**完善简易兴趣监控 GUI:**
|
|
||||||
- 改进现有的、用于监控聊天兴趣度 (`InterestChatting`?) 的简单 GUI 界面。
|
|
||||||
- 使其能更清晰地展示关键参数和状态,作为查看日志之外的更直观的监控方式。
|
|
||||||
- 作为完整外部 UI 开发完成前的临时替代方案。
|
|
||||||
|
|
||||||
- [0.6.3]**修复/完善中期记忆 (Midterm Memory):**
|
|
||||||
- 检查当前中期记忆模块的状态。
|
|
||||||
- 修复已知问题,使其能够稳定运行。
|
|
||||||
- (优先级视开发时间而定)
|
|
||||||
|
|
||||||
|
|
||||||
对于有些群频繁激活HFC,却不回复,需要处理一下
|
|
||||||
@@ -106,8 +106,8 @@ c HeartFChatting工作方式
|
|||||||
- 负责所有 `SubHeartflow` 实例的生命周期管理,包括:
|
- 负责所有 `SubHeartflow` 实例的生命周期管理,包括:
|
||||||
- 创建和获取 (`get_or_create_subheartflow`)。
|
- 创建和获取 (`get_or_create_subheartflow`)。
|
||||||
- 停止和清理 (`sleep_subheartflow`, `cleanup_inactive_subheartflows`)。
|
- 停止和清理 (`sleep_subheartflow`, `cleanup_inactive_subheartflows`)。
|
||||||
- 根据 `Heartflow` 的状态 (`self.mai_state_info`) 和限制条件,激活、停用或调整子心流的状态(例如 `enforce_subheartflow_limits`, `randomly_deactivate_subflows`, `evaluate_interest_and_promote`)。
|
- 根据 `Heartflow` 的状态 (`self.mai_state_info`) 和限制条件,激活、停用或调整子心流的状态(例如 `enforce_subheartflow_limits`, `randomly_deactivate_subflows`, `sbhf_absent_into_focus`)。
|
||||||
- **新增**: 通过调用 `evaluate_and_transition_subflows_by_llm` 方法,使用 LLM (配置与 `Heartflow` 主 LLM 相同) 评估处于 `ABSENT` 或 `CHAT` 状态的子心流,根据观察到的活动摘要和 `Heartflow` 的当前状态,判断是否应在 `ABSENT` 和 `CHAT` 之间进行转换 (同样受限于 `CHAT` 状态的数量上限)。
|
- **新增**: 通过调用 `sbhf_absent_into_chat` 方法,使用 LLM (配置与 `Heartflow` 主 LLM 相同) 评估处于 `ABSENT` 或 `CHAT` 状态的子心流,根据观察到的活动摘要和 `Heartflow` 的当前状态,判断是否应在 `ABSENT` 和 `CHAT` 之间进行转换 (同样受限于 `CHAT` 状态的数量上限)。
|
||||||
- **清理机制**: 通过后台任务 (`BackgroundTaskManager`) 定期调用 `cleanup_inactive_subheartflows` 方法,此方法会识别并**删除**那些处于 `ABSENT` 状态超过一小时 (`INACTIVE_THRESHOLD_SECONDS`) 的子心流实例。
|
- **清理机制**: 通过后台任务 (`BackgroundTaskManager`) 定期调用 `cleanup_inactive_subheartflows` 方法,此方法会识别并**删除**那些处于 `ABSENT` 状态超过一小时 (`INACTIVE_THRESHOLD_SECONDS`) 的子心流实例。
|
||||||
|
|
||||||
### 1.5. 消息处理与回复流程 (Message Processing vs. Replying Flow)
|
### 1.5. 消息处理与回复流程 (Message Processing vs. Replying Flow)
|
||||||
@@ -155,20 +155,20 @@ c HeartFChatting工作方式
|
|||||||
- **初始状态**: 新创建的 `SubHeartflow` 默认为 `ABSENT` 状态。
|
- **初始状态**: 新创建的 `SubHeartflow` 默认为 `ABSENT` 状态。
|
||||||
- **`ABSENT` -> `CHAT` (激活闲聊)**:
|
- **`ABSENT` -> `CHAT` (激活闲聊)**:
|
||||||
- **触发条件**: `Heartflow` 的主状态 (`MaiState`) 允许 `CHAT` 模式,且当前 `CHAT` 状态的子心流数量未达上限。
|
- **触发条件**: `Heartflow` 的主状态 (`MaiState`) 允许 `CHAT` 模式,且当前 `CHAT` 状态的子心流数量未达上限。
|
||||||
- **判定机制**: `SubHeartflowManager` 中的 `evaluate_and_transition_subflows_by_llm` 方法调用大模型(LLM)。LLM 读取该群聊的近期内容和结合自身个性信息,判断是否"想"在该群开始聊天。
|
- **判定机制**: `SubHeartflowManager` 中的 `sbhf_absent_into_chat` 方法调用大模型(LLM)。LLM 读取该群聊的近期内容和结合自身个性信息,判断是否"想"在该群开始聊天。
|
||||||
- **执行**: 若 LLM 判断为是,且名额未满,`SubHeartflowManager` 调用 `change_chat_state(ChatState.CHAT)`。
|
- **执行**: 若 LLM 判断为是,且名额未满,`SubHeartflowManager` 调用 `change_chat_state(ChatState.CHAT)`。
|
||||||
- **`CHAT` -> `FOCUSED` (激活专注)**:
|
- **`CHAT` -> `FOCUSED` (激活专注)**:
|
||||||
- **触发条件**: 子心流处于 `CHAT` 状态,其内部维护的"开屎热聊"概率 (`InterestChatting.start_hfc_probability`) 达到预设阈值(表示对当前聊天兴趣浓厚),同时 `Heartflow` 的主状态允许 `FOCUSED` 模式,且 `FOCUSED` 名额未满。
|
- **触发条件**: 子心流处于 `CHAT` 状态,其内部维护的"开屎热聊"概率 (`InterestChatting.start_hfc_probability`) 达到预设阈值(表示对当前聊天兴趣浓厚),同时 `Heartflow` 的主状态允许 `FOCUSED` 模式,且 `FOCUSED` 名额未满。
|
||||||
- **判定机制**: `SubHeartflowManager` 中的 `evaluate_interest_and_promote` 方法定期检查满足条件的 `CHAT` 子心流。
|
- **判定机制**: `SubHeartflowManager` 中的 `sbhf_absent_into_focus` 方法定期检查满足条件的 `CHAT` 子心流。
|
||||||
- **执行**: 若满足所有条件,`SubHeartflowManager` 调用 `change_chat_state(ChatState.FOCUSED)`。
|
- **执行**: 若满足所有条件,`SubHeartflowManager` 调用 `change_chat_state(ChatState.FOCUSED)`。
|
||||||
- **注意**: 无法从 `ABSENT` 直接跳到 `FOCUSED`,必须先经过 `CHAT`。
|
- **注意**: 无法从 `ABSENT` 直接跳到 `FOCUSED`,必须先经过 `CHAT`。
|
||||||
- **`FOCUSED` -> `ABSENT` (退出专注)**:
|
- **`FOCUSED` -> `ABSENT` (退出专注)**:
|
||||||
- **主要途径 (内部驱动)**: 在 `FOCUSED` 状态下运行的 `HeartFlowChatInstance` 连续多次决策为 `no_reply` (例如达到 5 次,次数可配),它会通过回调函数 (`request_absent_transition`) 请求 `SubHeartflowManager` 将其状态**直接**设置为 `ABSENT`。
|
- **主要途径 (内部驱动)**: 在 `FOCUSED` 状态下运行的 `HeartFlowChatInstance` 连续多次决策为 `no_reply` (例如达到 5 次,次数可配),它会通过回调函数 (`sbhf_focus_into_absent`) 请求 `SubHeartflowManager` 将其状态**直接**设置为 `ABSENT`。
|
||||||
- **其他途径 (外部驱动)**:
|
- **其他途径 (外部驱动)**:
|
||||||
- `Heartflow` 主状态变为 `OFFLINE`,`SubHeartflowManager` 强制所有子心流变为 `ABSENT`。
|
- `Heartflow` 主状态变为 `OFFLINE`,`SubHeartflowManager` 强制所有子心流变为 `ABSENT`。
|
||||||
- `SubHeartflowManager` 因 `FOCUSED` 名额超限 (`enforce_subheartflow_limits`) 或随机停用 (`randomly_deactivate_subflows`) 而将其设置为 `ABSENT`。
|
- `SubHeartflowManager` 因 `FOCUSED` 名额超限 (`enforce_subheartflow_limits`) 或随机停用 (`randomly_deactivate_subflows`) 而将其设置为 `ABSENT`。
|
||||||
- **`CHAT` -> `ABSENT` (退出闲聊)**:
|
- **`CHAT` -> `ABSENT` (退出闲聊)**:
|
||||||
- **主要途径 (内部驱动)**: `SubHeartflowManager` 中的 `evaluate_and_transition_subflows_by_llm` 方法调用 LLM。LLM 读取群聊内容和结合自身状态,判断是否"不想"继续在此群闲聊。
|
- **主要途径 (内部驱动)**: `SubHeartflowManager` 中的 `sbhf_absent_into_chat` 方法调用 LLM。LLM 读取群聊内容和结合自身状态,判断是否"不想"继续在此群闲聊。
|
||||||
- **执行**: 若 LLM 判断为是,`SubHeartflowManager` 调用 `change_chat_state(ChatState.ABSENT)`。
|
- **执行**: 若 LLM 判断为是,`SubHeartflowManager` 调用 `change_chat_state(ChatState.ABSENT)`。
|
||||||
- **其他途径 (外部驱动)**:
|
- **其他途径 (外部驱动)**:
|
||||||
- `Heartflow` 主状态变为 `OFFLINE`。
|
- `Heartflow` 主状态变为 `OFFLINE`。
|
||||||
|
|||||||
@@ -12,11 +12,17 @@ from src.heart_flow.interest_logger import InterestLogger
|
|||||||
|
|
||||||
logger = get_logger("background_tasks")
|
logger = get_logger("background_tasks")
|
||||||
|
|
||||||
# 新增随机停用间隔 (5 分钟)
|
|
||||||
RANDOM_DEACTIVATION_INTERVAL_SECONDS = 300
|
|
||||||
# 新增兴趣评估间隔
|
# 新增兴趣评估间隔
|
||||||
INTEREST_EVAL_INTERVAL_SECONDS = 5
|
INTEREST_EVAL_INTERVAL_SECONDS = 5
|
||||||
|
# 新增聊天超时检查间隔
|
||||||
|
NORMAL_CHAT_TIMEOUT_CHECK_INTERVAL_SECONDS = 60
|
||||||
|
# 新增状态评估间隔
|
||||||
|
HF_JUDGE_STATE_UPDATE_INTERVAL_SECONDS = 60
|
||||||
|
|
||||||
|
CLEANUP_INTERVAL_SECONDS = 1200
|
||||||
|
STATE_UPDATE_INTERVAL_SECONDS = 60
|
||||||
|
LOG_INTERVAL_SECONDS = 3
|
||||||
|
|
||||||
class BackgroundTaskManager:
|
class BackgroundTaskManager:
|
||||||
"""管理 Heartflow 的后台周期性任务。"""
|
"""管理 Heartflow 的后台周期性任务。"""
|
||||||
@@ -26,34 +32,21 @@ class BackgroundTaskManager:
|
|||||||
mai_state_info: MaiStateInfo, # Needs current state info
|
mai_state_info: MaiStateInfo, # Needs current state info
|
||||||
mai_state_manager: MaiStateManager,
|
mai_state_manager: MaiStateManager,
|
||||||
subheartflow_manager: SubHeartflowManager,
|
subheartflow_manager: SubHeartflowManager,
|
||||||
interest_logger: InterestLogger,
|
interest_logger: InterestLogger
|
||||||
update_interval: int,
|
|
||||||
cleanup_interval: int,
|
|
||||||
log_interval: int,
|
|
||||||
# 新增兴趣评估间隔参数
|
|
||||||
interest_eval_interval: int = INTEREST_EVAL_INTERVAL_SECONDS,
|
|
||||||
# 新增随机停用间隔参数
|
|
||||||
random_deactivation_interval: int = RANDOM_DEACTIVATION_INTERVAL_SECONDS,
|
|
||||||
):
|
):
|
||||||
self.mai_state_info = mai_state_info
|
self.mai_state_info = mai_state_info
|
||||||
self.mai_state_manager = mai_state_manager
|
self.mai_state_manager = mai_state_manager
|
||||||
self.subheartflow_manager = subheartflow_manager
|
self.subheartflow_manager = subheartflow_manager
|
||||||
self.interest_logger = interest_logger
|
self.interest_logger = interest_logger
|
||||||
|
|
||||||
# Intervals
|
|
||||||
self.update_interval = update_interval
|
|
||||||
self.cleanup_interval = cleanup_interval
|
|
||||||
self.log_interval = log_interval
|
|
||||||
self.interest_eval_interval = interest_eval_interval # 存储兴趣评估间隔
|
|
||||||
self.random_deactivation_interval = random_deactivation_interval # 存储随机停用间隔
|
|
||||||
|
|
||||||
# Task references
|
# Task references
|
||||||
self._state_update_task: Optional[asyncio.Task] = None
|
self._state_update_task: Optional[asyncio.Task] = None
|
||||||
self._cleanup_task: Optional[asyncio.Task] = None
|
self._cleanup_task: Optional[asyncio.Task] = None
|
||||||
self._logging_task: Optional[asyncio.Task] = None
|
self._logging_task: Optional[asyncio.Task] = None
|
||||||
self._interest_eval_task: Optional[asyncio.Task] = None # 新增兴趣评估任务引用
|
self._normal_chat_timeout_check_task: Optional[asyncio.Task] = None # Nyaa~ 添加聊天超时检查任务的引用
|
||||||
self._random_deactivation_task: Optional[asyncio.Task] = None # 新增随机停用任务引用
|
self._hf_judge_state_update_task: Optional[asyncio.Task] = None # Nyaa~ 添加状态评估任务的引用
|
||||||
self._hf_judge_state_update_task: Optional[asyncio.Task] = None # 新增状态评估任务引用
|
self._into_focus_task: Optional[asyncio.Task] = None # Nyaa~ 添加兴趣评估任务的引用
|
||||||
self._tasks: List[Optional[asyncio.Task]] = [] # Keep track of all tasks
|
self._tasks: List[Optional[asyncio.Task]] = [] # Keep track of all tasks
|
||||||
|
|
||||||
async def start_tasks(self):
|
async def start_tasks(self):
|
||||||
@@ -65,57 +58,53 @@ class BackgroundTaskManager:
|
|||||||
- 将任务引用保存到任务列表
|
- 将任务引用保存到任务列表
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# 任务配置列表: (任务变量名, 任务函数, 任务名称, 日志级别, 额外日志信息, 任务对象引用属性名)
|
# 任务配置列表: (任务函数, 任务名称, 日志级别, 额外日志信息, 任务对象引用属性名)
|
||||||
task_configs = [
|
task_configs = [
|
||||||
(
|
(
|
||||||
self._state_update_task,
|
lambda: self._run_state_update_cycle(STATE_UPDATE_INTERVAL_SECONDS),
|
||||||
lambda: self._run_state_update_cycle(self.update_interval),
|
|
||||||
"hf_state_update",
|
|
||||||
"debug",
|
"debug",
|
||||||
f"聊天状态更新任务已启动 间隔:{self.update_interval}s",
|
f"聊天状态更新任务已启动 间隔:{STATE_UPDATE_INTERVAL_SECONDS}s",
|
||||||
"_state_update_task",
|
"_state_update_task",
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
self._hf_judge_state_update_task,
|
lambda: self._run_normal_chat_timeout_check_cycle(NORMAL_CHAT_TIMEOUT_CHECK_INTERVAL_SECONDS),
|
||||||
lambda: self._run_hf_judge_state_update_cycle(60),
|
|
||||||
"hf_judge_state_update",
|
|
||||||
"debug",
|
"debug",
|
||||||
f"状态评估任务已启动 间隔:{60}s",
|
f"聊天超时检查任务已启动 间隔:{NORMAL_CHAT_TIMEOUT_CHECK_INTERVAL_SECONDS}s",
|
||||||
|
"_normal_chat_timeout_check_task",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
lambda: self._run_absent_into_chat(HF_JUDGE_STATE_UPDATE_INTERVAL_SECONDS),
|
||||||
|
"debug",
|
||||||
|
f"状态评估任务已启动 间隔:{HF_JUDGE_STATE_UPDATE_INTERVAL_SECONDS}s",
|
||||||
"_hf_judge_state_update_task",
|
"_hf_judge_state_update_task",
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
self._cleanup_task,
|
|
||||||
self._run_cleanup_cycle,
|
self._run_cleanup_cycle,
|
||||||
"hf_cleanup",
|
|
||||||
"info",
|
"info",
|
||||||
f"清理任务已启动 间隔:{self.cleanup_interval}s",
|
f"清理任务已启动 间隔:{CLEANUP_INTERVAL_SECONDS}s",
|
||||||
"_cleanup_task",
|
"_cleanup_task",
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
self._logging_task,
|
|
||||||
self._run_logging_cycle,
|
self._run_logging_cycle,
|
||||||
"hf_logging",
|
|
||||||
"info",
|
"info",
|
||||||
f"日志任务已启动 间隔:{self.log_interval}s",
|
f"日志任务已启动 间隔:{LOG_INTERVAL_SECONDS}s",
|
||||||
"_logging_task",
|
"_logging_task",
|
||||||
),
|
),
|
||||||
# 新增兴趣评估任务配置
|
# 新增兴趣评估任务配置
|
||||||
(
|
(
|
||||||
self._interest_eval_task,
|
self._run_into_focus_cycle,
|
||||||
self._run_interest_eval_cycle,
|
|
||||||
"hf_interest_eval",
|
|
||||||
"debug", # 设为debug,避免过多日志
|
"debug", # 设为debug,避免过多日志
|
||||||
f"兴趣评估任务已启动 间隔:{self.interest_eval_interval}s",
|
f"专注评估任务已启动 间隔:{INTEREST_EVAL_INTERVAL_SECONDS}s",
|
||||||
"_interest_eval_task",
|
"_into_focus_task",
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# 统一启动所有任务
|
# 统一启动所有任务
|
||||||
for _task_var, task_func, task_name, log_level, log_msg, task_attr_name in task_configs:
|
for task_func,log_level, log_msg, task_attr_name in task_configs:
|
||||||
# 检查任务变量是否存在且未完成
|
# 检查任务变量是否存在且未完成
|
||||||
current_task_var = getattr(self, task_attr_name)
|
current_task_var = getattr(self, task_attr_name)
|
||||||
if current_task_var is None or current_task_var.done():
|
if current_task_var is None or current_task_var.done():
|
||||||
new_task = asyncio.create_task(task_func(), name=task_name)
|
new_task = asyncio.create_task(task_func())
|
||||||
setattr(self, task_attr_name, new_task) # 更新任务变量
|
setattr(self, task_attr_name, new_task) # 更新任务变量
|
||||||
if new_task not in self._tasks: # 避免重复添加
|
if new_task not in self._tasks: # 避免重复添加
|
||||||
self._tasks.append(new_task)
|
self._tasks.append(new_task)
|
||||||
@@ -123,7 +112,7 @@ class BackgroundTaskManager:
|
|||||||
# 根据配置记录不同级别的日志
|
# 根据配置记录不同级别的日志
|
||||||
getattr(logger, log_level)(log_msg)
|
getattr(logger, log_level)(log_msg)
|
||||||
else:
|
else:
|
||||||
logger.warning(f"{task_name}任务已在运行")
|
logger.warning(f"{task_attr_name}任务已在运行")
|
||||||
|
|
||||||
async def stop_tasks(self):
|
async def stop_tasks(self):
|
||||||
"""停止所有后台任务。
|
"""停止所有后台任务。
|
||||||
@@ -209,10 +198,15 @@ class BackgroundTaskManager:
|
|||||||
logger.info("检测到离线,停用所有子心流")
|
logger.info("检测到离线,停用所有子心流")
|
||||||
await self.subheartflow_manager.deactivate_all_subflows()
|
await self.subheartflow_manager.deactivate_all_subflows()
|
||||||
|
|
||||||
async def _perform_hf_judge_state_update_work(self):
|
async def _perform_absent_into_chat(self):
|
||||||
"""调用llm检测是否转换ABSENT-CHAT状态"""
|
"""调用llm检测是否转换ABSENT-CHAT状态"""
|
||||||
logger.info("[状态评估任务] 开始基于LLM评估子心流状态...")
|
logger.info("[状态评估任务] 开始基于LLM评估子心流状态...")
|
||||||
await self.subheartflow_manager.evaluate_and_transition_subflows_by_llm()
|
await self.subheartflow_manager.sbhf_absent_into_chat()
|
||||||
|
|
||||||
|
async def _normal_chat_timeout_check_work(self):
|
||||||
|
"""检查处于CHAT状态的子心流是否因长时间未发言而超时,并将其转为ABSENT"""
|
||||||
|
logger.info("[聊天超时检查] 开始检查处于CHAT状态的子心流...")
|
||||||
|
await self.subheartflow_manager.sbhf_chat_into_absent()
|
||||||
|
|
||||||
async def _perform_cleanup_work(self):
|
async def _perform_cleanup_work(self):
|
||||||
"""执行子心流清理任务
|
"""执行子心流清理任务
|
||||||
@@ -244,10 +238,10 @@ class BackgroundTaskManager:
|
|||||||
await self.interest_logger.log_all_states()
|
await self.interest_logger.log_all_states()
|
||||||
|
|
||||||
# --- 新增兴趣评估工作函数 ---
|
# --- 新增兴趣评估工作函数 ---
|
||||||
async def _perform_interest_eval_work(self):
|
async def _perform_into_focus_work(self):
|
||||||
"""执行一轮子心流兴趣评估与提升检查。"""
|
"""执行一轮子心流兴趣评估与提升检查。"""
|
||||||
# 直接调用 subheartflow_manager 的方法,并传递当前状态信息
|
# 直接调用 subheartflow_manager 的方法,并传递当前状态信息
|
||||||
await self.subheartflow_manager.evaluate_interest_and_promote()
|
await self.subheartflow_manager.sbhf_absent_into_focus()
|
||||||
|
|
||||||
# --- 结束新增 ---
|
# --- 结束新增 ---
|
||||||
|
|
||||||
@@ -259,25 +253,30 @@ class BackgroundTaskManager:
|
|||||||
task_name="State Update", interval=interval, task_func=self._perform_state_update_work
|
task_name="State Update", interval=interval, task_func=self._perform_state_update_work
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _run_hf_judge_state_update_cycle(self, interval: int):
|
async def _run_absent_into_chat(self, interval: int):
|
||||||
await self._run_periodic_loop(
|
await self._run_periodic_loop(
|
||||||
task_name="State Update", interval=interval, task_func=self._perform_hf_judge_state_update_work
|
task_name="Into Chat", interval=interval, task_func=self._perform_absent_into_chat
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _run_normal_chat_timeout_check_cycle(self, interval: int):
|
||||||
|
await self._run_periodic_loop(
|
||||||
|
task_name="Normal Chat Timeout Check", interval=interval, task_func=self._normal_chat_timeout_check_work
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _run_cleanup_cycle(self):
|
async def _run_cleanup_cycle(self):
|
||||||
await self._run_periodic_loop(
|
await self._run_periodic_loop(
|
||||||
task_name="Subflow Cleanup", interval=self.cleanup_interval, task_func=self._perform_cleanup_work
|
task_name="Subflow Cleanup", interval=CLEANUP_INTERVAL_SECONDS, task_func=self._perform_cleanup_work
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _run_logging_cycle(self):
|
async def _run_logging_cycle(self):
|
||||||
await self._run_periodic_loop(
|
await self._run_periodic_loop(
|
||||||
task_name="State Logging", interval=self.log_interval, task_func=self._perform_logging_work
|
task_name="State Logging", interval=LOG_INTERVAL_SECONDS, task_func=self._perform_logging_work
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- 新增兴趣评估任务运行器 ---
|
# --- 新增兴趣评估任务运行器 ---
|
||||||
async def _run_interest_eval_cycle(self):
|
async def _run_into_focus_cycle(self):
|
||||||
await self._run_periodic_loop(
|
await self._run_periodic_loop(
|
||||||
task_name="Interest Evaluation",
|
task_name="Into Focus",
|
||||||
interval=self.interest_eval_interval,
|
interval=INTEREST_EVAL_INTERVAL_SECONDS,
|
||||||
task_func=self._perform_interest_eval_work,
|
task_func=self._perform_into_focus_work,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,20 +11,9 @@ from src.heart_flow.subheartflow_manager import SubHeartflowManager
|
|||||||
from src.heart_flow.mind import Mind
|
from src.heart_flow.mind import Mind
|
||||||
from src.heart_flow.interest_logger import InterestLogger # Import InterestLogger
|
from src.heart_flow.interest_logger import InterestLogger # Import InterestLogger
|
||||||
from src.heart_flow.background_tasks import BackgroundTaskManager # Import BackgroundTaskManager
|
from src.heart_flow.background_tasks import BackgroundTaskManager # Import BackgroundTaskManager
|
||||||
# --- End import ---
|
|
||||||
|
|
||||||
logger = get_logger("heartflow")
|
logger = get_logger("heartflow")
|
||||||
|
|
||||||
|
|
||||||
# Task Intervals (should be in BackgroundTaskManager or config)
|
|
||||||
CLEANUP_INTERVAL_SECONDS = 1200
|
|
||||||
STATE_UPDATE_INTERVAL_SECONDS = 60
|
|
||||||
|
|
||||||
# Thresholds (should be in SubHeartflowManager or config)
|
|
||||||
INACTIVE_THRESHOLD_SECONDS = 1200
|
|
||||||
# --- End Constants --- #
|
|
||||||
|
|
||||||
|
|
||||||
class Heartflow:
|
class Heartflow:
|
||||||
"""主心流协调器,负责初始化并协调各个子系统:
|
"""主心流协调器,负责初始化并协调各个子系统:
|
||||||
- 状态管理 (MaiState)
|
- 状态管理 (MaiState)
|
||||||
@@ -65,9 +54,6 @@ class Heartflow:
|
|||||||
mai_state_manager=self.mai_state_manager,
|
mai_state_manager=self.mai_state_manager,
|
||||||
subheartflow_manager=self.subheartflow_manager,
|
subheartflow_manager=self.subheartflow_manager,
|
||||||
interest_logger=self.interest_logger,
|
interest_logger=self.interest_logger,
|
||||||
update_interval=STATE_UPDATE_INTERVAL_SECONDS,
|
|
||||||
cleanup_interval=CLEANUP_INTERVAL_SECONDS,
|
|
||||||
log_interval=3, # Example: Using value directly, ideally get from config
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_or_create_subheartflow(self, subheartflow_id: Any) -> Optional["SubHeartflow"]:
|
async def get_or_create_subheartflow(self, subheartflow_id: Any) -> Optional["SubHeartflow"]:
|
||||||
|
|||||||
@@ -4,24 +4,30 @@ import random
|
|||||||
from typing import List, Tuple, Optional
|
from typing import List, Tuple, Optional
|
||||||
from src.common.logger_manager import get_logger
|
from src.common.logger_manager import get_logger
|
||||||
from src.plugins.moods.moods import MoodManager
|
from src.plugins.moods.moods import MoodManager
|
||||||
|
from src.config.config import global_config
|
||||||
logger = get_logger("mai_state")
|
logger = get_logger("mai_state")
|
||||||
|
|
||||||
|
|
||||||
# -- 状态相关的可配置参数 (可以从 glocal_config 加载) --
|
# -- 状态相关的可配置参数 (可以从 glocal_config 加载) --
|
||||||
enable_unlimited_hfc_chat = True # 调试用:无限专注聊天
|
# enable_unlimited_hfc_chat = True # 调试用:无限专注聊天
|
||||||
# enable_unlimited_hfc_chat = False
|
enable_unlimited_hfc_chat = False
|
||||||
prevent_offline_state = True # 调试用:防止进入离线状态
|
prevent_offline_state = True
|
||||||
|
# 目前默认不启用OFFLINE状态
|
||||||
|
|
||||||
# 不同状态下普通聊天的最大消息数
|
# 不同状态下普通聊天的最大消息数
|
||||||
MAX_NORMAL_CHAT_NUM_PEEKING = 30
|
base_normal_chat_num = global_config.base_normal_chat_num
|
||||||
MAX_NORMAL_CHAT_NUM_NORMAL = 40
|
base_focused_chat_num = global_config.base_focused_chat_num
|
||||||
MAX_NORMAL_CHAT_NUM_FOCUSED = 30
|
|
||||||
|
|
||||||
|
|
||||||
|
MAX_NORMAL_CHAT_NUM_PEEKING = int(base_normal_chat_num/2)
|
||||||
|
MAX_NORMAL_CHAT_NUM_NORMAL = base_normal_chat_num
|
||||||
|
MAX_NORMAL_CHAT_NUM_FOCUSED = base_normal_chat_num + 1
|
||||||
|
|
||||||
# 不同状态下专注聊天的最大消息数
|
# 不同状态下专注聊天的最大消息数
|
||||||
MAX_FOCUSED_CHAT_NUM_PEEKING = 20
|
MAX_FOCUSED_CHAT_NUM_PEEKING = int(base_focused_chat_num/2)
|
||||||
MAX_FOCUSED_CHAT_NUM_NORMAL = 30
|
MAX_FOCUSED_CHAT_NUM_NORMAL = base_focused_chat_num
|
||||||
MAX_FOCUSED_CHAT_NUM_FOCUSED = 40
|
MAX_FOCUSED_CHAT_NUM_FOCUSED = base_focused_chat_num + 2
|
||||||
|
|
||||||
# -- 状态定义 --
|
# -- 状态定义 --
|
||||||
|
|
||||||
@@ -164,7 +170,7 @@ class MaiStateManager:
|
|||||||
if random.random() < 0.03: # 3% 概率切换到 OFFLINE
|
if random.random() < 0.03: # 3% 概率切换到 OFFLINE
|
||||||
potential_next = MaiState.OFFLINE
|
potential_next = MaiState.OFFLINE
|
||||||
resolved_next = _resolve_offline(potential_next)
|
resolved_next = _resolve_offline(potential_next)
|
||||||
logger.debug(f"规则1:概率触发下线,resolve 为 {resolved_next.value}")
|
logger.debug(f"概率触发下线,resolve 为 {resolved_next.value}")
|
||||||
# 只有当解析后的状态与当前状态不同时才设置 next_state
|
# 只有当解析后的状态与当前状态不同时才设置 next_state
|
||||||
if resolved_next != current_status:
|
if resolved_next != current_status:
|
||||||
next_state = resolved_next
|
next_state = resolved_next
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ class ChattingObservation(Observation):
|
|||||||
|
|
||||||
self.talking_message_str = await build_readable_messages(
|
self.talking_message_str = await build_readable_messages(
|
||||||
messages=self.talking_message,
|
messages=self.talking_message,
|
||||||
timestamp_mode="normal",
|
timestamp_mode="lite",
|
||||||
read_mark=last_obs_time_mark,
|
read_mark=last_obs_time_mark,
|
||||||
)
|
)
|
||||||
self.talking_message_str_truncate = await build_readable_messages(
|
self.talking_message_str_truncate = await build_readable_messages(
|
||||||
|
|||||||
@@ -15,20 +15,15 @@ from src.heart_flow.mai_state_manager import MaiStateInfo
|
|||||||
from src.heart_flow.chat_state_info import ChatState, ChatStateInfo
|
from src.heart_flow.chat_state_info import ChatState, ChatStateInfo
|
||||||
from src.heart_flow.sub_mind import SubMind
|
from src.heart_flow.sub_mind import SubMind
|
||||||
|
|
||||||
# # --- REMOVE: Conditional import --- #
|
|
||||||
# if TYPE_CHECKING:
|
|
||||||
# from src.heart_flow.subheartflow_manager import SubHeartflowManager
|
|
||||||
# # --- END REMOVE --- #
|
|
||||||
|
|
||||||
|
|
||||||
# 定义常量 (从 interest.py 移动过来)
|
# 定义常量 (从 interest.py 移动过来)
|
||||||
MAX_INTEREST = 15.0
|
MAX_INTEREST = 15.0
|
||||||
|
|
||||||
logger = get_logger("subheartflow")
|
logger = get_logger("subheartflow")
|
||||||
|
|
||||||
base_reply_probability = 0.05
|
PROBABILITY_INCREASE_RATE_PER_SECOND = 0.1
|
||||||
probability_increase_rate_per_second = 0.08
|
PROBABILITY_DECREASE_RATE_PER_SECOND = 0.1
|
||||||
max_reply_probability = 1
|
MAX_REPLY_PROBABILITY = 1
|
||||||
|
|
||||||
|
|
||||||
class InterestChatting:
|
class InterestChatting:
|
||||||
@@ -37,24 +32,15 @@ class InterestChatting:
|
|||||||
decay_rate=global_config.default_decay_rate_per_second,
|
decay_rate=global_config.default_decay_rate_per_second,
|
||||||
max_interest=MAX_INTEREST,
|
max_interest=MAX_INTEREST,
|
||||||
trigger_threshold=global_config.reply_trigger_threshold,
|
trigger_threshold=global_config.reply_trigger_threshold,
|
||||||
base_reply_probability=base_reply_probability,
|
max_probability=MAX_REPLY_PROBABILITY,
|
||||||
increase_rate=probability_increase_rate_per_second,
|
|
||||||
decay_factor=global_config.probability_decay_factor_per_second,
|
|
||||||
max_probability=max_reply_probability,
|
|
||||||
):
|
):
|
||||||
# 基础属性初始化
|
# 基础属性初始化
|
||||||
self.interest_level: float = 0.0
|
self.interest_level: float = 0.0
|
||||||
self.last_update_time: float = time.time()
|
|
||||||
self.decay_rate_per_second: float = decay_rate
|
self.decay_rate_per_second: float = decay_rate
|
||||||
self.max_interest: float = max_interest
|
self.max_interest: float = max_interest
|
||||||
self.last_interaction_time: float = self.last_update_time
|
|
||||||
|
|
||||||
self.trigger_threshold: float = trigger_threshold
|
self.trigger_threshold: float = trigger_threshold
|
||||||
self.base_reply_probability: float = base_reply_probability
|
|
||||||
self.probability_increase_rate: float = increase_rate
|
|
||||||
self.probability_decay_factor: float = decay_factor
|
|
||||||
self.max_reply_probability: float = max_probability
|
self.max_reply_probability: float = max_probability
|
||||||
self.current_reply_probability: float = 0.0
|
|
||||||
self.is_above_threshold: bool = False
|
self.is_above_threshold: bool = False
|
||||||
|
|
||||||
# 任务相关属性初始化
|
# 任务相关属性初始化
|
||||||
@@ -100,7 +86,6 @@ class InterestChatting:
|
|||||||
"""
|
"""
|
||||||
# 添加新消息
|
# 添加新消息
|
||||||
self.interest_dict[message.message_info.message_id] = (message, interest_value, is_mentioned)
|
self.interest_dict[message.message_info.message_id] = (message, interest_value, is_mentioned)
|
||||||
self.last_interaction_time = time.time()
|
|
||||||
|
|
||||||
# 如果字典长度超过10,删除最旧的消息
|
# 如果字典长度超过10,删除最旧的消息
|
||||||
if len(self.interest_dict) > 10:
|
if len(self.interest_dict) > 10:
|
||||||
@@ -144,10 +129,10 @@ class InterestChatting:
|
|||||||
async def _update_reply_probability(self):
|
async def _update_reply_probability(self):
|
||||||
self.above_threshold = self.interest_level >= self.trigger_threshold
|
self.above_threshold = self.interest_level >= self.trigger_threshold
|
||||||
if self.above_threshold:
|
if self.above_threshold:
|
||||||
self.start_hfc_probability += 0.1
|
self.start_hfc_probability += PROBABILITY_INCREASE_RATE_PER_SECOND
|
||||||
else:
|
else:
|
||||||
if self.start_hfc_probability > 0:
|
if self.start_hfc_probability > 0:
|
||||||
self.start_hfc_probability = max(0, self.start_hfc_probability - 0.1)
|
self.start_hfc_probability = max(0, self.start_hfc_probability - PROBABILITY_DECREASE_RATE_PER_SECOND)
|
||||||
|
|
||||||
async def increase_interest(self, value: float):
|
async def increase_interest(self, value: float):
|
||||||
self.interest_level += value
|
self.interest_level += value
|
||||||
@@ -168,12 +153,7 @@ class InterestChatting:
|
|||||||
"above_threshold": self.above_threshold,
|
"above_threshold": self.above_threshold,
|
||||||
}
|
}
|
||||||
|
|
||||||
async def should_evaluate_reply(self) -> bool:
|
|
||||||
if self.current_reply_probability > 0:
|
|
||||||
trigger = random.random() < self.current_reply_probability
|
|
||||||
return trigger
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# --- 新增后台更新任务相关方法 ---
|
# --- 新增后台更新任务相关方法 ---
|
||||||
async def _run_update_loop(self, update_interval: float = 1.0):
|
async def _run_update_loop(self, update_interval: float = 1.0):
|
||||||
@@ -493,11 +473,10 @@ class SubHeartflow:
|
|||||||
async def get_interest_state(self) -> dict:
|
async def get_interest_state(self) -> dict:
|
||||||
return await self.interest_chatting.get_state()
|
return await self.interest_chatting.get_state()
|
||||||
|
|
||||||
async def get_interest_level(self) -> float:
|
def get_normal_chat_last_speak_time(self) -> float:
|
||||||
return await self.interest_chatting.get_interest()
|
if self.normal_chat_instance:
|
||||||
|
return self.normal_chat_instance.last_speak_time
|
||||||
async def should_evaluate_reply(self) -> bool:
|
return 0
|
||||||
return await self.interest_chatting.should_evaluate_reply()
|
|
||||||
|
|
||||||
def get_interest_dict(self) -> Dict[str, tuple[MessageRecv, float, bool]]:
|
def get_interest_dict(self) -> Dict[str, tuple[MessageRecv, float, bool]]:
|
||||||
return self.interest_chatting.interest_dict
|
return self.interest_chatting.interest_dict
|
||||||
|
|||||||
@@ -140,11 +140,11 @@ class SubMind:
|
|||||||
individuality = Individuality.get_instance()
|
individuality = Individuality.get_instance()
|
||||||
|
|
||||||
relation_prompt = ""
|
relation_prompt = ""
|
||||||
print(f"person_list: {person_list}")
|
# print(f"person_list: {person_list}")
|
||||||
for person in person_list:
|
for person in person_list:
|
||||||
relation_prompt += await relationship_manager.build_relationship_info(person, is_id=True)
|
relation_prompt += await relationship_manager.build_relationship_info(person, is_id=True)
|
||||||
|
|
||||||
print(f"relat22222ion_prompt: {relation_prompt}")
|
# print(f"relat22222ion_prompt: {relation_prompt}")
|
||||||
|
|
||||||
# 构建个性部分
|
# 构建个性部分
|
||||||
prompt_personality = individuality.get_prompt(x_person=2, level=2)
|
prompt_personality = individuality.get_prompt(x_person=2, level=2)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ logger = get_logger("subheartflow_manager")
|
|||||||
|
|
||||||
# 子心流管理相关常量
|
# 子心流管理相关常量
|
||||||
INACTIVE_THRESHOLD_SECONDS = 3600 # 子心流不活跃超时时间(秒)
|
INACTIVE_THRESHOLD_SECONDS = 3600 # 子心流不活跃超时时间(秒)
|
||||||
|
NORMAL_CHAT_TIMEOUT_SECONDS = 30 * 60 # 30分钟
|
||||||
|
|
||||||
class SubHeartflowManager:
|
class SubHeartflowManager:
|
||||||
"""管理所有活跃的 SubHeartflow 实例。"""
|
"""管理所有活跃的 SubHeartflow 实例。"""
|
||||||
@@ -256,7 +256,7 @@ class SubHeartflowManager:
|
|||||||
f"{log_prefix} 完成,共处理 {processed_count} 个子心流,成功将 {changed_count} 个非 ABSENT 子心流的状态更改为 ABSENT。"
|
f"{log_prefix} 完成,共处理 {processed_count} 个子心流,成功将 {changed_count} 个非 ABSENT 子心流的状态更改为 ABSENT。"
|
||||||
)
|
)
|
||||||
|
|
||||||
async def evaluate_interest_and_promote(self):
|
async def sbhf_absent_into_focus(self):
|
||||||
"""评估子心流兴趣度,满足条件且未达上限则提升到FOCUSED状态(基于start_hfc_probability)"""
|
"""评估子心流兴趣度,满足条件且未达上限则提升到FOCUSED状态(基于start_hfc_probability)"""
|
||||||
try:
|
try:
|
||||||
log_prefix = "[兴趣评估]"
|
log_prefix = "[兴趣评估]"
|
||||||
@@ -271,9 +271,6 @@ class SubHeartflowManager:
|
|||||||
return # 如果不允许,直接返回
|
return # 如果不允许,直接返回
|
||||||
# --- 结束新增 ---
|
# --- 结束新增 ---
|
||||||
|
|
||||||
logger.debug(f"{log_prefix} 当前状态 ({current_state.value}) 开始尝试提升到FOCUSED状态")
|
|
||||||
|
|
||||||
if int(time.time()) % 20 == 0: # 每20秒输出一次
|
|
||||||
logger.debug(f"{log_prefix} 当前状态 ({current_state.value}) 可以在{focused_limit}个群激情聊天")
|
logger.debug(f"{log_prefix} 当前状态 ({current_state.value}) 可以在{focused_limit}个群激情聊天")
|
||||||
|
|
||||||
if focused_limit <= 0:
|
if focused_limit <= 0:
|
||||||
@@ -333,137 +330,187 @@ class SubHeartflowManager:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"启动HFC 兴趣评估失败: {e}", exc_info=True)
|
logger.error(f"启动HFC 兴趣评估失败: {e}", exc_info=True)
|
||||||
|
|
||||||
async def evaluate_and_transition_subflows_by_llm(self):
|
async def sbhf_absent_into_chat(self):
|
||||||
"""
|
"""
|
||||||
使用LLM评估每个子心流的状态,并根据LLM的判断执行状态转换(ABSENT <-> CHAT)。
|
随机选一个 ABSENT 状态的子心流,评估是否应转换为 CHAT 状态。
|
||||||
注意:此函数包含对假设的LLM函数的调用。
|
每次调用最多转换一个。
|
||||||
"""
|
"""
|
||||||
# 获取当前状态和限制,用于CHAT激活检查
|
|
||||||
current_mai_state = self.mai_state_info.get_current_state()
|
current_mai_state = self.mai_state_info.get_current_state()
|
||||||
chat_limit = current_mai_state.get_normal_chat_max_num()
|
chat_limit = current_mai_state.get_normal_chat_max_num()
|
||||||
|
|
||||||
transitioned_to_chat = 0
|
async with self._lock:
|
||||||
transitioned_to_absent = 0
|
# 1. 筛选出所有 ABSENT 状态的子心流
|
||||||
|
absent_subflows = [
|
||||||
|
hf for hf in self.subheartflows.values()
|
||||||
|
if hf.chat_state.chat_status == ChatState.ABSENT
|
||||||
|
]
|
||||||
|
|
||||||
async with self._lock: # 在锁内获取快照并迭代
|
if not absent_subflows:
|
||||||
subflows_snapshot = list(self.subheartflows.values())
|
logger.debug("没有摸鱼的子心流可以评估。") # 日志太频繁,注释掉
|
||||||
# 使用不上锁的版本,因为我们已经在锁内
|
return # 没有目标,直接返回
|
||||||
|
|
||||||
|
# 2. 随机选一个幸运儿
|
||||||
|
sub_hf_to_evaluate = random.choice(absent_subflows)
|
||||||
|
flow_id = sub_hf_to_evaluate.subheartflow_id
|
||||||
|
stream_name = chat_manager.get_stream_name(flow_id) or flow_id
|
||||||
|
log_prefix = f"[{stream_name}]"
|
||||||
|
|
||||||
|
# 3. 检查 CHAT 上限
|
||||||
current_chat_count = self.count_subflows_by_state_nolock(ChatState.CHAT)
|
current_chat_count = self.count_subflows_by_state_nolock(ChatState.CHAT)
|
||||||
|
if current_chat_count >= chat_limit:
|
||||||
|
logger.debug(f"{log_prefix} 想看看能不能聊,但是聊天太多了, ({current_chat_count}/{chat_limit}) 满了。")
|
||||||
|
return # 满了,这次就算了
|
||||||
|
|
||||||
|
# --- 获取 FOCUSED 计数 ---
|
||||||
|
current_focused_count = self.count_subflows_by_state_nolock(ChatState.FOCUSED)
|
||||||
|
focused_limit = current_mai_state.get_focused_chat_max_num()
|
||||||
|
|
||||||
|
# --- 新增:获取聊天和专注群名 ---
|
||||||
|
chatting_group_names = []
|
||||||
|
focused_group_names = []
|
||||||
|
for flow_id, hf in self.subheartflows.items():
|
||||||
|
stream_name = chat_manager.get_stream_name(flow_id) or str(flow_id) # 保证有名字
|
||||||
|
if hf.chat_state.chat_status == ChatState.CHAT:
|
||||||
|
chatting_group_names.append(stream_name)
|
||||||
|
elif hf.chat_state.chat_status == ChatState.FOCUSED:
|
||||||
|
focused_group_names.append(stream_name)
|
||||||
|
# --- 结束新增 ---
|
||||||
|
|
||||||
|
# --- 获取观察信息和构建 Prompt ---
|
||||||
|
first_observation = sub_hf_to_evaluate.observations[0] # 喵~第一个观察者肯定存在的说
|
||||||
|
await first_observation.observe()
|
||||||
|
current_chat_log = first_observation.talking_message_str or "当前没啥聊天内容。"
|
||||||
|
_observation_summary = f"最近聊了这些:\n{current_chat_log}"
|
||||||
|
|
||||||
|
mai_state_description = f"你当前状态: {current_mai_state.value}。"
|
||||||
|
individuality = Individuality.get_instance()
|
||||||
|
personality_prompt = individuality.get_prompt(x_person=2, level = 2)
|
||||||
|
prompt_personality = f"你正在扮演名为{individuality.name}的人类,{personality_prompt}"
|
||||||
|
|
||||||
|
# --- 修改:在 prompt 中加入当前聊天计数和群名信息 (条件显示) ---
|
||||||
|
chat_status_lines = []
|
||||||
|
if chatting_group_names:
|
||||||
|
chat_status_lines.append(f"正在闲聊 ({current_chat_count}/{chat_limit}): {', '.join(chatting_group_names)}")
|
||||||
|
if focused_group_names:
|
||||||
|
chat_status_lines.append(f"正在专注 ({current_focused_count}/{focused_limit}): {', '.join(focused_group_names)}")
|
||||||
|
|
||||||
|
chat_status_prompt = "当前没有在任何群聊中。" # 默认消息喵~
|
||||||
|
if chat_status_lines:
|
||||||
|
chat_status_prompt = "当前聊天情况:\n" + "\n".join(chat_status_lines) # 拼接状态信息
|
||||||
|
|
||||||
|
prompt = (
|
||||||
|
f"{prompt_personality}\\n"
|
||||||
|
f"你当前没在 [{stream_name}] 群聊天。\\n"
|
||||||
|
f"{mai_state_description}\\n"
|
||||||
|
f"{chat_status_prompt}\\n" # <-- 喵!用了新的状态信息~
|
||||||
|
f"{_observation_summary}\\n---\\n"
|
||||||
|
f"基于以上信息,你想不想开始在这个群闲聊?\\n"
|
||||||
|
f"请说明理由,并以 JSON 格式回答,包含 'decision' (布尔值) 和 'reason' (字符串)。\\n"
|
||||||
|
f'例如:{{\"decision\": true, \"reason\": \"看起来挺热闹的,插个话\"}}\\n'
|
||||||
|
f'例如:{{\"decision\": false, \"reason\": \"已经聊了好多,休息一下\"}}\\n'
|
||||||
|
f"请只输出有效的 JSON 对象。"
|
||||||
|
)
|
||||||
|
# --- 结束修改 ---
|
||||||
|
|
||||||
|
# --- 4. LLM 评估是否想聊 ---
|
||||||
|
yao_kai_shi_liao_ma = await self._llm_evaluate_state_transition(prompt)
|
||||||
|
|
||||||
|
if yao_kai_shi_liao_ma is None:
|
||||||
|
logger.debug(f"{log_prefix} 问AI想不想聊失败了,这次算了。")
|
||||||
|
return # 评估失败,结束
|
||||||
|
|
||||||
|
if not yao_kai_shi_liao_ma:
|
||||||
|
logger.info(f"{log_prefix} 现在不想聊这个群。")
|
||||||
|
return # 不想聊,结束
|
||||||
|
|
||||||
|
# --- 5. AI想聊,再次检查额度并尝试转换 ---
|
||||||
|
# 再次检查以防万一
|
||||||
|
current_chat_count_before_change = self.count_subflows_by_state_nolock(ChatState.CHAT)
|
||||||
|
if current_chat_count_before_change < chat_limit:
|
||||||
|
logger.info(
|
||||||
|
f"{log_prefix} 想聊,而且还有空位 ({current_chat_count_before_change}/{chat_limit}),这就去聊!"
|
||||||
|
)
|
||||||
|
await sub_hf_to_evaluate.change_chat_state(ChatState.CHAT)
|
||||||
|
# 确认转换成功
|
||||||
|
if sub_hf_to_evaluate.chat_state.chat_status == ChatState.CHAT:
|
||||||
|
logger.debug(f"{log_prefix} 成功进入聊天状态!本次评估圆满结束。")
|
||||||
|
else:
|
||||||
|
logger.warning(f"{log_prefix} 奇怪,尝试进入聊天状态失败了。当前状态: {sub_hf_to_evaluate.chat_state.chat_status.value}")
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
f"{log_prefix} AI说想聊,但是刚问完就没空位了 ({current_chat_count_before_change}/{chat_limit})。真不巧,下次再说吧。"
|
||||||
|
)
|
||||||
|
# 无论转换成功与否,本次评估都结束了
|
||||||
|
|
||||||
|
# 锁在这里自动释放
|
||||||
|
|
||||||
|
# --- 新增:单独检查 CHAT 状态超时的任务 ---
|
||||||
|
async def sbhf_chat_into_absent(self):
|
||||||
|
"""定期检查处于 CHAT 状态的子心流是否因长时间未发言而超时,并将其转为 ABSENT。"""
|
||||||
|
log_prefix_task = "[聊天超时检查]"
|
||||||
|
transitioned_to_absent = 0
|
||||||
|
checked_count = 0
|
||||||
|
|
||||||
|
async with self._lock:
|
||||||
|
subflows_snapshot = list(self.subheartflows.values())
|
||||||
|
checked_count = len(subflows_snapshot)
|
||||||
|
|
||||||
if not subflows_snapshot:
|
if not subflows_snapshot:
|
||||||
logger.info("当前没有子心流需要评估。")
|
# logger.debug(f"{log_prefix_task} 没有子心流需要检查超时。")
|
||||||
return
|
return
|
||||||
|
|
||||||
for sub_hf in subflows_snapshot:
|
for sub_hf in subflows_snapshot:
|
||||||
|
# 只检查 CHAT 状态的子心流
|
||||||
|
if sub_hf.chat_state.chat_status != ChatState.CHAT:
|
||||||
|
continue
|
||||||
|
|
||||||
flow_id = sub_hf.subheartflow_id
|
flow_id = sub_hf.subheartflow_id
|
||||||
stream_name = chat_manager.get_stream_name(flow_id) or flow_id
|
stream_name = chat_manager.get_stream_name(flow_id) or flow_id
|
||||||
log_prefix = f"[{stream_name}]"
|
log_prefix = f"[{stream_name}]({log_prefix_task})"
|
||||||
current_subflow_state = sub_hf.chat_state.chat_status
|
|
||||||
|
|
||||||
_observation_summary = "没有可用的观察信息。" # 默认值
|
should_deactivate = False
|
||||||
|
reason = ""
|
||||||
|
|
||||||
first_observation = sub_hf.observations[0]
|
try:
|
||||||
if isinstance(first_observation, ChattingObservation):
|
# 使用变量名 last_bot_dong_zuo_time 替代 last_bot_activity_time
|
||||||
# 组合中期记忆和当前聊天内容
|
last_bot_dong_zuo_time = sub_hf.get_normal_chat_last_speak_time()
|
||||||
await first_observation.observe()
|
|
||||||
current_chat = first_observation.talking_message_str or "当前无聊天内容。"
|
|
||||||
combined_summary = f"当前聊天内容:\n{current_chat}"
|
|
||||||
else:
|
|
||||||
logger.warning(f"{log_prefix} [{stream_name}] 第一个观察者不是 ChattingObservation 类型。")
|
|
||||||
|
|
||||||
# --- 获取麦麦状态 ---
|
if last_bot_dong_zuo_time > 0:
|
||||||
mai_state_description = f"你当前状态: {current_mai_state.value}。"
|
current_time = time.time()
|
||||||
|
# 使用变量名 time_since_last_bb 替代 time_since_last_reply
|
||||||
|
time_since_last_bb = current_time - last_bot_dong_zuo_time
|
||||||
|
|
||||||
# 获取个性化信息
|
if time_since_last_bb > NORMAL_CHAT_TIMEOUT_SECONDS:
|
||||||
individuality = Individuality.get_instance()
|
should_deactivate = True
|
||||||
|
reason = f"超过 {NORMAL_CHAT_TIMEOUT_SECONDS / 60:.0f} 分钟没 BB"
|
||||||
|
logger.info(f"{log_prefix} 检测到超时 ({reason}),准备转为 ABSENT。上次活动时间: {last_bot_dong_zuo_time:.0f}")
|
||||||
|
# else:
|
||||||
|
# logger.debug(f"{log_prefix} Bot活动时间未超时 ({time_since_last_bb:.0f}s < {NORMAL_CHAT_TIMEOUT_SECONDS}s),保持 CHAT 状态。")
|
||||||
|
# else:
|
||||||
|
# 如果没有记录到Bot的活动时间,暂时不因为超时而转换状态
|
||||||
|
# logger.debug(f"{log_prefix} 未找到有效的 Bot 最后活动时间记录,不执行超时检查。")
|
||||||
|
|
||||||
# 构建个性部分
|
except AttributeError:
|
||||||
prompt_personality = f"你正在扮演名为{individuality.personality.bot_nickname}的人类,你"
|
logger.error(f"{log_prefix} 无法获取 Bot 最后 BB 时间,请确保 SubHeartflow 相关实现正确。跳过超时检查。")
|
||||||
prompt_personality += individuality.personality.personality_core
|
except Exception as e:
|
||||||
|
logger.error(f"{log_prefix} 检查 Bot 超时状态时出错: {e}", exc_info=True)
|
||||||
# 随机添加个性侧面
|
|
||||||
if individuality.personality.personality_sides:
|
|
||||||
random_side = random.choice(individuality.personality.personality_sides)
|
|
||||||
prompt_personality += f",{random_side}"
|
|
||||||
|
|
||||||
# 随机添加身份细节
|
|
||||||
if individuality.identity.identity_detail:
|
|
||||||
random_detail = random.choice(individuality.identity.identity_detail)
|
|
||||||
prompt_personality += f",{random_detail}"
|
|
||||||
|
|
||||||
# --- 针对 ABSENT 状态 ---
|
|
||||||
if current_subflow_state == ChatState.ABSENT:
|
|
||||||
# 构建Prompt
|
|
||||||
prompt = (
|
|
||||||
f"{prompt_personality}\n"
|
|
||||||
f"你当前没有在: [{stream_name}] 群中聊天。\n"
|
|
||||||
f"{mai_state_description}\n"
|
|
||||||
f"这个群里最近的聊天内容是:\n---\n{combined_summary}\n---\n"
|
|
||||||
f"基于以上信息,请判断你是否愿意在这个群开始闲聊,"
|
|
||||||
f"进入常规聊天(CHAT)状态?\n"
|
|
||||||
f"给出你的判断,和理由,然后以 JSON 格式回答"
|
|
||||||
f"包含键 'decision',如果要开始聊天,值为 true ,否则为 false.\n"
|
|
||||||
f"包含键 'reason',其值为你的理由。\n"
|
|
||||||
f'例如:{{"decision": true, "reason": "因为我想聊天"}}\n'
|
|
||||||
f"请只输出有效的 JSON 对象。"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 调用LLM评估
|
|
||||||
should_activate = await self._llm_evaluate_state_transition(prompt)
|
|
||||||
if should_activate is None: # 处理解析失败或意外情况
|
|
||||||
logger.warning(f"{log_prefix}LLM评估返回无效结果,跳过。")
|
|
||||||
continue
|
|
||||||
|
|
||||||
if should_activate:
|
|
||||||
# 检查CHAT限额
|
|
||||||
# 使用不上锁的版本,因为我们已经在锁内
|
|
||||||
current_chat_count = self.count_subflows_by_state_nolock(ChatState.CHAT)
|
|
||||||
if current_chat_count < chat_limit:
|
|
||||||
logger.info(
|
|
||||||
f"{log_prefix}LLM建议激活到CHAT状态,且未达上限({current_chat_count}/{chat_limit})。正在尝试转换..."
|
|
||||||
)
|
|
||||||
await sub_hf.change_chat_state(ChatState.CHAT)
|
|
||||||
if sub_hf.chat_state.chat_status == ChatState.CHAT:
|
|
||||||
transitioned_to_chat += 1
|
|
||||||
else:
|
|
||||||
logger.warning(f"{log_prefix}尝试激活到CHAT失败。")
|
|
||||||
else:
|
|
||||||
logger.info(
|
|
||||||
f"{log_prefix}LLM建议激活到CHAT状态,但已达到上限({current_chat_count}/{chat_limit})。跳过转换。"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
logger.info(f"{log_prefix}LLM建议不激活到CHAT状态。")
|
|
||||||
|
|
||||||
# --- 针对 CHAT 状态 ---
|
|
||||||
elif current_subflow_state == ChatState.CHAT:
|
|
||||||
# 构建Prompt
|
|
||||||
prompt = (
|
|
||||||
f"{prompt_personality}\n"
|
|
||||||
f"你正在在: [{stream_name}] 群中聊天。\n"
|
|
||||||
f"{mai_state_description}\n"
|
|
||||||
f"这个群里最近的聊天内容是:\n---\n{combined_summary}\n---\n"
|
|
||||||
f"基于以上信息,请判断你是否愿意在这个群继续闲聊,"
|
|
||||||
f"还是暂时离开聊天,进入休眠状态?\n"
|
|
||||||
f"给出你的判断,和理由,然后以 JSON 格式回答"
|
|
||||||
f"包含键 'decision',如果要离开聊天,值为 true ,否则为 false.\n"
|
|
||||||
f"包含键 'reason',其值为你的理由。\n"
|
|
||||||
f'例如:{{"decision": true, "reason": "因为我想休息"}}\n'
|
|
||||||
f"请只输出有效的 JSON 对象。"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 调用LLM评估
|
|
||||||
should_deactivate = await self._llm_evaluate_state_transition(prompt)
|
|
||||||
if should_deactivate is None: # 处理解析失败或意外情况
|
|
||||||
logger.warning(f"{log_prefix}LLM评估返回无效结果,跳过。")
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
# --- 执行状态转换(如果超时) ---
|
||||||
if should_deactivate:
|
if should_deactivate:
|
||||||
logger.info(f"{log_prefix}LLM建议进入ABSENT状态。正在尝试转换...")
|
logger.info(f"{log_prefix} 因超时 ({reason}),尝试转换为 ABSENT 状态。")
|
||||||
await sub_hf.change_chat_state(ChatState.ABSENT)
|
await sub_hf.change_chat_state(ChatState.ABSENT)
|
||||||
|
# 再次检查确保状态已改变
|
||||||
if sub_hf.chat_state.chat_status == ChatState.ABSENT:
|
if sub_hf.chat_state.chat_status == ChatState.ABSENT:
|
||||||
transitioned_to_absent += 1
|
transitioned_to_absent += 1
|
||||||
|
logger.info(f"{log_prefix} 已成功转换为 ABSENT 状态。")
|
||||||
else:
|
else:
|
||||||
logger.info(f"{log_prefix}LLM建议不进入ABSENT状态。")
|
logger.warning(f"{log_prefix} 尝试因超时转换为 ABSENT 失败。")
|
||||||
|
|
||||||
|
if transitioned_to_absent > 0:
|
||||||
|
logger.info(f"{log_prefix_task} 完成,共检查 {checked_count} 个子心流,{transitioned_to_absent} 个因超时转为 ABSENT。")
|
||||||
|
# else:
|
||||||
|
# logger.debug(f"{log_prefix_task} 完成,共检查 {checked_count} 个子心流,无超时转换。")
|
||||||
|
# --- 结束新增 ---
|
||||||
|
|
||||||
async def _llm_evaluate_state_transition(self, prompt: str) -> Optional[bool]:
|
async def _llm_evaluate_state_transition(self, prompt: str) -> Optional[bool]:
|
||||||
"""
|
"""
|
||||||
@@ -579,14 +626,14 @@ class SubHeartflowManager:
|
|||||||
# --- 新增:处理 HFC 无回复回调的专用方法 --- #
|
# --- 新增:处理 HFC 无回复回调的专用方法 --- #
|
||||||
async def _handle_hfc_no_reply(self, subheartflow_id: Any):
|
async def _handle_hfc_no_reply(self, subheartflow_id: Any):
|
||||||
"""处理来自 HeartFChatting 的连续无回复信号 (通过 partial 绑定 ID)"""
|
"""处理来自 HeartFChatting 的连续无回复信号 (通过 partial 绑定 ID)"""
|
||||||
# 注意:这里不需要再获取锁,因为 request_absent_transition 内部会处理锁
|
# 注意:这里不需要再获取锁,因为 sbhf_focus_into_absent 内部会处理锁
|
||||||
logger.debug(f"[管理器 HFC 处理器] 接收到来自 {subheartflow_id} 的 HFC 无回复信号")
|
logger.debug(f"[管理器 HFC 处理器] 接收到来自 {subheartflow_id} 的 HFC 无回复信号")
|
||||||
await self.request_absent_transition(subheartflow_id)
|
await self.sbhf_focus_into_absent(subheartflow_id)
|
||||||
|
|
||||||
# --- 结束新增 --- #
|
# --- 结束新增 --- #
|
||||||
|
|
||||||
# --- 新增:处理来自 HeartFChatting 的状态转换请求 --- #
|
# --- 新增:处理来自 HeartFChatting 的状态转换请求 --- #
|
||||||
async def request_absent_transition(self, subflow_id: Any):
|
async def sbhf_focus_into_absent(self, subflow_id: Any):
|
||||||
"""
|
"""
|
||||||
接收来自 HeartFChatting 的请求,将特定子心流的状态转换为 ABSENT。
|
接收来自 HeartFChatting 的请求,将特定子心流的状态转换为 ABSENT。
|
||||||
通常在连续多次 "no_reply" 后被调用。
|
通常在连续多次 "no_reply" 后被调用。
|
||||||
@@ -606,12 +653,42 @@ class SubHeartflowManager:
|
|||||||
# 仅当子心流处于 FOCUSED 状态时才进行转换
|
# 仅当子心流处于 FOCUSED 状态时才进行转换
|
||||||
# 因为 HeartFChatting 只在 FOCUSED 状态下运行
|
# 因为 HeartFChatting 只在 FOCUSED 状态下运行
|
||||||
if current_state == ChatState.FOCUSED:
|
if current_state == ChatState.FOCUSED:
|
||||||
logger.info(f"[状态转换请求] 接收到请求,将 {stream_name} (当前: {current_state.value}) 转换为 ABSENT")
|
target_state = ChatState.ABSENT # 默认目标状态
|
||||||
|
log_reason = "默认转换"
|
||||||
|
|
||||||
|
# 决定是去 ABSENT 还是 CHAT
|
||||||
|
if random.random() < 0.5:
|
||||||
|
target_state = ChatState.ABSENT
|
||||||
|
log_reason = "随机选择 ABSENT"
|
||||||
|
logger.debug(f"[状态转换请求] {stream_name} ({current_state.value}) 随机决定进入 ABSENT")
|
||||||
|
else:
|
||||||
|
# 尝试进入 CHAT,先检查限制
|
||||||
|
current_mai_state = self.mai_state_info.get_current_state()
|
||||||
|
chat_limit = current_mai_state.get_normal_chat_max_num()
|
||||||
|
# 使用不上锁的版本,因为我们已经在锁内
|
||||||
|
current_chat_count = self.count_subflows_by_state_nolock(ChatState.CHAT)
|
||||||
|
|
||||||
|
if current_chat_count < chat_limit:
|
||||||
|
target_state = ChatState.CHAT
|
||||||
|
log_reason = f"随机选择 CHAT (当前 {current_chat_count}/{chat_limit})"
|
||||||
|
logger.debug(f"[状态转换请求] {stream_name} ({current_state.value}) 随机决定进入 CHAT,未达上限 ({current_chat_count}/{chat_limit})")
|
||||||
|
else:
|
||||||
|
target_state = ChatState.ABSENT
|
||||||
|
log_reason = f"随机选择 CHAT 但已达上限 ({current_chat_count}/{chat_limit}),转为 ABSENT"
|
||||||
|
logger.debug(f"[状态转换请求] {stream_name} ({current_state.value}) 随机决定进入 CHAT,但已达上限 ({current_chat_count}/{chat_limit}),改为进入 ABSENT")
|
||||||
|
|
||||||
|
#开始转换
|
||||||
|
logger.info(f"[状态转换请求] 接收到请求,将 {stream_name} (当前: {current_state.value}) 尝试转换为 {target_state.value} ({log_reason})")
|
||||||
try:
|
try:
|
||||||
await subflow.change_chat_state(ChatState.ABSENT)
|
await subflow.change_chat_state(target_state)
|
||||||
logger.info(f"[状态转换请求] {stream_name} 状态已成功转换为 ABSENT")
|
# 检查最终状态
|
||||||
|
final_state = subflow.chat_state.chat_status
|
||||||
|
if final_state == target_state:
|
||||||
|
logger.debug(f"[状态转换请求] {stream_name} 状态已成功转换为 {final_state.value}")
|
||||||
|
else:
|
||||||
|
logger.warning(f"[状态转换请求] 尝试将 {stream_name} 转换为 {target_state.value} 后,状态实际为 {final_state.value}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[状态转换请求] 转换 {stream_name} 到 ABSENT 时出错: {e}", exc_info=True)
|
logger.error(f"[状态转换请求] 转换 {stream_name} 到 {target_state.value} 时出错: {e}", exc_info=True)
|
||||||
elif current_state == ChatState.ABSENT:
|
elif current_state == ChatState.ABSENT:
|
||||||
logger.debug(f"[状态转换请求] {stream_name} 已处于 ABSENT 状态,无需转换")
|
logger.debug(f"[状态转换请求] {stream_name} 已处于 ABSENT 状态,无需转换")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ class Individuality:
|
|||||||
获取合并的个体特征prompt
|
获取合并的个体特征prompt
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
level (int): 详细程度 (1: 核心/随机细节, 2: 核心+侧面/细节+其他, 3: 全部)
|
level (int): 详细程度 (1: 核心/随机细节, 2: 核心+随机侧面/全部细节, 3: 全部)
|
||||||
x_person (int, optional): 人称代词 (0: 无人称, 1: 我, 2: 你). 默认为 2.
|
x_person (int, optional): 人称代词 (0: 无人称, 1: 我, 2: 你). 默认为 2.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|||||||
@@ -99,15 +99,20 @@ class ChatBot:
|
|||||||
template_group_name = None
|
template_group_name = None
|
||||||
|
|
||||||
async def preprocess():
|
async def preprocess():
|
||||||
|
logger.trace("开始预处理消息...")
|
||||||
# 如果在私聊中
|
# 如果在私聊中
|
||||||
if groupinfo is None:
|
if groupinfo is None:
|
||||||
|
logger.trace("检测到私聊消息")
|
||||||
# 是否在配置信息中开启私聊模式
|
# 是否在配置信息中开启私聊模式
|
||||||
if global_config.enable_friend_chat:
|
if global_config.enable_friend_chat:
|
||||||
|
logger.trace("私聊模式已启用")
|
||||||
# 是否进入PFC
|
# 是否进入PFC
|
||||||
if global_config.enable_pfc_chatting:
|
if global_config.enable_pfc_chatting:
|
||||||
|
logger.trace("进入PFC私聊处理流程")
|
||||||
userinfo = message.message_info.user_info
|
userinfo = message.message_info.user_info
|
||||||
messageinfo = message.message_info
|
messageinfo = message.message_info
|
||||||
# 创建聊天流
|
# 创建聊天流
|
||||||
|
logger.trace(f"为{userinfo.user_id}创建/获取聊天流")
|
||||||
chat = await chat_manager.get_or_create_stream(
|
chat = await chat_manager.get_or_create_stream(
|
||||||
platform=messageinfo.platform,
|
platform=messageinfo.platform,
|
||||||
user_info=userinfo,
|
user_info=userinfo,
|
||||||
@@ -118,9 +123,11 @@ class ChatBot:
|
|||||||
await self._create_pfc_chat(message)
|
await self._create_pfc_chat(message)
|
||||||
# 禁止PFC,进入普通的心流消息处理逻辑
|
# 禁止PFC,进入普通的心流消息处理逻辑
|
||||||
else:
|
else:
|
||||||
|
logger.trace("进入普通心流私聊处理")
|
||||||
await self.heartflow_processor.process_message(message_data)
|
await self.heartflow_processor.process_message(message_data)
|
||||||
# 群聊默认进入心流消息处理逻辑
|
# 群聊默认进入心流消息处理逻辑
|
||||||
else:
|
else:
|
||||||
|
logger.trace(f"检测到群聊消息,群ID: {groupinfo.group_id}")
|
||||||
await self.heartflow_processor.process_message(message_data)
|
await self.heartflow_processor.process_message(message_data)
|
||||||
|
|
||||||
if template_group_name:
|
if template_group_name:
|
||||||
|
|||||||
@@ -732,6 +732,9 @@ def translate_timestamp_to_human_readable(timestamp: float, mode: str = "normal"
|
|||||||
return f"{int(diff / 86400)}天前:\n"
|
return f"{int(diff / 86400)}天前:\n"
|
||||||
else:
|
else:
|
||||||
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp)) + ":\n"
|
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp)) + ":\n"
|
||||||
|
elif mode == "lite":
|
||||||
|
# 只返回时分秒格式,喵~
|
||||||
|
return time.strftime("%H:%M:%S", time.localtime(timestamp))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,10 +30,12 @@ from src.plugins.moods.moods import MoodManager
|
|||||||
from src.individuality.individuality import Individuality
|
from src.individuality.individuality import Individuality
|
||||||
|
|
||||||
|
|
||||||
INITIAL_DURATION = 60.0
|
|
||||||
|
|
||||||
WAITING_TIME_THRESHOLD = 300 # 等待新消息时间阈值,单位秒
|
WAITING_TIME_THRESHOLD = 300 # 等待新消息时间阈值,单位秒
|
||||||
|
|
||||||
|
EMOJI_SEND_PRO = 0.3 # 设置一个概率,比如 30% 才真的发
|
||||||
|
|
||||||
|
CONSECUTIVE_NO_REPLY_THRESHOLD = 3 # 连续不回复的阈值
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger("interest") # Logger Name Changed
|
logger = get_logger("interest") # Logger Name Changed
|
||||||
|
|
||||||
@@ -179,8 +181,6 @@ class HeartFChatting:
|
|||||||
其生命周期现在由其关联的 SubHeartflow 的 FOCUSED 状态控制。
|
其生命周期现在由其关联的 SubHeartflow 的 FOCUSED 状态控制。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
CONSECUTIVE_NO_REPLY_THRESHOLD = 3 # 连续不回复的阈值
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
chat_id: str,
|
chat_id: str,
|
||||||
@@ -644,14 +644,14 @@ class HeartFChatting:
|
|||||||
self._lian_xu_bu_hui_fu_ci_shu += 1
|
self._lian_xu_bu_hui_fu_ci_shu += 1
|
||||||
self._lian_xu_deng_dai_shi_jian += dang_qian_deng_dai # 累加等待时间
|
self._lian_xu_deng_dai_shi_jian += dang_qian_deng_dai # 累加等待时间
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{self.log_prefix} 连续不回复计数增加: {self._lian_xu_bu_hui_fu_ci_shu}/{self.CONSECUTIVE_NO_REPLY_THRESHOLD}, "
|
f"{self.log_prefix} 连续不回复计数增加: {self._lian_xu_bu_hui_fu_ci_shu}/{CONSECUTIVE_NO_REPLY_THRESHOLD}, "
|
||||||
f"本次等待: {dang_qian_deng_dai:.2f}秒, 累计等待: {self._lian_xu_deng_dai_shi_jian:.2f}秒"
|
f"本次等待: {dang_qian_deng_dai:.2f}秒, 累计等待: {self._lian_xu_deng_dai_shi_jian:.2f}秒"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 检查是否同时达到次数和时间阈值
|
# 检查是否同时达到次数和时间阈值
|
||||||
time_threshold = 0.66 * WAITING_TIME_THRESHOLD * self.CONSECUTIVE_NO_REPLY_THRESHOLD
|
time_threshold = 0.66 * WAITING_TIME_THRESHOLD * CONSECUTIVE_NO_REPLY_THRESHOLD
|
||||||
if (
|
if (
|
||||||
self._lian_xu_bu_hui_fu_ci_shu >= self.CONSECUTIVE_NO_REPLY_THRESHOLD
|
self._lian_xu_bu_hui_fu_ci_shu >= CONSECUTIVE_NO_REPLY_THRESHOLD
|
||||||
and self._lian_xu_deng_dai_shi_jian >= time_threshold
|
and self._lian_xu_deng_dai_shi_jian >= time_threshold
|
||||||
):
|
):
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -661,7 +661,7 @@ class HeartFChatting:
|
|||||||
)
|
)
|
||||||
# 调用回调。注意:这里不重置计数器和时间,依赖回调函数成功改变状态来隐式重置上下文。
|
# 调用回调。注意:这里不重置计数器和时间,依赖回调函数成功改变状态来隐式重置上下文。
|
||||||
await self.on_consecutive_no_reply_callback()
|
await self.on_consecutive_no_reply_callback()
|
||||||
elif self._lian_xu_bu_hui_fu_ci_shu >= self.CONSECUTIVE_NO_REPLY_THRESHOLD:
|
elif self._lian_xu_bu_hui_fu_ci_shu >= CONSECUTIVE_NO_REPLY_THRESHOLD:
|
||||||
# 仅次数达到阈值,但时间未达到
|
# 仅次数达到阈值,但时间未达到
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{self.log_prefix} 连续不回复次数达到阈值 ({self._lian_xu_bu_hui_fu_ci_shu}次) "
|
f"{self.log_prefix} 连续不回复次数达到阈值 ({self._lian_xu_bu_hui_fu_ci_shu}次) "
|
||||||
@@ -979,6 +979,20 @@ class HeartFChatting:
|
|||||||
f"{self.log_prefix}[Planner] 恢复了原始动作集, 当前可用: {list(self.action_manager.get_available_actions().keys())}"
|
f"{self.log_prefix}[Planner] 恢复了原始动作集, 当前可用: {list(self.action_manager.get_available_actions().keys())}"
|
||||||
)
|
)
|
||||||
# --- 结束:确保动作恢复 ---
|
# --- 结束:确保动作恢复 ---
|
||||||
|
|
||||||
|
# --- 新增:概率性忽略文本回复附带的表情(正确的位置)---
|
||||||
|
|
||||||
|
|
||||||
|
if action == "text_reply" and emoji_query:
|
||||||
|
logger.debug(f"{self.log_prefix}[Planner] 大模型想让麦麦发文字时带表情: '{emoji_query}'")
|
||||||
|
# 掷骰子看看要不要听它的
|
||||||
|
if random.random() > EMOJI_SEND_PRO:
|
||||||
|
logger.info(f"{self.log_prefix}[Planner] 但是麦麦这次不想加表情 ({1-EMOJI_SEND_PRO:.0%}),忽略表情 '{emoji_query}'")
|
||||||
|
emoji_query = "" # 把表情请求清空,就不发了
|
||||||
|
else:
|
||||||
|
logger.info(f"{self.log_prefix}[Planner] 好吧,加上表情 '{emoji_query}'")
|
||||||
|
# --- 结束:概率性忽略 ---
|
||||||
|
|
||||||
# --- 结束 LLM 决策 --- #
|
# --- 结束 LLM 决策 --- #
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ class PromptBuilder:
|
|||||||
message_list_before_now = get_raw_msg_before_timestamp_with_chat(
|
message_list_before_now = get_raw_msg_before_timestamp_with_chat(
|
||||||
chat_id=chat_stream.stream_id,
|
chat_id=chat_stream.stream_id,
|
||||||
timestamp=time.time(),
|
timestamp=time.time(),
|
||||||
limit=global_config.MAX_CONTEXT_SIZE,
|
limit=global_config.observation_context_size,
|
||||||
)
|
)
|
||||||
|
|
||||||
chat_talking_prompt = await build_readable_messages(
|
chat_talking_prompt = await build_readable_messages(
|
||||||
@@ -242,6 +242,8 @@ class PromptBuilder:
|
|||||||
moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"),
|
moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger.debug(f"focus_chat_prompt: \n{prompt}")
|
||||||
|
|
||||||
return prompt
|
return prompt
|
||||||
|
|
||||||
async def _build_prompt_normal(self, chat_stream, message_txt: str, sender_name: str = "某人") -> tuple[str, str]:
|
async def _build_prompt_normal(self, chat_stream, message_txt: str, sender_name: str = "某人") -> tuple[str, str]:
|
||||||
@@ -255,7 +257,7 @@ class PromptBuilder:
|
|||||||
who_chat_in_group += get_recent_group_speaker(
|
who_chat_in_group += get_recent_group_speaker(
|
||||||
chat_stream.stream_id,
|
chat_stream.stream_id,
|
||||||
(chat_stream.user_info.platform, chat_stream.user_info.user_id),
|
(chat_stream.user_info.platform, chat_stream.user_info.user_id),
|
||||||
limit=global_config.MAX_CONTEXT_SIZE,
|
limit=global_config.observation_context_size,
|
||||||
)
|
)
|
||||||
|
|
||||||
relation_prompt = ""
|
relation_prompt = ""
|
||||||
@@ -314,7 +316,7 @@ class PromptBuilder:
|
|||||||
message_list_before_now = get_raw_msg_before_timestamp_with_chat(
|
message_list_before_now = get_raw_msg_before_timestamp_with_chat(
|
||||||
chat_id=chat_stream.stream_id,
|
chat_id=chat_stream.stream_id,
|
||||||
timestamp=time.time(),
|
timestamp=time.time(),
|
||||||
limit=global_config.MAX_CONTEXT_SIZE,
|
limit=global_config.observation_context_size,
|
||||||
)
|
)
|
||||||
|
|
||||||
chat_talking_prompt = await build_readable_messages(
|
chat_talking_prompt = await build_readable_messages(
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ class NormalChat:
|
|||||||
# 存储此实例的兴趣监控任务
|
# 存储此实例的兴趣监控任务
|
||||||
self.start_time = time.time()
|
self.start_time = time.time()
|
||||||
|
|
||||||
|
self.last_speak_time = 0
|
||||||
|
|
||||||
self._chat_task: Optional[asyncio.Task] = None
|
self._chat_task: Optional[asyncio.Task] = None
|
||||||
logger.info(f"[{self.stream_name}] NormalChat 实例初始化完成。")
|
logger.info(f"[{self.stream_name}] NormalChat 实例初始化完成。")
|
||||||
|
|
||||||
@@ -119,6 +121,8 @@ class NormalChat:
|
|||||||
|
|
||||||
await message_manager.add_message(message_set)
|
await message_manager.add_message(message_set)
|
||||||
|
|
||||||
|
self.last_speak_time = time.time()
|
||||||
|
|
||||||
return first_bot_msg
|
return first_bot_msg
|
||||||
|
|
||||||
# 改为实例方法
|
# 改为实例方法
|
||||||
|
|||||||
@@ -632,7 +632,7 @@ class LLMRequest:
|
|||||||
**params_copy,
|
**params_copy,
|
||||||
}
|
}
|
||||||
if "max_tokens" not in payload and "max_completion_tokens" not in payload:
|
if "max_tokens" not in payload and "max_completion_tokens" not in payload:
|
||||||
payload["max_tokens"] = global_config.max_response_length
|
payload["max_tokens"] = global_config.model_max_output_length
|
||||||
# 如果 payload 中依然存在 max_tokens 且需要转换,在这里进行再次检查
|
# 如果 payload 中依然存在 max_tokens 且需要转换,在这里进行再次检查
|
||||||
if self.model_name.lower() in self.MODELS_NEEDING_TRANSFORMATION and "max_tokens" in payload:
|
if self.model_name.lower() in self.MODELS_NEEDING_TRANSFORMATION and "max_tokens" in payload:
|
||||||
payload["max_completion_tokens"] = payload.pop("max_tokens")
|
payload["max_completion_tokens"] = payload.pop("max_tokens")
|
||||||
|
|||||||
@@ -282,10 +282,10 @@ class RelationshipManager:
|
|||||||
if is_id:
|
if is_id:
|
||||||
person_id = person
|
person_id = person
|
||||||
else:
|
else:
|
||||||
print(f"person: {person}")
|
# print(f"person: {person}")
|
||||||
person_id = person_info_manager.get_person_id(person[0], person[1])
|
person_id = person_info_manager.get_person_id(person[0], person[1])
|
||||||
person_name = await person_info_manager.get_value(person_id, "person_name")
|
person_name = await person_info_manager.get_value(person_id, "person_name")
|
||||||
print(f"person_name: {person_name}")
|
# print(f"person_name: {person_name}")
|
||||||
relationship_value = await person_info_manager.get_value(person_id, "relationship_value")
|
relationship_value = await person_info_manager.get_value(person_id, "relationship_value")
|
||||||
level_num = self.calculate_level_num(relationship_value)
|
level_num = self.calculate_level_num(relationship_value)
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,12 @@ from typing import List
|
|||||||
|
|
||||||
class InfoCatcher:
|
class InfoCatcher:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.chat_history = [] # 聊天历史,长度为三倍使用的上下文
|
self.chat_history = [] # 聊天历史,长度为三倍使用的上下文喵~
|
||||||
self.context_length = global_config.MAX_CONTEXT_SIZE
|
self.context_length = global_config.observation_context_size
|
||||||
self.chat_history_in_thinking = [] # 思考期间的聊天内容
|
self.chat_history_in_thinking = [] # 思考期间的聊天内容喵~
|
||||||
self.chat_history_after_response = [] # 回复后的聊天内容,长度为一倍上下文
|
self.chat_history_after_response = [] # 回复后的聊天内容,长度为一倍上下文喵~
|
||||||
|
|
||||||
self.chat_id = ""
|
self.chat_id = ""
|
||||||
self.response_mode = global_config.response_mode
|
|
||||||
self.trigger_response_text = ""
|
self.trigger_response_text = ""
|
||||||
self.response_text = ""
|
self.response_text = ""
|
||||||
|
|
||||||
@@ -36,10 +35,10 @@ class InfoCatcher:
|
|||||||
"model": "",
|
"model": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
# 使用字典来存储 reasoning 模式的数据
|
# 使用字典来存储 reasoning 模式的数据喵~
|
||||||
self.reasoning_data = {"thinking_log": "", "prompt": "", "response": "", "model": ""}
|
self.reasoning_data = {"thinking_log": "", "prompt": "", "response": "", "model": ""}
|
||||||
|
|
||||||
# 耗时
|
# 耗时喵~
|
||||||
self.timing_results = {
|
self.timing_results = {
|
||||||
"interested_rate_time": 0,
|
"interested_rate_time": 0,
|
||||||
"sub_heartflow_observe_time": 0,
|
"sub_heartflow_observe_time": 0,
|
||||||
@@ -73,15 +72,25 @@ class InfoCatcher:
|
|||||||
self.heartflow_data["sub_heartflow_now"] = current_mind
|
self.heartflow_data["sub_heartflow_now"] = current_mind
|
||||||
|
|
||||||
def catch_after_llm_generated(self, prompt: str, response: str, reasoning_content: str = "", model_name: str = ""):
|
def catch_after_llm_generated(self, prompt: str, response: str, reasoning_content: str = "", model_name: str = ""):
|
||||||
if self.response_mode == "heart_flow":
|
# if self.response_mode == "heart_flow": # 条件判断不需要了喵~
|
||||||
self.heartflow_data["prompt"] = prompt
|
# self.heartflow_data["prompt"] = prompt
|
||||||
self.heartflow_data["response"] = response
|
# self.heartflow_data["response"] = response
|
||||||
self.heartflow_data["model"] = model_name
|
# self.heartflow_data["model"] = model_name
|
||||||
elif self.response_mode == "reasoning":
|
# elif self.response_mode == "reasoning": # 条件判断不需要了喵~
|
||||||
|
# self.reasoning_data["thinking_log"] = reasoning_content
|
||||||
|
# self.reasoning_data["prompt"] = prompt
|
||||||
|
# self.reasoning_data["response"] = response
|
||||||
|
# self.reasoning_data["model"] = model_name
|
||||||
|
|
||||||
|
# 直接记录信息喵~
|
||||||
self.reasoning_data["thinking_log"] = reasoning_content
|
self.reasoning_data["thinking_log"] = reasoning_content
|
||||||
self.reasoning_data["prompt"] = prompt
|
self.reasoning_data["prompt"] = prompt
|
||||||
self.reasoning_data["response"] = response
|
self.reasoning_data["response"] = response
|
||||||
self.reasoning_data["model"] = model_name
|
self.reasoning_data["model"] = model_name
|
||||||
|
# 如果 heartflow 数据也需要通用字段,可以取消下面的注释喵~
|
||||||
|
# self.heartflow_data["prompt"] = prompt
|
||||||
|
# self.heartflow_data["response"] = response
|
||||||
|
# self.heartflow_data["model"] = model_name
|
||||||
|
|
||||||
self.response_text = response
|
self.response_text = response
|
||||||
|
|
||||||
@@ -172,13 +181,13 @@ class InfoCatcher:
|
|||||||
}
|
}
|
||||||
|
|
||||||
def done_catch(self):
|
def done_catch(self):
|
||||||
"""将收集到的信息存储到数据库的 thinking_log 集合中"""
|
"""将收集到的信息存储到数据库的 thinking_log 集合中喵~"""
|
||||||
try:
|
try:
|
||||||
# 将消息对象转换为可序列化的字典
|
# 将消息对象转换为可序列化的字典喵~
|
||||||
|
|
||||||
thinking_log_data = {
|
thinking_log_data = {
|
||||||
"chat_id": self.chat_id,
|
"chat_id": self.chat_id,
|
||||||
"response_mode": self.response_mode,
|
# "response_mode": self.response_mode, # 这个也删掉喵~
|
||||||
"trigger_text": self.trigger_response_text,
|
"trigger_text": self.trigger_response_text,
|
||||||
"response_text": self.response_text,
|
"response_text": self.response_text,
|
||||||
"trigger_info": {
|
"trigger_info": {
|
||||||
@@ -195,18 +204,20 @@ class InfoCatcher:
|
|||||||
"chat_history_after_response": self.message_list_to_dict(self.chat_history_after_response),
|
"chat_history_after_response": self.message_list_to_dict(self.chat_history_after_response),
|
||||||
}
|
}
|
||||||
|
|
||||||
# 根据不同的响应模式添加相应的数据
|
# 根据不同的响应模式添加相应的数据喵~ # 现在直接都加上去好了喵~
|
||||||
if self.response_mode == "heart_flow":
|
# if self.response_mode == "heart_flow":
|
||||||
thinking_log_data["mode_specific_data"] = self.heartflow_data
|
# thinking_log_data["mode_specific_data"] = self.heartflow_data
|
||||||
elif self.response_mode == "reasoning":
|
# elif self.response_mode == "reasoning":
|
||||||
thinking_log_data["mode_specific_data"] = self.reasoning_data
|
# thinking_log_data["mode_specific_data"] = self.reasoning_data
|
||||||
|
thinking_log_data["heartflow_data"] = self.heartflow_data
|
||||||
|
thinking_log_data["reasoning_data"] = self.reasoning_data
|
||||||
|
|
||||||
# 将数据插入到 thinking_log 集合中
|
# 将数据插入到 thinking_log 集合中喵~
|
||||||
db.thinking_log.insert_one(thinking_log_data)
|
db.thinking_log.insert_one(thinking_log_data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"存储思考日志时出错: {str(e)}")
|
print(f"存储思考日志时出错: {str(e)} 喵~")
|
||||||
print(traceback.format_exc())
|
print(traceback.format_exc())
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[inner]
|
[inner]
|
||||||
version = "1.5.1"
|
version = "1.6.0"
|
||||||
|
|
||||||
#----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读----
|
#----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读----
|
||||||
#如果你想要修改配置文件,请在修改后将version的值进行变更
|
#如果你想要修改配置文件,请在修改后将version的值进行变更
|
||||||
@@ -65,33 +65,14 @@ time_zone = "Asia/Shanghai" # 给你的机器人设置时区,可以解决运
|
|||||||
[platforms] # 必填项目,填写每个平台适配器提供的链接
|
[platforms] # 必填项目,填写每个平台适配器提供的链接
|
||||||
nonebot-qq="http://127.0.0.1:18002/api/message"
|
nonebot-qq="http://127.0.0.1:18002/api/message"
|
||||||
|
|
||||||
[response] #群聊的回复策略
|
[chat] #麦麦的聊天通用设置
|
||||||
#一般回复参数
|
allow_focus_mode = true # 是否允许专注聊天状态
|
||||||
model_reasoning_probability = 0.7 # 麦麦回答时选择推理模型 模型的概率
|
# 是否启用heart_flowC(HFC)模式
|
||||||
model_normal_probability = 0.3 # 麦麦回答时选择一般模型 模型的概率
|
|
||||||
|
|
||||||
[heartflow]
|
|
||||||
allow_focus_mode = true # 是否允许进入FOCUSED状态
|
|
||||||
# 是否启用heart_flowC(心流聊天,HFC)模式
|
|
||||||
# 启用后麦麦会自主选择进入heart_flowC模式(持续一段时间),进行主动的观察和回复,并给出回复,比较消耗token
|
# 启用后麦麦会自主选择进入heart_flowC模式(持续一段时间),进行主动的观察和回复,并给出回复,比较消耗token
|
||||||
reply_trigger_threshold = 3.0 # 心流聊天触发阈值,越低越容易进入心流聊天
|
base_normal_chat_num = 3 # 最多允许多少个群进行普通聊天
|
||||||
probability_decay_factor_per_second = 0.2 # 概率衰减因子,越大衰减越快,越高越容易退出心流聊天
|
base_focused_chat_num = 2 # 最多允许多少个群进行专注聊天
|
||||||
default_decay_rate_per_second = 0.98 # 默认衰减率,越大衰减越快,越高越难进入心流聊天
|
|
||||||
|
|
||||||
|
observation_context_size = 15 # 观察到的最长上下文大小,建议15,太短太长都会导致脑袋尖尖
|
||||||
|
|
||||||
sub_heart_flow_stop_time = 500 # 子心流停止时间,超过这个时间没有回复,子心流会停止,间隔 单位秒
|
|
||||||
|
|
||||||
observation_context_size = 20 # 心流观察到的最长上下文大小,超过这个值的上下文会被压缩
|
|
||||||
compressed_length = 5 # 不能大于observation_context_size,心流上下文压缩的最短压缩长度,超过心流观察到的上下文长度,会压缩,最短压缩长度为5
|
|
||||||
compress_length_limit = 5 #最多压缩份数,超过该数值的压缩上下文会被删除
|
|
||||||
|
|
||||||
|
|
||||||
[message]
|
|
||||||
max_context_size = 12 # 麦麦回复时获得的上文数量,建议12,太短太长都会导致脑袋尖尖
|
|
||||||
emoji_chance = 0.2 # 麦麦一般回复时使用表情包的概率,设置为1让麦麦自己决定发不发
|
|
||||||
thinking_timeout = 100 # 麦麦最长思考时间,超过这个时间的思考会放弃(往往是api反应太慢)
|
|
||||||
max_response_length = 256 # 麦麦单次回答的最大token数
|
|
||||||
message_buffer = true # 启用消息缓冲器?启用此项以解决消息的拆分问题,但会使麦麦的回复延迟
|
message_buffer = true # 启用消息缓冲器?启用此项以解决消息的拆分问题,但会使麦麦的回复延迟
|
||||||
|
|
||||||
# 以下是消息过滤,可以根据规则过滤特定消息,将不会读取这些消息
|
# 以下是消息过滤,可以根据规则过滤特定消息,将不会读取这些消息
|
||||||
@@ -106,7 +87,14 @@ ban_msgs_regex = [
|
|||||||
# "\\[CQ:at,qq=\\d+\\]" # 匹配@
|
# "\\[CQ:at,qq=\\d+\\]" # 匹配@
|
||||||
]
|
]
|
||||||
|
|
||||||
[willing] # 一般回复模式的回复意愿设置
|
[normal_chat] #普通聊天
|
||||||
|
#一般回复参数
|
||||||
|
model_reasoning_probability = 0.7 # 麦麦回答时选择推理模型 模型的概率
|
||||||
|
model_normal_probability = 0.3 # 麦麦回答时选择一般模型 模型的概率
|
||||||
|
|
||||||
|
emoji_chance = 0.2 # 麦麦一般回复时使用表情包的概率,设置为1让麦麦自己决定发不发
|
||||||
|
thinking_timeout = 100 # 麦麦最长思考时间,超过这个时间的思考会放弃(往往是api反应太慢)
|
||||||
|
|
||||||
willing_mode = "classical" # 回复意愿模式 —— 经典模式:classical,动态模式:dynamic,mxp模式:mxp,自定义模式:custom(需要你自己实现)
|
willing_mode = "classical" # 回复意愿模式 —— 经典模式:classical,动态模式:dynamic,mxp模式:mxp,自定义模式:custom(需要你自己实现)
|
||||||
response_willing_amplifier = 1 # 麦麦回复意愿放大系数,一般为1
|
response_willing_amplifier = 1 # 麦麦回复意愿放大系数,一般为1
|
||||||
response_interested_rate_amplifier = 1 # 麦麦回复兴趣度放大系数,听到记忆里的内容时放大系数
|
response_interested_rate_amplifier = 1 # 麦麦回复兴趣度放大系数,听到记忆里的内容时放大系数
|
||||||
@@ -115,6 +103,16 @@ emoji_response_penalty = 0 # 表情包回复惩罚系数,设为0为不回复
|
|||||||
mentioned_bot_inevitable_reply = false # 提及 bot 必然回复
|
mentioned_bot_inevitable_reply = false # 提及 bot 必然回复
|
||||||
at_bot_inevitable_reply = false # @bot 必然回复
|
at_bot_inevitable_reply = false # @bot 必然回复
|
||||||
|
|
||||||
|
[focus_chat] #专注聊天
|
||||||
|
reply_trigger_threshold = 3.5 # 专注聊天触发阈值,越低越容易进入专注聊天
|
||||||
|
default_decay_rate_per_second = 0.98 # 默认衰减率,越大衰减越快,越高越难进入专注聊天
|
||||||
|
consecutive_no_reply_threshold = 3 # 连续不回复的阈值,越低越容易结束专注聊天
|
||||||
|
|
||||||
|
# 以下选项暂时无效
|
||||||
|
compressed_length = 5 # 不能大于observation_context_size,心流上下文压缩的最短压缩长度,超过心流观察到的上下文长度,会压缩,最短压缩长度为5
|
||||||
|
compress_length_limit = 5 #最多压缩份数,超过该数值的压缩上下文会被删除
|
||||||
|
|
||||||
|
|
||||||
[emoji]
|
[emoji]
|
||||||
max_emoji_num = 40 # 表情包最大数量
|
max_emoji_num = 40 # 表情包最大数量
|
||||||
max_reach_deletion = true # 开启则在达到最大数量时删除表情包,关闭则达到最大数量时不删除,只是不会继续收集表情包
|
max_reach_deletion = true # 开启则在达到最大数量时删除表情包,关闭则达到最大数量时不删除,只是不会继续收集表情包
|
||||||
@@ -181,6 +179,8 @@ response_max_length = 256 # 回复允许的最大长度
|
|||||||
response_max_sentence_num = 4 # 回复允许的最大句子数
|
response_max_sentence_num = 4 # 回复允许的最大句子数
|
||||||
enable_kaomoji_protection = false # 是否启用颜文字保护
|
enable_kaomoji_protection = false # 是否启用颜文字保护
|
||||||
|
|
||||||
|
model_max_output_length = 256 # 模型单次返回的最大token数
|
||||||
|
|
||||||
[remote] #发送统计信息,主要是看全球有多少只麦麦
|
[remote] #发送统计信息,主要是看全球有多少只麦麦
|
||||||
enable = true
|
enable = true
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user