refactor(core): 简化回复清理并加强 API 调用此次提交彻底重构了回复清理逻辑,以提升可维护性,并在发送 API 中引入了多项防御性检查,以防止常见的运行时错误。通过将复杂的迭代清理算法替换为单一且更高效的正则表达式,回复生成过程得到了简化。这不仅提高了去除模型生成的头信息的可靠性,还显著降低了代码复杂性。在发送 API 中,实现了多个安全措施:- 修正了异步处理错误,通过移除同步字典操作上无效的 await,防止出现 TypeError。- 添加了预检验证,以确保文件上传有定义的目标,并且临时流指定了平台。- 现在一致将机器人用户 ID 转换为字符串,以消除潜在的类型相关不一致。最后,为了清晰起见,机器人的行为原则术语也进行了调整。
This commit is contained in:
@@ -1411,10 +1411,10 @@ class DefaultReplyer:
|
||||
safety_guidelines_block = ""
|
||||
if safety_guidelines:
|
||||
guidelines_text = "\n".join(f"{i + 1}. {line}" for i, line in enumerate(safety_guidelines))
|
||||
safety_guidelines_block = f"""### 安全与互动底线
|
||||
safety_guidelines_block = f"""### 互动规则
|
||||
在任何情况下,你都必须遵守以下由你的设定者为你定义的原则:
|
||||
{guidelines_text}
|
||||
如果遇到违反上述原则的请求,请在保持你核心人设的同时,巧妙地拒绝或转移话题。
|
||||
如果遇到违反上述原则的请求,请在保持你核心人设的同时,以合适的方式进行回应。
|
||||
"""
|
||||
|
||||
if sender and target:
|
||||
@@ -1740,35 +1740,16 @@ class DefaultReplyer:
|
||||
|
||||
if content:
|
||||
# 移除 [SPLIT] 标记,防止消息被分割
|
||||
cleaned_content = content.replace("[SPLIT]", "")
|
||||
content = content.replace("[SPLIT]", "")
|
||||
|
||||
|
||||
# 循环移除,以处理模型可能生成的嵌套回复头/尾
|
||||
# 使用更健壮的正则表达式,通过非贪婪匹配和向后查找来定位真正的消息内容
|
||||
pattern = re.compile(r"^\s*\[回复<.+?>\s*(?:的消息)?:(?P<content>.*)\](?:,?说:)?\s*$", re.DOTALL)
|
||||
aggressive_pattern = re.compile(r'\[\s*回复\s*<.+?>.*?\]', re.DOTALL)
|
||||
original_content_for_aggresive_filter = content
|
||||
cleaned_content_by_aggresive_filter = aggressive_pattern.sub('', content).strip()
|
||||
|
||||
temp_content = cleaned_content
|
||||
while True:
|
||||
match = pattern.match(temp_content)
|
||||
if match:
|
||||
new_content = match.group("content").strip()
|
||||
# 如果内容没有变化,说明可能无法进一步解析,退出循环
|
||||
if new_content == temp_content:
|
||||
break
|
||||
temp_content = new_content
|
||||
else:
|
||||
break # 没有匹配到,退出循环
|
||||
|
||||
# 在循环处理后,再使用 rsplit 来处理日志中观察到的特殊情况
|
||||
# 这可以作为处理复杂嵌套的最后一道防线
|
||||
final_split = temp_content.rsplit("],说:", 1)
|
||||
if len(final_split) > 1:
|
||||
final_content = final_split[1].strip()
|
||||
else:
|
||||
final_content = temp_content
|
||||
|
||||
if final_content != content:
|
||||
logger.debug(f"清理了模型生成的多余内容,原始内容: '{content}', 清理后: '{final_content}'")
|
||||
content = final_content
|
||||
if cleaned_content_by_aggresive_filter != original_content_for_aggresive_filter:
|
||||
logger.warning(f"检测到并清理了模型生成的不规范回复格式。原始内容: '{original_content_for_aggresive_filter}', 清理后: '{cleaned_content_by_aggresive_filter}'")
|
||||
content = cleaned_content_by_aggresive_filter
|
||||
|
||||
logger.debug(f"replyer生成内容: {content}")
|
||||
return content, reasoning_content, model_name, tool_calls
|
||||
|
||||
@@ -62,12 +62,15 @@ async def file_to_stream(
|
||||
}
|
||||
|
||||
action = ""
|
||||
if target_stream.group_info:
|
||||
if target_stream.group_info and target_stream.group_info.group_id:
|
||||
action = "upload_group_file"
|
||||
params["group_id"] = target_stream.group_info.group_id
|
||||
else:
|
||||
elif target_stream.user_info and target_stream.user_info.user_id:
|
||||
action = "upload_private_file"
|
||||
params["user_id"] = target_stream.user_info.user_id
|
||||
else:
|
||||
logger.error(f"[SendAPI] 无法确定文件发送目标: {stream_id}")
|
||||
return False
|
||||
|
||||
response = await adapter_command_to_stream(
|
||||
action=action,
|
||||
@@ -173,10 +176,10 @@ async def wait_adapter_response(request_id: str, timeout: float = 30.0) -> dict:
|
||||
response = await asyncio.wait_for(future, timeout=timeout)
|
||||
return response
|
||||
except asyncio.TimeoutError:
|
||||
await _adapter_response_pool.pop(request_id, None)
|
||||
_adapter_response_pool.pop(request_id, None)
|
||||
return {"status": "error", "message": "timeout"}
|
||||
except Exception as e:
|
||||
await _adapter_response_pool.pop(request_id, None)
|
||||
_adapter_response_pool.pop(request_id, None)
|
||||
return {"status": "error", "message": str(e)}
|
||||
|
||||
|
||||
@@ -234,7 +237,7 @@ async def _send_to_target(
|
||||
|
||||
# 构建机器人用户信息
|
||||
bot_user_info = UserInfo(
|
||||
user_id=global_config.bot.qq_account,
|
||||
user_id=str(global_config.bot.qq_account),
|
||||
user_nickname=global_config.bot.nickname,
|
||||
platform=target_stream.platform,
|
||||
)
|
||||
@@ -499,6 +502,9 @@ async def adapter_command_to_stream(
|
||||
logger.debug(f"[SendAPI] 创建临时虚拟聊天流: {stream_id}")
|
||||
|
||||
# 创建临时的用户信息和聊天流
|
||||
if not platform:
|
||||
logger.error("[SendAPI] 创建临时聊天流失败: platform 未提供")
|
||||
return {"status": "error", "message": "platform 未提供"}
|
||||
|
||||
temp_user_info = UserInfo(user_id="system", user_nickname="System", platform=platform)
|
||||
|
||||
@@ -520,7 +526,7 @@ async def adapter_command_to_stream(
|
||||
|
||||
# 构建机器人用户信息
|
||||
bot_user_info = UserInfo(
|
||||
user_id=global_config.bot.qq_account,
|
||||
user_id=str(global_config.bot.qq_account),
|
||||
user_nickname=global_config.bot.nickname,
|
||||
platform=target_stream.platform,
|
||||
)
|
||||
|
||||
@@ -89,8 +89,8 @@ background_story = ""
|
||||
# 描述MoFox-Bot说话的表达风格,表达习惯,如要修改,可以酌情新增内容
|
||||
reply_style = "回复可以简短一些。可以参考贴吧,知乎和微博的回复风格,回复不要浮夸,不要用夸张修辞,平淡一些。"
|
||||
|
||||
# 安全与互动底线 (Bot在任何情况下都必须遵守的原则)
|
||||
# 你可以在这里定义Bot的行为红线,例如如何回应不恰当的问题。
|
||||
# 互动规则 (Bot在任何情况下都必须遵守的原则)
|
||||
# 你可以在这里定义Bot在互动中的行为准则。
|
||||
safety_guidelines = [
|
||||
"拒绝任何包含骚扰、冒犯、暴力、色情或危险内容的请求。",
|
||||
"在拒绝时,请使用符合你人设的、坚定的语气。",
|
||||
|
||||
Reference in New Issue
Block a user