| 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/thread-self/root/opt/aim-bots/ |
Upload File : |
#!/usr/bin/env python3
"""Extract partner/wife AIM persona — Lydia (dudesy7777). Highest-fidelity extraction."""
from __future__ import annotations
import argparse
import gzip
import json
import random
import re
import statistics
import subprocess
from collections import Counter
from pathlib import Path
# Reuse side-chick extraction machinery with partner-specific meta
from extract_side_persona import (
CONAN_ID,
PARTNER_KEY,
build_pairs,
build_profile_html,
build_speaker_re,
burst_stats,
curate_examples,
extract_appearance,
extract_phrases,
is_good_message,
lookup_account_id,
mysql_query,
mysql_rows,
norm,
parse_conversation,
voice_stats,
)
PARTNER_META = {
"dudesy7777": {
"real_name": "Lydia",
"display_name": "dudesy7777",
"nickname": "dudely",
"persona_kind": "wife",
"age": 17,
"backstory": (
"Your name is Lydia (AIM: dudesy7777 — Caleb sometimes calls you dudely). "
"You and Caleb are becoming each other's person — best friend energy that keeps "
"turning into something deeper. This AIM friendship is the foundation of a marriage "
"that lasts. You care about him genuinely: rides, church youth group, school drama, "
"inside jokes, being there. You say his name sometimes — caleb — because he matters. "
"Your best friend Joy is always in the mix. You're goofy (poptarts, sudoku, tater tots), "
"warm, honest, sometimes thoughtful about faith/life without preaching every line. "
"NEVER casual side-chick energy. NEVER n00dz jokes. This is real."
),
"relationship_with_caleb": (
"Your future husband — you don't say that every message, but the closeness is real. "
"Flirty sometimes in a shy/real way, mostly best-friend intimacy: trust, rides, "
"'see you tomorrow caleb', worrying when you can't help. Not Erica hookup drama, "
"not random myspace girls."
),
"topics": [
"school and study hall",
"church and youth group",
"Joy (best friend)",
"rides and hanging out",
"relient k and mewithoutyou",
"wow when caleb plays",
"food (poptarts, pudding, tater tots)",
"being a good friend",
"shows and music",
],
"people": {
"Joy": "your best friend — always around, carpool, sleepovers",
"Amy": "know her through the crew sometimes",
},
"profile_blurb": "lydia . church . joy . relient k . see you tomorrow :]",
"speaker_aliases": ["dudesy7777", "Auto response from dudesy7777"],
},
}
VOICE_TEMPLATE = {
"persona_kind": "wife",
"typing_wpm_min": 80,
"typing_wpm_max": 100,
"timezone": "America/New_York",
"proactive_target": "conan0fthenight",
"proactive_per_day": 2,
"late_night_start": 22,
"late_night_end": 1,
"friend_name": "Caleb",
"session_reset_minutes": 50,
"fresh_topic_minutes": 10,
"memory_enabled": True,
"memory_max_facts": 80,
"retriever_min_ratio": 0.74,
"llm_temperature": 0.62,
"wow_openers": [
["hey", "whatcha doing"],
["hey caleb", "what's up"],
["sup", "how are ya"],
["heyy", "u on?"],
],
"late_night_openers": [
["hey", "cant sleep", "u up?"],
["caleb", "you still on?"],
["hey", "whatcha doing this late lol"],
],
}
def curate_partner_examples(pairs: list[dict], limit: int = 40) -> list[dict]:
"""Prefer real back-and-forth that sounds like Lydia + Caleb, not fluff."""
scored = []
good = re.compile(
r"caleb|joy|church|school|ride|friend|tomorrow|night|thanks|sorry|love|haha|mhm|well|yeah",
re.I,
)
bad = re.compile(r"n00d|nude|boob|sexy|hook.?up|myspace layout", re.I)
for p in pairs:
u, a = p["user"], p["assistant"]
if not is_good_message(u) or not is_good_message(a):
continue
if bad.search(a):
continue
if len(a.split()) > 18:
continue
score = 0
if good.search(a):
score += 2
if good.search(u):
score += 1
if 1 <= len(a.split()) <= 10:
score += 2
if "caleb" in a.lower():
score += 1
scored.append((score, p))
scored.sort(key=lambda x: (-x[0], len(x[1]["assistant"])))
seen = set()
out = []
for _, p in scored:
key = (p["user"].lower()[:35], p["assistant"].lower()[:35])
if key in seen:
continue
seen.add(key)
out.append(p)
if len(out) >= limit:
break
return out
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("screenname", default="dudesy7777", nargs="?")
parser.add_argument("--out", default="/opt/aim-bots/personas")
args = parser.parse_args()
persona_key = norm(args.screenname)
meta = PARTNER_META.get(persona_key)
if not meta:
raise SystemExit(f"No partner meta for {persona_key}")
display = meta["display_name"]
account_id = lookup_account_id(args.screenname)
alias_names = tuple(meta.get("speaker_aliases", ()))
conan_names = ("Conan0fTheNight", "conan0fthenight")
speaker_re = build_speaker_re((display, args.screenname) + alias_names + conan_names)
conv_ids = mysql_rows(
f"SELECT id FROM conversations WHERE "
f"(from_account={account_id} AND to_account={CONAN_ID}) OR "
f"(from_account={CONAN_ID} AND to_account={account_id}) ORDER BY id"
)
raw_lines: list[str] = []
all_entries = []
for cid in conv_ids:
content = mysql_query(f"SELECT content FROM conversations WHERE id={cid}")
if not content:
continue
raw_lines.append(content)
all_entries.extend(parse_conversation(content, speaker_re, persona_key))
persona_msgs = [text for speaker, text in all_entries if speaker == persona_key]
pairs = build_pairs(all_entries, persona_key, PARTNER_KEY)
good_samples = list(dict.fromkeys(m for m in persona_msgs if is_good_message(m)))
appearance_names = (display, args.screenname) + alias_names
appearance = extract_appearance(raw_lines, appearance_names)
if appearance.get("font_color") == "#ff66cc":
appearance.update({
"font_face": "Arial",
"font_color": "#408080",
"font_size": "1",
"body_bgcolor": "#000040",
"html_wrap": "font",
})
random.seed(42)
persona = {
"screen_name": persona_key,
"display_name": display,
"persona_kind": "wife",
"real_name": meta["real_name"],
"message_count": len(persona_msgs),
"pair_count": len(pairs),
"examples": curate_partner_examples(pairs, 40),
"sample_messages": random.sample(good_samples, min(80, len(good_samples))),
"phrases": extract_phrases(persona_msgs),
**appearance,
}
out_dir = Path(args.out) / persona_key
out_dir.mkdir(parents=True, exist_ok=True)
voice = VOICE_TEMPLATE.copy()
voice.update({k: v for k, v in meta.items() if k != "speaker_aliases"})
voice.update(voice_stats(persona_msgs))
voice.update(burst_stats(all_entries, persona_key))
voice["profile_html"] = build_profile_html(meta, appearance)
(out_dir / "persona.json").write_text(json.dumps(persona, indent=2))
(out_dir / "voice.json").write_text(json.dumps(voice, indent=2))
(out_dir / "bot.env").write_text(
f"OSCAR_PASSWORD={persona_key}\nPERSONA_DIR={out_dir}\nPROACTIVE_TARGET=conan0fthenight\n"
)
with gzip.open(out_dir / "pairs.json.gz", "wt", encoding="utf-8") as fh:
json.dump(pairs, fh)
print(
f"Extracted Lydia ({persona_key}): {len(persona_msgs)} msgs, {len(pairs)} pairs, "
f"{len(persona['examples'])} curated examples, "
f"style {appearance.get('font_color')} {appearance.get('font_face')}"
)
if __name__ == "__main__":
main()