AI-Agent / memory.py
Valtry's picture
Upload 7 files
3aaa9f7 verified
import json
import re
from pathlib import Path
from typing import Dict, List
MEMORY_DIR = Path("data") / "memory"
MEMORY_DIR.mkdir(parents=True, exist_ok=True)
def _safe_user_id(user_id: str) -> str:
safe = re.sub(r"[^a-zA-Z0-9_-]", "_", user_id.strip())
return safe or "default_user"
def _memory_path(user_id: str) -> Path:
return MEMORY_DIR / f"{_safe_user_id(user_id)}.json"
def load_history(user_id: str) -> List[Dict[str, str]]:
path = _memory_path(user_id)
if not path.exists():
return []
try:
with path.open("r", encoding="utf-8") as f:
data = json.load(f)
if isinstance(data, list):
return data
return []
except Exception:
return []
def save_history(user_id: str, history: List[Dict[str, str]]) -> None:
path = _memory_path(user_id)
with path.open("w", encoding="utf-8") as f:
json.dump(history, f, ensure_ascii=True, indent=2)
def append_message(user_id: str, role: str, content: str, max_items: int = 30) -> None:
history = load_history(user_id)
history.append({"role": role, "content": content})
history = history[-max_items:]
save_history(user_id, history)
def save_interaction(user_id: str, user_message: str, assistant_response: str) -> None:
append_message(user_id, "user", user_message)
append_message(user_id, "assistant", assistant_response)
def get_relevant_context(user_id: str, message: str, max_items: int = 8) -> str:
history = load_history(user_id)
if not history:
return ""
query_terms = {t for t in re.findall(r"\w+", message.lower()) if len(t) > 2}
scored = []
total = len(history)
for idx, item in enumerate(history):
content = item.get("content", "")
role = item.get("role", "")
terms = {t for t in re.findall(r"\w+", content.lower()) if len(t) > 2}
overlap = len(query_terms & terms)
recency_bonus = (idx + 1) / max(total, 1)
score = overlap + (0.35 * recency_bonus)
if overlap > 0 or idx >= total - 6:
scored.append((score, idx, role, content))
if not scored:
trimmed = history[-max_items:]
else:
scored.sort(key=lambda row: row[0], reverse=True)
top = sorted(scored[:max_items], key=lambda row: row[1])
trimmed = [{"role": role, "content": content} for _, _, role, content in top]
lines = []
for item in trimmed:
role = item.get("role", "assistant").capitalize()
content = item.get("content", "")
lines.append(f"{role}: {content}")
return "\n".join(lines)