"""群聊人设卡 —— 采集编排(Service 层)。 把 __init__.py 里的采样/复读/刷屏检测与落库编排抽到此处,使入口更薄。 """ from __future__ import annotations import json import time from collections import deque from nonebot import get_driver from .. import processor, repository # 采样/复读检测的内存状态(不进库) _recent_texts: dict[int, deque[str]] = {} # group_id -> 最近消息文本 _last_store: dict[tuple[int, int], float] = {} # (group_id, user_id) -> 上次落库时间戳 def _is_repeat(group_id: int, content: str) -> bool: """复读检测:内容在最近 N 条里出现过则丢弃""" queue = _recent_texts.setdefault(group_id, deque(maxlen=processor.REPEAT_WINDOW)) if content in queue: return True queue.append(content) return False def _throttled(group_id: int, user_id: int) -> bool: """刷屏采样:5 秒内同一个人只落库一次""" key = (group_id, user_id) now = time.time() if now - _last_store.get(key, 0) < processor.THROTTLE_SECONDS: return True _last_store[key] = now return False async def collect(event): """鉴权 + 治理 + 采样 + 落库。""" if not await repository.is_group_enabled(event.group_id): return if not await repository.is_joined(event.user_id, event.group_id): return if event.user_id == event.self_id: return command_starts = get_driver().config.command_start if not processor.has_recordable_content(event): return text = processor.filter_content( processor.extract_text(event), command_starts=command_starts ) image_hashes = processor.extract_image_hashes(event) content = processor.build_content( text or "", len(image_hashes), processor.count_faces(event) ) if content is None: return context = " ".join(_recent_texts.get(event.group_id, ())) content = processor.desensitize(content, context) if _is_repeat(event.group_id, content): return if _throttled(event.group_id, event.user_id): return await repository.add_chat_log( user_id=event.user_id, group_id=event.group_id, content=content, nickname=event.sender.card or event.sender.nickname or "", target_user_id=processor.extract_target_user_id(event), reply_to_content=processor.extract_reply_to_content(event), image_count=len(image_hashes), image_hashes=json.dumps(image_hashes, ensure_ascii=False) if image_hashes else None, )