403Webshell
Server IP : 157.230.181.24  /  Your IP : 216.73.217.11
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux conductive 6.8.0-117-generic #117-Ubuntu SMP PREEMPT_DYNAMIC Tue May 5 19:26:24 UTC 2026 x86_64
User :  ( 1000)
PHP Version : 8.3.31
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /proc/self/root/opt/aim-bots/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /proc/self/root/opt/aim-bots/buddy_memory.py
"""Persistent buddy memory — facts learned across AIM sessions."""

from __future__ import annotations

import json
import logging
import re
import threading
import time
from datetime import datetime, timezone
from difflib import SequenceMatcher
from pathlib import Path


def _now_iso() -> str:
    return datetime.now(timezone.utc).replace(microsecond=0).isoformat()


class BuddyMemoryStore:
    """Per-buddy JSON memory that survives session resets and bot restarts."""

    def __init__(
        self,
        persona_dir: Path,
        friend_name: str = "Caleb",
        max_facts: int = 50,
    ) -> None:
        self.persona_dir = persona_dir
        self.mem_dir = persona_dir / "memories"
        self.mem_dir.mkdir(exist_ok=True)
        self.friend_name = friend_name
        self.max_facts = max_facts
        self.log = logging.getLogger(f"memory.{persona_dir.name}")
        self._lock = threading.Lock()
        self._cache: dict[str, dict] = {}

    def _path(self, buddy: str) -> Path:
        safe = re.sub(r"[^\w.-]", "", buddy.lower()) or "buddy"
        return self.mem_dir / f"{safe}.json"

    def load(self, buddy: str) -> dict:
        key = buddy.lower()
        with self._lock:
            if key in self._cache:
                return self._cache[key]
            path = self._path(buddy)
            if path.exists():
                data = json.loads(path.read_text())
            else:
                data = {"buddy": buddy, "facts": [], "updated_at": None}
            self._cache[key] = data
            return data

    def _save(self, buddy: str, data: dict) -> None:
        key = buddy.lower()
        data["updated_at"] = _now_iso()
        path = self._path(buddy)
        path.write_text(json.dumps(data, indent=2) + "\n")
        self._cache[key] = data

    def facts(self, buddy: str) -> list[dict]:
        return list(self.load(buddy).get("facts", []))

    def format_for_prompt(self, buddy: str) -> str | None:
        items = self.facts(buddy)
        if not items:
            return None
        recent = items[-25:]
        lines = []
        for item in recent:
            text = item.get("text", "").strip()
            if text:
                lines.append(f"- {text}")
        if not lines:
            return None
        return (
            f"LONG-TERM MEMORY about {self.friend_name} (from past AIM convos — days or weeks ago):\n"
            + "\n".join(lines)
            + "\n\nUse this naturally when relevant. Don't recite the list. Don't say you 'remember' or 'stored' anything."
        )

    @staticmethod
    def _similar(a: str, b: str) -> bool:
        return SequenceMatcher(None, a.lower().strip(), b.lower().strip()).ratio() >= 0.82

    def add_facts(self, buddy: str, new_facts: list[str], source: str = "") -> list[str]:
        cleaned = [f.strip() for f in new_facts if f and len(f.strip()) >= 8]
        if not cleaned:
            return []
        with self._lock:
            data = self.load(buddy)
            facts: list[dict] = list(data.get("facts", []))
            added: list[str] = []
            for text in cleaned:
                if any(self._similar(text, f.get("text", "")) for f in facts):
                    facts = [
                        {**f, "text": text, "learned_at": _now_iso(), "source": source or f.get("source", "")}
                        if self._similar(text, f.get("text", ""))
                        else f
                        for f in facts
                    ]
                    if text not in added:
                        added.append(text)
                    continue
                facts.append(
                    {
                        "text": text,
                        "learned_at": _now_iso(),
                        "source": source[:200] if source else "",
                    }
                )
                added.append(text)
            if len(facts) > self.max_facts:
                facts = facts[-self.max_facts :]
            data["facts"] = facts
            self._save(buddy, data)
        if added:
            self.log.info("learned %d fact(s) for %s: %s", len(added), buddy, added[:3])
        return added

    def should_try_learn(self, message: str) -> bool:
        clean = message.strip()
        if len(clean) < 12:
            return False
        lower = clean.lower()
        if re.match(
            r"^(hey|sup|yo|hi|hello|lol|haha|hahah|rofl|ok|k|kk|bye|later|ttyl|bai|nm|nothing)\.?!?$",
            lower,
        ):
            return False
        if re.search(
            r"\b(i|im|i'm|i've|my|me|we|our|got|have|going|work|job|school|girl|guy|show|"
            r"concert|tomorrow|tonight|weekend|next week|today|dating|broke|mom|dad|parent|"
            r"moving|car|interview|sick|tired|stressed|excited|nervous|crush)\b",
            lower,
        ):
            return True
        return len(clean.split()) >= 10

    def learn_from_exchange(
        self,
        llm,
        buddy: str,
        user_msg: str,
        bot_reply: str,
        recent_context: str,
    ) -> None:
        if not self.should_try_learn(user_msg):
            return
        try:
            facts = llm.extract_memory_facts(
                self.friend_name,
                user_msg,
                bot_reply,
                recent_context,
            )
            if facts:
                self.add_facts(buddy, facts, source=user_msg[:200])
        except Exception as exc:
            self.log.warning("memory learn failed for %s: %s", buddy, exc)

    def learn_async(
        self,
        llm,
        buddy: str,
        user_msg: str,
        bot_reply: str,
        recent_context: str,
    ) -> None:
        threading.Thread(
            target=self.learn_from_exchange,
            args=(llm, buddy, user_msg, bot_reply, recent_context),
            daemon=True,
            name=f"memory-{buddy}",
        ).start()

Youez - 2016 - github.com/yon3zu
LinuXploit