53 lines
1.7 KiB
Python
53 lines
1.7 KiB
Python
import json
|
|
|
|
|
|
def _match_entry(entry: dict, text: str) -> bool:
|
|
keys = entry.get("keys", [])
|
|
if isinstance(keys, str):
|
|
keys = [k.strip() for k in keys.split(",") if k.strip()]
|
|
text_lower = text.lower()
|
|
for key in keys:
|
|
if key and key.lower() in text_lower:
|
|
return True
|
|
secondary = entry.get("secondary_keys", []) or entry.get("keysecondary", [])
|
|
if isinstance(secondary, str):
|
|
secondary = [k.strip() for k in secondary.split(",") if k.strip()]
|
|
for key in secondary:
|
|
if key and key.lower() in text_lower:
|
|
return True
|
|
return False
|
|
|
|
|
|
def get_lorebook_context(lorebook_json: str, context: str | list, max_entries: int = 5) -> str:
|
|
"""Match lorebook entries against context.
|
|
context can be a string or a list of message dicts (role/content).
|
|
"""
|
|
try:
|
|
entries = json.loads(lorebook_json or "[]")
|
|
except json.JSONDecodeError:
|
|
return ""
|
|
|
|
if isinstance(entries, dict):
|
|
entries = list(entries.values())
|
|
|
|
if isinstance(context, list):
|
|
text = " ".join(m.get("content", "") for m in context if m.get("role") in ("user", "assistant"))
|
|
else:
|
|
text = context
|
|
|
|
matched = []
|
|
for entry in entries:
|
|
if not entry.get("enabled", True):
|
|
continue
|
|
if _match_entry(entry, text):
|
|
content = entry.get("content", "").strip()
|
|
if content:
|
|
name = entry.get("name", entry.get("comment", "Lore"))
|
|
matched.append(f"[{name}]\n{content}")
|
|
|
|
if not matched:
|
|
return ""
|
|
|
|
block = "\n\n".join(matched[:max_entries])
|
|
return f"--- Lorebook (relevant world info) ---\n{block}\n---"
|