diff --git a/auto_reply.py b/auto_reply.py index 4516ced..a9977eb 100644 --- a/auto_reply.py +++ b/auto_reply.py @@ -65,8 +65,10 @@ class AutoReply: return {"platform": platform, "answer": answer, "sender": sender} def _get_answer(self, platform: str, msg: str, doc: dict, score: float) -> str or None: - """提取答案 + 防重复检查。""" - answer = doc["content"].strip() + """提取答案 + 防重复检查。 + 优先返回 doc['answer'](Q&A 段),兜底用整段 content。 + """ + answer = (doc.get("answer") or doc["content"]).strip() if not answer: return None diff --git a/knowledge_base.py b/knowledge_base.py index f7a61bc..d9d5f78 100644 --- a/knowledge_base.py +++ b/knowledge_base.py @@ -27,6 +27,50 @@ class KnowledgeBase: """jieba 分词""" return list(jieba.cut(text)) + @staticmethod + def _parse_qa_segments(content: str) -> list: + """解析 Q&A 格式文件为独立问答段。 + 格式:问题[N]:xxx\\n答:xxx + 返回 [{"question": str, "answer": str, "raw": str}] + """ + segments = [] + cur_q = [] + cur_a = [] + state = None # None, 'q', 'a' + + def flush(): + if not cur_q and not cur_a: + return + q = '\n'.join(cur_q).strip() + a = '\n'.join(cur_a).strip() + if q or a: + segments.append({ + "question": q, + "answer": a, + "raw": f"问题:{q}\n答:{a}", + }) + cur_q.clear() + cur_a.clear() + + for line in content.split('\n'): + qm = re.match(r'^问题\d*\s*[::]\s*(.*)', line) + am = re.match(r'^答\s*[::]\s*(.*)', line) + if qm: + flush() + state = 'q' + cur_q.append(qm.group(1)) + elif am: + state = 'a' + cur_a.append(am.group(1)) + elif state == 'q': + cur_q.append(line) + elif state == 'a': + cur_a.append(line) + # else: 文件头空白/注释,忽略 + + flush() + return segments + def set_path(self, path: str): self.root_path = path self.reload() @@ -45,11 +89,24 @@ class KnowledgeBase: try: content = fp.read_text("utf-8", errors="ignore") title = fp.stem - self.docs.append({ - "path": str(fp), - "title": title, - "content": content, - }) + # 解析 Q&A 段 + segments = self._parse_qa_segments(content) + if segments: + for seg in segments: + self.docs.append({ + "path": str(fp), + "title": title, + "content": seg["raw"], + "answer": seg["answer"], + "question": seg["question"], + }) + else: + # 非 Q&A 格式,整文件作为一段 + self.docs.append({ + "path": str(fp), + "title": title, + "content": content, + }) except Exception: continue diff --git a/monitor.py b/monitor.py index 7e32204..7c94494 100644 --- a/monitor.py +++ b/monitor.py @@ -570,9 +570,9 @@ class MessageMonitor: # 先切 QQ 到前台再截屏,避免 CMD 窗口遮挡→OCR 读到终端文字 self._ensure_foreground(hwnd) time.sleep(0.15) - # 左边界 35%,从消息面板左侧开始(联系人/会话列表 / 消息面板分界约 55%) - # 但消息正文在面板左侧,因此稍左移 35% 覆盖消息文字左侧边缘 - cap_left = int(left + win_w * 0.35) + # 左边界 25%,覆盖消息文字区域(他人消息在面板左侧) + # 从 c9acd7e 版本恢复:0.35 仅截到时间戳,0.25 才覆盖文字 + cap_left = int(left + win_w * 0.25) cap_top = top + max(40, int(win_h * 0.04)) # 标题栏下方 cap_right = int(left + win_w * 0.95) # 跳过滚动条 cap_bottom = bottom - max(100, int(win_h * 0.10)) # 输入框上方