feat(config): 添加消息缓存系统配置和表达方式过期天数设置

feat(expression_learner): 实现清理过期表达方式功能
fix(context_manager): 根据配置检查消息缓存系统启用状态
This commit is contained in:
Windpicker-owo
2025-11-05 11:54:07 +08:00
parent 26ae2c5b8e
commit 57475b475d
4 changed files with 117 additions and 12 deletions

View File

@@ -132,6 +132,56 @@ class ExpressionLearner:
self.chat_name = stream_name or self.chat_id self.chat_name = stream_name or self.chat_id
self._chat_name_initialized = True self._chat_name_initialized = True
async def cleanup_expired_expressions(self, expiration_days: int | None = None) -> int:
"""
清理过期的表达方式
Args:
expiration_days: 过期天数,超过此天数未激活的表达方式将被删除(不指定则从配置读取)
Returns:
int: 删除的表达方式数量
"""
# 从配置读取过期天数
if expiration_days is None:
expiration_days = global_config.expression.expiration_days
current_time = time.time()
expiration_threshold = current_time - (expiration_days * 24 * 3600)
try:
deleted_count = 0
async with get_db_session() as session:
# 查询过期的表达方式只清理当前chat_id的
query = await session.execute(
select(Expression).where(
(Expression.chat_id == self.chat_id)
& (Expression.last_active_time < expiration_threshold)
)
)
expired_expressions = list(query.scalars())
if expired_expressions:
for expr in expired_expressions:
await session.delete(expr)
deleted_count += 1
await session.commit()
logger.info(f"清理了 {deleted_count} 个过期表达方式(超过 {expiration_days} 天未使用)")
# 清除缓存
from src.common.database.optimization.cache_manager import get_cache
from src.common.database.utils.decorators import generate_cache_key
cache = await get_cache()
await cache.delete(generate_cache_key("chat_expressions", self.chat_id))
else:
logger.debug(f"没有发现过期的表达方式(阈值:{expiration_days} 天)")
return deleted_count
except Exception as e:
logger.error(f"清理过期表达方式失败: {e}")
return 0
def can_learn_for_chat(self) -> bool: def can_learn_for_chat(self) -> bool:
""" """
检查指定聊天流是否允许学习表达 检查指定聊天流是否允许学习表达
@@ -214,6 +264,9 @@ class ExpressionLearner:
try: try:
logger.info(f"为聊天流 {self.chat_name} 触发表达学习") logger.info(f"为聊天流 {self.chat_name} 触发表达学习")
# 🔥 改进3在学习前清理过期的表达方式
await self.cleanup_expired_expressions()
# 学习语言风格 # 学习语言风格
learnt_style = await self.learn_and_store(type="style", num=25) learnt_style = await self.learn_and_store(type="style", num=25)
@@ -397,9 +450,29 @@ class ExpressionLearner:
for chat_id, expr_list in chat_dict.items(): for chat_id, expr_list in chat_dict.items():
async with get_db_session() as session: async with get_db_session() as session:
for new_expr in expr_list: for new_expr in expr_list:
# 查是否存在相似表达方式 # 🔥 改进1查是否存在相同情景或相同表达的数据
# 注意: get_all_by 不支持复杂条件,这里仍需使用 session # 情况1相同 chat_id + type + situation相同情景不同表达
query = await session.execute( query_same_situation = await session.execute(
select(Expression).where(
(Expression.chat_id == chat_id)
& (Expression.type == type)
& (Expression.situation == new_expr["situation"])
)
)
same_situation_expr = query_same_situation.scalar()
# 情况2相同 chat_id + type + style相同表达不同情景
query_same_style = await session.execute(
select(Expression).where(
(Expression.chat_id == chat_id)
& (Expression.type == type)
& (Expression.style == new_expr["style"])
)
)
same_style_expr = query_same_style.scalar()
# 情况3完全相同相同情景+相同表达)
query_exact_match = await session.execute(
select(Expression).where( select(Expression).where(
(Expression.chat_id == chat_id) (Expression.chat_id == chat_id)
& (Expression.type == type) & (Expression.type == type)
@@ -407,16 +480,29 @@ class ExpressionLearner:
& (Expression.style == new_expr["style"]) & (Expression.style == new_expr["style"])
) )
) )
existing_expr = query.scalar() exact_match_expr = query_exact_match.scalar()
if existing_expr:
expr_obj = existing_expr # 优先处理完全匹配的情况
# 50%概率替换内容 if exact_match_expr:
if random.random() < 0.5: # 完全相同增加count更新时间
expr_obj.situation = new_expr["situation"] expr_obj = exact_match_expr
expr_obj.style = new_expr["style"]
expr_obj.count = expr_obj.count + 1 expr_obj.count = expr_obj.count + 1
expr_obj.last_active_time = current_time expr_obj.last_active_time = current_time
logger.debug(f"完全匹配更新count {expr_obj.count}")
elif same_situation_expr:
# 相同情景,不同表达:覆盖旧的表达
logger.info(f"相同情景覆盖:'{same_situation_expr.situation}' 的表达从 '{same_situation_expr.style}' 更新为 '{new_expr['style']}'")
same_situation_expr.style = new_expr["style"]
same_situation_expr.count = same_situation_expr.count + 1
same_situation_expr.last_active_time = current_time
elif same_style_expr:
# 相同表达,不同情景:覆盖旧的情景
logger.info(f"相同表达覆盖:'{same_style_expr.style}' 的情景从 '{same_style_expr.situation}' 更新为 '{new_expr['situation']}'")
same_style_expr.situation = new_expr["situation"]
same_style_expr.count = same_style_expr.count + 1
same_style_expr.last_active_time = current_time
else: else:
# 完全新的表达方式:创建新记录
new_expression = Expression( new_expression = Expression(
situation=new_expr["situation"], situation=new_expr["situation"],
style=new_expr["style"], style=new_expr["style"],
@@ -427,6 +513,7 @@ class ExpressionLearner:
create_date=current_time, # 手动设置创建日期 create_date=current_time, # 手动设置创建日期
) )
session.add(new_expression) session.add(new_expression)
logger.debug(f"新增表达方式:{new_expr['situation']} -> {new_expr['style']}")
# 限制最大数量 - 使用 get_all_by_sorted 获取排序结果 # 限制最大数量 - 使用 get_all_by_sorted 获取排序结果
exprs_result = await session.execute( exprs_result = await session.execute(

View File

@@ -69,7 +69,11 @@ class SingleStreamContextManager:
try: try:
from .message_manager import message_manager as mm from .message_manager import message_manager as mm
message_manager = mm message_manager = mm
use_cache_system = message_manager.is_running # 检查配置是否启用消息缓存系统
cache_enabled = global_config.chat.enable_message_cache
use_cache_system = message_manager.is_running and cache_enabled
if not cache_enabled:
logger.debug(f"消息缓存系统已在配置中禁用")
except Exception as e: except Exception as e:
logger.debug(f"MessageManager不可用使用直接添加: {e}") logger.debug(f"MessageManager不可用使用直接添加: {e}")
use_cache_system = False use_cache_system = False

View File

@@ -120,6 +120,10 @@ class ChatConfig(ValidatedConfigBase):
timestamp_display_mode: Literal["normal", "normal_no_YMD", "relative"] = Field( timestamp_display_mode: Literal["normal", "normal_no_YMD", "relative"] = Field(
default="normal_no_YMD", description="时间戳显示模式" default="normal_no_YMD", description="时间戳显示模式"
) )
# 消息缓存系统配置
enable_message_cache: bool = Field(
default=True, description="是否启用消息缓存系统(启用后,处理中收到的消息会被缓存,处理完成后统一刷新到未读列表)"
)
# 消息打断系统配置 - 线性概率模型 # 消息打断系统配置 - 线性概率模型
interruption_enabled: bool = Field(default=True, description="是否启用消息打断系统") interruption_enabled: bool = Field(default=True, description="是否启用消息打断系统")
allow_reply_interruption: bool = Field( allow_reply_interruption: bool = Field(
@@ -181,6 +185,10 @@ class ExpressionConfig(ValidatedConfigBase):
default="classic", default="classic",
description="表达方式选择模式: classic=经典LLM评估, exp_model=机器学习模型预测" description="表达方式选择模式: classic=经典LLM评估, exp_model=机器学习模型预测"
) )
expiration_days: int = Field(
default=90,
description="表达方式过期天数,超过此天数未激活的表达方式将被清理"
)
rules: list[ExpressionRule] = Field(default_factory=list, description="表达学习规则") rules: list[ExpressionRule] = Field(default_factory=list, description="表达学习规则")
@staticmethod @staticmethod

View File

@@ -1,5 +1,5 @@
[inner] [inner]
version = "7.5.7" version = "7.5.8"
#----以下是给开发人员阅读的如果你只是部署了MoFox-Bot不需要阅读---- #----以下是给开发人员阅读的如果你只是部署了MoFox-Bot不需要阅读----
#如果你想要修改配置文件请递增version的值 #如果你想要修改配置文件请递增version的值
@@ -107,6 +107,9 @@ compress_identity = true # 是否压缩身份,压缩后会精简身份信息
# - "exp_model": 表达模型模式,使用机器学习模型预测最合适的表达 # - "exp_model": 表达模型模式,使用机器学习模型预测最合适的表达
mode = "classic" mode = "classic"
# expiration_days: 表达方式过期天数,超过此天数未激活的表达方式将被清理
expiration_days = 3
# rules是一个列表每个元素都是一个学习规则 # rules是一个列表每个元素都是一个学习规则
# chat_stream_id: 聊天流ID格式为 "platform:id:type",例如 "qq:123456:private"。空字符串""表示全局配置 # chat_stream_id: 聊天流ID格式为 "platform:id:type",例如 "qq:123456:private"。空字符串""表示全局配置
# use_expression: 是否使用学到的表达 (true/false) # use_expression: 是否使用学到的表达 (true/false)
@@ -139,6 +142,9 @@ allow_reply_self = false # 是否允许回复自己说的话
max_context_size = 25 # 上下文长度 max_context_size = 25 # 上下文长度
thinking_timeout = 40 # MoFox-Bot一次回复最长思考规划时间超过这个时间的思考会放弃往往是api反应太慢 thinking_timeout = 40 # MoFox-Bot一次回复最长思考规划时间超过这个时间的思考会放弃往往是api反应太慢
# 消息缓存系统配置
enable_message_cache = true # 是否启用消息缓存系统(启用后,处理中收到的消息会被缓存,处理完成后统一刷新到未读列表)
# 消息打断系统配置 - 反比例函数概率模型 # 消息打断系统配置 - 反比例函数概率模型
interruption_enabled = true # 是否启用消息打断系统 interruption_enabled = true # 是否启用消息打断系统
allow_reply_interruption = false # 是否允许在正在生成回复时打断true=允许打断回复false=回复期间不允许打断) allow_reply_interruption = false # 是否允许在正在生成回复时打断true=允许打断回复false=回复期间不允许打断)