fix: address bot identity review regressions
This commit is contained in:
@@ -157,6 +157,14 @@ def test_unknown_platform_no_longer_falls_back_to_qq(monkeypatch):
|
|||||||
assert "unknown_platform" in logger.warning_messages[-1]
|
assert "unknown_platform" in logger.warning_messages[-1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_unknown_platform_warns_only_once(monkeypatch):
|
||||||
|
utils_module, logger = load_utils_module(monkeypatch, qq_account=123456, platforms=[])
|
||||||
|
|
||||||
|
assert utils_module.is_bot_self("unknown_platform", "first") is False
|
||||||
|
assert utils_module.is_bot_self(" unknown_platform ", "second") is False
|
||||||
|
assert len(logger.warning_messages) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_unconfigured_qq_account_disables_qq_and_webui_identity(monkeypatch):
|
def test_unconfigured_qq_account_disables_qq_and_webui_identity(monkeypatch):
|
||||||
utils_module, _logger = load_utils_module(monkeypatch, qq_account=0, platforms=["telegram:tg_bot"])
|
utils_module, _logger = load_utils_module(monkeypatch, qq_account=0, platforms=["telegram:tg_bot"])
|
||||||
|
|
||||||
@@ -185,3 +193,24 @@ def test_is_mentioned_bot_in_message_uses_platform_account(monkeypatch):
|
|||||||
assert is_mentioned is True
|
assert is_mentioned is True
|
||||||
assert is_at is True
|
assert is_at is True
|
||||||
assert reply_probability == 1.0
|
assert reply_probability == 1.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_mentioned_bot_in_message_normalizes_qq_platform(monkeypatch):
|
||||||
|
utils_module, _logger = load_utils_module(monkeypatch, qq_account=123456, platforms=[])
|
||||||
|
|
||||||
|
message = SimpleNamespace(
|
||||||
|
processed_plain_text="@<MaiBot:123456> 你好",
|
||||||
|
platform=" QQ ",
|
||||||
|
is_mentioned=False,
|
||||||
|
message_segment=None,
|
||||||
|
message_info=SimpleNamespace(
|
||||||
|
additional_config={},
|
||||||
|
user_info=SimpleNamespace(user_id="user_1"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
is_mentioned, is_at, reply_probability = utils_module.is_mentioned_bot_in_message(message)
|
||||||
|
|
||||||
|
assert is_mentioned is True
|
||||||
|
assert is_at is True
|
||||||
|
assert reply_probability == 1.0
|
||||||
|
|||||||
@@ -42,8 +42,12 @@ class DirectMessageSender:
|
|||||||
segments = Seg(type="seglist", data=[Seg(type="text", data=content)])
|
segments = Seg(type="seglist", data=[Seg(type="text", data=content)])
|
||||||
|
|
||||||
# 获取麦麦的信息
|
# 获取麦麦的信息
|
||||||
|
bot_user_id = get_bot_account(chat_stream.platform)
|
||||||
|
if not bot_user_id:
|
||||||
|
logger.warning(f"[私聊][{self.private_name}]平台 {chat_stream.platform} 未配置机器人账号,发送消息时回退到 QQ 账号")
|
||||||
|
bot_user_id = str(getattr(global_config.bot, "qq_account", "")).strip()
|
||||||
bot_user_info = UserInfo(
|
bot_user_info = UserInfo(
|
||||||
user_id=get_bot_account(chat_stream.platform),
|
user_id=bot_user_id,
|
||||||
user_nickname=global_config.bot.nickname,
|
user_nickname=global_config.bot.nickname,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1115,6 +1115,10 @@ class DefaultReplyer:
|
|||||||
anchor_message: Optional[MaiMessage] = None,
|
anchor_message: Optional[MaiMessage] = None,
|
||||||
) -> SessionMessage:
|
) -> SessionMessage:
|
||||||
"""构建单个发送消息"""
|
"""构建单个发送消息"""
|
||||||
|
bot_user_id = get_bot_account(self.chat_stream.platform)
|
||||||
|
if not bot_user_id:
|
||||||
|
logger.warning(f"平台 {self.chat_stream.platform} 未配置机器人账号,发送消息时回退到 QQ 账号")
|
||||||
|
bot_user_id = str(getattr(global_config.bot, "qq_account", "")).strip()
|
||||||
|
|
||||||
maim_message = MessageBase(
|
maim_message = MessageBase(
|
||||||
message_info=BaseMessageInfo(
|
message_info=BaseMessageInfo(
|
||||||
@@ -1122,7 +1126,7 @@ class DefaultReplyer:
|
|||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
time=thinking_start_time,
|
time=thinking_start_time,
|
||||||
user_info=MaimUserInfo(
|
user_info=MaimUserInfo(
|
||||||
user_id=get_bot_account(self.chat_stream.platform),
|
user_id=bot_user_id,
|
||||||
user_nickname=global_config.bot.nickname,
|
user_nickname=global_config.bot.nickname,
|
||||||
),
|
),
|
||||||
additional_config={},
|
additional_config={},
|
||||||
|
|||||||
@@ -955,6 +955,10 @@ class PrivateReplyer:
|
|||||||
anchor_message: Optional[MaiMessage] = None,
|
anchor_message: Optional[MaiMessage] = None,
|
||||||
) -> SessionMessage:
|
) -> SessionMessage:
|
||||||
"""构建单个发送消息"""
|
"""构建单个发送消息"""
|
||||||
|
bot_user_id = get_bot_account(self.chat_stream.platform)
|
||||||
|
if not bot_user_id:
|
||||||
|
logger.warning(f"平台 {self.chat_stream.platform} 未配置机器人账号,发送消息时回退到 QQ 账号")
|
||||||
|
bot_user_id = str(getattr(global_config.bot, "qq_account", "")).strip()
|
||||||
|
|
||||||
maim_message = MessageBase(
|
maim_message = MessageBase(
|
||||||
message_info=BaseMessageInfo(
|
message_info=BaseMessageInfo(
|
||||||
@@ -962,7 +966,7 @@ class PrivateReplyer:
|
|||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
time=thinking_start_time,
|
time=thinking_start_time,
|
||||||
user_info=MaimUserInfo(
|
user_info=MaimUserInfo(
|
||||||
user_id=get_bot_account(self.chat_stream.platform),
|
user_id=bot_user_id,
|
||||||
user_nickname=global_config.bot.nickname,
|
user_nickname=global_config.bot.nickname,
|
||||||
),
|
),
|
||||||
group_info=None,
|
group_info=None,
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing import TYPE_CHECKING, List, Optional, Tuple
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
|
||||||
from typing import Optional, Tuple, List, TYPE_CHECKING
|
|
||||||
|
|
||||||
import jieba
|
import jieba
|
||||||
|
|
||||||
@@ -15,12 +16,14 @@ from src.common.logger import get_logger
|
|||||||
from src.config.config import global_config, model_config
|
from src.config.config import global_config, model_config
|
||||||
from src.llm_models.utils_model import LLMRequest
|
from src.llm_models.utils_model import LLMRequest
|
||||||
from src.person_info.person_info import Person
|
from src.person_info.person_info import Person
|
||||||
|
|
||||||
from .typo_generator import ChineseTypoGenerator
|
from .typo_generator import ChineseTypoGenerator
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from src.common.data_models.info_data_model import TargetPersonInfo
|
from src.common.data_models.info_data_model import TargetPersonInfo
|
||||||
|
|
||||||
logger = get_logger("chat_utils")
|
logger = get_logger("chat_utils")
|
||||||
|
_warned_unconfigured_platforms: set[str] = set()
|
||||||
|
|
||||||
|
|
||||||
def is_english_letter(char: str) -> bool:
|
def is_english_letter(char: str) -> bool:
|
||||||
@@ -122,6 +125,8 @@ def is_bot_self(platform: str, user_id: str) -> bool:
|
|||||||
if bot_account:
|
if bot_account:
|
||||||
return user_id_str == bot_account
|
return user_id_str == bot_account
|
||||||
|
|
||||||
|
if normalized_platform not in _warned_unconfigured_platforms:
|
||||||
|
_warned_unconfigured_platforms.add(normalized_platform)
|
||||||
logger.warning(f"平台 {normalized_platform} 未配置机器人账号,无法判断用户 {user_id_str} 是否为机器人自己")
|
logger.warning(f"平台 {normalized_platform} 未配置机器人账号,无法判断用户 {user_id_str} 是否为机器人自己")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -129,7 +134,7 @@ def is_bot_self(platform: str, user_id: str) -> bool:
|
|||||||
def is_mentioned_bot_in_message(message: SessionMessage) -> tuple[bool, bool, float]:
|
def is_mentioned_bot_in_message(message: SessionMessage) -> tuple[bool, bool, float]:
|
||||||
"""检查消息是否提到了机器人(统一多平台实现)"""
|
"""检查消息是否提到了机器人(统一多平台实现)"""
|
||||||
text = message.processed_plain_text or ""
|
text = message.processed_plain_text or ""
|
||||||
platform = message.platform or ""
|
platform = str(message.platform or "").strip().lower()
|
||||||
|
|
||||||
# 获取当前平台对应的账号
|
# 获取当前平台对应的账号
|
||||||
current_account = get_bot_account(platform)
|
current_account = get_bot_account(platform)
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import traceback
|
|||||||
from sqlalchemy import and_, func, not_, or_
|
from sqlalchemy import and_, func, not_, or_
|
||||||
from sqlmodel import col, select
|
from sqlmodel import col, select
|
||||||
|
|
||||||
|
from src.chat.message_receive.message import SessionMessage
|
||||||
from src.common.database.database import get_db_session
|
from src.common.database.database import get_db_session
|
||||||
from src.common.database.database_model import Messages
|
from src.common.database.database_model import Messages
|
||||||
from src.chat.message_receive.message import SessionMessage
|
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
@@ -162,17 +162,26 @@ def find_messages(
|
|||||||
after_time=after_time,
|
after_time=after_time,
|
||||||
)
|
)
|
||||||
if filter_bot:
|
if filter_bot:
|
||||||
from src.chat.utils.utils import get_all_bot_accounts
|
from src.chat.utils.utils import _get_configured_qq_account, get_all_bot_accounts
|
||||||
|
|
||||||
bot_accounts = get_all_bot_accounts()
|
bot_accounts = get_all_bot_accounts()
|
||||||
|
exclusion_conditions: list[Any] = []
|
||||||
if bot_accounts:
|
if bot_accounts:
|
||||||
bot_identity_predicate = or_(
|
exclusion_conditions.append(
|
||||||
|
or_(
|
||||||
*[
|
*[
|
||||||
and_(Messages.platform == platform_name, Messages.user_id == account)
|
and_(Messages.platform == platform_name, Messages.user_id == account)
|
||||||
for platform_name, account in bot_accounts.items()
|
for platform_name, account in bot_accounts.items()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
conditions.append(not_(bot_identity_predicate))
|
)
|
||||||
|
|
||||||
|
# 兼容旧数据:历史机器人消息在所有平台上都使用 QQ 账号进行存储。
|
||||||
|
if qq_fallback := _get_configured_qq_account():
|
||||||
|
exclusion_conditions.append(Messages.user_id == qq_fallback)
|
||||||
|
|
||||||
|
if exclusion_conditions:
|
||||||
|
conditions.append(not_(or_(*exclusion_conditions)))
|
||||||
if filter_command:
|
if filter_command:
|
||||||
conditions.append(Messages.is_command == False) # noqa: E712
|
conditions.append(Messages.is_command == False) # noqa: E712
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# TODO: 这个兼容包装层后续可以删除,统一直接使用 src.chat.utils.utils.is_bot_self
|
# TODO: 这个包装层后续可以删除,统一直接使用 src.chat.utils.utils.is_bot_self
|
||||||
|
# 注意:参数顺序已从旧版 (user_id, platform) 变更为 (platform, user_id),与统一接口一致
|
||||||
def is_bot_self(platform: str, user_id: str) -> bool:
|
def is_bot_self(platform: str, user_id: str) -> bool:
|
||||||
"""
|
"""
|
||||||
判断用户 ID 是否是机器人自己。
|
判断用户 ID 是否是机器人自己。
|
||||||
|
|||||||
@@ -83,6 +83,10 @@ async def _send_to_target(
|
|||||||
additional_config: dict[str, object] = {}
|
additional_config: dict[str, object] = {}
|
||||||
if selected_expressions is not None:
|
if selected_expressions is not None:
|
||||||
additional_config["selected_expressions"] = selected_expressions
|
additional_config["selected_expressions"] = selected_expressions
|
||||||
|
bot_user_id = get_bot_account(target_stream.platform)
|
||||||
|
if not bot_user_id:
|
||||||
|
logger.warning(f"[SendService] 平台 {target_stream.platform} 未配置机器人账号,发送消息时回退到 QQ 账号")
|
||||||
|
bot_user_id = str(getattr(global_config.bot, "qq_account", "")).strip()
|
||||||
|
|
||||||
maim_message = MessageBase(
|
maim_message = MessageBase(
|
||||||
message_info=BaseMessageInfo(
|
message_info=BaseMessageInfo(
|
||||||
@@ -90,7 +94,7 @@ async def _send_to_target(
|
|||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
time=current_time,
|
time=current_time,
|
||||||
user_info=MaimUserInfo(
|
user_info=MaimUserInfo(
|
||||||
user_id=get_bot_account(target_stream.platform),
|
user_id=bot_user_id,
|
||||||
user_nickname=global_config.bot.nickname,
|
user_nickname=global_config.bot.nickname,
|
||||||
platform=target_stream.platform,
|
platform=target_stream.platform,
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user