from __future__ import annotations import re from typing import Any, Dict, List TECH_OVERLAP_KEYWORDS = [ "报错", "日志", "配置", "接口", "插件", "部署", "docker", "python", "openclaw", "机器人", "qdrant", "ollama", ] ANSWER_KEYWORDS = [ "先", "然后", "重启", "配置", "日志", "接口", "看一下", "试试", "排查", "报错", "原因", "因为", "改成", "装", "部署", "重现", "检查", "确认", ] def build_conversation_hints( recent_messages: List[Dict], current_sender: str, current_content: str, quote_context: Dict[str, Any], bot_name: str, ) -> Dict[str, Any]: previous_messages = list(recent_messages[:-1]) if recent_messages else [] recent_window = previous_messages[-4:] solver_count = 0 solver_senders = set() current_tokens = extract_overlap_tokens(current_content) for item in recent_window: sender = str(item.get("sender", "") or "") if not sender or sender == current_sender: continue content = str(item.get("content") or item.get("message") or "").strip().lower() if looks_like_answer(content) and has_topic_overlap(current_tokens, content): solver_count += 1 solver_senders.add(sender) previous_same_sender_directed = False same_sender_recent_count = 0 bot_name_lower = str(bot_name or "").lower() for item in reversed(previous_messages[-6:]): sender = str(item.get("sender", "") or "") if sender != current_sender: continue same_sender_recent_count += 1 content = str(item.get("content") or item.get("message") or "").strip().lower() if bool(item.get("is_at")) or (bot_name_lower and bot_name_lower in content): previous_same_sender_directed = True break quote_targets_bot = False quote_sender_name = str(quote_context.get("quote_sender_name", "") or "").strip().lower() if quote_sender_name and bot_name_lower and bot_name_lower in quote_sender_name: quote_targets_bot = True return { "has_recent_human_solver": solver_count >= 2 and len(solver_senders) >= 1, "solver_count": solver_count, "previous_same_sender_directed": previous_same_sender_directed, "same_sender_recent_count": same_sender_recent_count, "quote_targets_bot": quote_targets_bot, } def looks_like_answer(content: str) -> bool: if not content: return False if len(content) >= 18: return True return any(keyword in content for keyword in ANSWER_KEYWORDS) def extract_overlap_tokens(content: str) -> set[str]: text = str(content or "").lower() tokens = set(re.findall(r"[a-z0-9_\\-]{3,}", text)) for keyword in TECH_OVERLAP_KEYWORDS: if keyword in text: tokens.add(keyword) return tokens def has_topic_overlap(current_tokens: set[str], previous_content: str) -> bool: if not current_tokens: return False previous_tokens = extract_overlap_tokens(previous_content) return bool(current_tokens & previous_tokens)