Fixed RPG
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
from services.llm import send_message_with_model, send_message
|
||||
|
||||
FACTS_MODEL = os.getenv("RPG_FACTS_MODEL", "").strip() or "deepseek/deepseek-chat-v3"
|
||||
|
||||
FACTS_SYSTEM = """Extract stable facts from the conversation.
|
||||
Return ONLY valid JSON (no markdown), as an array of short strings.
|
||||
Rules:
|
||||
- Facts must be durable (names, relations, inventory, locations, world rules).
|
||||
- Do not include ephemeral actions unless they change state.
|
||||
- Avoid duplicates.
|
||||
- Keep each fact <= 120 chars.
|
||||
Example output:
|
||||
["User name is Alex", "We are in a ruined castle", "NPC Mira distrusts the user"]"""
|
||||
|
||||
|
||||
def merge_facts(existing_json: str, new_facts: list[str], limit: int = 80) -> str:
|
||||
try:
|
||||
existing = json.loads(existing_json or "[]")
|
||||
if not isinstance(existing, list):
|
||||
existing = []
|
||||
except json.JSONDecodeError:
|
||||
existing = []
|
||||
|
||||
seen = {str(x).strip() for x in existing if str(x).strip()}
|
||||
merged = [str(x).strip() for x in existing if str(x).strip()]
|
||||
for f in new_facts:
|
||||
s = str(f).strip()
|
||||
if not s or s in seen:
|
||||
continue
|
||||
seen.add(s)
|
||||
merged.append(s)
|
||||
|
||||
if len(merged) > limit:
|
||||
merged = merged[-limit:]
|
||||
return json.dumps(merged, ensure_ascii=False)
|
||||
|
||||
|
||||
async def extract_facts(context_messages: list[dict]) -> list[str]:
|
||||
# Build a compact transcript
|
||||
transcript = "\n".join(
|
||||
f"{m.get('role')}: {m.get('content','')}".strip()
|
||||
for m in context_messages
|
||||
if m.get("role") in ("user", "assistant")
|
||||
)[-6000:]
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": FACTS_SYSTEM},
|
||||
{"role": "user", "content": transcript},
|
||||
]
|
||||
|
||||
raw = await (send_message_with_model(messages, FACTS_MODEL) if FACTS_MODEL else send_message(messages))
|
||||
try:
|
||||
data = json.loads(raw.strip())
|
||||
if isinstance(data, list):
|
||||
return [str(x) for x in data][:40]
|
||||
except Exception:
|
||||
return []
|
||||
return []
|
||||
|
||||
|
||||
def facts_to_prompt(facts_json: str, max_items: int = 20) -> str:
|
||||
try:
|
||||
facts = json.loads(facts_json or "[]")
|
||||
if not isinstance(facts, list):
|
||||
return ""
|
||||
except json.JSONDecodeError:
|
||||
return ""
|
||||
facts = [str(x).strip() for x in facts if str(x).strip()]
|
||||
if not facts:
|
||||
return ""
|
||||
block = "\n".join(f"- {x}" for x in facts[-max_items:])
|
||||
return f"--- Facts (persistent memory) ---\n{block}\n---"
|
||||
|
||||
Reference in New Issue
Block a user