remove & fix:移除人格表达,修复过滤词失效,私聊强制focus
This commit is contained in:
@@ -109,3 +109,4 @@ async def get_system_basic_info():
|
|||||||
def start_api_server():
|
def start_api_server():
|
||||||
"""启动API服务器"""
|
"""启动API服务器"""
|
||||||
get_global_server().register_router(router, prefix="/api/v1")
|
get_global_server().register_router(router, prefix="/api/v1")
|
||||||
|
# pass
|
||||||
|
|||||||
@@ -80,14 +80,16 @@ class ExpressionSelector:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_random_expressions(
|
def get_random_expressions(
|
||||||
self, chat_id: str, style_num: int, grammar_num: int, personality_num: int
|
self, chat_id: str, total_num: int, style_percentage: float, grammar_percentage: float
|
||||||
) -> Tuple[List[Dict[str, str]], List[Dict[str, str]]]:
|
) -> Tuple[List[Dict[str, str]], List[Dict[str, str]]]:
|
||||||
(
|
(
|
||||||
learnt_style_expressions,
|
learnt_style_expressions,
|
||||||
learnt_grammar_expressions,
|
learnt_grammar_expressions,
|
||||||
personality_expressions,
|
|
||||||
) = self.expression_learner.get_expression_by_chat_id(chat_id)
|
) = self.expression_learner.get_expression_by_chat_id(chat_id)
|
||||||
|
|
||||||
|
style_num = int(total_num * style_percentage)
|
||||||
|
grammar_num = int(total_num * grammar_percentage)
|
||||||
|
|
||||||
# 按权重抽样(使用count作为权重)
|
# 按权重抽样(使用count作为权重)
|
||||||
if learnt_style_expressions:
|
if learnt_style_expressions:
|
||||||
style_weights = [expr.get("count", 1) for expr in learnt_style_expressions]
|
style_weights = [expr.get("count", 1) for expr in learnt_style_expressions]
|
||||||
@@ -101,13 +103,7 @@ class ExpressionSelector:
|
|||||||
else:
|
else:
|
||||||
selected_grammar = []
|
selected_grammar = []
|
||||||
|
|
||||||
if personality_expressions:
|
return selected_style, selected_grammar
|
||||||
personality_weights = [expr.get("count", 1) for expr in personality_expressions]
|
|
||||||
selected_personality = weighted_sample(personality_expressions, personality_weights, personality_num)
|
|
||||||
else:
|
|
||||||
selected_personality = []
|
|
||||||
|
|
||||||
return selected_style, selected_grammar, selected_personality
|
|
||||||
|
|
||||||
def update_expressions_count_batch(self, expressions_to_update: List[Dict[str, str]], increment: float = 0.1):
|
def update_expressions_count_batch(self, expressions_to_update: List[Dict[str, str]], increment: float = 0.1):
|
||||||
"""对一批表达方式更新count值,按文件分组后一次性写入"""
|
"""对一批表达方式更新count值,按文件分组后一次性写入"""
|
||||||
@@ -174,7 +170,7 @@ class ExpressionSelector:
|
|||||||
"""使用LLM选择适合的表达方式"""
|
"""使用LLM选择适合的表达方式"""
|
||||||
|
|
||||||
# 1. 获取35个随机表达方式(现在按权重抽取)
|
# 1. 获取35个随机表达方式(现在按权重抽取)
|
||||||
style_exprs, grammar_exprs, personality_exprs = self.get_random_expressions(chat_id, 25, 25, 10)
|
style_exprs, grammar_exprs= self.get_random_expressions(chat_id, 50, 0.5, 0.5)
|
||||||
|
|
||||||
# 2. 构建所有表达方式的索引和情境列表
|
# 2. 构建所有表达方式的索引和情境列表
|
||||||
all_expressions = []
|
all_expressions = []
|
||||||
@@ -196,13 +192,6 @@ class ExpressionSelector:
|
|||||||
all_expressions.append(expr_with_type)
|
all_expressions.append(expr_with_type)
|
||||||
all_situations.append(f"{len(all_expressions)}.{expr['situation']}")
|
all_situations.append(f"{len(all_expressions)}.{expr['situation']}")
|
||||||
|
|
||||||
# 添加personality表达方式
|
|
||||||
for expr in personality_exprs:
|
|
||||||
if isinstance(expr, dict) and "situation" in expr and "style" in expr:
|
|
||||||
expr_with_type = expr.copy()
|
|
||||||
expr_with_type["type"] = "style_personality"
|
|
||||||
all_expressions.append(expr_with_type)
|
|
||||||
all_situations.append(f"{len(all_expressions)}.{expr['situation']}")
|
|
||||||
|
|
||||||
if not all_expressions:
|
if not all_expressions:
|
||||||
logger.warning("没有找到可用的表达方式")
|
logger.warning("没有找到可用的表达方式")
|
||||||
@@ -260,7 +249,7 @@ class ExpressionSelector:
|
|||||||
|
|
||||||
# 对选中的所有表达方式,一次性更新count数
|
# 对选中的所有表达方式,一次性更新count数
|
||||||
if valid_expressions:
|
if valid_expressions:
|
||||||
self.update_expressions_count_batch(valid_expressions, 0.003)
|
self.update_expressions_count_batch(valid_expressions, 0.006)
|
||||||
|
|
||||||
# logger.info(f"LLM从{len(all_expressions)}个情境中选择了{len(valid_expressions)}个")
|
# logger.info(f"LLM从{len(all_expressions)}个情境中选择了{len(valid_expressions)}个")
|
||||||
return valid_expressions
|
return valid_expressions
|
||||||
|
|||||||
@@ -76,14 +76,13 @@ class ExpressionLearner:
|
|||||||
|
|
||||||
def get_expression_by_chat_id(
|
def get_expression_by_chat_id(
|
||||||
self, chat_id: str
|
self, chat_id: str
|
||||||
) -> Tuple[List[Dict[str, str]], List[Dict[str, str]], List[Dict[str, str]]]:
|
) -> Tuple[List[Dict[str, str]], List[Dict[str, str]]]:
|
||||||
"""
|
"""
|
||||||
获取指定chat_id的style和grammar表达方式, 同时获取全局的personality表达方式
|
获取指定chat_id的style和grammar表达方式
|
||||||
返回的每个表达方式字典中都包含了source_id, 用于后续的更新操作
|
返回的每个表达方式字典中都包含了source_id, 用于后续的更新操作
|
||||||
"""
|
"""
|
||||||
learnt_style_expressions = []
|
learnt_style_expressions = []
|
||||||
learnt_grammar_expressions = []
|
learnt_grammar_expressions = []
|
||||||
personality_expressions = []
|
|
||||||
|
|
||||||
# 获取style表达方式
|
# 获取style表达方式
|
||||||
style_dir = os.path.join("data", "expression", "learnt_style", str(chat_id))
|
style_dir = os.path.join("data", "expression", "learnt_style", str(chat_id))
|
||||||
@@ -111,19 +110,8 @@ class ExpressionLearner:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"读取grammar表达方式失败: {e}")
|
logger.error(f"读取grammar表达方式失败: {e}")
|
||||||
|
|
||||||
# 获取personality表达方式
|
|
||||||
personality_file = os.path.join("data", "expression", "personality", "expressions.json")
|
|
||||||
if os.path.exists(personality_file):
|
|
||||||
try:
|
|
||||||
with open(personality_file, "r", encoding="utf-8") as f:
|
|
||||||
expressions = json.load(f)
|
|
||||||
for expr in expressions:
|
|
||||||
expr["source_id"] = "personality" # 添加来源ID
|
|
||||||
personality_expressions.append(expr)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"读取personality表达方式失败: {e}")
|
|
||||||
|
|
||||||
return learnt_style_expressions, learnt_grammar_expressions, personality_expressions
|
return learnt_style_expressions, learnt_grammar_expressions
|
||||||
|
|
||||||
def is_similar(self, s1: str, s2: str) -> bool:
|
def is_similar(self, s1: str, s2: str) -> bool:
|
||||||
"""
|
"""
|
||||||
@@ -428,11 +416,12 @@ class ExpressionLearner:
|
|||||||
|
|
||||||
init_prompt()
|
init_prompt()
|
||||||
|
|
||||||
expression_learner = None
|
|
||||||
|
|
||||||
|
if global_config.expression.enable_expression:
|
||||||
|
expression_learner = None
|
||||||
|
|
||||||
def get_expression_learner():
|
def get_expression_learner():
|
||||||
global expression_learner
|
global expression_learner
|
||||||
if expression_learner is None:
|
if expression_learner is None:
|
||||||
expression_learner = ExpressionLearner()
|
expression_learner = ExpressionLearner()
|
||||||
return expression_learner
|
return expression_learner
|
||||||
|
|||||||
@@ -3,16 +3,14 @@ from src.config.config import global_config
|
|||||||
from src.chat.message_receive.message import MessageRecv
|
from src.chat.message_receive.message import MessageRecv
|
||||||
from src.chat.message_receive.storage import MessageStorage
|
from src.chat.message_receive.storage import MessageStorage
|
||||||
from src.chat.heart_flow.heartflow import heartflow
|
from src.chat.heart_flow.heartflow import heartflow
|
||||||
from src.chat.message_receive.chat_stream import get_chat_manager, ChatStream
|
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||||
from src.chat.utils.utils import is_mentioned_bot_in_message
|
from src.chat.utils.utils import is_mentioned_bot_in_message
|
||||||
from src.chat.utils.timer_calculator import Timer
|
from src.chat.utils.timer_calculator import Timer
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
|
|
||||||
import math
|
|
||||||
import re
|
import re
|
||||||
|
import math
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
from maim_message import UserInfo
|
|
||||||
|
|
||||||
from src.person_info.relationship_manager import get_relationship_manager
|
from src.person_info.relationship_manager import get_relationship_manager
|
||||||
|
|
||||||
@@ -90,44 +88,7 @@ async def _calculate_interest(message: MessageRecv) -> Tuple[float, bool]:
|
|||||||
return interested_rate, is_mentioned
|
return interested_rate, is_mentioned
|
||||||
|
|
||||||
|
|
||||||
def _check_ban_words(text: str, chat: ChatStream, userinfo: UserInfo) -> bool:
|
|
||||||
"""检查消息是否包含过滤词
|
|
||||||
|
|
||||||
Args:
|
|
||||||
text: 待检查的文本
|
|
||||||
chat: 聊天对象
|
|
||||||
userinfo: 用户信息
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: 是否包含过滤词
|
|
||||||
"""
|
|
||||||
for word in global_config.message_receive.ban_words:
|
|
||||||
if word in text:
|
|
||||||
chat_name = chat.group_info.group_name if chat.group_info else "私聊"
|
|
||||||
logger.info(f"[{chat_name}]{userinfo.user_nickname}:{text}")
|
|
||||||
logger.info(f"[过滤词识别]消息中含有{word},filtered")
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def _check_ban_regex(text: str, chat: ChatStream, userinfo: UserInfo) -> bool:
|
|
||||||
"""检查消息是否匹配过滤正则表达式
|
|
||||||
|
|
||||||
Args:
|
|
||||||
text: 待检查的文本
|
|
||||||
chat: 聊天对象
|
|
||||||
userinfo: 用户信息
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: 是否匹配过滤正则
|
|
||||||
"""
|
|
||||||
for pattern in global_config.message_receive.ban_msgs_regex:
|
|
||||||
if re.search(pattern, text):
|
|
||||||
chat_name = chat.group_info.group_name if chat.group_info else "私聊"
|
|
||||||
logger.info(f"[{chat_name}]{userinfo.user_nickname}:{text}")
|
|
||||||
logger.info(f"[正则表达式过滤]消息匹配到{pattern},filtered")
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class HeartFCMessageReceiver:
|
class HeartFCMessageReceiver:
|
||||||
@@ -167,12 +128,6 @@ class HeartFCMessageReceiver:
|
|||||||
subheartflow = await heartflow.get_or_create_subheartflow(chat.stream_id)
|
subheartflow = await heartflow.get_or_create_subheartflow(chat.stream_id)
|
||||||
message.update_chat_stream(chat)
|
message.update_chat_stream(chat)
|
||||||
|
|
||||||
# 3. 过滤检查
|
|
||||||
if _check_ban_words(message.processed_plain_text, chat, userinfo) or _check_ban_regex(
|
|
||||||
message.raw_message, chat, userinfo
|
|
||||||
):
|
|
||||||
return
|
|
||||||
|
|
||||||
# 6. 兴趣度计算与更新
|
# 6. 兴趣度计算与更新
|
||||||
interested_rate, is_mentioned = await _calculate_interest(message)
|
interested_rate, is_mentioned = await _calculate_interest(message)
|
||||||
subheartflow.add_message_to_normal_chat_cache(message, interested_rate, is_mentioned)
|
subheartflow.add_message_to_normal_chat_cache(message, interested_rate, is_mentioned)
|
||||||
@@ -183,7 +138,6 @@ class HeartFCMessageReceiver:
|
|||||||
current_talk_frequency = global_config.chat.get_current_talk_frequency(chat.stream_id)
|
current_talk_frequency = global_config.chat.get_current_talk_frequency(chat.stream_id)
|
||||||
|
|
||||||
# 如果消息中包含图片标识,则日志展示为图片
|
# 如果消息中包含图片标识,则日志展示为图片
|
||||||
import re
|
|
||||||
|
|
||||||
picid_match = re.search(r"\[picid:([^\]]+)\]", message.processed_plain_text)
|
picid_match = re.search(r"\[picid:([^\]]+)\]", message.processed_plain_text)
|
||||||
if picid_match:
|
if picid_match:
|
||||||
|
|||||||
@@ -62,7 +62,10 @@ class SubHeartflow:
|
|||||||
"""异步初始化方法,创建兴趣流并确定聊天类型"""
|
"""异步初始化方法,创建兴趣流并确定聊天类型"""
|
||||||
|
|
||||||
# 根据配置决定初始状态
|
# 根据配置决定初始状态
|
||||||
if global_config.chat.chat_mode == "focus":
|
if not self.is_group_chat:
|
||||||
|
logger.debug(f"{self.log_prefix} 检测到是私聊,将直接尝试进入 FOCUSED 状态。")
|
||||||
|
await self.change_chat_state(ChatState.FOCUSED)
|
||||||
|
elif global_config.chat.chat_mode == "focus":
|
||||||
logger.debug(f"{self.log_prefix} 配置为 focus 模式,将直接尝试进入 FOCUSED 状态。")
|
logger.debug(f"{self.log_prefix} 配置为 focus 模式,将直接尝试进入 FOCUSED 状态。")
|
||||||
await self.change_chat_state(ChatState.FOCUSED)
|
await self.change_chat_state(ChatState.FOCUSED)
|
||||||
else: # "auto" 或其他模式保持原有逻辑或默认为 NORMAL
|
else: # "auto" 或其他模式保持原有逻辑或默认为 NORMAL
|
||||||
|
|||||||
@@ -91,16 +91,10 @@ class SubHeartflowManager:
|
|||||||
return subflow
|
return subflow
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 初始化子心流, 传入 mai_state_info
|
|
||||||
new_subflow = SubHeartflow(
|
new_subflow = SubHeartflow(
|
||||||
subheartflow_id,
|
subheartflow_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 首先创建并添加聊天观察者
|
|
||||||
# observation = ChattingObservation(chat_id=subheartflow_id)
|
|
||||||
# await observation.initialize()
|
|
||||||
# new_subflow.add_observation(observation)
|
|
||||||
|
|
||||||
# 然后再进行异步初始化,此时 SubHeartflow 内部若需启动 HeartFChatting,就能拿到 observation
|
# 然后再进行异步初始化,此时 SubHeartflow 内部若需启动 HeartFChatting,就能拿到 observation
|
||||||
await new_subflow.initialize()
|
await new_subflow.initialize()
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ from src.config.config import global_config
|
|||||||
from src.plugin_system.core.component_registry import component_registry # 导入新插件系统
|
from src.plugin_system.core.component_registry import component_registry # 导入新插件系统
|
||||||
from src.plugin_system.base.base_command import BaseCommand
|
from src.plugin_system.base.base_command import BaseCommand
|
||||||
from src.mais4u.mais4u_chat.s4u_msg_processor import S4UMessageProcessor
|
from src.mais4u.mais4u_chat.s4u_msg_processor import S4UMessageProcessor
|
||||||
|
from maim_message import UserInfo
|
||||||
|
from src.chat.message_receive.chat_stream import ChatStream
|
||||||
|
import re
|
||||||
# 定义日志配置
|
# 定义日志配置
|
||||||
|
|
||||||
# 获取项目根目录(假设本文件在src/chat/message_receive/下,根目录为上上上级目录)
|
# 获取项目根目录(假设本文件在src/chat/message_receive/下,根目录为上上上级目录)
|
||||||
@@ -29,6 +32,44 @@ if ENABLE_S4U_CHAT:
|
|||||||
# 配置主程序日志格式
|
# 配置主程序日志格式
|
||||||
logger = get_logger("chat")
|
logger = get_logger("chat")
|
||||||
|
|
||||||
|
def _check_ban_words(text: str, chat: ChatStream, userinfo: UserInfo) -> bool:
|
||||||
|
"""检查消息是否包含过滤词
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: 待检查的文本
|
||||||
|
chat: 聊天对象
|
||||||
|
userinfo: 用户信息
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 是否包含过滤词
|
||||||
|
"""
|
||||||
|
for word in global_config.message_receive.ban_words:
|
||||||
|
if word in text:
|
||||||
|
chat_name = chat.group_info.group_name if chat.group_info else "私聊"
|
||||||
|
logger.info(f"[{chat_name}]{userinfo.user_nickname}:{text}")
|
||||||
|
logger.info(f"[过滤词识别]消息中含有{word},filtered")
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _check_ban_regex(text: str, chat: ChatStream, userinfo: UserInfo) -> bool:
|
||||||
|
"""检查消息是否匹配过滤正则表达式
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: 待检查的文本
|
||||||
|
chat: 聊天对象
|
||||||
|
userinfo: 用户信息
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 是否匹配过滤正则
|
||||||
|
"""
|
||||||
|
for pattern in global_config.message_receive.ban_msgs_regex:
|
||||||
|
if re.search(pattern, text):
|
||||||
|
chat_name = chat.group_info.group_name if chat.group_info else "私聊"
|
||||||
|
logger.info(f"[{chat_name}]{userinfo.user_nickname}:{text}")
|
||||||
|
logger.info(f"[正则表达式过滤]消息匹配到{pattern},filtered")
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
class ChatBot:
|
class ChatBot:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -49,17 +90,6 @@ class ChatBot:
|
|||||||
|
|
||||||
self._started = True
|
self._started = True
|
||||||
|
|
||||||
async def _create_pfc_chat(self, message: MessageRecv):
|
|
||||||
try:
|
|
||||||
if global_config.experimental.pfc_chatting:
|
|
||||||
chat_id = str(message.chat_stream.stream_id)
|
|
||||||
private_name = str(message.message_info.user_info.user_nickname)
|
|
||||||
|
|
||||||
await self.pfc_manager.get_or_create_conversation(chat_id, private_name)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"创建PFC聊天失败: {e}")
|
|
||||||
|
|
||||||
async def _process_commands_with_new_system(self, message: MessageRecv):
|
async def _process_commands_with_new_system(self, message: MessageRecv):
|
||||||
# sourcery skip: use-named-expression
|
# sourcery skip: use-named-expression
|
||||||
"""使用新插件系统处理命令"""
|
"""使用新插件系统处理命令"""
|
||||||
@@ -149,14 +179,20 @@ class ChatBot:
|
|||||||
return
|
return
|
||||||
|
|
||||||
get_chat_manager().register_message(message)
|
get_chat_manager().register_message(message)
|
||||||
|
|
||||||
# 创建聊天流
|
|
||||||
chat = await get_chat_manager().get_or_create_stream(
|
chat = await get_chat_manager().get_or_create_stream(
|
||||||
platform=message.message_info.platform,
|
platform=message.message_info.platform,
|
||||||
user_info=user_info,
|
user_info=user_info,
|
||||||
group_info=group_info,
|
group_info=group_info,
|
||||||
)
|
)
|
||||||
|
|
||||||
message.update_chat_stream(chat)
|
message.update_chat_stream(chat)
|
||||||
|
|
||||||
|
# 过滤检查
|
||||||
|
if _check_ban_words(message.processed_plain_text, chat, user_info) or _check_ban_regex(
|
||||||
|
message.raw_message, chat, user_info
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
# 处理消息内容,生成纯文本
|
# 处理消息内容,生成纯文本
|
||||||
await message.process()
|
await message.process()
|
||||||
@@ -183,26 +219,12 @@ class ChatBot:
|
|||||||
template_group_name = None
|
template_group_name = None
|
||||||
|
|
||||||
async def preprocess():
|
async def preprocess():
|
||||||
logger.debug("开始预处理消息...")
|
if ENABLE_S4U_CHAT:
|
||||||
# 如果在私聊中
|
logger.info("进入S4U流程")
|
||||||
if group_info is None:
|
await self.s4u_message_processor.process_message(message)
|
||||||
logger.debug("检测到私聊消息")
|
return
|
||||||
if ENABLE_S4U_CHAT:
|
|
||||||
logger.debug("进入S4U私聊处理流程")
|
await self.heartflow_message_receiver.process_message(message)
|
||||||
await self.s4u_message_processor.process_message(message)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
logger.debug("进入普通心流私聊处理")
|
|
||||||
await self.heartflow_message_receiver.process_message(message)
|
|
||||||
# 群聊默认进入心流消息处理逻辑
|
|
||||||
else:
|
|
||||||
if ENABLE_S4U_CHAT:
|
|
||||||
logger.debug("进入S4U私聊处理流程")
|
|
||||||
await self.s4u_message_processor.process_message(message)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
logger.debug(f"检测到群聊消息,群ID: {group_info.group_id}")
|
|
||||||
await self.heartflow_message_receiver.process_message(message)
|
|
||||||
|
|
||||||
if template_group_name:
|
if template_group_name:
|
||||||
async with global_prompt_manager.async_message_scope(template_group_name):
|
async with global_prompt_manager.async_message_scope(template_group_name):
|
||||||
|
|||||||
@@ -336,6 +336,9 @@ class DefaultReplyer:
|
|||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
async def build_relation_info(self, reply_data=None, chat_history=None):
|
async def build_relation_info(self, reply_data=None, chat_history=None):
|
||||||
|
if not global_config.relationship.enable_relationship:
|
||||||
|
return ""
|
||||||
|
|
||||||
relationship_fetcher = relationship_fetcher_manager.get_fetcher(self.chat_stream.stream_id)
|
relationship_fetcher = relationship_fetcher_manager.get_fetcher(self.chat_stream.stream_id)
|
||||||
if not reply_data:
|
if not reply_data:
|
||||||
return ""
|
return ""
|
||||||
@@ -355,6 +358,9 @@ class DefaultReplyer:
|
|||||||
return relation_info
|
return relation_info
|
||||||
|
|
||||||
async def build_expression_habits(self, chat_history, target):
|
async def build_expression_habits(self, chat_history, target):
|
||||||
|
if not global_config.expression.enable_expression:
|
||||||
|
return ""
|
||||||
|
|
||||||
style_habbits = []
|
style_habbits = []
|
||||||
grammar_habbits = []
|
grammar_habbits = []
|
||||||
|
|
||||||
@@ -390,6 +396,9 @@ class DefaultReplyer:
|
|||||||
return expression_habits_block
|
return expression_habits_block
|
||||||
|
|
||||||
async def build_memory_block(self, chat_history, target):
|
async def build_memory_block(self, chat_history, target):
|
||||||
|
if not global_config.memory.enable_memory:
|
||||||
|
return ""
|
||||||
|
|
||||||
running_memorys = await self.memory_activator.activate_memory_with_chat_history(
|
running_memorys = await self.memory_activator.activate_memory_with_chat_history(
|
||||||
target_message=target, chat_history_prompt=chat_history
|
target_message=target, chat_history_prompt=chat_history
|
||||||
)
|
)
|
||||||
@@ -415,6 +424,7 @@ class DefaultReplyer:
|
|||||||
Returns:
|
Returns:
|
||||||
str: 工具信息字符串
|
str: 工具信息字符串
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not reply_data:
|
if not reply_data:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|||||||
@@ -322,6 +322,9 @@ class FocusChatConfig(ConfigBase):
|
|||||||
class ExpressionConfig(ConfigBase):
|
class ExpressionConfig(ConfigBase):
|
||||||
"""表达配置类"""
|
"""表达配置类"""
|
||||||
|
|
||||||
|
enable_expression: bool = True
|
||||||
|
"""是否启用表达方式"""
|
||||||
|
|
||||||
expression_style: str = ""
|
expression_style: str = ""
|
||||||
"""表达风格"""
|
"""表达风格"""
|
||||||
|
|
||||||
|
|||||||
@@ -1,238 +0,0 @@
|
|||||||
import random
|
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
|
||||||
from src.llm_models.utils_model import LLMRequest
|
|
||||||
from src.config.config import global_config
|
|
||||||
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
|
|
||||||
from typing import List, Tuple
|
|
||||||
import os
|
|
||||||
import json
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
logger = get_logger("expressor")
|
|
||||||
|
|
||||||
|
|
||||||
def init_prompt() -> None:
|
|
||||||
personality_expression_prompt = """
|
|
||||||
你的人物设定:{personality}
|
|
||||||
|
|
||||||
你说话的表达方式:{expression_style}
|
|
||||||
|
|
||||||
请从以上表达方式中总结出这个角色可能的语言风格,你必须严格根据人设引申,不要输出例子
|
|
||||||
思考回复的特殊内容和情感
|
|
||||||
思考有没有特殊的梗,一并总结成语言风格
|
|
||||||
总结成如下格式的规律,总结的内容要详细,但具有概括性:
|
|
||||||
当"xxx"时,可以"xxx", xxx不超过10个字
|
|
||||||
|
|
||||||
例如(不要输出例子):
|
|
||||||
当"表示十分惊叹"时,使用"我嘞个xxxx"
|
|
||||||
当"表示讽刺的赞同,不想讲道理"时,使用"对对对"
|
|
||||||
当"想说明某个观点,但懒得明说",使用"懂的都懂"
|
|
||||||
|
|
||||||
现在请你概括
|
|
||||||
"""
|
|
||||||
Prompt(personality_expression_prompt, "personality_expression_prompt")
|
|
||||||
|
|
||||||
|
|
||||||
class PersonalityExpression:
|
|
||||||
def __init__(self):
|
|
||||||
self.express_learn_model: LLMRequest = LLMRequest(
|
|
||||||
model=global_config.model.replyer_1,
|
|
||||||
max_tokens=512,
|
|
||||||
request_type="expressor.learner",
|
|
||||||
)
|
|
||||||
self.meta_file_path = os.path.join("data", "expression", "personality", "expression_style_meta.json")
|
|
||||||
self.expressions_file_path = os.path.join("data", "expression", "personality", "expressions.json")
|
|
||||||
self.max_calculations = 20
|
|
||||||
|
|
||||||
def _read_meta_data(self):
|
|
||||||
if os.path.exists(self.meta_file_path):
|
|
||||||
try:
|
|
||||||
with open(self.meta_file_path, "r", encoding="utf-8") as meta_file:
|
|
||||||
meta_data = json.load(meta_file)
|
|
||||||
# 检查是否有last_update_time字段
|
|
||||||
if "last_update_time" not in meta_data:
|
|
||||||
logger.warning(f"{self.meta_file_path} 中缺少last_update_time字段,将重新开始。")
|
|
||||||
# 清空并重写元数据文件
|
|
||||||
self._write_meta_data({"last_style_text": None, "count": 0, "last_update_time": None})
|
|
||||||
# 清空并重写表达文件
|
|
||||||
if os.path.exists(self.expressions_file_path):
|
|
||||||
with open(self.expressions_file_path, "w", encoding="utf-8") as expressions_file:
|
|
||||||
json.dump([], expressions_file, ensure_ascii=False, indent=2)
|
|
||||||
logger.debug(f"已清空表达文件: {self.expressions_file_path}")
|
|
||||||
return {"last_style_text": None, "count": 0, "last_update_time": None}
|
|
||||||
return meta_data
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
logger.warning(f"无法解析 {self.meta_file_path} 中的JSON数据,将重新开始。")
|
|
||||||
# 清空并重写元数据文件
|
|
||||||
self._write_meta_data({"last_style_text": None, "count": 0, "last_update_time": None})
|
|
||||||
# 清空并重写表达文件
|
|
||||||
if os.path.exists(self.expressions_file_path):
|
|
||||||
with open(self.expressions_file_path, "w", encoding="utf-8") as expressions_file:
|
|
||||||
json.dump([], expressions_file, ensure_ascii=False, indent=2)
|
|
||||||
logger.debug(f"已清空表达文件: {self.expressions_file_path}")
|
|
||||||
return {"last_style_text": None, "count": 0, "last_update_time": None}
|
|
||||||
return {"last_style_text": None, "count": 0, "last_update_time": None}
|
|
||||||
|
|
||||||
def _write_meta_data(self, data):
|
|
||||||
os.makedirs(os.path.dirname(self.meta_file_path), exist_ok=True)
|
|
||||||
with open(self.meta_file_path, "w", encoding="utf-8") as meta_file:
|
|
||||||
json.dump(data, meta_file, ensure_ascii=False, indent=2)
|
|
||||||
|
|
||||||
async def extract_and_store_personality_expressions(self):
|
|
||||||
"""
|
|
||||||
检查data/expression/personality目录,不存在则创建。
|
|
||||||
用peronality变量作为chat_str,调用LLM生成表达风格,解析后count=100,存储到expressions.json。
|
|
||||||
如果expression_style、personality或identity发生变化,则删除旧的expressions.json并重置计数。
|
|
||||||
对于相同的expression_style,最多计算self.max_calculations次。
|
|
||||||
"""
|
|
||||||
os.makedirs(os.path.dirname(self.expressions_file_path), exist_ok=True)
|
|
||||||
|
|
||||||
current_style_text = global_config.expression.expression_style
|
|
||||||
current_personality = global_config.personality.personality_core
|
|
||||||
|
|
||||||
meta_data = self._read_meta_data()
|
|
||||||
|
|
||||||
last_style_text = meta_data.get("last_style_text")
|
|
||||||
last_personality = meta_data.get("last_personality")
|
|
||||||
count = meta_data.get("count", 0)
|
|
||||||
|
|
||||||
# 检查是否有任何变化
|
|
||||||
if current_style_text != last_style_text or current_personality != last_personality:
|
|
||||||
logger.info(
|
|
||||||
f"检测到变化:\n风格: '{last_style_text}' -> '{current_style_text}'\n人格: '{last_personality}' -> '{current_personality}'"
|
|
||||||
)
|
|
||||||
count = 0
|
|
||||||
if os.path.exists(self.expressions_file_path):
|
|
||||||
try:
|
|
||||||
os.remove(self.expressions_file_path)
|
|
||||||
logger.info(f"已删除旧的表达文件: {self.expressions_file_path}")
|
|
||||||
except OSError as e:
|
|
||||||
logger.error(f"删除旧的表达文件 {self.expressions_file_path} 失败: {e}")
|
|
||||||
|
|
||||||
if count >= self.max_calculations:
|
|
||||||
logger.debug(f"对于当前配置已达到最大计算次数 ({self.max_calculations})。跳过提取。")
|
|
||||||
# 即使跳过,也更新元数据以反映当前配置已被识别且计数已满
|
|
||||||
self._write_meta_data(
|
|
||||||
{
|
|
||||||
"last_style_text": current_style_text,
|
|
||||||
"last_personality": current_personality,
|
|
||||||
"count": count,
|
|
||||||
"last_update_time": meta_data.get("last_update_time"),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
# 构建prompt
|
|
||||||
prompt = await global_prompt_manager.format_prompt(
|
|
||||||
"personality_expression_prompt",
|
|
||||||
personality=current_personality,
|
|
||||||
expression_style=current_style_text,
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
response, _ = await self.express_learn_model.generate_response_async(prompt)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"个性表达方式提取失败: {e}")
|
|
||||||
# 如果提取失败,保存当前的配置和未增加的计数
|
|
||||||
self._write_meta_data(
|
|
||||||
{
|
|
||||||
"last_style_text": current_style_text,
|
|
||||||
"last_personality": current_personality,
|
|
||||||
"count": count,
|
|
||||||
"last_update_time": meta_data.get("last_update_time"),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.info(f"个性表达方式提取response: {response}")
|
|
||||||
|
|
||||||
# 转为dict并count=100
|
|
||||||
if response != "":
|
|
||||||
expressions = self.parse_expression_response(response, "personality")
|
|
||||||
# 读取已有的表达方式
|
|
||||||
existing_expressions = []
|
|
||||||
if os.path.exists(self.expressions_file_path):
|
|
||||||
try:
|
|
||||||
with open(self.expressions_file_path, "r", encoding="utf-8") as f:
|
|
||||||
existing_expressions = json.load(f)
|
|
||||||
except (json.JSONDecodeError, FileNotFoundError):
|
|
||||||
logger.warning(f"无法读取或解析 {self.expressions_file_path},将创建新的表达文件。")
|
|
||||||
|
|
||||||
# 创建新的表达方式
|
|
||||||
new_expressions = []
|
|
||||||
for _, situation, style in expressions:
|
|
||||||
new_expressions.append({"situation": situation, "style": style, "count": 1})
|
|
||||||
|
|
||||||
# 合并表达方式,如果situation和style相同则累加count
|
|
||||||
merged_expressions = existing_expressions.copy()
|
|
||||||
for new_expr in new_expressions:
|
|
||||||
found = False
|
|
||||||
for existing_expr in merged_expressions:
|
|
||||||
if (
|
|
||||||
existing_expr["situation"] == new_expr["situation"]
|
|
||||||
and existing_expr["style"] == new_expr["style"]
|
|
||||||
):
|
|
||||||
existing_expr["count"] += new_expr["count"]
|
|
||||||
found = True
|
|
||||||
break
|
|
||||||
if not found:
|
|
||||||
merged_expressions.append(new_expr)
|
|
||||||
|
|
||||||
# 超过50条时随机删除多余的,只保留50条
|
|
||||||
if len(merged_expressions) > 50:
|
|
||||||
remove_count = len(merged_expressions) - 50
|
|
||||||
remove_indices = set(random.sample(range(len(merged_expressions)), remove_count))
|
|
||||||
merged_expressions = [item for idx, item in enumerate(merged_expressions) if idx not in remove_indices]
|
|
||||||
|
|
||||||
with open(self.expressions_file_path, "w", encoding="utf-8") as f:
|
|
||||||
json.dump(merged_expressions, f, ensure_ascii=False, indent=2)
|
|
||||||
logger.info(f"已写入{len(merged_expressions)}条表达到{self.expressions_file_path}")
|
|
||||||
|
|
||||||
# 成功提取后更新元数据
|
|
||||||
count += 1
|
|
||||||
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
self._write_meta_data(
|
|
||||||
{
|
|
||||||
"last_style_text": current_style_text,
|
|
||||||
"last_personality": current_personality,
|
|
||||||
"count": count,
|
|
||||||
"last_update_time": current_time,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
logger.info(f"成功处理。当前配置的计数现在是 {count},最后更新时间:{current_time}。")
|
|
||||||
else:
|
|
||||||
logger.warning(f"个性表达方式提取失败,模型返回空内容: {response}")
|
|
||||||
|
|
||||||
def parse_expression_response(self, response: str, chat_id: str) -> List[Tuple[str, str, str]]:
|
|
||||||
"""
|
|
||||||
解析LLM返回的表达风格总结,每一行提取"当"和"使用"之间的内容,存储为(situation, style)元组
|
|
||||||
"""
|
|
||||||
expressions: List[Tuple[str, str, str]] = []
|
|
||||||
for line in response.splitlines():
|
|
||||||
line = line.strip()
|
|
||||||
if not line:
|
|
||||||
continue
|
|
||||||
# 查找"当"和下一个引号
|
|
||||||
idx_when = line.find('当"')
|
|
||||||
if idx_when == -1:
|
|
||||||
continue
|
|
||||||
idx_quote1 = idx_when + 1
|
|
||||||
idx_quote2 = line.find('"', idx_quote1 + 1)
|
|
||||||
if idx_quote2 == -1:
|
|
||||||
continue
|
|
||||||
situation = line[idx_quote1 + 1 : idx_quote2]
|
|
||||||
# 查找"使用"
|
|
||||||
idx_use = line.find('使用"', idx_quote2)
|
|
||||||
if idx_use == -1:
|
|
||||||
continue
|
|
||||||
idx_quote3 = idx_use + 2
|
|
||||||
idx_quote4 = line.find('"', idx_quote3 + 1)
|
|
||||||
if idx_quote4 == -1:
|
|
||||||
continue
|
|
||||||
style = line[idx_quote3 + 1 : idx_quote4]
|
|
||||||
expressions.append((chat_id, situation, style))
|
|
||||||
return expressions
|
|
||||||
|
|
||||||
|
|
||||||
init_prompt()
|
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
import asyncio
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
from src.llm_models.utils_model import LLMRequest
|
from src.llm_models.utils_model import LLMRequest
|
||||||
from .personality import Personality
|
from .personality import Personality
|
||||||
from .identity import Identity
|
from .identity import Identity
|
||||||
from .expression_style import PersonalityExpression
|
|
||||||
import random
|
import random
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
@@ -27,7 +25,6 @@ class Individuality:
|
|||||||
# 正常初始化实例属性
|
# 正常初始化实例属性
|
||||||
self.personality: Optional[Personality] = None
|
self.personality: Optional[Personality] = None
|
||||||
self.identity: Optional[Identity] = None
|
self.identity: Optional[Identity] = None
|
||||||
self.express_style: PersonalityExpression = PersonalityExpression()
|
|
||||||
|
|
||||||
self.name = ""
|
self.name = ""
|
||||||
self.bot_person_id = ""
|
self.bot_person_id = ""
|
||||||
@@ -151,8 +148,6 @@ class Individuality:
|
|||||||
else:
|
else:
|
||||||
logger.error("人设构建失败")
|
logger.error("人设构建失败")
|
||||||
|
|
||||||
asyncio.create_task(self.express_style.extract_and_store_personality_expressions())
|
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
"""将个体特征转换为字典格式"""
|
"""将个体特征转换为字典格式"""
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from src.common.logger import get_logger
|
|||||||
from src.individuality.individuality import get_individuality, Individuality
|
from src.individuality.individuality import get_individuality, Individuality
|
||||||
from src.common.server import get_global_server, Server
|
from src.common.server import get_global_server, Server
|
||||||
from rich.traceback import install
|
from rich.traceback import install
|
||||||
from src.api.main import start_api_server
|
# from src.api.main import start_api_server
|
||||||
|
|
||||||
# 导入新的插件管理器
|
# 导入新的插件管理器
|
||||||
from src.plugin_system.core.plugin_manager import plugin_manager
|
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||||
@@ -85,8 +85,8 @@ class MainSystem:
|
|||||||
await async_task_manager.add_task(TelemetryHeartBeatTask())
|
await async_task_manager.add_task(TelemetryHeartBeatTask())
|
||||||
|
|
||||||
# 启动API服务器
|
# 启动API服务器
|
||||||
start_api_server()
|
# start_api_server()
|
||||||
logger.info("API服务器启动成功")
|
# logger.info("API服务器启动成功")
|
||||||
|
|
||||||
# 加载所有actions,包括默认的和插件的
|
# 加载所有actions,包括默认的和插件的
|
||||||
plugin_count, component_count = plugin_manager.load_all_plugins()
|
plugin_count, component_count = plugin_manager.load_all_plugins()
|
||||||
|
|||||||
@@ -155,13 +155,18 @@ class S4UChat:
|
|||||||
self._vip_queue = asyncio.PriorityQueue()
|
self._vip_queue = asyncio.PriorityQueue()
|
||||||
self._normal_queue = asyncio.PriorityQueue()
|
self._normal_queue = asyncio.PriorityQueue()
|
||||||
|
|
||||||
|
# 优先级管理配置
|
||||||
|
self.normal_queue_max_size = 20 # 普通队列最大容量,可以后续移到配置文件
|
||||||
|
self.interest_dict = {} # 用户兴趣分字典,可以后续移到配置文件. e.g. {"user_id": 5.0}
|
||||||
|
self.at_bot_priority_bonus = 100.0 # @机器人时的额外优先分
|
||||||
|
|
||||||
self._entry_counter = 0 # 保证FIFO的全局计数器
|
self._entry_counter = 0 # 保证FIFO的全局计数器
|
||||||
self._new_message_event = asyncio.Event() # 用于唤醒处理器
|
self._new_message_event = asyncio.Event() # 用于唤醒处理器
|
||||||
|
|
||||||
self._processing_task = asyncio.create_task(self._message_processor())
|
self._processing_task = asyncio.create_task(self._message_processor())
|
||||||
self._current_generation_task: Optional[asyncio.Task] = None
|
self._current_generation_task: Optional[asyncio.Task] = None
|
||||||
# 当前消息的元数据:(队列类型, 优先级, 计数器, 消息对象)
|
# 当前消息的元数据:(队列类型, 优先级分数, 计数器, 消息对象)
|
||||||
self._current_message_being_replied: Optional[Tuple[str, int, int, MessageRecv]] = None
|
self._current_message_being_replied: Optional[Tuple[str, float, int, MessageRecv]] = None
|
||||||
|
|
||||||
self._is_replying = False
|
self._is_replying = False
|
||||||
self.gpt = S4UStreamGenerator()
|
self.gpt = S4UStreamGenerator()
|
||||||
@@ -174,23 +179,35 @@ class S4UChat:
|
|||||||
vip_user_ids = [""]
|
vip_user_ids = [""]
|
||||||
return message.message_info.user_info.user_id in vip_user_ids
|
return message.message_info.user_info.user_id in vip_user_ids
|
||||||
|
|
||||||
def _get_message_priority(self, message: MessageRecv) -> int:
|
def _get_interest_score(self, user_id: str) -> float:
|
||||||
"""为消息分配优先级。数字越小,优先级越高。"""
|
"""获取用户的兴趣分,默认为1.0"""
|
||||||
|
return self.interest_dict.get(user_id, 1.0)
|
||||||
|
|
||||||
|
def _calculate_base_priority_score(self, message: MessageRecv) -> float:
|
||||||
|
"""
|
||||||
|
为消息计算基础优先级分数。分数越高,优先级越高。
|
||||||
|
"""
|
||||||
|
score = 0.0
|
||||||
|
# 如果消息 @ 了机器人,则增加一个很大的分数
|
||||||
if f"@{global_config.bot.nickname}" in message.processed_plain_text or any(
|
if f"@{global_config.bot.nickname}" in message.processed_plain_text or any(
|
||||||
f"@{alias}" in message.processed_plain_text for alias in global_config.bot.alias_names
|
f"@{alias}" in message.processed_plain_text for alias in global_config.bot.alias_names
|
||||||
):
|
):
|
||||||
return 0
|
score += self.at_bot_priority_bonus
|
||||||
return 1
|
|
||||||
|
# 加上用户的固有兴趣分
|
||||||
|
score += self._get_interest_score(message.message_info.user_info.user_id)
|
||||||
|
return score
|
||||||
|
|
||||||
async def add_message(self, message: MessageRecv) -> None:
|
async def add_message(self, message: MessageRecv) -> None:
|
||||||
"""根据VIP状态和中断逻辑将消息放入相应队列。"""
|
"""根据VIP状态和中断逻辑将消息放入相应队列。"""
|
||||||
is_vip = self._is_vip(message)
|
is_vip = self._is_vip(message)
|
||||||
new_priority = self._get_message_priority(message)
|
# 优先级分数越高,优先级越高。
|
||||||
|
new_priority_score = self._calculate_base_priority_score(message)
|
||||||
|
|
||||||
should_interrupt = False
|
should_interrupt = False
|
||||||
if self._current_generation_task and not self._current_generation_task.done():
|
if self._current_generation_task and not self._current_generation_task.done():
|
||||||
if self._current_message_being_replied:
|
if self._current_message_being_replied:
|
||||||
current_queue, current_priority, _, current_msg = self._current_message_being_replied
|
current_queue, current_priority_score, _, current_msg = self._current_message_being_replied
|
||||||
|
|
||||||
# 规则:VIP从不被打断
|
# 规则:VIP从不被打断
|
||||||
if current_queue == "vip":
|
if current_queue == "vip":
|
||||||
@@ -207,11 +224,11 @@ class S4UChat:
|
|||||||
new_sender_id = message.message_info.user_info.user_id
|
new_sender_id = message.message_info.user_info.user_id
|
||||||
current_sender_id = current_msg.message_info.user_info.user_id
|
current_sender_id = current_msg.message_info.user_info.user_id
|
||||||
# 新消息优先级更高
|
# 新消息优先级更高
|
||||||
if new_priority < current_priority:
|
if new_priority_score > current_priority_score:
|
||||||
should_interrupt = True
|
should_interrupt = True
|
||||||
logger.info(f"[{self.stream_name}] New normal message has higher priority, interrupting.")
|
logger.info(f"[{self.stream_name}] New normal message has higher priority, interrupting.")
|
||||||
# 同用户,同级或更高级
|
# 同用户,新消息的优先级不能更低
|
||||||
elif new_sender_id == current_sender_id and new_priority <= current_priority:
|
elif new_sender_id == current_sender_id and new_priority_score >= current_priority_score:
|
||||||
should_interrupt = True
|
should_interrupt = True
|
||||||
logger.info(f"[{self.stream_name}] Same user sent new message, interrupting.")
|
logger.info(f"[{self.stream_name}] Same user sent new message, interrupting.")
|
||||||
|
|
||||||
@@ -220,12 +237,21 @@ class S4UChat:
|
|||||||
logger.warning(f"[{self.stream_name}] Interrupting reply. Already generated: '{self.gpt.partial_response}'")
|
logger.warning(f"[{self.stream_name}] Interrupting reply. Already generated: '{self.gpt.partial_response}'")
|
||||||
self._current_generation_task.cancel()
|
self._current_generation_task.cancel()
|
||||||
|
|
||||||
# 将消息放入对应的队列
|
# asyncio.PriorityQueue 是最小堆,所以我们存入分数的相反数
|
||||||
item = (new_priority, self._entry_counter, time.time(), message)
|
# 这样,原始分数越高的消息,在队列中的优先级数字越小,越靠前
|
||||||
|
item = (-new_priority_score, self._entry_counter, time.time(), message)
|
||||||
|
|
||||||
if is_vip:
|
if is_vip:
|
||||||
await self._vip_queue.put(item)
|
await self._vip_queue.put(item)
|
||||||
logger.info(f"[{self.stream_name}] VIP message added to queue.")
|
logger.info(f"[{self.stream_name}] VIP message added to queue.")
|
||||||
else:
|
else:
|
||||||
|
# 应用普通队列的最大容量限制
|
||||||
|
if self._normal_queue.qsize() >= self.normal_queue_max_size:
|
||||||
|
# 队列已满,简单忽略新消息
|
||||||
|
# 更复杂的逻辑(如替换掉队列中优先级最低的)对于 asyncio.PriorityQueue 来说实现复杂
|
||||||
|
logger.debug(f"[{self.stream_name}] Normal queue is full, ignoring new message from {message.message_info.user_info.user_id}")
|
||||||
|
return
|
||||||
|
|
||||||
await self._normal_queue.put(item)
|
await self._normal_queue.put(item)
|
||||||
|
|
||||||
self._entry_counter += 1
|
self._entry_counter += 1
|
||||||
@@ -241,11 +267,13 @@ class S4UChat:
|
|||||||
|
|
||||||
# 优先处理VIP队列
|
# 优先处理VIP队列
|
||||||
if not self._vip_queue.empty():
|
if not self._vip_queue.empty():
|
||||||
priority, entry_count, _, message = self._vip_queue.get_nowait()
|
neg_priority, entry_count, _, message = self._vip_queue.get_nowait()
|
||||||
|
priority = -neg_priority
|
||||||
queue_name = "vip"
|
queue_name = "vip"
|
||||||
# 其次处理普通队列
|
# 其次处理普通队列
|
||||||
elif not self._normal_queue.empty():
|
elif not self._normal_queue.empty():
|
||||||
priority, entry_count, timestamp, message = self._normal_queue.get_nowait()
|
neg_priority, entry_count, timestamp, message = self._normal_queue.get_nowait()
|
||||||
|
priority = -neg_priority
|
||||||
# 检查普通消息是否超时
|
# 检查普通消息是否超时
|
||||||
if time.time() - timestamp > self._MESSAGE_TIMEOUT_SECONDS:
|
if time.time() - timestamp > self._MESSAGE_TIMEOUT_SECONDS:
|
||||||
logger.info(f"[{self.stream_name}] Discarding stale normal message: {message.processed_plain_text[:20]}...")
|
logger.info(f"[{self.stream_name}] Discarding stale normal message: {message.processed_plain_text[:20]}...")
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from src.config.config import global_config
|
from src.config.config import global_config
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.individuality.individuality import get_individuality
|
|
||||||
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
|
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
|
||||||
from src.chat.utils.chat_message_builder import build_readable_messages, get_raw_msg_before_timestamp_with_chat
|
from src.chat.utils.chat_message_builder import build_readable_messages, get_raw_msg_before_timestamp_with_chat
|
||||||
import time
|
import time
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[inner]
|
[inner]
|
||||||
version = "3.0.0"
|
version = "3.1.0"
|
||||||
|
|
||||||
#----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读----
|
#----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读----
|
||||||
#如果你想要修改配置文件,请在修改后将version的值进行变更
|
#如果你想要修改配置文件,请在修改后将version的值进行变更
|
||||||
@@ -44,6 +44,7 @@ compress_indentity = true # 是否压缩身份,压缩后会精简身份信息
|
|||||||
|
|
||||||
[expression]
|
[expression]
|
||||||
# 表达方式
|
# 表达方式
|
||||||
|
enable_expression = true # 是否启用表达方式
|
||||||
expression_style = "描述麦麦说话的表达风格,表达习惯,例如:(请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景。)"
|
expression_style = "描述麦麦说话的表达风格,表达习惯,例如:(请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景。)"
|
||||||
enable_expression_learning = false # 是否启用表达学习,麦麦会学习不同群里人类说话风格(群之间不互通)
|
enable_expression_learning = false # 是否启用表达学习,麦麦会学习不同群里人类说话风格(群之间不互通)
|
||||||
learning_interval = 600 # 学习间隔 单位秒
|
learning_interval = 600 # 学习间隔 单位秒
|
||||||
|
|||||||
Reference in New Issue
Block a user