mrj-crom commited on
Commit
00eab41
Β·
verified Β·
1 Parent(s): 8bb4681

sync: scripts/dna_decoder.py

Browse files
Files changed (1) hide show
  1. scripts/dna_decoder.py +198 -0
scripts/dna_decoder.py ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ ╔══════════════════════════════════════════════════════════════╗
4
+ β•‘ 🧬 CROM-IA V2: Decoder Streaming DNA β†’ Texto Humano β•‘
5
+ β•‘ β•‘
6
+ β•‘ Recebe tokens DNA do llama-cli via stdin (pipe) β•‘
7
+ β•‘ Decodifica usando codebook semΓ’ntico (hashmap O(1)) β•‘
8
+ β•‘ Emite texto humano em tempo real via stdout β•‘
9
+ β•‘ Emite mΓ©tricas SRE no stderr ao final β•‘
10
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
11
+
12
+ Uso:
13
+ llama-cli -m model.gguf -p "..." | python3 dna_decoder.py --codebook codebook_1x3_fixo.json
14
+ """
15
+
16
+ import os
17
+ import sys
18
+ import json
19
+ import time
20
+ import argparse
21
+
22
+
23
+ def carregar_codebook(caminho):
24
+ """Carrega codebook e prepara hashmap de lookup."""
25
+ with open(caminho, 'r', encoding='utf-8') as f:
26
+ codebook = json.load(f)
27
+
28
+ entries = codebook.get("entries", {})
29
+ escape = codebook.get("escape_prefix", "@@")
30
+ taxa = codebook.get("taxa_alvo", "?")
31
+ modo = codebook.get("modo", "?")
32
+
33
+ sys.stderr.write(f"[CROM DNA Decoder]\n")
34
+ sys.stderr.write(f" Codebook : {os.path.basename(caminho)}\n")
35
+ sys.stderr.write(f" Taxa : {taxa}\n")
36
+ sys.stderr.write(f" Modo : {modo}\n")
37
+ sys.stderr.write(f" Entradas : {len(entries)}\n")
38
+ sys.stderr.write(f" Escape : {escape}\n")
39
+ sys.stderr.write(f" ─────────────────────────\n")
40
+ sys.stderr.flush()
41
+
42
+ return entries, escape, taxa, modo
43
+
44
+
45
+ def decoder_streaming(entries, escape_prefix, max_buffer=10):
46
+ """
47
+ Decodifica stream de tokens DNA do stdin.
48
+
49
+ Protocolo:
50
+ - Tokens sΓ£o separados por espaΓ§os ou newlines
51
+ - Tokens que comeΓ§am com o escape_prefix sΓ£o texto literal
52
+ - Tokens que existem no codebook sΓ£o expandidos
53
+ - Tokens desconhecidos sΓ£o marcados como [?token]
54
+ """
55
+ stats = {
56
+ "tokens_recebidos": 0,
57
+ "tokens_validos": 0,
58
+ "tokens_escape": 0,
59
+ "tokens_alucinados": 0,
60
+ "palavras_emitidas": 0,
61
+ "t_inicio": time.time(),
62
+ "t_primeiro_token": None,
63
+ }
64
+
65
+ buffer = ""
66
+
67
+ for char in sys.stdin:
68
+ for c in char:
69
+ if c in (' ', '\n', '\t'):
70
+ if buffer:
71
+ _processar_token(buffer, entries, escape_prefix, stats)
72
+ buffer = ""
73
+ else:
74
+ buffer += c
75
+
76
+ # Safety: se buffer ficou muito grande, Γ© alucinaΓ§Γ£o
77
+ if len(buffer) > 20:
78
+ stats["tokens_alucinados"] += 1
79
+ stats["tokens_recebidos"] += 1
80
+ sys.stdout.write(f"[?{buffer}] ")
81
+ sys.stdout.flush()
82
+ buffer = ""
83
+
84
+ # Flush final
85
+ if buffer:
86
+ _processar_token(buffer, entries, escape_prefix, stats)
87
+
88
+ return stats
89
+
90
+
91
+ def _processar_token(token, entries, escape_prefix, stats):
92
+ """Processa um token individual."""
93
+ stats["tokens_recebidos"] += 1
94
+
95
+ if stats["t_primeiro_token"] is None:
96
+ stats["t_primeiro_token"] = time.time()
97
+
98
+ # Modo escape: texto literal
99
+ if token.startswith(escape_prefix):
100
+ texto = token[len(escape_prefix):]
101
+ sys.stdout.write(texto + " ")
102
+ sys.stdout.flush()
103
+ stats["tokens_escape"] += 1
104
+ stats["palavras_emitidas"] += 1
105
+ return
106
+
107
+ # Lookup no codebook
108
+ if token in entries:
109
+ texto = entries[token]["text"]
110
+ n_palavras = entries[token].get("n", len(texto.split()))
111
+ sys.stdout.write(texto + " ")
112
+ sys.stdout.flush()
113
+ stats["tokens_validos"] += 1
114
+ stats["palavras_emitidas"] += n_palavras
115
+ return
116
+
117
+ # Token desconhecido (alucinaΓ§Γ£o)
118
+ sys.stdout.write(f"[?{token}] ")
119
+ sys.stdout.flush()
120
+ stats["tokens_alucinados"] += 1
121
+
122
+
123
+ def emitir_metricas(stats, taxa, modo, codebook_name):
124
+ """Emite mΓ©tricas SRE no stderr."""
125
+ t_total = time.time() - stats["t_inicio"]
126
+ t_primeiro = (stats["t_primeiro_token"] - stats["t_inicio"]
127
+ if stats["t_primeiro_token"] else 0)
128
+
129
+ total = stats["tokens_recebidos"]
130
+ validos = stats["tokens_validos"]
131
+ escapes = stats["tokens_escape"]
132
+ alucinados = stats["tokens_alucinados"]
133
+ palavras = stats["palavras_emitidas"]
134
+
135
+ hit_rate = (validos / max(total, 1)) * 100
136
+ alucinacao = (alucinados / max(total, 1)) * 100
137
+ taxa_real = palavras / max(total, 1)
138
+ palavras_por_s = palavras / max(t_total, 0.001)
139
+
140
+ sys.stderr.write(f"\n")
141
+ sys.stderr.write(f"{'═' * 55}\n")
142
+ sys.stderr.write(f" [CROM DNA Decoder] RELATΓ“RIO FINAL\n")
143
+ sys.stderr.write(f"{'═' * 55}\n")
144
+ sys.stderr.write(f" Codebook : {codebook_name}\n")
145
+ sys.stderr.write(f" Taxa alvo : {taxa}\n")
146
+ sys.stderr.write(f" Modo : {modo}\n")
147
+ sys.stderr.write(f" ─────────────────────────\n")
148
+ sys.stderr.write(f" Tokens DNA in : {total}\n")
149
+ sys.stderr.write(f" Tokens vΓ‘lidos : {validos} ({hit_rate:.1f}%)\n")
150
+ sys.stderr.write(f" Tokens escape : {escapes}\n")
151
+ sys.stderr.write(f" Tokens alucinados : {alucinados} ({alucinacao:.1f}%)\n")
152
+ sys.stderr.write(f" ─────────────────────────\n")
153
+ sys.stderr.write(f" Palavras emitidas : {palavras}\n")
154
+ sys.stderr.write(f" Taxa real : 1:{taxa_real:.1f}\n")
155
+ sys.stderr.write(f" Velocidade : {palavras_por_s:.1f} palavras/s\n")
156
+ sys.stderr.write(f" LatΓͺncia 1ΒΊ token : {t_primeiro*1000:.0f} ms\n")
157
+ sys.stderr.write(f" Tempo total : {t_total:.2f} s\n")
158
+ sys.stderr.write(f"{'═' * 55}\n")
159
+ sys.stderr.flush()
160
+
161
+
162
+ def main():
163
+ parser = argparse.ArgumentParser(
164
+ description="🧬 CROM-IA V2: DNA Decoder Streaming"
165
+ )
166
+ parser.add_argument(
167
+ "--codebook", type=str, required=True,
168
+ help="Caminho para o codebook JSON"
169
+ )
170
+ parser.add_argument(
171
+ "--quiet", action="store_true",
172
+ help="Suprime mΓ©tricas no stderr"
173
+ )
174
+ args = parser.parse_args()
175
+
176
+ if not os.path.exists(args.codebook):
177
+ sys.stderr.write(f"❌ Codebook não encontrado: {args.codebook}\n")
178
+ sys.exit(1)
179
+
180
+ entries, escape, taxa, modo = carregar_codebook(args.codebook)
181
+
182
+ try:
183
+ stats = decoder_streaming(entries, escape)
184
+ except KeyboardInterrupt:
185
+ stats = {"tokens_recebidos": 0, "tokens_validos": 0,
186
+ "tokens_escape": 0, "tokens_alucinados": 0,
187
+ "palavras_emitidas": 0, "t_inicio": time.time(),
188
+ "t_primeiro_token": None}
189
+
190
+ sys.stdout.write("\n")
191
+ sys.stdout.flush()
192
+
193
+ if not args.quiet:
194
+ emitir_metricas(stats, taxa, modo, os.path.basename(args.codebook))
195
+
196
+
197
+ if __name__ == "__main__":
198
+ main()