#!/usr/bin/env python3
"""
run_agent.py — chat locale con un agente definito da un Modelfile (Prompt Forge).

Scarica questo file + un Modelfile dal sito, mettili nella stessa cartella, poi:
    python3 run_agent.py                          # usa Modelfile.txt + modello di default
    python3 run_agent.py Modelfile.txt            # Modelfile specifico
    python3 run_agent.py Modelfile.txt -m llama2  # scegli il modello base

Legge il SYSTEM prompt dal Modelfile e conversa col TUO modello Ollama,
mantenendo la history. Niente dato esce dal tuo PC. L'utente scrive per primo.

Comandi in chat:  /reset  (azzera la conversazione) ·  /exit  (esci)

Prerequisito: Ollama in esecuzione (http://localhost:11434) + un modello scaricato.
Per contenuto adult usa un modello UNCENSORED (i default tipo llama3.1 rifiutano):
    ollama pull nexusriot/Gemma-4-Uncensored-HauhauCS-Aggressive:e2b
"""
import json
import re
import sys
import urllib.request

OLLAMA = "http://localhost:11434/api/chat"
# default = un modello uncensored sensato; cambialo con -m oppure edita qui
DEFAULT_MODEL = "nexusriot/Gemma-4-Uncensored-HauhauCS-Aggressive:e2b"


def parse_modelfile(path):
    """Estrae il SYSTEM prompt (blocco triple-quote) dal Modelfile."""
    text = open(path, encoding="utf-8").read()
    m = re.search(r'SYSTEM\s+"""(.*?)"""', text, re.S)
    if not m:
        sys.exit(f"Nessun blocco SYSTEM \"\"\"...\"\"\" trovato in {path}")
    system = m.group(1).replace('\\"\\"\\"', '"""').strip()
    fm = re.search(r'^FROM\s+(\S+)', text, re.M)
    base = fm.group(1) if fm else None
    return system, base


def chat(model, messages, think=False):
    """Una risposta dal modello via Ollama /api/chat (non-streaming)."""
    body = json.dumps({
        "model": model,
        "messages": messages,
        "stream": False,
        "think": think,            # False = niente dump del ragionamento
        "options": {"temperature": 0.85, "top_p": 0.9},
    }).encode()
    req = urllib.request.Request(OLLAMA, data=body, headers={"Content-Type": "application/json"})
    try:
        with urllib.request.urlopen(req, timeout=600) as r:
            data = json.loads(r.read())
        return data.get("message", {}).get("content", "").strip()
    except urllib.error.URLError as e:
        sys.exit(f"\nOllama non raggiungibile ({e}). Avvialo: `ollama serve`")


def main():
    args = [a for a in sys.argv[1:]]
    model = DEFAULT_MODEL
    if "-m" in args:
        i = args.index("-m")
        model = args[i + 1]
        del args[i:i + 2]
    path = args[0] if args else "Modelfile.txt"

    system, base = parse_modelfile(path)
    print(f"Modelfile: {path}")
    print(f"FROM nel file: {base or '(non indicato)'} · modello usato: {model}")
    print(f"System prompt: {len(system)} char caricati.")
    print("Scrivi un messaggio. /reset per azzerare, /exit per uscire.\n")

    history = [{"role": "system", "content": system}]
    # l'utente inizia la conversazione (il bot NON apre da solo)
    while True:
        try:
            user = input("tu: ").strip()
        except (EOFError, KeyboardInterrupt):
            print("\nciao."); break
        if not user:
            continue
        if user == "/exit":
            print("ciao."); break
        if user == "/reset":
            history = [{"role": "system", "content": system}]
            print("[conversazione azzerata]\n"); continue
        history.append({"role": "user", "content": user})
        print("agente: ", end="", flush=True)
        reply = chat(model, history)
        print(reply + "\n")
        history.append({"role": "assistant", "content": reply})


if __name__ == "__main__":
    main()
