""" RM ProfileOps CLI — run modes and manage approved drafts. """ import argparse import json import logging import os import sys from pathlib import Path from .db import init_db, get_variant_history, get_conn from .api_client import RentMasseurAPI from .auth import AuthSession, get_credential from .content_optimizer import apply_bio_variant, draft_bio_variant from .daemon import ProfileOpsDaemon from .execution_engine import execute_visibility from .state import snapshot_state, save_snapshot from .approval_queue import approve_draft, list_pending, list_approved from .endpoint_registry import seed_registry from .cdp_discovery import run_discovery from .search_rank import check_all_search_ranks from .reports import generate_report, save_report, print_report from .blog_agent import generate_blog_drafts, save_blog_drafts_to_disk from .interview_agent import generate_interview_drafts, monitor_interview from .bio_generator import run_generation from .bio_evolver import run_evolution from .stats_dashboard import generate_dashboard from .bio_tokenizer import build_vocab, save_vocab, load_vocab, tokenize from .bio_appraiser import full_appraisal from .bio_ml_trainer import full_training_pipeline, k_fold_cv, walk_forward_validation # AGI orchestrator from rm_agi.orchestrator import RMAGIOrchestrator, CPPEngine, ReceiptLedger # RM-PRI (Profile Revenue Intelligence) from rm_agi.rm_pri import ( validate_corpus as pri_validate_corpus, validate_enriched as pri_validate_enriched, enrich_bios as pri_enrich_bios, rank_by_views_per_day as pri_rank_views, atomize_bios as pri_atomize_bios, compute_lift as pri_compute_lift, ReceiptLedger as PRIReceiptLedger, RAW_PATH, ENRICHED_PATH, RANKED_PATH, ) REQUIRED_FIELDS_CLI = ["id", "username", "city", "headline", "description", "ratingAverage", "reviewsCount", "isGold", "isAvailable", "isCertified"] def _api_login(args): api = RentMasseurAPI() auth = AuthSession(api, session_file=args.session) if not auth.login(): print("Login failed") sys.exit(1) return api def cmd_status(args): init_db() api = _api_login(args) state = snapshot_state(api) save_snapshot(state) keep = state.get("keeponline", {}) avail = state.get("availability", {}) about = state.get("about", {}) assets = about.get("userProps", {}).get("assets", {}) stats = state.get("stats", {}).get("profileStatistics", {}) dashboard = state.get("dashboard", {}) print(json.dumps({ "timestamp": state["timestamp"], "visible": not bool(keep.get("isAdHidden", 0)), "available": avail.get("selected", "unknown"), "availability_minutes_left": max(0, int(avail.get("countdown", 0) - __import__('time').time()) // 60), "views": stats.get("totalPageViews"), "contact_clicks": stats.get("totalContactClicks"), "new_visits": keep.get("newVisits"), "new_emails": keep.get("newEmails"), "online_bookmarks": dashboard.get("onlineBookmarks"), "headline": assets.get("headline"), "description_len": len(assets.get("description", "")), }, indent=2, default=str)) def cmd_snapshot(args): init_db() api = _api_login(args) state = snapshot_state(api) path = save_snapshot(state) print(f"Snapshot saved: {path}") def cmd_unhide(args): init_db() api = _api_login(args) result = execute_visibility(api, True) print(json.dumps(result, indent=2, default=str)) def cmd_draft_bio(args): init_db() api = _api_login(args) variant = draft_bio_variant(api) print(json.dumps(variant, indent=2, default=str)) def cmd_draft_blog(args): init_db() drafts = generate_blog_drafts(count=args.count) save_blog_drafts_to_disk(drafts) print(json.dumps(drafts, indent=2, default=str)) def cmd_draft_interview(args): init_db() api = _api_login(args) status = monitor_interview(api) drafts = generate_interview_drafts() print(json.dumps({"status": status, "drafts": drafts}, indent=2, default=str)) def cmd_generate_bios(args): init_db() ids = run_generation(count=args.count, top_n=args.top_n) print(f"Generated {len(ids)} bio variants") print("Top 3:") for vid in ids[:3]: print(f" {vid}") def cmd_evolve_bios(args): init_db() from .bio_generator import generate_bios initial = generate_bios(count=args.population, top_n=args.population) ids = run_evolution(initial_bios=initial, generations=args.generations, population_size=args.population, elite_size=args.elites, top_n=args.elites) print(f"Evolution complete. Saved {len(ids)} elite variants.") print("Top 3:") for vid in ids[:3]: print(f" {vid}") def cmd_dashboard(args): init_db() path = generate_dashboard() print(f"Dashboard generated: {path}") def cmd_tokenize(args): init_db() conn = get_conn() rows = conn.execute("SELECT headline, description FROM content_variants WHERE kind='bio'").fetchall() conn.close() bios = [{"headline": r[0], "description": r[1]} for r in rows] vocab = build_vocab(bios, min_freq=args.min_freq) path = Path("rm_traffic/data/models/vocab.json") save_vocab(vocab, path) print(f"Vocabulary: {vocab['unique_tokens']} unique tokens, {vocab['total_tokens']} total") print(f"Saved to: {path}") print("Top 20 tokens:") for token, freq in list(vocab["token_freq"].items())[:20]: print(f" {token}: {freq}") def cmd_approve(args): init_db() approve_draft(args.variant_id) print(f"Approved {args.variant_id}") def cmd_apply(args): init_db() api = _api_login(args) ok = apply_bio_variant(api, args.variant_id) print("Applied" if ok else "Failed") def cmd_list_drafts(args): init_db() if args.status == "pending": drafts = list_pending(args.kind) elif args.status == "approved": drafts = list_approved(args.kind) else: drafts = get_variant_history(args.kind, limit=args.limit) for d in drafts: print(f"{d['variant_id']} | {d['status']:18s} | {d['headline'][:50] if d['headline'] else 'N/A'}") def cmd_discover(args): init_db() seed_registry() result = run_discovery(args.target) print(json.dumps(result, indent=2, default=str)) def cmd_rank_check(args): init_db() api = _api_login(args) ranks = check_all_search_ranks(api, args.username) print(json.dumps(ranks, indent=2, default=str)) def cmd_report(args): init_db() api = _api_login(args) state = snapshot_state(api) ranks = check_all_search_ranks(api, args.username) report = generate_report(args.username, state, ranks) path = save_report(report) print(report) print(f"\nReport saved: {path}") # ─── AGI Commands ─── def cmd_agi_inspect(args): """Show real corpus stats from C++ engine.""" engine = CPPEngine() bios = args.bios or "rm_traffic/data/real_bios.jsonl" print(engine.inspect(bios)) def cmd_agi_train(args): """Train model on real data using C++ engine.""" engine = CPPEngine() bios = args.bios or "rm_traffic/data/real_bios.jsonl" print(engine.train(bios, label=args.label, cv=args.cv, walk_forward=args.walk_forward, epochs=args.epochs, lr=args.lr, hidden=args.hidden)) def cmd_agi_pipeline(args): """Run full AGI pipeline: train → generate → score → evolve → select.""" agi = RMAGIOrchestrator() bios = args.bios or "rm_traffic/data/real_bios.jsonl" agi.run_pipeline(bios, count=args.count, label=args.label, generations=args.generations, top=args.top) def cmd_agi_import(args): """Import top candidates into approval queue.""" agi = RMAGIOrchestrator() from pathlib import Path path = Path(args.path) if args.path else None count = agi.import_winners(path) print(f"Imported {count} candidates into approval queue") def cmd_agi_list_drafts(args): """List AGI draft candidates.""" agi = RMAGIOrchestrator() if args.status == "pending": drafts = agi.queue.list_pending() elif args.status == "approved": drafts = agi.queue.list_approved() else: drafts = agi.queue.list_pending() + agi.queue.list_approved() for d in drafts: rank = d.get("rank", "?") score = d.get("score", 0) risk = d.get("risk", 0) status = d.get("status", "?") headline = d.get("headline", "N/A")[:50] print(f" #{rank} score={score:.4f} risk={risk:.4f} [{status}] {headline}") def cmd_agi_approve(args): """Approve an AGI candidate.""" agi = RMAGIOrchestrator() result = agi.approve(args.variant_id) if result: print(f"Approved: {result.get('headline', args.variant_id)}") else: print(f"Not found: {args.variant_id}") def cmd_agi_receipts(args): """Show receipt ledger.""" agi = RMAGIOrchestrator() print(agi.receipt_report()) if args.verbose: for e in agi.ledger.entries[-10:]: print(f" [{e['index']}] {e['action']}: {e['description']}") def cmd_agi_experiments(args): """List experiment results.""" agi = RMAGIOrchestrator() exps = agi.experiments.list_experiments() if not exps: print("No experiments yet.") return for e in exps[-10:]: label = e.get("result_label", "running") ctr_lift = e.get("ctr_lift", 0) print(f" {e['experiment_id']} variant={e['variant_id']} result={label} ctr_lift={ctr_lift:.4f}") def cmd_agi_dashboard(args): """Show AGI control panel.""" agi = RMAGIOrchestrator() data = agi.dashboard_data() print("RENTMASSEUR AGI CONTROL PANEL") print("=" * 60) if "account" in data: acct = data["account"] print(f"ACCOUNT:") print(f" Visible: {acct.get('visible', '?')}") print(f" Available: {acct.get('is_available', '?')}") print(f" Gold: {acct.get('is_gold', '?')}") print(f" Headline: {acct.get('headline', '?')[:50]}") print(f" Bio length: {acct.get('description_len', '?')} chars") print(f" Views: {acct.get('profile_views', '?')}") print(f" Contact clicks: {acct.get('contact_clicks', '?')}") print(f" CTR: {acct.get('contact_click_rate', 0):.4f}") print(f"\nCORPUS & MODEL:") print(f" Pending drafts: {data['pending_count']}") print(f" Approved drafts: {data['approved_count']}") print(f"\nRECEIPTS:") r = data["receipts"] print(f" Total: {r['total_receipts']} Valid: {r['chain_valid']} Last: {r['last_action']}") if data["experiments"]: print(f"\nRECENT EXPERIMENTS:") for e in data["experiments"]: print(f" {e['experiment_id']} → {e.get('result_label', 'running')}") # ─── RM-PRI Commands (honest naming) ─── def cmd_validate_corpus(args): """Gate 1: validate corpus schema.""" path = Path(args.path) if args.path else RAW_PATH result = pri_validate_corpus(path) print(f"CORPUS VALIDATION: {path}") print(f" Total rows: {result['total']}") print(f" Valid: {result['valid']}") print(f" Invalid: {result['invalid']}") print(f" PASS: {result['pass']}") if result["errors"]: print(f" Errors ({len(result['errors'])}):") for e in result["errors"][:5]: print(f" {e}") print(f"\nField completeness:") for f in REQUIRED_FIELDS_CLI: p = result["fields_present"][f] t = result["total"] print(f" {f:20s} {p}/{t} ({100*p/t:.1f}%)") if args.check_enriched: print(f"\nENRICHED VALIDATION:") er = pri_validate_enriched(ENRICHED_PATH) if "error" in er: print(f" {er['error']}") else: print(f" Total: {er['total']}") print(f" Has views_per_day: {er['has_views_per_day']}") print(f" Missing: {er['missing_views_per_day']}") print(f" PASS: {er['pass']}") def cmd_enrich_views(args): """Gate 2: enrich bios with public visits/member-since.""" inp = Path(args.input) if args.input else RAW_PATH out = Path(args.output) if args.output else ENRICHED_PATH result = pri_enrich_bios(inp, out, workers=args.workers, rate_limit=args.rate_limit) print(f"\nENRICHMENT RESULT:") print(f" Total: {result['total']}") print(f" Enriched: {result['enriched']}") print(f" Failed: {result['failed']}") if result.get("captcha"): print(f" BLOCKED: CrowdSec captcha active") print(f" Next: Wait for ban to clear, then re-run this command") else: print(f" Output: {out}") def cmd_rank_real(args): """Rank real bios by views_per_day.""" inp = Path(args.input) if args.input else ENRICHED_PATH out = Path(args.output) if args.output else RANKED_PATH result = pri_rank_views(inp, out) if "error" in result: print(f"ERROR: {result['error']}") else: print(f"Ranked {result['ranked_bios']}/{result['total_bios']} bios by views/day") print(f"Output: {result['output']}") if result.get("top_5"): print(f"\nTop 5 by views/day:") for i, b in enumerate(result["top_5"], 1): print(f" #{i} {b['username']} — {b['views_per_day']:.1f} v/day — {b['headline'][:50]}") def cmd_atomize_bios(args): """Extract structural atoms from bios.""" inp = Path(args.input) if args.input else RAW_PATH out = Path(args.output) if args.output else Path("rm_traffic/data/bio_atoms.jsonl") result = pri_atomize_bios(inp, out) print(f"Atomized {result['atomized']} bios") print(f"Output: {result['output']}") def cmd_pri_status(args): """Show honest system status — what stage we're at.""" print("RM-PRI STATUS — RentMasseur Profile Revenue Intelligence") print("=" * 60) # Stage 1: corpus v = pri_validate_corpus(RAW_PATH) print(f"\nStage 1: Real Corpus") print(f" Rows: {v['total']} Valid: {v['valid']} PASS: {v['pass']}") # Stage 2: enrichment e = pri_validate_enriched(ENRICHED_PATH) print(f"\nStage 2: Views/Day Enrichment") if "error" in e: print(f" STATUS: NOT STARTED — {e['error']}") print(f" BLOCKER: CrowdSec captcha on rentmasseur.com") print(f" NEXT: Run 'enrich-views' when ban clears") else: print(f" Total: {e['total']} Has v/day: {e['has_views_per_day']} PASS: {e['pass']}") # Stage 3: dashboard print(f"\nStage 3: Dashboard Time Series") print(f" STATUS: NOT STARTED — requires API access") print(f" NEXT: Run 'snapshot' when API is accessible") # Stage 4: experiments print(f"\nStage 4: Live Experiment Labels") print(f" STATUS: NOT STARTED — requires approved variant + apply + measure") # Stage 5: online learning print(f"\nStage 5: Validated Online Learner") print(f" STATUS: NOT STARTED — requires stages 2-4") # Receipts ledger = PRIReceiptLedger() s = ledger.summary() print(f"\nReceipts: {s['total']} total, chain valid: {s['valid']}") print(f"\nHONEST ASSESSMENT:") print(f" This is Stage 1: real corpus loaded.") print(f" Not AGI. Not revenue oracle. Not CTR predictor.") print(f" It is a real market corpus + language analysis foundation.") print(f" Next real step: enrich with public visits/member-since.") def cmd_audit(args): init_db() seed_registry() d = ProfileOpsDaemon(mode="audit", city=args.city, session_file=args.session) d.run() def cmd_guard(args): init_db() seed_registry() d = ProfileOpsDaemon(mode="guard", city=args.city, session_file=args.session) d.run() def cmd_draft(args): init_db() seed_registry() d = ProfileOpsDaemon(mode="draft", city=args.city, session_file=args.session) d.run() def cmd_daemon(args): init_db() seed_registry() mode = "execute" if args.execute_approved else "safe" d = ProfileOpsDaemon(mode=mode, city=args.city, session_file=args.session) d.run() def main(): logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") parser = argparse.ArgumentParser(description="RM ProfileOps CLI") sub = parser.add_subparsers(dest="command", required=True) p = sub.add_parser("status", help="Read-only profile status") p.add_argument("--city", default="manhattan-ny") p.add_argument("--session", default="rm_traffic/session.json") p.set_defaults(func=cmd_status) p = sub.add_parser("snapshot", help="Save profile state snapshot") p.add_argument("--session", default="rm_traffic/session.json") p.set_defaults(func=cmd_snapshot) p = sub.add_parser("unhide", help="Ensure profile is visible") p.add_argument("--session", default="rm_traffic/session.json") p.set_defaults(func=cmd_unhide) p = sub.add_parser("draft-bio", help="Generate a bio draft") p.add_argument("--session", default="rm_traffic/session.json") p.set_defaults(func=cmd_draft_bio) p = sub.add_parser("draft-blog", help="Generate blog drafts") p.add_argument("--count", type=int, default=1) p.set_defaults(func=cmd_draft_blog) p = sub.add_parser("draft-interview", help="Generate interview drafts") p.add_argument("--session", default="rm_traffic/session.json") p.set_defaults(func=cmd_draft_interview) p = sub.add_parser("generate-bios", help="Generate many bio variants with scoring") p.add_argument("--count", type=int, default=1000) p.add_argument("--top-n", type=int, default=100) p.set_defaults(func=cmd_generate_bios) p = sub.add_parser("evolve-bios", help="Run GA to optimize bios for CTR/email/phone") p.add_argument("--population", type=int, default=100) p.add_argument("--generations", type=int, default=50) p.add_argument("--elites", type=int, default=10) p.set_defaults(func=cmd_evolve_bios) p = sub.add_parser("dashboard", help="Generate HTML stats dashboard") p.set_defaults(func=cmd_dashboard) p = sub.add_parser("tokenize", help="Build vocabulary from all bio drafts") p.add_argument("--min-freq", type=int, default=2) p.set_defaults(func=cmd_tokenize) p = sub.add_parser("approve", help="Approve a draft variant") p.add_argument("variant_id") p.set_defaults(func=cmd_approve) p = sub.add_parser("apply", help="Apply an approved bio variant") p.add_argument("variant_id") p.add_argument("--session", default="rm_traffic/session.json") p.set_defaults(func=cmd_apply) p = sub.add_parser("list-drafts", help="List content drafts") p.add_argument("--kind", default="bio") p.add_argument("--status", choices=["all", "pending", "approved"], default="all") p.add_argument("--limit", type=int, default=20) p.set_defaults(func=cmd_list_drafts) p = sub.add_parser("discover", help="Discover an endpoint via CDP") p.add_argument("target", choices=["availability", "blog", "interview"]) p.set_defaults(func=cmd_discover) p = sub.add_parser("rank-check", help="Check search rank") p.add_argument("username") p.add_argument("--city", default="manhattan-ny") p.add_argument("--session", default="rm_traffic/session.json") p.set_defaults(func=cmd_rank_check) p = sub.add_parser("report", help="Generate daily report") p.add_argument("username") p.add_argument("--city", default="manhattan-ny") p.add_argument("--session", default="rm_traffic/session.json") p.set_defaults(func=cmd_report) for mode in ["audit", "guard", "draft"]: p = sub.add_parser(mode, help=f"Run {mode} mode") p.add_argument("--city", default="manhattan-ny") p.add_argument("--session", default="rm_traffic/session.json") p.set_defaults(func=globals()[f"cmd_{mode}"]) p = sub.add_parser("daemon", help="Run daemon") p.add_argument("--city", default="manhattan-ny") p.add_argument("--session", default="rm_traffic/session.json") p.add_argument("--execute-approved", action="store_true", help="Auto-apply approved bio changes") p.set_defaults(func=cmd_daemon) # ─── AGI Commands ─── p = sub.add_parser("agi-inspect", help="Show real corpus stats via C++ engine") p.add_argument("--bios", default=None, help="Path to real_bios.jsonl") p.set_defaults(func=cmd_agi_inspect) p = sub.add_parser("agi-train", help="Train model on real data via C++ engine") p.add_argument("--bios", default=None) p.add_argument("--label", default="reviews", choices=["reviews", "views_per_day", "rating"]) p.add_argument("--cv", type=int, default=5) p.add_argument("--walk-forward", action="store_true") p.add_argument("--epochs", type=int, default=100) p.add_argument("--lr", type=float, default=0.001) p.add_argument("--hidden", type=int, default=64) p.set_defaults(func=cmd_agi_train) p = sub.add_parser("agi-pipeline", help="Run full AGI pipeline (train→generate→score→evolve→select)") p.add_argument("--bios", default=None) p.add_argument("--count", type=int, default=100000) p.add_argument("--label", default="reviews") p.add_argument("--generations", type=int, default=100) p.add_argument("--top", type=int, default=25) p.set_defaults(func=cmd_agi_pipeline) p = sub.add_parser("agi-import", help="Import top candidates into approval queue") p.add_argument("--path", default=None) p.set_defaults(func=cmd_agi_import) p = sub.add_parser("agi-drafts", help="List AGI draft candidates") p.add_argument("--status", choices=["all", "pending", "approved"], default="all") p.set_defaults(func=cmd_agi_list_drafts) p = sub.add_parser("agi-approve", help="Approve an AGI candidate") p.add_argument("variant_id") p.set_defaults(func=cmd_agi_approve) p = sub.add_parser("agi-receipts", help="Show receipt ledger") p.add_argument("--verbose", action="store_true") p.set_defaults(func=cmd_agi_receipts) p = sub.add_parser("agi-experiments", help="List experiment results") p.set_defaults(func=cmd_agi_experiments) p = sub.add_parser("agi-dashboard", help="Show AGI control panel") p.set_defaults(func=cmd_agi_dashboard) # ─── RM-PRI Commands (honest naming) ─── p = sub.add_parser("validate-corpus", help="Gate 1: validate corpus schema") p.add_argument("path", nargs="?", default=None) p.add_argument("--check-enriched", action="store_true") p.set_defaults(func=cmd_validate_corpus) p = sub.add_parser("enrich-views", help="Gate 2: enrich bios with public visits/member-since") p.add_argument("--input", default=None) p.add_argument("--output", default=None) p.add_argument("--workers", type=int, default=16) p.add_argument("--rate-limit", type=float, default=0.5) p.set_defaults(func=cmd_enrich_views) p = sub.add_parser("rank-real", help="Rank real bios by views_per_day") p.add_argument("--input", default=None) p.add_argument("--output", default=None) p.add_argument("--metric", default="views_per_day") p.set_defaults(func=cmd_rank_real) p = sub.add_parser("atomize-bios", help="Extract structural atoms from bios") p.add_argument("--input", default=None) p.add_argument("--output", default=None) p.set_defaults(func=cmd_atomize_bios) p = sub.add_parser("pri-status", help="Show honest RM-PRI system status") p.set_defaults(func=cmd_pri_status) args = parser.parse_args() # Credentials check for commands that need them if args.command in ("status", "snapshot", "unhide", "draft-bio", "apply", "audit", "guard", "draft", "daemon", "rank-check", "report"): if not get_credential("RM_USER") or not get_credential("RM_PASS"): print("Set RM_USER and RM_PASS environment variables first.") print("Do not hardcode credentials.") sys.exit(1) args.func(args) if __name__ == "__main__": main()