初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -0,0 +1,80 @@
|
||||
"""世谱匹配引擎:关键词 / 正则 / selective / constant / 递归扫描。
|
||||
|
||||
纯逻辑,无 IO。扫描文本由调用方(集成层)从对话历史截取后传入。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
from app.modules.lorebook.types import LorebookBook, LorebookEntry, MatchedEntry
|
||||
|
||||
_RECURSION_MAX_ITERATIONS = 5
|
||||
|
||||
|
||||
def match_entries(book: LorebookBook, scan_text: str) -> list[MatchedEntry]:
|
||||
"""返回命中的条目(含 constant 与关键词命中);递归扫描按 book 配置。"""
|
||||
matched: list[MatchedEntry] = []
|
||||
for entry in book.entries:
|
||||
if not entry.enabled:
|
||||
continue
|
||||
if entry.constant:
|
||||
matched.append(MatchedEntry(entry=entry, reason="constant"))
|
||||
continue
|
||||
if _entry_matches(entry, scan_text):
|
||||
matched.append(MatchedEntry(entry=entry, reason="key"))
|
||||
|
||||
if book.recursive_scanning:
|
||||
matched = _expand_recursive(matched, book, scan_text)
|
||||
return matched
|
||||
|
||||
|
||||
def _entry_matches(entry: LorebookEntry, scan_text: str) -> bool:
|
||||
if entry.selective and entry.secondary_keys:
|
||||
return _any_key_hit(entry.keys, entry, scan_text) and _any_key_hit(
|
||||
entry.secondary_keys, entry, scan_text
|
||||
)
|
||||
return _any_key_hit(entry.keys, entry, scan_text)
|
||||
|
||||
|
||||
def _any_key_hit(keys: list[str], entry: LorebookEntry, scan_text: str) -> bool:
|
||||
for key in keys:
|
||||
if not key:
|
||||
continue
|
||||
if entry.use_regex:
|
||||
flags = 0 if entry.case_sensitive else re.IGNORECASE
|
||||
try:
|
||||
if re.search(key, scan_text, flags):
|
||||
return True
|
||||
except re.error:
|
||||
# 非法正则降级为字面量包含
|
||||
pass
|
||||
else:
|
||||
hay = scan_text if entry.case_sensitive else scan_text.casefold()
|
||||
needle = key if entry.case_sensitive else key.casefold()
|
||||
if needle in hay:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _expand_recursive(
|
||||
matched: list[MatchedEntry], book: LorebookBook, original_text: str
|
||||
) -> list[MatchedEntry]:
|
||||
"""已命中条目的 content 追加进扫描文本,再扫未命中条目;限迭代防振荡。"""
|
||||
hit_ids = {m.entry.id for m in matched}
|
||||
pool = list(matched)
|
||||
extra_text = original_text + "\n" + "\n".join(m.entry.content for m in matched)
|
||||
|
||||
for _ in range(_RECURSION_MAX_ITERATIONS):
|
||||
grew = False
|
||||
for entry in book.entries:
|
||||
if entry.id in hit_ids or not entry.enabled or entry.constant:
|
||||
continue
|
||||
if _entry_matches(entry, extra_text):
|
||||
pool.append(MatchedEntry(entry=entry, reason="recursive"))
|
||||
hit_ids.add(entry.id)
|
||||
extra_text += "\n" + entry.content
|
||||
grew = True
|
||||
if not grew:
|
||||
break
|
||||
return pool
|
||||
Reference in new issue
Block a user