File size: 3,631 Bytes
9013a70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/bin/env python3
import sys
import subprocess
import json
import os
import re

def carregar_codebook(caminho):
    with open(caminho, 'r', encoding='utf-8') as f:
        codebook = json.load(f)
    return codebook.get("entries", {}), codebook.get("escape_prefix", "@@")

def limpa_ansi(texto):
    """Remove códigos ANSI de cor caso o llama os gere na saída."""
    ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
    return ansi_escape.sub('', texto)

def run_chat_loop(llama_cli, modelo, ctx, threads, system_prompt, codebook_path):
    entries, escape = carregar_codebook(codebook_path)
    historico = f"<|im_start|>system\n{system_prompt}<|im_end|>\n"
    
    print("\n[!] Loop Conversacional CROM Híbrido Ativado (Interação Blindada)")
    print("Digite 'sair' ou pressione Ctrl+C para encerrar.\n")
    
    while True:
        try:
            pergunta = input("\033[0;36m👤 Você:\033[0m ").strip()
            if not pergunta: continue
            if pergunta.lower() in ["sair", "exit", "quit", "/exit"]:
                print("Saindo...")
                break
                
            # Atualiza histórico para QWEN/TinyLLaMa ChatML Format
            historico += f"<|im_start|>user\n{pergunta}<|im_end|>\n<|im_start|>assistant\n"
            
            # Chama a Llama em modo raw/batch. O "--log-disable" blinda a tela!
            cmd = [
                llama_cli, "-m", modelo, "-c", str(ctx), "-t", str(threads),
                "-n", "128", "--temp", "0.2", "--repeat-penalty", "1.18",
                "--log-disable", "-p", historico
            ]
            
            print("\033[0;32m🤖 CROM:\033[0m ", end="", flush=True)
            
            proc = subprocess.Popen(
                cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.DEVNULL, # Ignora meta dados TTY do stdout/stderr
            )
            
            # Pega saida bash, ignora o proprio prompt inserido
            out, _ = proc.communicate()
            resposta_raw = out.decode("utf-8", "ignore")
            
            # A Llama cospe o prompt inteiro de novo no modo '-p'. Precisamos fatiar apenas a resposta nova!
            if "<|im_start|>assistant\n" in resposta_raw:
                # Pega só o que ele respondeu por ultimo
                partes = resposta_raw.split("<|im_start|>assistant\n")
                nova_resposta = partes[-1].split("<|im_end|>")[0].strip()
            else:
                # Fallback caso a modelagem corte as tags
                nova_resposta = resposta_raw.replace(historico, "").strip()
            
            # Decodificador em Lote Super Rápido (1x5)
            nova_resposta_limpa = limpa_ansi(nova_resposta)
            tokens = nova_resposta_limpa.split()
            saida_final = []
            
            for t in tokens:
                if t.startswith(escape):
                    saida_final.append(t[len(escape):]) # É humano com @@
                elif t in entries:
                    saida_final.append(entries[t]["text"]) # É DNA CROM
                else:
                    saida_final.append(t) # Letras soltas ou pontuação
                    
            frase = " ".join(saida_final)
            print(f"{frase}\n")
            
            # Alimenta o loop para a proxima rodada
            historico += nova_resposta + "<|im_end|>\n"
            
        except KeyboardInterrupt:
            print("\n[!] Conversa abortada.")
            break

if __name__ == "__main__":
    run_chat_loop(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6])