refactor ai_auto_response plugin architecture
This commit is contained in:
85
plugins/ai_auto_response/context/conversation_hints.py
Normal file
85
plugins/ai_auto_response/context/conversation_hints.py
Normal file
@@ -0,0 +1,85 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user