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 :  /opt/aim-bots/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /opt/aim-bots//reply_retriever.py
"""Fuzzy retrieval over archived AIM user→assistant pairs."""

from __future__ import annotations

import gzip
import json
import re
from difflib import SequenceMatcher
from pathlib import Path

from coherence import is_followup


def normalize(text: str) -> str:
    text = re.sub(r"\s+", " ", text.lower().strip())
    return re.sub(r"[^\w\s!?=.\-]", "", text)


class ReplyRetriever:
    """Map incoming lines to archived replies when the match is close enough."""

    def __init__(self, pairs_path: Path, min_ratio: float = 0.72) -> None:
        self.min_ratio = min_ratio
        if not pairs_path.exists():
            self.pairs: list[dict] = []
            self.index: list[tuple[str, dict]] = []
            return
        with gzip.open(pairs_path, "rt", encoding="utf-8") as fh:
            self.pairs = json.load(fh)
        self.index = [(normalize(p["user"]), p) for p in self.pairs if p.get("user") and p.get("assistant")]

    def match(self, message: str, limit: int = 5) -> list[tuple[float, dict]]:
        q = normalize(message)
        if not q or not self.index:
            return []
        scored: list[tuple[float, dict]] = []
        qlen = len(q)
        for norm, pair in self.index:
            if abs(len(norm) - qlen) > max(24, qlen * 2):
                continue
            ratio = SequenceMatcher(None, q, norm).ratio()
            if ratio >= self.min_ratio:
                scored.append((ratio, pair))
        scored.sort(key=lambda x: -x[0])
        return scored[:limit]

    def _context_boost(self, history: list[dict] | None, pair: dict) -> float:
        if not history or len(history) < 2:
            return 0.0
        prev_user = None
        for msg in reversed(history[:-1]):
            if msg.get("role") == "user":
                prev_user = normalize(msg["content"].split("\n")[-1])
                break
        if not prev_user:
            return 0.0
        # archived pair user line often follows similar prior banter
        return SequenceMatcher(None, prev_user, normalize(pair.get("user", ""))).ratio() * 0.08

    def best_reply(
        self,
        message: str,
        history: list[dict] | None = None,
        relaxed: bool = False,
    ) -> str | None:
        # Short follow-ups (y?, why?, huh?) need full thread context — archive fuzzy match misfires.
        if is_followup(message):
            return None

        hits = self.match(message, 8)
        if not hits:
            return None

        scored = []
        for ratio, pair in hits:
            boost = self._context_boost(history, pair)
            scored.append((ratio + boost, ratio, pair))
        scored.sort(key=lambda x: -x[0])
        best_total, best_ratio, best = scored[0]

        short = len(message.split()) <= 5
        threshold = self.min_ratio if relaxed else 0.78
        if best_ratio >= 0.86:
            return best["assistant"]
        if short and best_ratio >= threshold:
            # Extra strict for tiny messages that aren't follow-ups (sup, hey, yo).
            if len(message.split()) <= 2 and best_ratio < 0.88:
                return None
            return best["assistant"]
        if best_ratio >= 0.80 and len(message) >= 8:
            return best["assistant"]
        if relaxed and best_ratio >= self.min_ratio:
            return best["assistant"]
        return None

    def hint_for_llm(self, message: str, history: list[dict] | None = None) -> str | None:
        """Similar archived exchanges to steer the LLM without copying verbatim."""
        hits = self.match(message, 5)
        if not hits or hits[0][0] < 0.52:
            return None
        lines = []
        for ratio, pair in hits:
            if ratio < 0.52:
                break
            lines.append(
                f"- (similarity {ratio:.0%}) they said: {pair['user'][:80]} → you said: {pair['assistant'][:80]}"
            )
        if not lines:
            return None
        ctx = ""
        if history and len(history) >= 2:
            recent = [m["content"].split("\n")[-1][:60] for m in history[-4:] if m.get("role") == "user"]
            if recent:
                ctx = f"\nRecent thread from Caleb: {' | '.join(recent[-2:])}"
        return (
            "Similar moments from your real AIM logs (match the rhythm and length — write something NEW):"
            f"{ctx}\n" + "\n".join(lines[:4])
        )

Youez - 2016 - github.com/yon3zu
LinuXploit