remove:移除表达反思功能
This commit is contained in:
@@ -1,24 +0,0 @@
|
|||||||
你是一个表达反思助手。Bot之前询问了表达方式是否合适。
|
|
||||||
你需要根据提供的上下文对话,判断是否对该表达方式做出了肯定或否定的评价。
|
|
||||||
|
|
||||||
**询问内容**
|
|
||||||
情景: {situation}
|
|
||||||
风格: {style}
|
|
||||||
|
|
||||||
**上下文对话**
|
|
||||||
{context_block}
|
|
||||||
|
|
||||||
**判断要求**
|
|
||||||
1. 判断对话中是否包含对上述询问的回答。
|
|
||||||
2. 如果是,判断是肯定(Approve)还是否定(Reject),或者是提供了修改意见。
|
|
||||||
3. 如果不是回答,或者是无关内容,请返回 "Ignore"。
|
|
||||||
4. 如果是否定并提供了修改意见,请提取修正后的情景和风格。
|
|
||||||
|
|
||||||
请输出JSON格式:
|
|
||||||
```json
|
|
||||||
{{
|
|
||||||
"judgment": "Approve" | "Reject" | "Ignore",
|
|
||||||
"corrected_situation": "...", // 如果有修改意见,提取修正后的情景,否则留空
|
|
||||||
"corrected_style": "..." // 如果有修改意见,提取修正后的风格,否则留空
|
|
||||||
}}
|
|
||||||
```
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
import json
|
|
||||||
import re
|
|
||||||
import time
|
|
||||||
from typing import TYPE_CHECKING, Any, Optional
|
|
||||||
|
|
||||||
from json_repair import repair_json
|
|
||||||
|
|
||||||
from src.chat.utils.chat_message_builder import (
|
|
||||||
build_readable_messages,
|
|
||||||
get_raw_msg_by_timestamp_with_chat,
|
|
||||||
)
|
|
||||||
from src.common.database.database import get_db_session
|
|
||||||
from src.common.logger import get_logger
|
|
||||||
from src.config.config import model_config
|
|
||||||
from src.llm_models.utils_model import LLMRequest
|
|
||||||
from src.prompt.prompt_manager import prompt_manager
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from src.common.data_models.expression_data_model import MaiExpression
|
|
||||||
|
|
||||||
judge_model = LLMRequest(model_set=model_config.model_task_config.tool_use, request_type="reflect.tracker")
|
|
||||||
|
|
||||||
logger = get_logger("reflect_tracker")
|
|
||||||
|
|
||||||
|
|
||||||
class ReflectTracker:
|
|
||||||
def __init__(self, session_id: str):
|
|
||||||
self.session_id = session_id
|
|
||||||
self.last_check_msg_count = 0
|
|
||||||
self.max_msg_count = 30
|
|
||||||
self.max_duration = 15 * 60 # 15 分钟
|
|
||||||
self.expression: Optional["MaiExpression"] = None # 当前正在追踪的表达,由外部设置
|
|
||||||
|
|
||||||
# 运行状态
|
|
||||||
self.tracking = False
|
|
||||||
self.tracking_start_time: float = 0.0
|
|
||||||
|
|
||||||
def register_expression_and_track(self, expression: "MaiExpression"):
|
|
||||||
"""注册需要追踪的表达"""
|
|
||||||
if self.tracking:
|
|
||||||
raise RuntimeError("ReflectTracker is already tracking an expression.")
|
|
||||||
self.expression = expression
|
|
||||||
self.tracking = True
|
|
||||||
self.tracking_start_time = time.time()
|
|
||||||
|
|
||||||
def reset_tracker(self):
|
|
||||||
"""重置追踪状态"""
|
|
||||||
self.expression = None
|
|
||||||
self.tracking = False
|
|
||||||
self.last_check_msg_count = 0
|
|
||||||
|
|
||||||
# TODO test it
|
|
||||||
async def trigger_tracker(self) -> bool:
|
|
||||||
"""
|
|
||||||
触发追踪检查
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
return (bool): 如果返回True,表示追踪完成,Tracker运行结束(运行状态置为`False`);如果返回False,表示继续追踪
|
|
||||||
"""
|
|
||||||
# 对于没有正在追踪的表达,直接返回False
|
|
||||||
if not self.tracking or not self.expression:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Type narrowing: expression is guaranteed non-None when tracking
|
|
||||||
assert self.expression is not None
|
|
||||||
expr = self.expression
|
|
||||||
|
|
||||||
# 检查是否超时(无论是消息数量还是时间)
|
|
||||||
if time.time() - self.tracking_start_time > self.max_duration:
|
|
||||||
self.reset_tracker()
|
|
||||||
return True
|
|
||||||
|
|
||||||
# TODO: 完成追踪检查逻辑
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
from rich.traceback import install
|
|
||||||
from sqlmodel import select
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
import random
|
|
||||||
import time
|
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
|
||||||
from src.config.config import global_config
|
|
||||||
from src.common.database.database_model import Expression
|
|
||||||
from src.common.database.database import get_db_session
|
|
||||||
from src.common.data_models.expression_data_model import MaiExpression
|
|
||||||
from src.common.utils.utils_session import SessionUtils
|
|
||||||
from .expression_reflect_tracker import ReflectTracker
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from src.config.official_configs import TargetItem
|
|
||||||
|
|
||||||
logger = get_logger("expression_reflector")
|
|
||||||
|
|
||||||
install(extra_lines=3)
|
|
||||||
|
|
||||||
LOG_PREFIX = "[Expression Reflector]"
|
|
||||||
|
|
||||||
|
|
||||||
class ExpressionReflector:
|
|
||||||
"""表达反思器,管理单个聊天流的表达反思提问,使用每个session_id独立的实例"""
|
|
||||||
|
|
||||||
def __init__(self, session_id: str):
|
|
||||||
self.session_id = session_id
|
|
||||||
self.last_ask_time: float = time.time()
|
|
||||||
self.reflect_tracker: ReflectTracker = ReflectTracker(session_id)
|
|
||||||
|
|
||||||
async def check_and_ask(self) -> bool:
|
|
||||||
"""
|
|
||||||
检查是否需要提问表达反思,如果需要则提问
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: 是否执行了提问
|
|
||||||
"""
|
|
||||||
if not await self.check_need_ask():
|
|
||||||
return False
|
|
||||||
|
|
||||||
operator_config = global_config.expression.manual_reflect_operator_id
|
|
||||||
if not operator_config:
|
|
||||||
logger.debug(f"{LOG_PREFIX} Operator ID 未配置,跳过")
|
|
||||||
return False
|
|
||||||
|
|
||||||
if await self.ask_reflection(operator_config):
|
|
||||||
self.last_ask_time = time.time()
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def check_need_ask(self) -> bool:
|
|
||||||
"""
|
|
||||||
检查是否需要提问表达反思
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: 是否执行了提问
|
|
||||||
"""
|
|
||||||
if not global_config.expression.expression_manual_reflect:
|
|
||||||
logger.debug(f"{LOG_PREFIX} 表达反思功能未启用,跳过")
|
|
||||||
return False
|
|
||||||
logger.debug(f"{LOG_PREFIX} 开始检查是否需要提问 (session_id: {self.session_id})")
|
|
||||||
operator_config = global_config.expression.manual_reflect_operator_id
|
|
||||||
if not operator_config:
|
|
||||||
logger.debug(f"{LOG_PREFIX} Operator ID 未配置,跳过")
|
|
||||||
return False
|
|
||||||
|
|
||||||
if self.reflect_tracker.tracking:
|
|
||||||
logger.info(f"{LOG_PREFIX} Operator {operator_config} 已有活跃的 Tracker,跳过本次提问")
|
|
||||||
return False
|
|
||||||
|
|
||||||
if allow_reflect_list := global_config.expression.allow_reflect:
|
|
||||||
# 转换配置项为session_id列表
|
|
||||||
allow_reflect_session_ids = [
|
|
||||||
self._parse_config_item_2_session_id(stream_config) for stream_config in allow_reflect_list
|
|
||||||
]
|
|
||||||
if self.session_id not in allow_reflect_session_ids:
|
|
||||||
logger.info(f"{LOG_PREFIX} 当前聊天流 {self.session_id} 不在允许列表中,跳过")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 检查上一次提问时间
|
|
||||||
current_time = time.time()
|
|
||||||
time_since_last_ask = current_time - self.last_ask_time
|
|
||||||
|
|
||||||
# 随机选择10-15分钟间隔
|
|
||||||
ask_interval = random.uniform(10 * 60, 15 * 60)
|
|
||||||
if time_since_last_ask < ask_interval:
|
|
||||||
logger.info(
|
|
||||||
f"{LOG_PREFIX} 距离上次提问时间 {time_since_last_ask:.2f} 秒,未达到随机间隔 {ask_interval:.2f} 秒,跳过"
|
|
||||||
)
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def ask_reflection(self, operator_config: "TargetItem") -> bool:
|
|
||||||
"""执行提问表达反思的操作"""
|
|
||||||
# 选取未检查过的表达
|
|
||||||
logger.info(f"{LOG_PREFIX} 查询未检查且未拒绝的表达")
|
|
||||||
try:
|
|
||||||
with get_db_session() as session:
|
|
||||||
statement = select(Expression).filter_by(checked=False, rejected=False).limit(50)
|
|
||||||
results = session.exec(statement).all()
|
|
||||||
if not results:
|
|
||||||
logger.info(f"{LOG_PREFIX} 未找到未检查且未拒绝的表达")
|
|
||||||
return False
|
|
||||||
logger.info(f"{LOG_PREFIX} 找到 {len(results)} 个未检查且未拒绝的表达")
|
|
||||||
|
|
||||||
except Exception as selected_expression:
|
|
||||||
logger.error(f"{LOG_PREFIX} 查询表达时发生错误: {selected_expression}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 随机选取一个表达进行提问
|
|
||||||
selected_expression = MaiExpression.from_db_instance(random.choice(results))
|
|
||||||
item_id = selected_expression.item_id
|
|
||||||
situation = selected_expression.situation
|
|
||||||
style = selected_expression.style
|
|
||||||
logger.info(f"{LOG_PREFIX} 随机选择了表达 ID: {item_id}, Situation: {situation}, Style: {style}")
|
|
||||||
|
|
||||||
ask_text = (
|
|
||||||
f"我正在学习新的表达方式,请帮我看看这个是否合适?\n\n"
|
|
||||||
f"**学习到的表达信息**\n"
|
|
||||||
f"- 情景 (Situation): {situation}\n"
|
|
||||||
f"- 风格 (Style): {style}\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
# TODO: 在发送相关API重构完成后完成发送给operator的逻辑
|
|
||||||
|
|
||||||
self.reflect_tracker.register_expression_and_track(selected_expression)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _parse_config_item_2_session_id(self, config_item: "TargetItem") -> str:
|
|
||||||
if config_item.rule_type == "group":
|
|
||||||
return SessionUtils.calculate_session_id(config_item.platform, group_id=str(config_item.item_id))
|
|
||||||
else:
|
|
||||||
return SessionUtils.calculate_session_id(config_item.platform, user_id=str(config_item.item_id))
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
import random
|
|
||||||
import time
|
|
||||||
from typing import Optional, Dict
|
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
|
||||||
from src.common.database.database_model import Expression
|
|
||||||
from src.config.config import global_config
|
|
||||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
|
||||||
from src.plugin_system.apis import send_api
|
|
||||||
|
|
||||||
logger = get_logger("expression_reflector")
|
|
||||||
|
|
||||||
|
|
||||||
class ExpressionReflector:
|
|
||||||
"""表达反思器,管理单个聊天流的表达反思提问"""
|
|
||||||
|
|
||||||
def __init__(self, chat_id: str):
|
|
||||||
self.chat_id = chat_id
|
|
||||||
self.last_ask_time: float = 0.0
|
|
||||||
|
|
||||||
async def check_and_ask(self) -> bool:
|
|
||||||
"""
|
|
||||||
检查是否需要提问表达反思,如果需要则提问
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: 是否执行了提问
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
logger.debug(f"[Expression Reflection] 开始检查是否需要提问 (stream_id: {self.chat_id})")
|
|
||||||
|
|
||||||
if not global_config.expression.expression_manual_reflect:
|
|
||||||
logger.debug("[Expression Reflection] 表达反思功能未启用,跳过")
|
|
||||||
return False
|
|
||||||
|
|
||||||
operator_config = global_config.expression.manual_reflect_operator_id
|
|
||||||
if not operator_config:
|
|
||||||
logger.debug("[Expression Reflection] Operator ID 未配置,跳过")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 检查是否在允许列表中
|
|
||||||
allow_reflect = global_config.expression.allow_reflect
|
|
||||||
if allow_reflect:
|
|
||||||
# 将 allow_reflect 中的 platform:id:type 格式转换为 chat_id 列表
|
|
||||||
allow_reflect_chat_ids = []
|
|
||||||
for stream_config in allow_reflect:
|
|
||||||
parsed_chat_id = global_config.expression._parse_stream_config_to_chat_id(stream_config)
|
|
||||||
if parsed_chat_id:
|
|
||||||
allow_reflect_chat_ids.append(parsed_chat_id)
|
|
||||||
else:
|
|
||||||
logger.warning(f"[Expression Reflection] 无法解析 allow_reflect 配置项: {stream_config}")
|
|
||||||
|
|
||||||
if self.chat_id not in allow_reflect_chat_ids:
|
|
||||||
logger.info(f"[Expression Reflection] 当前聊天流 {self.chat_id} 不在允许列表中,跳过")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 检查上一次提问时间
|
|
||||||
current_time = time.time()
|
|
||||||
time_since_last_ask = current_time - self.last_ask_time
|
|
||||||
|
|
||||||
# 5-10分钟间隔,随机选择
|
|
||||||
min_interval = 10 * 60 # 5分钟
|
|
||||||
max_interval = 15 * 60 # 10分钟
|
|
||||||
interval = random.uniform(min_interval, max_interval)
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
f"[Expression Reflection] 上次提问时间: {self.last_ask_time:.2f}, 当前时间: {current_time:.2f}, 已过时间: {time_since_last_ask:.2f}秒 ({time_since_last_ask / 60:.2f}分钟), 需要间隔: {interval:.2f}秒 ({interval / 60:.2f}分钟)"
|
|
||||||
)
|
|
||||||
|
|
||||||
if time_since_last_ask < interval:
|
|
||||||
remaining_time = interval - time_since_last_ask
|
|
||||||
logger.info(
|
|
||||||
f"[Expression Reflection] 距离上次提问时间不足,还需等待 {remaining_time:.2f}秒 ({remaining_time / 60:.2f}分钟),跳过"
|
|
||||||
)
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 检查是否已经有针对该 Operator 的 Tracker 在运行
|
|
||||||
logger.info(f"[Expression Reflection] 检查 Operator {operator_config} 是否已有活跃的 Tracker")
|
|
||||||
if await _check_tracker_exists(operator_config):
|
|
||||||
logger.info(f"[Expression Reflection] Operator {operator_config} 已有活跃的 Tracker,跳过本次提问")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 获取未检查的表达
|
|
||||||
try:
|
|
||||||
logger.info("[Expression Reflection] 查询未检查且未拒绝的表达")
|
|
||||||
expressions = Expression.select().where((~Expression.checked) & (~Expression.rejected)).limit(50)
|
|
||||||
|
|
||||||
expr_list = list(expressions)
|
|
||||||
logger.info(f"[Expression Reflection] 找到 {len(expr_list)} 个候选表达")
|
|
||||||
|
|
||||||
if not expr_list:
|
|
||||||
logger.info("[Expression Reflection] 没有可用的表达,跳过")
|
|
||||||
return False
|
|
||||||
|
|
||||||
target_expr: Expression = random.choice(expr_list)
|
|
||||||
logger.info(
|
|
||||||
f"[Expression Reflection] 随机选择了表达 ID: {target_expr.id}, Situation: {target_expr.situation}, Style: {target_expr.style}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 生成询问文本
|
|
||||||
ask_text = _generate_ask_text(target_expr)
|
|
||||||
if not ask_text:
|
|
||||||
logger.warning("[Expression Reflection] 生成询问文本失败,跳过")
|
|
||||||
return False
|
|
||||||
|
|
||||||
logger.info(f"[Expression Reflection] 准备向 Operator {operator_config} 发送提问")
|
|
||||||
# 发送给 Operator
|
|
||||||
await _send_to_operator(operator_config, ask_text, target_expr)
|
|
||||||
|
|
||||||
# 更新上一次提问时间
|
|
||||||
self.last_ask_time = current_time
|
|
||||||
logger.info(f"[Expression Reflection] 提问成功,已更新上次提问时间为 {current_time:.2f}")
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"[Expression Reflection] 检查或提问过程中出错: {e}")
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return False
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"[Expression Reflection] 检查或提问过程中出错: {e}")
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class ExpressionReflectorManager:
|
|
||||||
"""表达反思管理器,管理多个聊天流的表达反思实例"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.reflectors: Dict[str, ExpressionReflector] = {}
|
|
||||||
|
|
||||||
def get_or_create_reflector(self, chat_id: str) -> ExpressionReflector:
|
|
||||||
"""获取或创建指定聊天流的表达反思实例"""
|
|
||||||
if chat_id not in self.reflectors:
|
|
||||||
self.reflectors[chat_id] = ExpressionReflector(chat_id)
|
|
||||||
return self.reflectors[chat_id]
|
|
||||||
|
|
||||||
|
|
||||||
# 创建全局实例
|
|
||||||
expression_reflector_manager = ExpressionReflectorManager()
|
|
||||||
|
|
||||||
|
|
||||||
async def _check_tracker_exists(operator_config: str) -> bool:
|
|
||||||
"""检查指定 Operator 是否已有活跃的 Tracker"""
|
|
||||||
from src.bw_learner.reflect_tracker import reflect_tracker_manager
|
|
||||||
|
|
||||||
chat_manager = get_chat_manager()
|
|
||||||
chat_stream = None
|
|
||||||
|
|
||||||
# 尝试解析配置字符串 "platform:id:type"
|
|
||||||
parts = operator_config.split(":")
|
|
||||||
if len(parts) == 3:
|
|
||||||
platform = parts[0]
|
|
||||||
id_str = parts[1]
|
|
||||||
stream_type = parts[2]
|
|
||||||
|
|
||||||
user_info = None
|
|
||||||
group_info = None
|
|
||||||
|
|
||||||
from maim_message import UserInfo, GroupInfo
|
|
||||||
|
|
||||||
if stream_type == "group":
|
|
||||||
group_info = GroupInfo(group_id=id_str, platform=platform)
|
|
||||||
user_info = UserInfo(user_id="system", user_nickname="System", platform=platform)
|
|
||||||
elif stream_type == "private":
|
|
||||||
user_info = UserInfo(user_id=id_str, platform=platform, user_nickname="Operator")
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if user_info:
|
|
||||||
try:
|
|
||||||
chat_stream = await chat_manager.get_or_create_stream(platform, user_info, group_info)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to get or create chat stream for checking tracker: {e}")
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
chat_stream = chat_manager.get_stream(operator_config)
|
|
||||||
|
|
||||||
if not chat_stream:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return reflect_tracker_manager.get_tracker(chat_stream.stream_id) is not None
|
|
||||||
|
|
||||||
|
|
||||||
def _generate_ask_text(expr: Expression) -> Optional[str]:
|
|
||||||
try:
|
|
||||||
ask_text = (
|
|
||||||
f"我正在学习新的表达方式,请帮我看看这个是否合适?\n\n"
|
|
||||||
f"**学习到的表达信息**\n"
|
|
||||||
f"- 情景 (Situation): {expr.situation}\n"
|
|
||||||
f"- 风格 (Style): {expr.style}\n"
|
|
||||||
)
|
|
||||||
return ask_text
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to generate ask text: {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
async def _send_to_operator(operator_config: str, text: str, expr: Expression):
|
|
||||||
chat_manager = get_chat_manager()
|
|
||||||
chat_stream = None
|
|
||||||
|
|
||||||
# 尝试解析配置字符串 "platform:id:type"
|
|
||||||
parts = operator_config.split(":")
|
|
||||||
if len(parts) == 3:
|
|
||||||
platform = parts[0]
|
|
||||||
id_str = parts[1]
|
|
||||||
stream_type = parts[2]
|
|
||||||
|
|
||||||
user_info = None
|
|
||||||
group_info = None
|
|
||||||
|
|
||||||
from maim_message import UserInfo, GroupInfo
|
|
||||||
|
|
||||||
if stream_type == "group":
|
|
||||||
group_info = GroupInfo(group_id=id_str, platform=platform)
|
|
||||||
user_info = UserInfo(user_id="system", user_nickname="System", platform=platform)
|
|
||||||
elif stream_type == "private":
|
|
||||||
user_info = UserInfo(user_id=id_str, platform=platform, user_nickname="Operator")
|
|
||||||
else:
|
|
||||||
logger.warning(f"Unknown stream type in operator config: {stream_type}")
|
|
||||||
return
|
|
||||||
|
|
||||||
if user_info:
|
|
||||||
try:
|
|
||||||
chat_stream = await chat_manager.get_or_create_stream(platform, user_info, group_info)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to get or create chat stream for operator {operator_config}: {e}")
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
chat_stream = chat_manager.get_stream(operator_config)
|
|
||||||
|
|
||||||
if not chat_stream:
|
|
||||||
logger.warning(f"Could not find or create chat stream for operator: {operator_config}")
|
|
||||||
return
|
|
||||||
|
|
||||||
stream_id = chat_stream.stream_id
|
|
||||||
|
|
||||||
# 注册 Tracker
|
|
||||||
from src.bw_learner.reflect_tracker import ReflectTracker, reflect_tracker_manager
|
|
||||||
|
|
||||||
tracker = ReflectTracker(chat_stream=chat_stream, expression=expr, created_time=time.time())
|
|
||||||
reflect_tracker_manager.add_tracker(stream_id, tracker)
|
|
||||||
|
|
||||||
# 发送消息
|
|
||||||
await send_api.text_to_stream(text=text, stream_id=stream_id, typing=True)
|
|
||||||
logger.info(f"Sent expression reflect query to operator {operator_config} for expr {expr.id}")
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
import time
|
|
||||||
from typing import Optional, Dict, TYPE_CHECKING
|
|
||||||
from src.common.logger import get_logger
|
|
||||||
from src.common.database.database_model import Expression
|
|
||||||
from src.llm_models.utils_model import LLMRequest
|
|
||||||
from src.prompt.prompt_manager import prompt_manager
|
|
||||||
from src.config.config import model_config
|
|
||||||
from src.chat.message_receive.chat_manager import BotChatSession
|
|
||||||
from src.chat.utils.chat_message_builder import (
|
|
||||||
get_raw_msg_by_timestamp_with_chat,
|
|
||||||
build_readable_messages,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger("reflect_tracker")
|
|
||||||
|
|
||||||
|
|
||||||
class ReflectTracker:
|
|
||||||
def __init__(self, chat_stream: BotChatSession, expression: Expression, created_time: float):
|
|
||||||
self.chat_stream = chat_stream
|
|
||||||
self.expression = expression
|
|
||||||
self.created_time = created_time
|
|
||||||
# self.message_count = 0 # Replaced by checking message list length
|
|
||||||
self.last_check_msg_count = 0
|
|
||||||
self.max_message_count = 30
|
|
||||||
self.max_duration = 15 * 60 # 15 minutes
|
|
||||||
|
|
||||||
# LLM for judging response
|
|
||||||
self.judge_model = LLMRequest(model_set=model_config.model_task_config.tool_use, request_type="reflect.tracker")
|
|
||||||
|
|
||||||
async def trigger_tracker(self) -> bool:
|
|
||||||
"""
|
|
||||||
触发追踪检查
|
|
||||||
Returns: True if resolved (should destroy tracker), False otherwise
|
|
||||||
"""
|
|
||||||
# Check timeout
|
|
||||||
if time.time() - self.created_time > self.max_duration:
|
|
||||||
logger.info(f"ReflectTracker for expr {self.expression.id} timed out (duration).")
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Fetch messages since creation
|
|
||||||
msg_list = get_raw_msg_by_timestamp_with_chat(
|
|
||||||
chat_id=self.chat_stream.session_id,
|
|
||||||
timestamp_start=self.created_time,
|
|
||||||
timestamp_end=time.time(),
|
|
||||||
)
|
|
||||||
|
|
||||||
current_msg_count = len(msg_list)
|
|
||||||
|
|
||||||
# Check message limit
|
|
||||||
if current_msg_count > self.max_message_count:
|
|
||||||
logger.info(f"ReflectTracker for expr {self.expression.id} timed out (message count).")
|
|
||||||
return True
|
|
||||||
|
|
||||||
# If no new messages since last check, skip
|
|
||||||
if current_msg_count <= self.last_check_msg_count:
|
|
||||||
return False
|
|
||||||
|
|
||||||
self.last_check_msg_count = current_msg_count
|
|
||||||
|
|
||||||
# Build context block
|
|
||||||
# Use simple readable format
|
|
||||||
context_block = build_readable_messages(
|
|
||||||
msg_list,
|
|
||||||
replace_bot_name=True,
|
|
||||||
timestamp_mode="relative",
|
|
||||||
read_mark=0.0,
|
|
||||||
show_actions=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
# LLM Judge
|
|
||||||
try:
|
|
||||||
prompt_template = prompt_manager.get_prompt("reflect_judge")
|
|
||||||
prompt_template.add_context("situation", str(self.expression.situation))
|
|
||||||
prompt_template.add_context("style", str(self.expression.style))
|
|
||||||
prompt_template.add_context("context_block", context_block)
|
|
||||||
prompt = await prompt_manager.render_prompt(prompt_template)
|
|
||||||
|
|
||||||
logger.info(f"ReflectTracker LLM Prompt: {prompt}")
|
|
||||||
|
|
||||||
response, _ = await self.judge_model.generate_response_async(prompt, temperature=0.1)
|
|
||||||
|
|
||||||
logger.info(f"ReflectTracker LLM Response: {response}")
|
|
||||||
|
|
||||||
# Parse JSON
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
from json_repair import repair_json
|
|
||||||
|
|
||||||
json_pattern = r"```json\s*(.*?)\s*```"
|
|
||||||
matches = re.findall(json_pattern, response, re.DOTALL) or [response]
|
|
||||||
|
|
||||||
json_obj = json.loads(repair_json(matches[0]))
|
|
||||||
|
|
||||||
judgment = json_obj.get("judgment")
|
|
||||||
|
|
||||||
if judgment == "Approve":
|
|
||||||
self.expression.checked = True
|
|
||||||
self.expression.rejected = False
|
|
||||||
self.expression.modified_by = "ai" # 通过LLM判断也标记为ai
|
|
||||||
self.expression.save()
|
|
||||||
logger.info(f"Expression {self.expression.id} approved by operator.")
|
|
||||||
return True
|
|
||||||
|
|
||||||
elif judgment == "Reject":
|
|
||||||
self.expression.checked = True
|
|
||||||
self.expression.modified_by = "ai" # 通过LLM判断也标记为ai
|
|
||||||
corrected_situation = json_obj.get("corrected_situation")
|
|
||||||
corrected_style = json_obj.get("corrected_style")
|
|
||||||
|
|
||||||
# 检查是否有更新
|
|
||||||
has_update = bool(corrected_situation or corrected_style)
|
|
||||||
|
|
||||||
if corrected_situation:
|
|
||||||
self.expression.situation = corrected_situation
|
|
||||||
if corrected_style:
|
|
||||||
self.expression.style = corrected_style
|
|
||||||
|
|
||||||
# 如果拒绝但未更新,标记为 rejected=1
|
|
||||||
self.expression.rejected = not has_update
|
|
||||||
|
|
||||||
self.expression.save()
|
|
||||||
|
|
||||||
if has_update:
|
|
||||||
logger.info(
|
|
||||||
f"Expression {self.expression.id} rejected and updated by operator. New situation: {corrected_situation}, New style: {corrected_style}"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
logger.info(
|
|
||||||
f"Expression {self.expression.id} rejected but no correction provided, marked as rejected=1."
|
|
||||||
)
|
|
||||||
return True
|
|
||||||
|
|
||||||
elif judgment == "Ignore":
|
|
||||||
logger.info(f"ReflectTracker for expr {self.expression.id} judged as Ignore.")
|
|
||||||
return False
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Error in ReflectTracker check: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
# Global manager for trackers
|
|
||||||
class ReflectTrackerManager:
|
|
||||||
def __init__(self):
|
|
||||||
self.trackers: Dict[str, ReflectTracker] = {} # chat_id -> tracker
|
|
||||||
|
|
||||||
def add_tracker(self, chat_id: str, tracker: ReflectTracker):
|
|
||||||
self.trackers[chat_id] = tracker
|
|
||||||
|
|
||||||
def get_tracker(self, chat_id: str) -> Optional[ReflectTracker]:
|
|
||||||
return self.trackers.get(chat_id)
|
|
||||||
|
|
||||||
def remove_tracker(self, chat_id: str):
|
|
||||||
if chat_id in self.trackers:
|
|
||||||
del self.trackers[chat_id]
|
|
||||||
|
|
||||||
|
|
||||||
reflect_tracker_manager = ReflectTrackerManager()
|
|
||||||
@@ -252,28 +252,6 @@ class BrainChatting:
|
|||||||
recent_messages_list = []
|
recent_messages_list = []
|
||||||
_reply_text = "" # 初始化reply_text变量,避免UnboundLocalError
|
_reply_text = "" # 初始化reply_text变量,避免UnboundLocalError
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# ReflectTracker Check
|
|
||||||
# 在每次回复前检查一次上下文,看是否有反思问题得到了解答
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
from src.bw_learner.reflect_tracker import reflect_tracker_manager
|
|
||||||
|
|
||||||
tracker = reflect_tracker_manager.get_tracker(self.stream_id)
|
|
||||||
if tracker:
|
|
||||||
resolved = await tracker.trigger_tracker()
|
|
||||||
if resolved:
|
|
||||||
reflect_tracker_manager.remove_tracker(self.stream_id)
|
|
||||||
logger.info(f"{self.log_prefix} ReflectTracker resolved and removed.")
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# Expression Reflection Check
|
|
||||||
# 检查是否需要提问表达反思
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
from src.bw_learner.expression_reflector_old import expression_reflector_manager
|
|
||||||
|
|
||||||
reflector = expression_reflector_manager.get_or_create_reflector(self.stream_id)
|
|
||||||
asyncio.create_task(reflector.check_and_ask())
|
|
||||||
|
|
||||||
async with global_prompt_manager.async_message_scope(self.chat_stream.context.get_template_name()):
|
async with global_prompt_manager.async_message_scope(self.chat_stream.context.get_template_name()):
|
||||||
# 通过 MessageRecorder 统一提取消息并分发给 expression_learner 和 jargon_miner
|
# 通过 MessageRecorder 统一提取消息并分发给 expression_learner 和 jargon_miner
|
||||||
# 在 replyer 执行时触发,统一管理时间窗口,避免重复获取消息
|
# 在 replyer 执行时触发,统一管理时间窗口,避免重复获取消息
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ from src.common.utils.utils_config import ExpressionConfigUtils, ChatConfigUtils
|
|||||||
from src.config.config import global_config
|
from src.config.config import global_config
|
||||||
from src.config.file_watcher import FileChange
|
from src.config.file_watcher import FileChange
|
||||||
from src.chat.message_receive.chat_manager import chat_manager
|
from src.chat.message_receive.chat_manager import chat_manager
|
||||||
from src.bw_learner.expression_reflector import ExpressionReflector
|
|
||||||
from src.bw_learner.expression_learner import ExpressionLearner
|
from src.bw_learner.expression_learner import ExpressionLearner
|
||||||
from src.bw_learner.jargon_miner import JargonMiner
|
from src.bw_learner.jargon_miner import JargonMiner
|
||||||
|
|
||||||
@@ -67,8 +66,6 @@ class HeartFChatting:
|
|||||||
self._enable_expression_use = expr_use # 允许使用表达方式,但不一定启用学习
|
self._enable_expression_use = expr_use # 允许使用表达方式,但不一定启用学习
|
||||||
self._enable_expression_learning = expr_learn # 允许学习表达方式
|
self._enable_expression_learning = expr_learn # 允许学习表达方式
|
||||||
self._enable_jargon_learning = jargon_learn # 允许学习黑话
|
self._enable_jargon_learning = jargon_learn # 允许学习黑话
|
||||||
# 反思器
|
|
||||||
self._reflector: ExpressionReflector = ExpressionReflector(session_id)
|
|
||||||
# 表达学习器
|
# 表达学习器
|
||||||
self._expression_learner: ExpressionLearner = ExpressionLearner(session_id)
|
self._expression_learner: ExpressionLearner = ExpressionLearner(session_id)
|
||||||
# 黑话挖掘器
|
# 黑话挖掘器
|
||||||
@@ -199,7 +196,6 @@ class HeartFChatting:
|
|||||||
|
|
||||||
async def _judge_and_response(self, mentioned_message: Optional["SessionMessage"] = None):
|
async def _judge_and_response(self, mentioned_message: Optional["SessionMessage"] = None):
|
||||||
"""判定和生成回复"""
|
"""判定和生成回复"""
|
||||||
await self._trigger_reflector()
|
|
||||||
asyncio.create_task(self._trigger_expression_learning(self.message_cache))
|
asyncio.create_task(self._trigger_expression_learning(self.message_cache))
|
||||||
# TODO: 完成反思器之后的逻辑
|
# TODO: 完成反思器之后的逻辑
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
@@ -228,13 +224,7 @@ class HeartFChatting:
|
|||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
logger.info(f"{self.log_prefix} HeartFChatting: 结束了聊天")
|
logger.info(f"{self.log_prefix} HeartFChatting: 结束了聊天")
|
||||||
|
|
||||||
# ====== 反思器和学习器触发逻辑 ======
|
# ====== 学习器触发逻辑 ======
|
||||||
async def _trigger_reflector(self):
|
|
||||||
await self._reflector.check_and_ask()
|
|
||||||
if self._reflector.reflect_tracker.tracking and await self._reflector.reflect_tracker.trigger_tracker():
|
|
||||||
logger.info(f"{self.log_prefix} 追踪检查已解决,结束追踪器")
|
|
||||||
self._reflector.reflect_tracker.reset_tracker() # 结束当前追踪器
|
|
||||||
|
|
||||||
async def _trigger_expression_learning(self, messages: List["SessionMessage"]):
|
async def _trigger_expression_learning(self, messages: List["SessionMessage"]):
|
||||||
self._expression_learner.add_messages(messages)
|
self._expression_learner.add_messages(messages)
|
||||||
if time.time() - self._last_extraction_time < self._min_extraction_interval:
|
if time.time() - self._last_extraction_time < self._min_extraction_interval:
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ from src.chat.planner_actions.action_manager import ActionManager
|
|||||||
from src.chat.heart_flow.hfc_utils_old import CycleDetail
|
from src.chat.heart_flow.hfc_utils_old import CycleDetail
|
||||||
from src.bw_learner.expression_learner_old import expression_learner_manager
|
from src.bw_learner.expression_learner_old import expression_learner_manager
|
||||||
from src.chat.heart_flow.frequency_control import frequency_control_manager
|
from src.chat.heart_flow.frequency_control import frequency_control_manager
|
||||||
from src.bw_learner.reflect_tracker import reflect_tracker_manager
|
|
||||||
from src.bw_learner.expression_reflector_old import expression_reflector_manager
|
|
||||||
from src.bw_learner.message_recorder_old import extract_and_distribute_messages
|
from src.bw_learner.message_recorder_old import extract_and_distribute_messages
|
||||||
from src.person_info.person_info import Person
|
from src.person_info.person_info import Person
|
||||||
from src.plugin_system.base.component_types import EventType, ActionInfo
|
from src.plugin_system.base.component_types import EventType, ActionInfo
|
||||||
@@ -298,20 +296,6 @@ class HeartFChatting:
|
|||||||
recent_messages_list = []
|
recent_messages_list = []
|
||||||
_reply_text = "" # 初始化reply_text变量,避免UnboundLocalError
|
_reply_text = "" # 初始化reply_text变量,避免UnboundLocalError
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# ReflectTracker Check
|
|
||||||
# 在每次回复前检查一次上下文,看是否有反思问题得到了解答
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
reflector = expression_reflector_manager.get_or_create_reflector(self.session_id)
|
|
||||||
await reflector.check_and_ask()
|
|
||||||
tracker = reflect_tracker_manager.get_tracker(self.session_id)
|
|
||||||
if tracker:
|
|
||||||
resolved = await tracker.trigger_tracker()
|
|
||||||
if resolved:
|
|
||||||
reflect_tracker_manager.remove_tracker(self.session_id)
|
|
||||||
logger.info(f"{self.log_prefix} ReflectTracker resolved and removed.")
|
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
async with global_prompt_manager.async_message_scope(self.chat_stream.context.get_template_name()):
|
async with global_prompt_manager.async_message_scope(self.chat_stream.context.get_template_name()):
|
||||||
# 通过 MessageRecorder 统一提取消息并分发给 expression_learner 和 jargon_miner
|
# 通过 MessageRecorder 统一提取消息并分发给 expression_learner 和 jargon_miner
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ def _migrate_expression_groups(expr: dict[str, Any]) -> bool:
|
|||||||
def _migrate_target_item_list(parent: dict[str, Any], key: str) -> bool:
|
def _migrate_target_item_list(parent: dict[str, Any], key: str) -> bool:
|
||||||
"""
|
"""
|
||||||
将 list[str] 的 "platform:id:type" 迁移为 list[{platform,item_id,rule_type}]
|
将 list[str] 的 "platform:id:type" 迁移为 list[{platform,item_id,rule_type}]
|
||||||
用于:memory.global_memory_blacklist / expression.allow_reflect 等。
|
用于:memory.global_memory_blacklist 等。
|
||||||
"""
|
"""
|
||||||
raw = _as_list(parent.get(key))
|
raw = _as_list(parent.get(key))
|
||||||
if raw is None:
|
if raw is None:
|
||||||
|
|||||||
@@ -641,33 +641,6 @@ class ExpressionConfig(ConfigBase):
|
|||||||
)
|
)
|
||||||
"""表达方式自动检查的额外自定义评估标准"""
|
"""表达方式自动检查的额外自定义评估标准"""
|
||||||
|
|
||||||
expression_manual_reflect: bool = Field(
|
|
||||||
default=False,
|
|
||||||
json_schema_extra={
|
|
||||||
"x-widget": "switch",
|
|
||||||
"x-icon": "hand",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
"""是否启用手动表达优化"""
|
|
||||||
|
|
||||||
manual_reflect_operator_id: Optional[TargetItem] = Field(
|
|
||||||
default=None,
|
|
||||||
json_schema_extra={
|
|
||||||
"x-widget": "custom",
|
|
||||||
"x-icon": "user-cog",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
"""手动表达优化操作员ID"""
|
|
||||||
|
|
||||||
allow_reflect: list[TargetItem] = Field(
|
|
||||||
default_factory=list,
|
|
||||||
json_schema_extra={
|
|
||||||
"x-widget": "custom",
|
|
||||||
"x-icon": "shield",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
"""允许进行表达反思的聊天流ID列表,只有在此列表中的聊天流才会提出问题并跟踪。如果列表为空,则所有聊天流都可以进行表达反思(前提是reflect为true)"""
|
|
||||||
|
|
||||||
all_global_jargon: bool = Field(
|
all_global_jargon: bool = Field(
|
||||||
default=True,
|
default=True,
|
||||||
json_schema_extra={
|
json_schema_extra={
|
||||||
|
|||||||
Reference in New Issue
Block a user