tighten ai_auto_response participation and spam guard

This commit is contained in:
liuwei
2026-04-10 09:56:34 +08:00
parent d2856bee2e
commit 3f9ae6442d
3 changed files with 70 additions and 17 deletions

View File

@@ -35,31 +35,31 @@ casual_topic = 0.35
[flow]
enable_flow_state = true
flow_decay_per_minute = 12
idle_threshold = 30
warming_threshold = 48
engaged_threshold = 78
flow_decay_per_minute = 16
idle_threshold = 36
warming_threshold = 60
engaged_threshold = 96
at_bot_boost = 40
question_boost = 30
followup_boost = 20
topic_boost = 10
returning_member_boost = 6
response_accepted_boost = 10
ignored_reply_penalty = 20
over_reply_penalty = 22
followup_boost = 12
topic_boost = 4
returning_member_boost = 3
response_accepted_boost = 6
ignored_reply_penalty = 26
over_reply_penalty = 32
night_penalty = 30
max_bot_reply_streak = 2
max_bot_reply_streak = 1
[cooldown]
group_reply_cooldown_sec = 90
same_user_followup_cooldown_sec = 18
group_reply_cooldown_sec = 150
same_user_followup_cooldown_sec = 28
at_mention_min_interval_sec = 5
at_mention_burst_window_sec = 90
at_mention_burst_limit = 5
at_mention_burst_limit = 4
at_mention_silent_sec = 180
directed_burst_window_sec = 240
directed_burst_limit = 4
directed_burst_silent_sec = 480
directed_burst_limit = 3
directed_burst_silent_sec = 600
night_silent_hours = ["01:00-07:30"]
[memory]
@@ -102,6 +102,11 @@ ignore_prefixes = ["/", "#"]
ignore_exact = ["收到", "好的", "嗯", "哦", "6", "1", "", "?"]
min_text_length = 1
[spam_guard]
repeat_window_sec = 10
repeat_threshold = 2
repeat_min_length = 4
[logging]
debug = true

View File

@@ -130,6 +130,7 @@ class AIAutoResponsePlugin(MessagePluginInterface):
self.cooldown_config = self._config.get("cooldown", {}) or {}
self.cooldown = CooldownManager(self.cooldown_config)
self.image_config = self._config.get("image", {}) or {}
self.spam_config = self._config.get("spam_guard", {}) or {}
self._synced_member_context_versions: Dict[str, str] = {}
self.log_debug = bool((self._config.get("logging", {}) or {}).get("debug", True))
self.LOG.debug(f"[{self.name}] 初始化完成")
@@ -197,6 +198,23 @@ class AIAutoResponsePlugin(MessagePluginInterface):
reply_mode="defense",
)
return False, "ignored_prompt_attack"
if self.dedup.should_skip_repeated_room_content(
room_id=room_id,
content=content,
window_sec=int(self.spam_config.get("repeat_window_sec", 45) or 45),
repeat_threshold=int(self.spam_config.get("repeat_threshold", 3) or 3),
min_length=int(self.spam_config.get("repeat_min_length", 4) or 4),
):
self._log_event(
"skip",
room_id=room_id,
sender=sender,
reason="repeated_room_content",
trigger_type="spam_guard",
reply_mode="guard",
topic="-",
)
return False, "repeated_room_content"
coding_work_request = is_coding_work_request(content)
if coding_work_request and not is_at:
return False, "skip_coding_work"

View File

@@ -1,7 +1,8 @@
from __future__ import annotations
import re
import time
from typing import Dict, Set
from typing import Dict, List, Set, Tuple
class DedupManager:
@@ -9,6 +10,7 @@ class DedupManager:
self.inflight_message_keys: Set[str] = set()
self.recent_message_keys: Dict[str, float] = {}
self.recent_reply_signatures: Dict[str, float] = {}
self.recent_room_content_hits: Dict[str, List[Tuple[float, str]]] = {}
def begin_message_processing(self, message_key: str, expiry_sec: int) -> bool:
if not message_key:
@@ -51,3 +53,31 @@ class DedupManager:
return True
self.recent_reply_signatures[signature] = now
return False
def should_skip_repeated_room_content(
self,
*,
room_id: str,
content: str,
window_sec: int,
repeat_threshold: int,
min_length: int = 4,
) -> bool:
text = self._normalize_room_content(content)
if not room_id or not text or len(text) < max(int(min_length or 4), 1):
return False
now = time.time()
window_sec = max(int(window_sec or 0), 1)
repeat_threshold = max(int(repeat_threshold or 0), 2)
room_items = self.recent_room_content_hits.get(room_id, [])
room_items = [(ts, item_text) for ts, item_text in room_items if now - ts <= window_sec]
same_count = sum(1 for _, item_text in room_items if item_text == text)
room_items.append((now, text))
self.recent_room_content_hits[room_id] = room_items[-80:]
return same_count + 1 >= repeat_threshold
@staticmethod
def _normalize_room_content(content: str) -> str:
text = str(content or "").strip().lower()
text = re.sub(r"\s+", "", text)
return text