Release V4.2 MultiBrain (0.6B + 3 LoRAs)
Browse files- .gitattributes +10 -0
- 00_CROM_IA_V4.2_DOCUMENTATION.md +242 -0
- 00_CROM_IA_V4.2_ROADMAP.md +171 -0
- 01_DPO_GUIDE.md +190 -0
- 02_CHAT_RAG_GUIDE.md +184 -0
- 1_extracao_local/codebooks/codebook_python_v42.json +321 -0
- 1_extracao_local/datasets_hibridos/Base_PTBR.jsonl +3 -0
- 1_extracao_local/datasets_hibridos/Python_DNA25.jsonl +3 -0
- 1_extracao_local/datasets_hibridos/canarim_30k.jsonl +3 -0
- 1_extracao_local/datasets_hibridos/dataset_DPO_python.jsonl +3 -0
- 1_extracao_local/datasets_hibridos/openhermes_10k_ptbr.jsonl +3 -0
- 1_extracao_local/datasets_hibridos/python_15k.jsonl +3 -0
- 1_extracao_local/download_datasets_v42.py +256 -0
- 1_extracao_local/gerador_codebook_v42.py +284 -0
- 1_extracao_local/gerador_pares_dpo.py +180 -0
- 1_extracao_local/tradutor_batch_argos.py +243 -0
- 1_extracao_local/transpilador_v42.py +143 -0
- 2_treinamento_nuvem/01_CROM_V42_TRAINING_FASE1.py +169 -0
- 2_treinamento_nuvem/02_CROM_V42_TRAINING_FASE2.py +150 -0
- 2_treinamento_nuvem/03_CROM_V42_DPO_TRAINING.py +183 -0
- 2_treinamento_nuvem/colab/00_CROM_V42_TRANSLATOR_COLAB.md +173 -0
- 3_inferencia_local/benchmark_matrix_v42.sh +83 -0
- 3_inferencia_local/chat_v42_brain.sh +413 -0
- 3_inferencia_local/micro_cerebros/Base_PTBR_lora.gguf +3 -0
- 3_inferencia_local/micro_cerebros/DPO_Preference_lora.gguf +3 -0
- 3_inferencia_local/micro_cerebros/Python_DNA_lora.gguf +3 -0
- 3_inferencia_local/micro_cerebros/qwen3-0.6b.Q4_K_M.gguf +3 -0
- 3_inferencia_local/rag_contexto.py +295 -0
- 3_inferencia_local/relatorio_estresse_v42.md +113 -0
- HUGGINGFACE_RELEASE.md +24 -0
- README.md +27 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,13 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
1_extracao_local/datasets_hibridos/Base_PTBR.jsonl filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
1_extracao_local/datasets_hibridos/Python_DNA25.jsonl filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
1_extracao_local/datasets_hibridos/canarim_30k.jsonl filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
1_extracao_local/datasets_hibridos/dataset_DPO_python.jsonl filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
1_extracao_local/datasets_hibridos/openhermes_10k_ptbr.jsonl filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
1_extracao_local/datasets_hibridos/python_15k.jsonl filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
3_inferencia_local/micro_cerebros/Base_PTBR_lora.gguf filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
3_inferencia_local/micro_cerebros/DPO_Preference_lora.gguf filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
3_inferencia_local/micro_cerebros/Python_DNA_lora.gguf filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
3_inferencia_local/micro_cerebros/qwen3-0.6b.Q4_K_M.gguf filter=lfs diff=lfs merge=lfs -text
|
00_CROM_IA_V4.2_DOCUMENTATION.md
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# CROM-IA V4.2 — Multi-Brain DNA Engine + DPO + RAG-Chat
|
| 2 |
+
> **Status:** Em construção
|
| 3 |
+
> **Base Model:** Qwen3-0.6B (`unsloth/Qwen3-0.6B-unsloth-bnb-4bit`)
|
| 4 |
+
> **Mudanças vs V4.1:** DPO, Chat com ingestão de arquivos, DNA conservador 25%, Datasets reais
|
| 5 |
+
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
## Evolução do Projeto
|
| 9 |
+
|
| 10 |
+
| Versão | Modelo | Velocidade | RAM | DNA | Resultado |
|
| 11 |
+
|---|---|---|---|---|---|
|
| 12 |
+
| V4.0 | Qwen2.5-1.5B | 3-5 t/s | ~1.2GB | 50% | ✅ Funcional mas lento |
|
| 13 |
+
| V4.1-α | Qwen3-0.6B | 7-9 t/s | 635MB | 75% | ❌ Catastrophic forgetting |
|
| 14 |
+
| **V4.2** | **Qwen3-0.6B** | **7-9 t/s** | **635MB** | **25%** | **🔧 Em construção** |
|
| 15 |
+
|
| 16 |
+
---
|
| 17 |
+
|
| 18 |
+
## Lições Aprendidas (V4.1-alpha → V4.2)
|
| 19 |
+
|
| 20 |
+
### O que DESTRUIU a V4.1:
|
| 21 |
+
| Erro | V4.1 (errado) | V4.2 (corrigido) |
|
| 22 |
+
|---|---|---|
|
| 23 |
+
| DNA mutação | 75% (destruiu coerência) | **25%** máximo |
|
| 24 |
+
| Steps | 2000 (overfitting) | **500-800** |
|
| 25 |
+
| Rank LoRA | 64 (reescreveu o modelo inteiro) | **16** |
|
| 26 |
+
| Target modules | q,k,v,o + gate,down,up (MLP!) | **q,k,v,o** (só attention) |
|
| 27 |
+
| Datasets | 15 templates repetidos | **30K+ do HuggingFace** |
|
| 28 |
+
| Épocas CROM_Self | 133 (memorizou) | **máximo 10** |
|
| 29 |
+
| Learning rate | 2e-5 | **1e-5** (mais suave) |
|
| 30 |
+
| LR scheduler | Linear | **Cosine** (convergência melhor) |
|
| 31 |
+
|
| 32 |
+
### O que DEU CERTO (mantemos):
|
| 33 |
+
- ✅ Pipeline completo: extração → codebook → transpilação → treino → deploy
|
| 34 |
+
- ✅ Velocidade: 7-9 t/s no i5-3320M (2x V4.0)
|
| 35 |
+
- ✅ RAM: 635MB (metade da V4.0)
|
| 36 |
+
- ✅ DNA ativo: tokens `@@PWAT`, `@@PWC` apareceram na saída
|
| 37 |
+
- ✅ Codebook data-driven por frequência real (filosofia Crompressor)
|
| 38 |
+
- ✅ Script `adicionar_cerebro.py` — adiciona cérebro em 1 comando
|
| 39 |
+
|
| 40 |
+
---
|
| 41 |
+
|
| 42 |
+
## Arquitetura V4.2
|
| 43 |
+
|
| 44 |
+
### Modelo Base
|
| 45 |
+
- **Qwen3-0.6B** — Velocidade é prioridade no i5 sem GPU
|
| 46 |
+
- Unsloth: `unsloth/Qwen3-0.6B-unsloth-bnb-4bit`
|
| 47 |
+
- GGUF: Q4_K_M (~379MB)
|
| 48 |
+
|
| 49 |
+
### Parâmetros de Treino (Conservadores)
|
| 50 |
+
```python
|
| 51 |
+
# LoRA
|
| 52 |
+
r = 16 # Rank (era 64)
|
| 53 |
+
lora_alpha = 32 # 2x rank
|
| 54 |
+
target_modules = ["q_proj", "k_proj", "v_proj", "o_proj"] # SEM MLP!
|
| 55 |
+
|
| 56 |
+
# SFT (Fases 1 e 2)
|
| 57 |
+
max_steps = 800 # Fase 1 / 500 para Fase 2
|
| 58 |
+
per_device_train_batch_size = 8
|
| 59 |
+
gradient_accumulation_steps = 4
|
| 60 |
+
learning_rate = 1e-5
|
| 61 |
+
lr_scheduler_type = "cosine"
|
| 62 |
+
warmup_ratio = 0.05
|
| 63 |
+
|
| 64 |
+
# DPO (Fase 3)
|
| 65 |
+
beta = 0.1 # Força da preferência
|
| 66 |
+
max_steps = 300
|
| 67 |
+
learning_rate = 5e-6 # Mais suave que SFT
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
### Datasets (Qualidade > Quantidade)
|
| 71 |
+
| Cérebro | Fonte | Amostras | DNA % | Fase |
|
| 72 |
+
|---|---|---|---|---|
|
| 73 |
+
| **Base_PTBR** | Canarim 30K + OpenHermes 10K trad. | 40.000 | 0% | Fase 1 |
|
| 74 |
+
| **Python_DNA** | `Vezora/Tested-22k-Python-Alpaca` | 15.000 | 25% | Fase 2 |
|
| 75 |
+
| **Medicina_DNA** | Dataset V4.0 + nosso | 8.000 | 25% | Fase 2 |
|
| 76 |
+
| **CROM_Self** | Docs .md do projeto | 500 | 0% | Fase 2 |
|
| 77 |
+
| **DPO_Pares** | Gerado automaticamente | 5.000 | chosen=DNA | Fase 3 |
|
| 78 |
+
|
| 79 |
+
**REGRAS:**
|
| 80 |
+
- DNA máximo 25%. O modelo PRIMEIRO sabe falar, DEPOIS usa DNA.
|
| 81 |
+
- Máximo 10 épocas por dataset.
|
| 82 |
+
- Filtros de qualidade: resposta > 100 chars, sem duplicatas.
|
| 83 |
+
|
| 84 |
+
---
|
| 85 |
+
|
| 86 |
+
## Estratégia de Treino: 3 Fases
|
| 87 |
+
|
| 88 |
+
### Fase 1 — SFT Base Conversacional (SEM DNA)
|
| 89 |
+
Treinar LoRA de "personalidade" com 40K conversas reais.
|
| 90 |
+
O modelo aprende a conversar bem em PT-BR primeiro.
|
| 91 |
+
```
|
| 92 |
+
Dataset: Canarim 30K + OpenHermes 10K (traduzido)
|
| 93 |
+
DNA: 0%
|
| 94 |
+
Steps: 800
|
| 95 |
+
Output: Base_PTBR_lora
|
| 96 |
+
```
|
| 97 |
+
|
| 98 |
+
### Fase 2 — SFT Especialização DNA (25% DNA)
|
| 99 |
+
Treinar LoRAs especializados com DNA sutil sobre a base conversacional.
|
| 100 |
+
```
|
| 101 |
+
Dataset Python: 15K com 25% DNA → Python_DNA_lora
|
| 102 |
+
Dataset Medicina: 8K com 25% DNA → Medicina_DNA_lora
|
| 103 |
+
Steps: 500 cada
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
### Fase 3 — DPO (Direct Preference Optimization)
|
| 107 |
+
O modelo aprende a PREFERIR respostas com DNA sobre texto normal.
|
| 108 |
+
```python
|
| 109 |
+
# Par DPO
|
| 110 |
+
{
|
| 111 |
+
"prompt": "Explique arritmia cardíaca",
|
| 112 |
+
"chosen": "Uma @@DGN de @@CRC onde o ritmo...", # DNA = preferido
|
| 113 |
+
"rejected": "Um diagnóstico de coração onde..." # Normal = rejeitado
|
| 114 |
+
}
|
| 115 |
+
```
|
| 116 |
+
- Usa `trl.DPOTrainer`
|
| 117 |
+
- 5K pares gerados automaticamente pelo `gerador_pares_dpo.py`
|
| 118 |
+
- Resultado: modelo usa DNA quando oportuno, sem forçar
|
| 119 |
+
|
| 120 |
+
---
|
| 121 |
+
|
| 122 |
+
## Inferência: Monitor de Orquestração + RAG
|
| 123 |
+
|
| 124 |
+
### O Monitor TUI
|
| 125 |
+
O `chat_v42_brain.sh` abre um **painel interativo** onde você configura tudo ANTES de iniciar o chat:
|
| 126 |
+
|
| 127 |
+
```
|
| 128 |
+
╔══════════════════════════════════════════════════════════════╗
|
| 129 |
+
║ 🧠 CROM-IA V4.2 — Monitor de Orquestração ║
|
| 130 |
+
╠══════════════════════════════════════════════════════════════╣
|
| 131 |
+
║ Configure seus cérebros e contexto antes de iniciar ║
|
| 132 |
+
╚═══════════════════════════════════════════════════════════��══╝
|
| 133 |
+
|
| 134 |
+
── Modelo Base ─────────────────────────────────────────────
|
| 135 |
+
✅ qwen3-0.6b-q4_k_m.gguf (379MB)
|
| 136 |
+
|
| 137 |
+
── Micro-Cérebros (LoRAs) ──────────────────────────────────
|
| 138 |
+
[1] ✅ ON Base_PTBR (32MB)
|
| 139 |
+
[2] ✅ ON Python_DNA (28MB)
|
| 140 |
+
[3] ⬚ OFF Medicina_DNA (30MB) ← desativado!
|
| 141 |
+
|
| 142 |
+
── Contexto RAG (Arquivos/Pastas) ──────────────────────────
|
| 143 |
+
📄 main.py
|
| 144 |
+
📂 ./src/ (15 arquivos)
|
| 145 |
+
|
| 146 |
+
── Ações ───────────────────────────────────────────────────
|
| 147 |
+
[1-9] Toggle cérebro ON/OFF
|
| 148 |
+
[a] Adicionar arquivo [p] Adicionar pasta
|
| 149 |
+
[r] Remover último RAG [c] Limpar RAG
|
| 150 |
+
[t] Temperatura [w] Janela de contexto
|
| 151 |
+
[*] Ativar TODOS [0] Desativar TODOS
|
| 152 |
+
[ENTER] 🚀 INICIAR CHAT
|
| 153 |
+
[q] Sair
|
| 154 |
+
```
|
| 155 |
+
|
| 156 |
+
### Uso
|
| 157 |
+
```bash
|
| 158 |
+
# Abrir monitor (interativo)
|
| 159 |
+
./chat_v42_brain.sh
|
| 160 |
+
|
| 161 |
+
# Pré-carregar arquivos e abrir monitor
|
| 162 |
+
./chat_v42_brain.sh --arquivo main.py --pasta ./src/
|
| 163 |
+
```
|
| 164 |
+
|
| 165 |
+
### Como Funciona
|
| 166 |
+
1. **Monitor TUI:** Painel interativo para orquestrar cérebros e contexto
|
| 167 |
+
2. **Toggle:** Ativa/desativa cérebros individuais com tecla numérica
|
| 168 |
+
3. **RAG-lite:** Adiciona arquivos/pastas que são lidos e injetados no prompt
|
| 169 |
+
4. **Config:** Ajusta temperatura, contexto, max tokens na hora
|
| 170 |
+
5. **Launch:** ENTER lança o chat com a config escolhida
|
| 171 |
+
6. **Retorno:** Ctrl+C no chat volta ao monitor para reconfigurar
|
| 172 |
+
|
| 173 |
+
---
|
| 174 |
+
|
| 175 |
+
## Estrutura de Diretórios V4.2
|
| 176 |
+
|
| 177 |
+
```
|
| 178 |
+
v4.2_multibrain_engine/
|
| 179 |
+
├── 00_CROM_IA_V4.2_DOCUMENTATION.md ← Este arquivo
|
| 180 |
+
├── 00_CROM_IA_V4.2_ROADMAP.md ← Roadmap original (referência)
|
| 181 |
+
├── 01_DPO_GUIDE.md ← Guia DPO detalhado
|
| 182 |
+
├── 02_CHAT_RAG_GUIDE.md ← Guia do Monitor + RAG
|
| 183 |
+
├── 1_extracao_local/
|
| 184 |
+
│ ├── codebooks/ ← Codebooks data-driven
|
| 185 |
+
│ ├── datasets_hibridos/ ← Datasets prontos para Colab
|
| 186 |
+
│ ├── download_datasets_v42.py ← Baixa HuggingFace
|
| 187 |
+
│ ├── tradutor_batch_argos.py ← Traduz EN→PT offline
|
| 188 |
+
│ ├── transpilador_v42.py ← DNA a 25% (era 75%)
|
| 189 |
+
│ ├── gerador_codebook_v42.py ← Mineração por frequência
|
| 190 |
+
│ └── gerador_pares_dpo.py ← Gera pares DPO automáticos
|
| 191 |
+
├── 2_treinamento_nuvem/
|
| 192 |
+
│ ├── 01_CROM_V42_TRAINING_FASE1.py ← SFT Base (40K, 0% DNA)
|
| 193 |
+
│ ├── 02_CROM_V42_TRAINING_FASE2.py ← SFT DNA (23K, 25% DNA)
|
| 194 |
+
│ ├── 03_CROM_V42_DPO_TRAINING.py ← DPO (5K pares, preferência)
|
| 195 |
+
│ ├── adapters_lora/ ← LoRAs PEFT do Colab
|
| 196 |
+
│ └── colab/ ← Notebooks prontos
|
| 197 |
+
├── 3_inferencia_local/
|
| 198 |
+
│ ├── chat_v42_brain.sh ← 🎛️ MONITOR TUI + Chat
|
| 199 |
+
│ ├── rag_contexto.py ← Motor RAG-lite (sem GPU)
|
| 200 |
+
│ ├── decodificador_dna/
|
| 201 |
+
│ │ └── decodificador_dna.py ← Traduz @@tokens → palavras
|
| 202 |
+
│ └── micro_cerebros/ ← LoRAs GGUF empilháveis
|
| 203 |
+
└── adicionar_cerebro.py ← Adicionar cérebro em 1 cmd
|
| 204 |
+
```
|
| 205 |
+
|
| 206 |
+
---
|
| 207 |
+
|
| 208 |
+
## Checklist de Execução
|
| 209 |
+
|
| 210 |
+
### Preparação (Local)
|
| 211 |
+
- [ ] Instalar argostranslate (`pip install argostranslate`)
|
| 212 |
+
- [ ] Baixar Canarim-PTBR 30K do HuggingFace
|
| 213 |
+
- [ ] Baixar Python Alpaca 15K
|
| 214 |
+
- [ ] Traduzir OpenHermes-2.5 top 10K (Argos)
|
| 215 |
+
- [ ] Gerar codebooks data-driven para novos datasets
|
| 216 |
+
- [ ] Transpilar datasets com DNA a 25%
|
| 217 |
+
- [ ] Gerar pares DPO (5K)
|
| 218 |
+
|
| 219 |
+
### Treino (Colab)
|
| 220 |
+
- [ ] Fase 1: Base_PTBR (40K, 0% DNA, 800 steps, rank 16)
|
| 221 |
+
- [ ] Fase 2: Python_DNA (15K, 25% DNA, 500 steps, rank 16)
|
| 222 |
+
- [ ] Fase 2: Medicina_DNA (8K, 25% DNA, 500 steps, rank 16)
|
| 223 |
+
- [ ] Fase 3: DPO (5K pares, 300 steps, rank 16)
|
| 224 |
+
- [ ] Converter PEFT → GGUF-LoRA com llama.cpp
|
| 225 |
+
|
| 226 |
+
### Deploy (Local)
|
| 227 |
+
- [ ] Baixar Qwen3-0.6B base GGUF
|
| 228 |
+
- [ ] Baixar LoRAs convertidos
|
| 229 |
+
- [ ] Testar chat_v42_brain.sh sem arquivos
|
| 230 |
+
- [ ] Testar chat_v42_brain.sh --arquivo test.py
|
| 231 |
+
- [ ] Testar chat_v42_brain.sh --pasta ./projeto/
|
| 232 |
+
- [ ] Testar LoRA stacking (2+ LoRAs)
|
| 233 |
+
- [ ] Benchmark: velocidade + qualidade + DNA %
|
| 234 |
+
|
| 235 |
+
---
|
| 236 |
+
|
| 237 |
+
## Hardware Alvo
|
| 238 |
+
- **CPU:** Intel i5-3320M @ 2.60GHz (4 threads)
|
| 239 |
+
- **RAM:** 7.4GB total
|
| 240 |
+
- **GPU:** Nenhuma
|
| 241 |
+
- **Disco:** ~25GB livres
|
| 242 |
+
- **llama-cli:** `/home/j/Área de trabalho/crompressor-ia/pesquisa/poc_llama_cpp_fuse/llama.cpp/build/bin/llama-cli`
|
00_CROM_IA_V4.2_ROADMAP.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# CROM-IA V4.2 — Roadmap de Melhorias
|
| 2 |
+
> **Status:** Planejamento
|
| 3 |
+
> **Base Model:** Qwen3.5-0.8B (https://huggingface.co/Qwen/Qwen3.5-0.8B)
|
| 4 |
+
> **Pré-requisito:** V4.1 concluída e validada
|
| 5 |
+
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
## Upgrade de Modelo: Qwen3.5-0.8B
|
| 9 |
+
|
| 10 |
+
### Por que trocar do Qwen3-0.6B?
|
| 11 |
+
| Aspecto | Qwen3-0.6B (V4.1) | Qwen3.5-0.8B (V4.2) |
|
| 12 |
+
|---|---|---|
|
| 13 |
+
| Parâmetros | 636M | ~800M (+25%) |
|
| 14 |
+
| Arquitetura | Qwen3 | Qwen3.5 (mais moderna) |
|
| 15 |
+
| PT-BR nativo | Bom | Melhor (mais dados de treino) |
|
| 16 |
+
| Velocidade i5 | ~8-10 t/s | ~6-8 t/s (ainda rápido) |
|
| 17 |
+
| Raciocínio | Básico | Melhorado (3.5 foca em reasoning) |
|
| 18 |
+
|
| 19 |
+
### Ação necessária:
|
| 20 |
+
Verificar se Unsloth disponibiliza `unsloth/Qwen3.5-0.8B-bnb-4bit`.
|
| 21 |
+
Se não, usar quantização manual via `BitsAndBytesConfig`.
|
| 22 |
+
|
| 23 |
+
---
|
| 24 |
+
|
| 25 |
+
## Melhorias Planejadas V4.2
|
| 26 |
+
|
| 27 |
+
### 1. DPO (Direct Preference Optimization)
|
| 28 |
+
**Problema V4.1:** O modelo sabe DNA mas nem sempre PREFERE usá-lo.
|
| 29 |
+
**Solução:** Treinar com pares (resposta_com_DNA=preferred, resposta_sem_DNA=rejected).
|
| 30 |
+
O modelo aprende que DNA é a resposta "correta" por preferência, não só por frequência.
|
| 31 |
+
|
| 32 |
+
```python
|
| 33 |
+
# Formato DPO
|
| 34 |
+
{
|
| 35 |
+
"prompt": "Explique arritmia cardíaca",
|
| 36 |
+
"chosen": "Uma @@DGN de @@CRC onde...", # DNA = preferido
|
| 37 |
+
"rejected": "Uma diagnóstico de coração..." # Normal = rejeitado
|
| 38 |
+
}
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
### 2. LoRA → GGUF Adapter (Empilhamento Real)
|
| 42 |
+
**Problema V4.1:** Ainda salvamos GGUF fundido (monolítico).
|
| 43 |
+
**Solução:** Converter adaptadores PEFT para formato GGUF-LoRA usando:
|
| 44 |
+
```bash
|
| 45 |
+
python3 llama.cpp/convert_lora_to_gguf.py \
|
| 46 |
+
--base qwen3.5-0.8b.gguf \
|
| 47 |
+
--adapter adapter_Python_DNA/ \
|
| 48 |
+
--outfile Python_DNA_lora.gguf
|
| 49 |
+
```
|
| 50 |
+
Resultado: `--lora A.gguf --lora B.gguf` na inferência.
|
| 51 |
+
|
| 52 |
+
### 3. Multi-Turn Conversation Training
|
| 53 |
+
**Problema V4.1:** Treinamos apenas single-turn (1 pergunta → 1 resposta).
|
| 54 |
+
**Solução:** Criar datasets com histórico de conversa:
|
| 55 |
+
```
|
| 56 |
+
<|im_start|>user
|
| 57 |
+
O que é Python?<|im_end|>
|
| 58 |
+
<|im_start|>assistant
|
| 59 |
+
@@DEF é uma linguagem...<|im_end|>
|
| 60 |
+
<|im_start|>user
|
| 61 |
+
Mostre um exemplo<|im_end|>
|
| 62 |
+
<|im_start|>assistant
|
| 63 |
+
@@IMP math\n@@PRT(math.sqrt(16))<|im_end|>
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
### 4. RAG + DNA Decoder Integrado
|
| 67 |
+
**Problema V4.1:** O decodificador DNA existe mas não está integrado no chat.
|
| 68 |
+
**Solução:** Pipeline completo:
|
| 69 |
+
```
|
| 70 |
+
Pergunta → Modelo (gera DNA) → Decodificador (traduz @@) → Usuário vê texto limpo
|
| 71 |
+
```
|
| 72 |
+
O usuário nunca vê os tokens @@, mas o modelo gera menos tokens = mais rápido.
|
| 73 |
+
|
| 74 |
+
### 5. Validação Automática Pós-Treino
|
| 75 |
+
**Problema V4.1:** Não temos métricas de qualidade automatizadas.
|
| 76 |
+
**Solução:** Script que após treino:
|
| 77 |
+
- Roda 50 perguntas padrão
|
| 78 |
+
- Mede % de tokens DNA na saída
|
| 79 |
+
- Calcula BLEU vs resposta esperada
|
| 80 |
+
- Mede velocidade de inferência
|
| 81 |
+
- Gera relatório comparativo automático
|
| 82 |
+
|
| 83 |
+
### 6. Datasets Estratégicos (Qualidade > Quantidade)
|
| 84 |
+
|
| 85 |
+
> [!IMPORTANT]
|
| 86 |
+
> A filosofia é: **poucos dados de alta qualidade** vencem toneladas de dados genéricos.
|
| 87 |
+
> Modelo de 0.8B não absorve 1M de amostras — ele precisa de ~20-50K muito bem escolhidas.
|
| 88 |
+
|
| 89 |
+
#### Estratégia de Dados V4.2: 3 Camadas
|
| 90 |
+
|
| 91 |
+
**Camada 1 — Base Conversacional (PT-BR nativo, ~30K amostras)**
|
| 92 |
+
| Dataset | Amostras | Por quê? | Prioridade |
|
| 93 |
+
|---|---|---|---|
|
| 94 |
+
| `dominguesm/Canarim-Instruct-PTBR` | Pegar 30K | JÁ em PT-BR, sem tradução, qualidade GPT-3.5 | 🔴 ALTA |
|
| 95 |
+
| `dominguesm/alpaca-data-pt-br` | 52K | Alpaca oficial em PT-BR, bom para base geral | 🟡 MÉDIA |
|
| 96 |
+
|
| 97 |
+
**Camada 2 — Destilação Inteligente (Traduzir EN→PT-BR, ~15K amostras)**
|
| 98 |
+
| Dataset Original (EN) | Pegar | Por quê? | Prioridade |
|
| 99 |
+
|---|---|---|---|
|
| 100 |
+
| `teknium/OpenHermes-2.5` | 10K melhores | Destilado do GPT-4, o melhor que existe | 🔴 ALTA |
|
| 101 |
+
| `Open-Orca/SlimOrca` | 5K filtrados | GPT-4 filtrado, instruções complexas | 🟡 MÉDIA |
|
| 102 |
+
|
| 103 |
+
> [!TIP]
|
| 104 |
+
> Não traduzir 1M de amostras! Filtrar as 10-15K com respostas mais longas e
|
| 105 |
+
> complexas. O modelo aprende mais com 10K respostas profundas do GPT-4 do que
|
| 106 |
+
> com 100K respostas rasas.
|
| 107 |
+
|
| 108 |
+
**Camada 3 — Especialização por Domínio (Nossos dados + HuggingFace, ~10K por cérebro)**
|
| 109 |
+
| Cérebro | Fonte | Amostras |
|
| 110 |
+
|---|---|---|
|
| 111 |
+
| Python | `Vezora/Tested-22k-Python-Alpaca` + nosso dataset | 10K |
|
| 112 |
+
| Medicina | Artigos SciELO + nosso dataset | 10K |
|
| 113 |
+
| CROM Self | Docs do projeto (já temos) | 500 |
|
| 114 |
+
| Conversa | Canarim filtrado para diálogo | 5K |
|
| 115 |
+
|
| 116 |
+
#### Resultado Final: ~60K amostras totais
|
| 117 |
+
- Peso do dataset: ~50-80MB (JSONL comprimido)
|
| 118 |
+
- Tempo de treino: ~1h no Colab A100
|
| 119 |
+
- Qualidade: Respostas nível GPT-4 em modelo de 500MB
|
| 120 |
+
|
| 121 |
+
#### Tradução Automática (Offline, Gratuita)
|
| 122 |
+
```bash
|
| 123 |
+
pip install argostranslate
|
| 124 |
+
python3 -c "
|
| 125 |
+
import argostranslate.translate
|
| 126 |
+
# Baixa pacote en→pt uma vez (~50MB)
|
| 127 |
+
argostranslate.package.update_package_index()
|
| 128 |
+
pkg = [p for p in argostranslate.package.get_available_packages()
|
| 129 |
+
if p.from_code=='en' and p.to_code=='pt'][0]
|
| 130 |
+
pkg.install()
|
| 131 |
+
# Traduzir
|
| 132 |
+
t = argostranslate.translate.get_translation_from_codes('en','pt')
|
| 133 |
+
print(t.translate('Hello, how are you?')) # → 'Olá, como vai?'
|
| 134 |
+
"
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
#### Filtro de Qualidade (O que torna isso MELHOR que modelos tradicionais)
|
| 138 |
+
Antes de treinar, cada amostra passa por 3 filtros:
|
| 139 |
+
1. **Tamanho mínimo:** Resposta > 100 chars (eliminar respostas rasas)
|
| 140 |
+
2. **Diversidade:** Remover duplicatas por similaridade cosine
|
| 141 |
+
3. **Complexidade:** Priorizar respostas com código, listas, explicações técnicas
|
| 142 |
+
|
| 143 |
+
### 8. Scheduler de Learning Rate
|
| 144 |
+
|
| 145 |
+
**Melhoria:** Ao invés de LR constante, usar cosine annealing:
|
| 146 |
+
```python
|
| 147 |
+
lr_scheduler_type = "cosine",
|
| 148 |
+
warmup_ratio = 0.05,
|
| 149 |
+
```
|
| 150 |
+
Isso ajuda o modelo a convergir melhor nos últimos steps.
|
| 151 |
+
|
| 152 |
+
### 8. Flash Attention 2
|
| 153 |
+
**Melhoria:** Instalar FA2 no Colab para treino 2x mais rápido:
|
| 154 |
+
```bash
|
| 155 |
+
pip install flash-attn --no-build-isolation
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
---
|
| 159 |
+
|
| 160 |
+
## Checklist de Execução V4.2
|
| 161 |
+
|
| 162 |
+
- [ ] Validar V4.1 no i5 local (testar os 4 cérebros)
|
| 163 |
+
- [ ] Verificar disponibilidade Qwen3.5-0.8B no Unsloth
|
| 164 |
+
- [ ] Criar gerador de pares DPO automático
|
| 165 |
+
- [ ] Implementar convert_lora_to_gguf no pipeline
|
| 166 |
+
- [ ] Criar datasets multi-turn
|
| 167 |
+
- [ ] Integrar decodificador DNA no chat_v42.sh
|
| 168 |
+
- [ ] Implementar benchmark automático pós-treino
|
| 169 |
+
- [ ] Coletar datasets maiores (GitHub, SciELO)
|
| 170 |
+
- [ ] Testar cosine annealing LR
|
| 171 |
+
- [ ] Benchmark comparativo V4.1 vs V4.2
|
01_DPO_GUIDE.md
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# CROM-IA V4.2 — Guia DPO (Direct Preference Optimization)
|
| 2 |
+
|
| 3 |
+
## O que é DPO?
|
| 4 |
+
|
| 5 |
+
DPO é uma técnica de alinhamento que ensina o modelo a **preferir** um tipo de resposta sobre outro, sem precisar de um modelo de recompensa separado (mais simples que RLHF).
|
| 6 |
+
|
| 7 |
+
### Por que DPO no CROM-IA?
|
| 8 |
+
|
| 9 |
+
Na V4.1, o modelo aprendeu DNA por SFT (Supervised Fine-Tuning) puro:
|
| 10 |
+
- Viu exemplos com @@tokens e tentou imitá-los
|
| 11 |
+
- Resultado: usou DNA mas também **esqueceu como conversar** (catastrophic forgetting)
|
| 12 |
+
|
| 13 |
+
Com DPO, a abordagem é diferente:
|
| 14 |
+
- O modelo recebe **pares**: resposta com DNA (preferida) vs sem DNA (rejeitada)
|
| 15 |
+
- Ele aprende que DNA é **a escolha melhor**, não uma obrigação
|
| 16 |
+
- Resultado: usa DNA quando faz sentido, mantém fluência
|
| 17 |
+
|
| 18 |
+
---
|
| 19 |
+
|
| 20 |
+
## Formato dos Dados DPO — 3 Níveis Hierárquicos
|
| 21 |
+
|
| 22 |
+
O DNA do Crompressor opera em **3 níveis**, e os pares DPO refletem isso:
|
| 23 |
+
|
| 24 |
+
### Nível W (Word) — Palavra isolada → 1 token DNA
|
| 25 |
+
```json
|
| 26 |
+
{
|
| 27 |
+
"prompt": "O que é arritmia?",
|
| 28 |
+
"chosen": "Uma @@DGN de @@CRC onde o ritmo cardíaco é irregular.",
|
| 29 |
+
"rejected": "Um diagnóstico de coração onde o ritmo cardíaco é irregular."
|
| 30 |
+
}
|
| 31 |
+
```
|
| 32 |
+
> `diagnóstico` (12 chars) → `@@DGN` (5 chars) = **7 bytes economizados** por hit
|
| 33 |
+
|
| 34 |
+
### Nível F (Phrase) — Frase repetida → 1 token DNA
|
| 35 |
+
```json
|
| 36 |
+
{
|
| 37 |
+
"prompt": "Como tratar hipertensão?",
|
| 38 |
+
"chosen": "@@MFG. O @@TRT inclui mudanças no estilo de vida e @@MED anti-hipertensivos.",
|
| 39 |
+
"rejected": "É importante consultar um médico especialista. O tratamento inclui mudanças no estilo de vida e medicamentos anti-hipertensivos."
|
| 40 |
+
}
|
| 41 |
+
```
|
| 42 |
+
> `É importante consultar um médico especialista` (46 chars) → `@@MFG` (5 chars) = **41 bytes** por hit!
|
| 43 |
+
|
| 44 |
+
### Nível P (Paragraph) — Bloco inteiro repetido → 1 token DNA
|
| 45 |
+
```json
|
| 46 |
+
{
|
| 47 |
+
"prompt": "Dê um exemplo de função Python",
|
| 48 |
+
"chosen": "@@PPA\n\ndef somar(a, b):\n return a + b",
|
| 49 |
+
"rejected": "Para criar uma função em Python, use a palavra-chave def seguida do nome da função e parâmetros entre parênteses. Veja o exemplo:\n\ndef somar(a, b):\n return a + b"
|
| 50 |
+
}
|
| 51 |
+
```
|
| 52 |
+
> `Para criar uma função em Python, use a palavra-chave def seguida...` (130 chars) → `@@PPA` (5 chars) = **125 bytes** por hit!
|
| 53 |
+
|
| 54 |
+
### Exemplo Misto (3 Níveis no mesmo par)
|
| 55 |
+
```json
|
| 56 |
+
{
|
| 57 |
+
"prompt": "Explique como fazer um loop for em Python",
|
| 58 |
+
"chosen": "@@PFC\n\n@@FOR item @@GFT:\n @@PRT(item)\n\n@@PFD",
|
| 59 |
+
"rejected": "O loop for em Python permite iterar sobre qualquer sequência como listas, tuplas ou strings.\n\nfor item in uma lista ou sequência iterável:\n print(item)\n\nIsso percorre cada elemento da sequência e executa o bloco de código para cada um."
|
| 60 |
+
}
|
| 61 |
+
```
|
| 62 |
+
> - `@@PFC` = parágrafo de introdução (~90 chars → 5) = **Nível P**
|
| 63 |
+
> - `@@FOR` = palavra `for` = **Nível W**
|
| 64 |
+
> - `@@GFT` = frase `in uma lista ou sequência iterável` (37 → 5) = **Nível F**
|
| 65 |
+
> - `@@PFD` = parágrafo de conclusão (~80 chars → 5) = **Nível P**
|
| 66 |
+
|
| 67 |
+
**Regras:**
|
| 68 |
+
- `chosen` e `rejected` devem ser **semanticamente idênticos** (mesma informação)
|
| 69 |
+
- A ÚNICA diferença é a presença de tokens @@DNA no `chosen`
|
| 70 |
+
- Tokens de **todos os 3 níveis** (W, F, P) devem aparecer nos pares
|
| 71 |
+
- DNA a ~25-30% do texto no `chosen` (sutil, não agressivo)
|
| 72 |
+
- Parágrafos repetidos (nível P) são os mais valiosos em economia
|
| 73 |
+
|
| 74 |
+
---
|
| 75 |
+
|
| 76 |
+
## Pipeline de Geração de Pares DPO
|
| 77 |
+
|
| 78 |
+
### Fluxo Automático
|
| 79 |
+
```
|
| 80 |
+
Dataset original (ex: Canarim 30K)
|
| 81 |
+
↓
|
| 82 |
+
gerador_pares_dpo.py
|
| 83 |
+
↓
|
| 84 |
+
Para cada amostra:
|
| 85 |
+
1. chosen = aplicar_mutacao_dna(resposta, codebook, taxa=0.25)
|
| 86 |
+
2. rejected = resposta original (sem DNA)
|
| 87 |
+
3. Emitir par {prompt, chosen, rejected}
|
| 88 |
+
↓
|
| 89 |
+
dataset_dpo_5k.jsonl
|
| 90 |
+
```
|
| 91 |
+
|
| 92 |
+
### Script: `gerador_pares_dpo.py`
|
| 93 |
+
```python
|
| 94 |
+
# Gera pares automaticamente a partir de dataset existente
|
| 95 |
+
# chosen = resposta com DNA aplicado (25%)
|
| 96 |
+
# rejected = resposta original (sem DNA)
|
| 97 |
+
|
| 98 |
+
python3 gerador_pares_dpo.py \
|
| 99 |
+
--input canarim_30k.jsonl \
|
| 100 |
+
--codebook codebook_geral.json \
|
| 101 |
+
--output dataset_dpo_5k.jsonl \
|
| 102 |
+
--max_pares 5000 \
|
| 103 |
+
--taxa_dna 0.25
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
---
|
| 107 |
+
|
| 108 |
+
## Treino DPO no Colab
|
| 109 |
+
|
| 110 |
+
### Pré-requisito
|
| 111 |
+
O modelo **já deve ter passado pela Fase 1 (SFT Base)** e Fase 2 (SFT DNA).
|
| 112 |
+
DPO é o **refinamento final** — polir, não ensinar do zero.
|
| 113 |
+
|
| 114 |
+
### Código Colab (Fase 3)
|
| 115 |
+
```python
|
| 116 |
+
from trl import DPOTrainer, DPOConfig
|
| 117 |
+
from unsloth import FastLanguageModel
|
| 118 |
+
from datasets import load_dataset
|
| 119 |
+
|
| 120 |
+
# Carregar modelo já treinado (Fase 1 + Fase 2)
|
| 121 |
+
model, tokenizer = FastLanguageModel.from_pretrained(
|
| 122 |
+
model_name="adapter_base_ptbr", # Já fine-tuned
|
| 123 |
+
max_seq_length=2048,
|
| 124 |
+
load_in_4bit=True,
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
# LoRA para DPO (pode ser novo ou continuar do existente)
|
| 128 |
+
model = FastLanguageModel.get_peft_model(
|
| 129 |
+
model, r=16, lora_alpha=32,
|
| 130 |
+
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
|
| 131 |
+
)
|
| 132 |
+
|
| 133 |
+
# Dataset DPO
|
| 134 |
+
dataset = load_dataset("json", data_files="dataset_dpo_5k.jsonl", split="train")
|
| 135 |
+
|
| 136 |
+
# Treinar com DPO
|
| 137 |
+
training_args = DPOConfig(
|
| 138 |
+
per_device_train_batch_size=4,
|
| 139 |
+
gradient_accumulation_steps=4,
|
| 140 |
+
max_steps=300,
|
| 141 |
+
learning_rate=5e-6, # Mais suave que SFT
|
| 142 |
+
beta=0.1, # Força da preferência
|
| 143 |
+
lr_scheduler_type="cosine",
|
| 144 |
+
warmup_ratio=0.1,
|
| 145 |
+
output_dir="./outputs_dpo",
|
| 146 |
+
logging_steps=25,
|
| 147 |
+
)
|
| 148 |
+
|
| 149 |
+
trainer = DPOTrainer(
|
| 150 |
+
model=model,
|
| 151 |
+
args=training_args,
|
| 152 |
+
train_dataset=dataset,
|
| 153 |
+
tokenizer=tokenizer,
|
| 154 |
+
)
|
| 155 |
+
|
| 156 |
+
trainer.train()
|
| 157 |
+
```
|
| 158 |
+
|
| 159 |
+
### Parâmetros DPO Explicados
|
| 160 |
+
| Parâmetro | Valor | Por quê? |
|
| 161 |
+
|---|---|---|
|
| 162 |
+
| `beta` | 0.1 | Controla quão forte é a preferência. 0.1 = sutil. 0.5 = agressivo. |
|
| 163 |
+
| `learning_rate` | 5e-6 | Metade do SFT. DPO é refinamento, não reeducação. |
|
| 164 |
+
| `max_steps` | 300 | Pouco. DPO converge rápido com bons pares. |
|
| 165 |
+
| `batch_size` | 4 | Menor que SFT (cada amostra tem 2 respostas = 2x memória). |
|
| 166 |
+
|
| 167 |
+
---
|
| 168 |
+
|
| 169 |
+
## Validação Pós-DPO
|
| 170 |
+
|
| 171 |
+
### Teste A/B
|
| 172 |
+
Rodar o modelo **antes e depois do DPO** com as mesmas 50 perguntas:
|
| 173 |
+
- Medir % de tokens @@DNA na saída
|
| 174 |
+
- Medir coerência (resposta faz sentido?)
|
| 175 |
+
- Medir fluência (PT-BR natural?)
|
| 176 |
+
|
| 177 |
+
### Resultado Esperado
|
| 178 |
+
- **Antes DPO:** Modelo conversa bem, usa DNA inconsistentemente
|
| 179 |
+
- **Depois DPO:** Modelo conversa bem E prefere usar DNA quando há codebook match
|
| 180 |
+
|
| 181 |
+
---
|
| 182 |
+
|
| 183 |
+
## Riscos e Mitigações
|
| 184 |
+
|
| 185 |
+
| Risco | Mitigação |
|
| 186 |
+
|---|---|
|
| 187 |
+
| DPO degrada fluência | `beta=0.1` (conservador) + poucos steps (300) |
|
| 188 |
+
| Pares DPO de baixa qualidade | Filtrar: chosen deve ter >3 tokens DNA, chosen e rejected devem ser >100 chars |
|
| 189 |
+
| Overfitting DPO | Early stopping + validação cada 100 steps |
|
| 190 |
+
| `trl` incompatível | Verificar `trl>=0.7.0` no Colab antes de treinar |
|
02_CHAT_RAG_GUIDE.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# CROM-IA V4.2 — Monitor de Orquestração + RAG-Lite
|
| 2 |
+
|
| 3 |
+
## Conceito
|
| 4 |
+
|
| 5 |
+
O `chat_v42_brain.sh` é um **painel de controle TUI** que permite configurar tudo antes de conversar: ativar/desativar cérebros, adicionar arquivos/pastas como contexto, ajustar parâmetros. Funciona como RAG (Retrieval Augmented Generation) adaptado para rodar sem GPU.
|
| 6 |
+
|
| 7 |
+
```
|
| 8 |
+
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
|
| 9 |
+
│ Arquivos │────▶│ rag_contexto │────▶│ System Prompt│
|
| 10 |
+
│ /pastas │ │ .py │ │ enriquecido │
|
| 11 |
+
└─────────────┘ └──────────────┘ └──────┬──────┘
|
| 12 |
+
│
|
| 13 |
+
┌──────────────┐ ┌──────▼──────┐
|
| 14 |
+
│ LoRA Stack │────▶│ llama-cli │
|
| 15 |
+
│ (auto) │ │ --conversation│
|
| 16 |
+
└──────────────┘ └──────┬──────┘
|
| 17 |
+
│
|
| 18 |
+
┌──────────────┐ ┌──────▼──────┐
|
| 19 |
+
│ DNA Decoder │◀────│ Resposta │
|
| 20 |
+
└──────────────┘ └─────────────┘
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
---
|
| 24 |
+
|
| 25 |
+
## Uso
|
| 26 |
+
|
| 27 |
+
### Monitor Interativo (recomendado)
|
| 28 |
+
```bash
|
| 29 |
+
./chat_v42_brain.sh
|
| 30 |
+
# Abre o painel TUI onde você configura tudo:
|
| 31 |
+
# [1-9] Toggle cérebros ON/OFF
|
| 32 |
+
# [a] Adicionar arquivo para RAG
|
| 33 |
+
# [p] Adicionar pasta para RAG
|
| 34 |
+
# [ENTER] Lançar chat com a config escolhida
|
| 35 |
+
# Ctrl+C no chat volta ao monitor!
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
### Pré-carregar arquivos (atalho)
|
| 39 |
+
```bash
|
| 40 |
+
./chat_v42_brain.sh --arquivo main.py --pasta ./src/
|
| 41 |
+
# Abre o monitor já com esses itens no RAG
|
| 42 |
+
# Você ainda pode ajustar antes de lançar
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
### Fluxo Típico
|
| 46 |
+
```
|
| 47 |
+
1. ./chat_v42_brain.sh
|
| 48 |
+
2. Pressiona [3] para desativar Medicina_DNA
|
| 49 |
+
3. Pressiona [a] e digita "./api.py"
|
| 50 |
+
4. Pressiona [p] e digita "./controllers/"
|
| 51 |
+
5. Pressiona [ENTER] → chat inicia!
|
| 52 |
+
6. Conversa...
|
| 53 |
+
7. Ctrl+C → volta ao monitor
|
| 54 |
+
8. Pressiona [3] para reativar Medicina_DNA
|
| 55 |
+
9. Pressiona [ENTER] → chat reinicia com nova config!
|
| 56 |
+
```
|
| 57 |
+
|
| 58 |
+
---
|
| 59 |
+
|
| 60 |
+
## Formatos Suportados
|
| 61 |
+
|
| 62 |
+
| Extensão | Tipo | Tratamento |
|
| 63 |
+
|---|---|---|
|
| 64 |
+
| `.py` | Python | Código completo |
|
| 65 |
+
| `.js` | JavaScript | Código completo |
|
| 66 |
+
| `.sh` | Shell | Código completo |
|
| 67 |
+
| `.md` | Markdown | Texto completo |
|
| 68 |
+
| `.txt` | Texto | Texto completo |
|
| 69 |
+
| `.json` | JSON | Estrutura + primeiros 2KB |
|
| 70 |
+
| `.jsonl` | JSON Lines | Primeiras 20 linhas |
|
| 71 |
+
| `.html` | HTML | Texto extraído (sem tags) |
|
| 72 |
+
| `.css` | CSS | Código completo |
|
| 73 |
+
| `.yaml/.yml` | YAML | Estrutura completa |
|
| 74 |
+
| `.toml` | TOML | Estrutura completa |
|
| 75 |
+
| `.cfg/.ini` | Config | Estrutura completa |
|
| 76 |
+
| `.log` | Log | Últimas 50 linhas |
|
| 77 |
+
|
| 78 |
+
**Limite por arquivo:** 3000 chars (para caber no contexto)
|
| 79 |
+
**Limite total:** ~6000 chars de contexto injetado (~1500 tokens)
|
| 80 |
+
|
| 81 |
+
---
|
| 82 |
+
|
| 83 |
+
## Como Funciona (Detalhes Técnicos)
|
| 84 |
+
|
| 85 |
+
### 1. Ingestão (`rag_contexto.py`)
|
| 86 |
+
```python
|
| 87 |
+
# Lê todos os arquivos/pastas especificados
|
| 88 |
+
# Retorna lista de {nome, conteudo, tipo}
|
| 89 |
+
```
|
| 90 |
+
|
| 91 |
+
### 2. Chunking
|
| 92 |
+
- Cada arquivo é dividido em chunks de ~500 chars
|
| 93 |
+
- Preserva limites de função/classe em código
|
| 94 |
+
- Preserva parágrafos em texto
|
| 95 |
+
|
| 96 |
+
### 3. Indexação por Keywords
|
| 97 |
+
Sem embeddings (sem GPU), usamos TF-IDF simplificado:
|
| 98 |
+
- Conta frequência de cada palavra em cada chunk
|
| 99 |
+
- Na hora da pergunta, busca chunks com mais keywords em comum
|
| 100 |
+
- Retorna top-3 chunks mais relevantes
|
| 101 |
+
|
| 102 |
+
### 4. Injeção no System Prompt
|
| 103 |
+
```
|
| 104 |
+
<|im_start|>system
|
| 105 |
+
Você é CROM-IA, assistente brasileiro com compressão DNA ativa.
|
| 106 |
+
|
| 107 |
+
CONTEXTO DOS ARQUIVOS CARREGADOS:
|
| 108 |
+
📄 main.py (Python, 45 linhas):
|
| 109 |
+
```python
|
| 110 |
+
def calcular_total(items):
|
| 111 |
+
return sum(item.price for item in items)
|
| 112 |
+
...
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
📄 README.md (Markdown):
|
| 116 |
+
# Meu Projeto
|
| 117 |
+
Calculadora de preços para e-commerce...
|
| 118 |
+
|
| 119 |
+
Responda perguntas sobre estes arquivos usando seu conhecimento.
|
| 120 |
+
<|im_end|>
|
| 121 |
+
```
|
| 122 |
+
|
| 123 |
+
### 5. LoRA Stacking
|
| 124 |
+
O script auto-detecta todos os `*_lora.gguf` em `micro_cerebros/`:
|
| 125 |
+
```bash
|
| 126 |
+
llama-cli -m base.gguf \
|
| 127 |
+
--lora Base_PTBR.gguf \
|
| 128 |
+
--lora Python_DNA.gguf \
|
| 129 |
+
-c 2048 \
|
| 130 |
+
--prompt "CONTEXTO: ..." \
|
| 131 |
+
--conversation
|
| 132 |
+
```
|
| 133 |
+
|
| 134 |
+
---
|
| 135 |
+
|
| 136 |
+
## Limitações
|
| 137 |
+
|
| 138 |
+
| Limitação | Causa | Workaround |
|
| 139 |
+
|---|---|---|
|
| 140 |
+
| Contexto máximo ~1500 tokens | i5 + RAM limitada | Chunking inteligente |
|
| 141 |
+
| Sem busca semântica | Sem GPU para embeddings | Keywords TF-IDF |
|
| 142 |
+
| Sem persistência entre sessões | Design stateless | Pode re-carregar arquivos |
|
| 143 |
+
| Arquivos grandes truncados | Limite de contexto | Mostra início + estrutura |
|
| 144 |
+
|
| 145 |
+
---
|
| 146 |
+
|
| 147 |
+
## Exemplos de Conversas
|
| 148 |
+
|
| 149 |
+
### Exemplo 1: Analisar código
|
| 150 |
+
```
|
| 151 |
+
$ ./chat_v42_brain.sh --arquivo api.py
|
| 152 |
+
|
| 153 |
+
> Explique o que faz a função handle_request
|
| 154 |
+
|
| 155 |
+
CROM-IA: A @@FNC handle_request recebe um @@DCT com os parâmetros
|
| 156 |
+
HTTP, valida os campos 'user_id' e 'action', e @@RET um JSON
|
| 157 |
+
com o resultado. Ela usa @@TRY/@@EXC para tratar erros de
|
| 158 |
+
conexão com o banco...
|
| 159 |
+
```
|
| 160 |
+
|
| 161 |
+
### Exemplo 2: Analisar projeto
|
| 162 |
+
```
|
| 163 |
+
$ ./chat_v42_brain.sh --pasta ./meu_app/
|
| 164 |
+
|
| 165 |
+
> Qual é a arquitetura desse projeto?
|
| 166 |
+
|
| 167 |
+
CROM-IA: Baseado nos arquivos que analisei, o projeto segue
|
| 168 |
+
arquitetura MVC:
|
| 169 |
+
- models/ → @@CLS de dados (User, Product)
|
| 170 |
+
- views/ → Templates HTML
|
| 171 |
+
- controllers/ → Lógica de negócio
|
| 172 |
+
- main.py → Entry point com @@IMP Flask
|
| 173 |
+
```
|
| 174 |
+
|
| 175 |
+
---
|
| 176 |
+
|
| 177 |
+
## Performance Esperada
|
| 178 |
+
|
| 179 |
+
| Métrica | Sem arquivos | Com 1 arquivo | Com pasta (10 arquivos) |
|
| 180 |
+
|---|---|---|---|
|
| 181 |
+
| Tempo de carga | ~5s | ~6s | ~8s |
|
| 182 |
+
| Velocidade chat | 7-9 t/s | 6-8 t/s | 5-7 t/s |
|
| 183 |
+
| RAM | 635MB | ~650MB | ~680MB |
|
| 184 |
+
| Qualidade resposta | Geral | Específica ao código | Visão do projeto |
|
1_extracao_local/codebooks/codebook_python_v42.json
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": "4.2",
|
| 3 |
+
"domain": "P",
|
| 4 |
+
"method": "hierarchical_frequency_x_size",
|
| 5 |
+
"total_tokens": 290,
|
| 6 |
+
"niveis": {
|
| 7 |
+
"W": "palavras isoladas",
|
| 8 |
+
"F": "frases (2-8 palavras)",
|
| 9 |
+
"P": "parágrafos/blocos (8-20 palavras)"
|
| 10 |
+
},
|
| 11 |
+
"economia_bytes_estimada": 10201862,
|
| 12 |
+
"stats": {
|
| 13 |
+
"economia_total_estimada": 10201862,
|
| 14 |
+
"por_nivel": {
|
| 15 |
+
"W_palavras": {
|
| 16 |
+
"tokens": 120,
|
| 17 |
+
"economia": 782629
|
| 18 |
+
},
|
| 19 |
+
"F_frases": {
|
| 20 |
+
"tokens": 118,
|
| 21 |
+
"economia": 7170412
|
| 22 |
+
},
|
| 23 |
+
"P_blocos": {
|
| 24 |
+
"tokens": 52,
|
| 25 |
+
"economia": 2248821
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
},
|
| 29 |
+
"codebook": {
|
| 30 |
+
"implementation": "@@PWA",
|
| 31 |
+
"function": "@@PWT",
|
| 32 |
+
"characters": "@@PWC",
|
| 33 |
+
"complexity": "@@PWG",
|
| 34 |
+
"dictionary": "@@PWTA",
|
| 35 |
+
"character": "@@PWTT",
|
| 36 |
+
"algorithm": "@@PWTC",
|
| 37 |
+
"elements": "@@PWTG",
|
| 38 |
+
"numbers": "@@PWCA",
|
| 39 |
+
"initialize": "@@PWCT",
|
| 40 |
+
"element": "@@PWCC",
|
| 41 |
+
"requirements": "@@PWCG",
|
| 42 |
+
"example": "@@PWGA",
|
| 43 |
+
"calculate": "@@PWGT",
|
| 44 |
+
"isinstance": "@@PWGC",
|
| 45 |
+
"valueerror": "@@PWGG",
|
| 46 |
+
"input_string": "@@PWTAA",
|
| 47 |
+
"current": "@@PWTAT",
|
| 48 |
+
"recursively": "@@PWTAC",
|
| 49 |
+
"is_prime": "@@PWTAG",
|
| 50 |
+
"corresponding": "@@PWTTA",
|
| 51 |
+
"explanation": "@@PWTTT",
|
| 52 |
+
"descending": "@@PWTTC",
|
| 53 |
+
"variable": "@@PWTTG",
|
| 54 |
+
"lowercase": "@@PWTCA",
|
| 55 |
+
"recursive": "@@PWTCT",
|
| 56 |
+
"divisible": "@@PWTCC",
|
| 57 |
+
"occurrences": "@@PWTCG",
|
| 58 |
+
"solution": "@@PWTGA",
|
| 59 |
+
"frequency": "@@PWTGT",
|
| 60 |
+
"fibonacci": "@@PWTGC",
|
| 61 |
+
"iterate": "@@PWTGG",
|
| 62 |
+
"returns": "@@PWCAA",
|
| 63 |
+
"punctuation": "@@PWCAT",
|
| 64 |
+
"substring": "@@PWCAC",
|
| 65 |
+
"additional": "@@PWCAG",
|
| 66 |
+
"possible": "@@PWCTA",
|
| 67 |
+
"expression": "@@PWCTT",
|
| 68 |
+
"otherwise": "@@PWCTC",
|
| 69 |
+
"through": "@@PWCTG",
|
| 70 |
+
"sentence": "@@PWCCA",
|
| 71 |
+
"conditions": "@@PWCCT",
|
| 72 |
+
"remove_duplicates": "@@PWCCC",
|
| 73 |
+
"iterates": "@@PWCCG",
|
| 74 |
+
"calculates": "@@PWCGA",
|
| 75 |
+
"duplicates": "@@PWCGT",
|
| 76 |
+
"permutations": "@@PWCGC",
|
| 77 |
+
"is_palindrome": "@@PWCGG",
|
| 78 |
+
"functions": "@@PWGAA",
|
| 79 |
+
"representation": "@@PWGAT",
|
| 80 |
+
"comprehension": "@@PWGAC",
|
| 81 |
+
"factorial": "@@PWGAG",
|
| 82 |
+
"strings": "@@PWGTA",
|
| 83 |
+
"prime_numbers": "@@PWGTT",
|
| 84 |
+
"ascending": "@@PWGTC",
|
| 85 |
+
"reversed_string": "@@PWGTG",
|
| 86 |
+
"finally": "@@PWGCA",
|
| 87 |
+
"__init__": "@@PWGCT",
|
| 88 |
+
"negative": "@@PWGCC",
|
| 89 |
+
"integers": "@@PWGCG",
|
| 90 |
+
"operations": "@@PWGGA",
|
| 91 |
+
"contains": "@@PWGGT",
|
| 92 |
+
"resulting": "@@PWGGC",
|
| 93 |
+
"positive": "@@PWGGG",
|
| 94 |
+
"variables": "@@PWTAAA",
|
| 95 |
+
"following": "@@PWTAAT",
|
| 96 |
+
"palindrome": "@@PWTAAC",
|
| 97 |
+
"dictionaries": "@@PWTAAG",
|
| 98 |
+
"duplicate": "@@PWTATA",
|
| 99 |
+
"common_elements": "@@PWTATT",
|
| 100 |
+
"remaining": "@@PWTATC",
|
| 101 |
+
"iteration": "@@PWTATG",
|
| 102 |
+
"different": "@@PWTACA",
|
| 103 |
+
"uppercase": "@@PWTACT",
|
| 104 |
+
"generate": "@@PWTACC",
|
| 105 |
+
"merge_sort": "@@PWTACG",
|
| 106 |
+
"initializes": "@@PWTAGA",
|
| 107 |
+
"increment": "@@PWTAGT",
|
| 108 |
+
"appropriate": "@@PWTAGC",
|
| 109 |
+
"exception": "@@PWTAGG",
|
| 110 |
+
"programming": "@@PWTTAA",
|
| 111 |
+
"difference": "@@PWTTAT",
|
| 112 |
+
"respectively": "@@PWTTAC",
|
| 113 |
+
"program": "@@PWTTAG",
|
| 114 |
+
"alphanumeric": "@@PWTTTA",
|
| 115 |
+
"original": "@@PWTTTT",
|
| 116 |
+
"maximum": "@@PWTTTC",
|
| 117 |
+
"integer": "@@PWTTTG",
|
| 118 |
+
"sequence": "@@PWTTCA",
|
| 119 |
+
"combinations": "@@PWTTCT",
|
| 120 |
+
"reverse_string": "@@PWTTCC",
|
| 121 |
+
"convert": "@@PWTTCG",
|
| 122 |
+
"iterating": "@@PWTTGA",
|
| 123 |
+
"parameters": "@@PWTTGT",
|
| 124 |
+
"unique_elements": "@@PWTTGC",
|
| 125 |
+
"whitespace": "@@PWTTGG",
|
| 126 |
+
"reverse": "@@PWTCAA",
|
| 127 |
+
"condition": "@@PWTCAT",
|
| 128 |
+
"multiplication": "@@PWTCAC",
|
| 129 |
+
"correctly": "@@PWTCAG",
|
| 130 |
+
"occurrence": "@@PWTCTA",
|
| 131 |
+
"modified": "@@PWTCTT",
|
| 132 |
+
"containing": "@@PWTCTC",
|
| 133 |
+
"greater": "@@PWTCTG",
|
| 134 |
+
"implement": "@@PWTCCA",
|
| 135 |
+
"efficiently": "@@PWTCCT",
|
| 136 |
+
"password": "@@PWTCCC",
|
| 137 |
+
"recursion": "@@PWTCCG",
|
| 138 |
+
"specified": "@@PWTCGA",
|
| 139 |
+
"position": "@@PWTCGT",
|
| 140 |
+
"binary_search": "@@PWTCGC",
|
| 141 |
+
"parameter": "@@PWTCGG",
|
| 142 |
+
"represents": "@@PWTGAA",
|
| 143 |
+
"approach": "@@PWTGAT",
|
| 144 |
+
"current_node": "@@PWTGAC",
|
| 145 |
+
"sorted_arr": "@@PWTGAG",
|
| 146 |
+
"pointers": "@@PWTGTA",
|
| 147 |
+
"between": "@@PWTGTT",
|
| 148 |
+
"modified_string": "@@PWTGTC",
|
| 149 |
+
"because": "@@PWTGTG",
|
| 150 |
+
"implementation of the": "@@PFA",
|
| 151 |
+
"time complexity of": "@@PFT",
|
| 152 |
+
"implementation of": "@@PFC",
|
| 153 |
+
"time complexity": "@@PFG",
|
| 154 |
+
"the function": "@@PFTA",
|
| 155 |
+
"complexity of": "@@PFTT",
|
| 156 |
+
"the implementation": "@@PFTC",
|
| 157 |
+
"is the implementation": "@@PFTG",
|
| 158 |
+
"the current": "@@PFCA",
|
| 159 |
+
"the implementation of": "@@PFCT",
|
| 160 |
+
"a time complexity": "@@PFCC",
|
| 161 |
+
"possible implementation": "@@PFCG",
|
| 162 |
+
"implementation in": "@@PFGA",
|
| 163 |
+
"a time complexity of": "@@PFGT",
|
| 164 |
+
"the implementation of the": "@@PFGC",
|
| 165 |
+
"# Output:": "@@PFGG",
|
| 166 |
+
"the number": "@@PFTAA",
|
| 167 |
+
"the length of the": "@@PFTAT",
|
| 168 |
+
"implementation in Python:": "@@PFTAC",
|
| 169 |
+
"the length of": "@@PFTAG",
|
| 170 |
+
"implementation in Python": "@@PFTTA",
|
| 171 |
+
") # Output:": "@@PFTTT",
|
| 172 |
+
"the number of": "@@PFTTC",
|
| 173 |
+
"implementation of the function": "@@PFTTG",
|
| 174 |
+
"length of the": "@@PFTCA",
|
| 175 |
+
"time complexity of this": "@@PFTCT",
|
| 176 |
+
"Here is the implementation": "@@PFTCC",
|
| 177 |
+
"complexity of this": "@@PFTCG",
|
| 178 |
+
"iterate through": "@@PFTGA",
|
| 179 |
+
"a possible implementation": "@@PFTGT",
|
| 180 |
+
"using the": "@@PFTGC",
|
| 181 |
+
"prime numbers": "@@PFTGG",
|
| 182 |
+
"to store the": "@@PFCAA",
|
| 183 |
+
"in descending order": "@@PFCAT",
|
| 184 |
+
"time complexity of O": "@@PFCAC",
|
| 185 |
+
"the given": "@@PFCAG",
|
| 186 |
+
"greater than": "@@PFCTA",
|
| 187 |
+
"has a time complexity": "@@PFCTT",
|
| 188 |
+
"is the implementation of": "@@PFCTC",
|
| 189 |
+
"function with": "@@PFCTG",
|
| 190 |
+
"the function with": "@@PFCCA",
|
| 191 |
+
"space complexity": "@@PFCCT",
|
| 192 |
+
")) # Output:": "@@PFCCC",
|
| 193 |
+
"function with the": "@@PFCCG",
|
| 194 |
+
"the input": "@@PFCGA",
|
| 195 |
+
"an example implementation": "@@PFCGT",
|
| 196 |
+
"the function returns": "@@PFCGC",
|
| 197 |
+
"the string": "@@PFCGG",
|
| 198 |
+
"each character": "@@PFGAA",
|
| 199 |
+
"The time complexity of": "@@PFGAT",
|
| 200 |
+
"` function": "@@PFGAC",
|
| 201 |
+
"possible implementation of": "@@PFGAG",
|
| 202 |
+
"complexity of O(": "@@PFGTA",
|
| 203 |
+
"function returns": "@@PFGTT",
|
| 204 |
+
"is greater than": "@@PFGTC",
|
| 205 |
+
"function that": "@@PFGTG",
|
| 206 |
+
"the array": "@@PFGCA",
|
| 207 |
+
"The time complexity": "@@PFGCT",
|
| 208 |
+
"an implementation of": "@@PFGCC",
|
| 209 |
+
"solve this problem,": "@@PFGCG",
|
| 210 |
+
"iterate through the": "@@PFGGA",
|
| 211 |
+
"returns the": "@@PFGGT",
|
| 212 |
+
"Check if the": "@@PFGGC",
|
| 213 |
+
"calculate the": "@@PFGGG",
|
| 214 |
+
"test the function": "@@PFTAAA",
|
| 215 |
+
"through the": "@@PFTAAT",
|
| 216 |
+
"each element": "@@PFTAAC",
|
| 217 |
+
"descending order": "@@PFTAAG",
|
| 218 |
+
"an example": "@@PFTATA",
|
| 219 |
+
"divisible by": "@@PFTATT",
|
| 220 |
+
"the implementation in": "@@PFTATC",
|
| 221 |
+
"test the function with": "@@PFTATG",
|
| 222 |
+
"Iterate through": "@@PFTACA",
|
| 223 |
+
"Here's an example": "@@PFTACT",
|
| 224 |
+
"complexity of O": "@@PFTACC",
|
| 225 |
+
"in descending": "@@PFTACG",
|
| 226 |
+
"in Python": "@@PFTAGA",
|
| 227 |
+
"possible implementation in": "@@PFTAGT",
|
| 228 |
+
"example implementation": "@@PFTAGC",
|
| 229 |
+
"through each": "@@PFTAGG",
|
| 230 |
+
"number of": "@@PFTTAA",
|
| 231 |
+
"checks if the": "@@PFTTAT",
|
| 232 |
+
"with the": "@@PFTTAC",
|
| 233 |
+
"each character in": "@@PFTTAG",
|
| 234 |
+
"the length": "@@PFTTTA",
|
| 235 |
+
"an implementation": "@@PFTTTT",
|
| 236 |
+
"possible implementation of the": "@@PFTTTC",
|
| 237 |
+
"__init__(self,": "@@PFTTTG",
|
| 238 |
+
"of the function": "@@PFTTCA",
|
| 239 |
+
"the list": "@@PFTTCT",
|
| 240 |
+
"iterates through": "@@PFTTCC",
|
| 241 |
+
"number is": "@@PFTTCG",
|
| 242 |
+
"i in range(": "@@PFTTGA",
|
| 243 |
+
"element in the": "@@PFTTGT",
|
| 244 |
+
"character in the": "@@PFTTGC",
|
| 245 |
+
"this implementation": "@@PFTTGG",
|
| 246 |
+
"in ascending order": "@@PFTCAA",
|
| 247 |
+
"keep track of the": "@@PFTCAT",
|
| 248 |
+
"the function with the": "@@PFTCAC",
|
| 249 |
+
"checks if": "@@PFTCAG",
|
| 250 |
+
"Iterate through each": "@@PFTCTA",
|
| 251 |
+
"the input string": "@@PFTCTT",
|
| 252 |
+
"in range(": "@@PFTCTC",
|
| 253 |
+
"complexity of O(n": "@@PFTCTG",
|
| 254 |
+
"this example, the": "@@PFTCCA",
|
| 255 |
+
"keep track of": "@@PFTCCT",
|
| 256 |
+
"each character in the": "@@PFTCCC",
|
| 257 |
+
"the character": "@@PFTCCG",
|
| 258 |
+
"The function": "@@PFTCGA",
|
| 259 |
+
"is a possible implementation": "@@PFTCGT",
|
| 260 |
+
"solve this problem": "@@PFTCGC",
|
| 261 |
+
"the sum of": "@@PFTCGG",
|
| 262 |
+
"the maximum": "@@PFTGAA",
|
| 263 |
+
"for i in range(": "@@PFTGAT",
|
| 264 |
+
"elements in the": "@@PFTGAC",
|
| 265 |
+
"without using any": "@@PFTGAG",
|
| 266 |
+
"the first": "@@PFTGTA",
|
| 267 |
+
"is divisible by": "@@PFTGTT",
|
| 268 |
+
"has a time complexity of": "@@PPA",
|
| 269 |
+
"a time complexity of O(": "@@PPT",
|
| 270 |
+
"time complexity of O(": "@@PPC",
|
| 271 |
+
"a time complexity of O": "@@PPG",
|
| 272 |
+
"where n is the length of the": "@@PPTA",
|
| 273 |
+
"a time complexity of O(n": "@@PPTT",
|
| 274 |
+
"time complexity of O(n": "@@PPTC",
|
| 275 |
+
"The time complexity of this": "@@PPTG",
|
| 276 |
+
"has a time complexity of O(": "@@PPCA",
|
| 277 |
+
"where n is the length of": "@@PPCT",
|
| 278 |
+
"has a time complexity of O": "@@PPCC",
|
| 279 |
+
"has a time complexity of O(n": "@@PPCG",
|
| 280 |
+
"to keep track of the": "@@PPGA",
|
| 281 |
+
"a time complexity of O(n)": "@@PPGT",
|
| 282 |
+
"O(n), where n is the": "@@PPGC",
|
| 283 |
+
"time complexity of this solution is": "@@PPGG",
|
| 284 |
+
"without using any built-in": "@@PPTAA",
|
| 285 |
+
"n is the length of the": "@@PPTAT",
|
| 286 |
+
"time complexity of O(n)": "@@PPTAC",
|
| 287 |
+
"solve this problem, we can": "@@PPTAG",
|
| 288 |
+
"is the length of the": "@@PPTTA",
|
| 289 |
+
"where n is the length": "@@PPTTT",
|
| 290 |
+
"time complexity of this solution": "@@PPTTC",
|
| 291 |
+
"has a time complexity of O(n)": "@@PPTTG",
|
| 292 |
+
"complexity of this solution is": "@@PPTCA",
|
| 293 |
+
"solve this problem, we": "@@PPTCT",
|
| 294 |
+
"from 2 to the square root of": "@@PPTCC",
|
| 295 |
+
"n is the length of": "@@PPTCG",
|
| 296 |
+
"to the square root of": "@@PPTGA",
|
| 297 |
+
"implementation has a time complexity of": "@@PPTGT",
|
| 298 |
+
"complexity of O(n)": "@@PPTGC",
|
| 299 |
+
"O(n), where n is": "@@PPTGG",
|
| 300 |
+
", where n is the length of the": "@@PPCAA",
|
| 301 |
+
"time complexity of this function is": "@@PPCAT",
|
| 302 |
+
"O(n), where n is the length": "@@PPCAC",
|
| 303 |
+
"implementation has a time complexity": "@@PPCAG",
|
| 304 |
+
"where n is the": "@@PPCTA",
|
| 305 |
+
"from 2 to the square root": "@@PPCTT",
|
| 306 |
+
"less than or equal to": "@@PPCTC",
|
| 307 |
+
"this problem, we can": "@@PPCTG",
|
| 308 |
+
"to keep track of": "@@PPCCA",
|
| 309 |
+
"with a time complexity of": "@@PPCCT",
|
| 310 |
+
"The time complexity of this solution is": "@@PPCCC",
|
| 311 |
+
"time complexity of this function": "@@PPCCG",
|
| 312 |
+
"complexity of this function is": "@@PPCGA",
|
| 313 |
+
", where n is the length of": "@@PPCGT",
|
| 314 |
+
"a time complexity of O(n),": "@@PPCGC",
|
| 315 |
+
"2 to the square root of": "@@PPCGG",
|
| 316 |
+
"without using any built-in functions or": "@@PPGAA",
|
| 317 |
+
"solve this problem, we can use": "@@PPGAT",
|
| 318 |
+
"n is the length of the input": "@@PPGAC",
|
| 319 |
+
"), where n is the length of": "@@PPGAG"
|
| 320 |
+
}
|
| 321 |
+
}
|
1_extracao_local/datasets_hibridos/Base_PTBR.jsonl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:104bdedf54e3149556d16676bde0b310eaf42062c8bf2b3e220af37f662b31db
|
| 3 |
+
size 46610873
|
1_extracao_local/datasets_hibridos/Python_DNA25.jsonl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:980754f9d03342c1a992cf0c7cf10ff1777543bacc736f184bb4f9d5a731189e
|
| 3 |
+
size 32569029
|
1_extracao_local/datasets_hibridos/canarim_30k.jsonl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e5686e452ba0bc508a280e33be9072239c627d927d443a6067002a6aae26ac66
|
| 3 |
+
size 16410543
|
1_extracao_local/datasets_hibridos/dataset_DPO_python.jsonl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3a1ab68a20d6caf810bf5885566082513f03b962eec5c8b2654cb2cf59bbf265
|
| 3 |
+
size 20874063
|
1_extracao_local/datasets_hibridos/openhermes_10k_ptbr.jsonl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1d0dd92f5559196b0a6cd4674e932e99d2108f9e392b40b0f245792b2401ef95
|
| 3 |
+
size 30200330
|
1_extracao_local/datasets_hibridos/python_15k.jsonl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:fa6960b964d43d56021d1f1cb3697716ca07ab9fc50720ea0bac46a2eaa1386b
|
| 3 |
+
size 33168239
|
1_extracao_local/download_datasets_v42.py
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
CROM-IA V4.2 — Download de Datasets Reais do HuggingFace
|
| 4 |
+
=========================================================
|
| 5 |
+
Downloads:
|
| 6 |
+
1. Canarim-Instruct-PTBR (30K) — Base conversacional PT-BR
|
| 7 |
+
2. Tested-22k-Python-Alpaca (15K) — Código Python
|
| 8 |
+
3. OpenHermes-2.5 (10K filtrados) — Destilação GPT-4 (para traduzir)
|
| 9 |
+
|
| 10 |
+
Filtra por qualidade: resposta > 100 chars, sem duplicatas.
|
| 11 |
+
"""
|
| 12 |
+
|
| 13 |
+
import json
|
| 14 |
+
import os
|
| 15 |
+
import sys
|
| 16 |
+
import hashlib
|
| 17 |
+
|
| 18 |
+
# Diretório de saída
|
| 19 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 20 |
+
OUTPUT_DIR = os.path.join(SCRIPT_DIR, "datasets_hibridos")
|
| 21 |
+
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def filtrar_qualidade(texto, min_chars=100):
|
| 25 |
+
"""Filtra respostas muito curtas ou vazias."""
|
| 26 |
+
if not texto or not isinstance(texto, str):
|
| 27 |
+
return False
|
| 28 |
+
return len(texto.strip()) >= min_chars
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def deduplicate(items, key_fn):
|
| 32 |
+
"""Remove duplicatas por hash do conteúdo."""
|
| 33 |
+
seen = set()
|
| 34 |
+
unicos = []
|
| 35 |
+
for item in items:
|
| 36 |
+
h = hashlib.md5(key_fn(item).encode()).hexdigest()
|
| 37 |
+
if h not in seen:
|
| 38 |
+
seen.add(h)
|
| 39 |
+
unicos.append(item)
|
| 40 |
+
return unicos
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def formatar_chatml(instruction, output, system_msg="Você é CROM-IA, um assistente inteligente brasileiro."):
|
| 44 |
+
"""Formata no padrão ChatML (Qwen)."""
|
| 45 |
+
texto = (
|
| 46 |
+
f"<|im_start|>system\n{system_msg}<|im_end|>\n"
|
| 47 |
+
f"<|im_start|>user\n{instruction}<|im_end|>\n"
|
| 48 |
+
f"<|im_start|>assistant\n{output}<|im_end|>"
|
| 49 |
+
)
|
| 50 |
+
return {"text": texto}
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def download_canarim(max_samples=30000):
|
| 54 |
+
"""1. Canarim-Instruct-PTBR — Base conversacional PT-BR."""
|
| 55 |
+
from datasets import load_dataset
|
| 56 |
+
|
| 57 |
+
path_out = os.path.join(OUTPUT_DIR, "canarim_30k.jsonl")
|
| 58 |
+
if os.path.exists(path_out):
|
| 59 |
+
linhas = sum(1 for _ in open(path_out))
|
| 60 |
+
print(f"⏭️ Canarim já existe: {path_out} ({linhas} linhas)")
|
| 61 |
+
return path_out
|
| 62 |
+
|
| 63 |
+
print("\n" + "=" * 60)
|
| 64 |
+
print("📥 Baixando Canarim-Instruct-PTBR...")
|
| 65 |
+
print("=" * 60)
|
| 66 |
+
|
| 67 |
+
ds = load_dataset('dominguesm/Canarim-Instruct-PTBR-Dataset', split='train')
|
| 68 |
+
print(f" Dataset total: {len(ds)} amostras")
|
| 69 |
+
|
| 70 |
+
# Detectar formato
|
| 71 |
+
colunas = ds.column_names
|
| 72 |
+
print(f" Colunas: {colunas}")
|
| 73 |
+
|
| 74 |
+
total = 0
|
| 75 |
+
with open(path_out, 'w', encoding='utf-8') as f:
|
| 76 |
+
for item in ds:
|
| 77 |
+
# Tentar múltiplos formatos
|
| 78 |
+
instruction = (item.get('instruction', '') or
|
| 79 |
+
item.get('input', '') or
|
| 80 |
+
item.get('prompt', '') or '')
|
| 81 |
+
output = (item.get('output', '') or
|
| 82 |
+
item.get('response', '') or
|
| 83 |
+
item.get('completion', '') or '')
|
| 84 |
+
|
| 85 |
+
# Se tem 'text' direto (formato single-field)
|
| 86 |
+
if not output and 'text' in item:
|
| 87 |
+
output = item['text']
|
| 88 |
+
instruction = ""
|
| 89 |
+
|
| 90 |
+
if not filtrar_qualidade(output, min_chars=50):
|
| 91 |
+
continue
|
| 92 |
+
|
| 93 |
+
formatted = formatar_chatml(instruction, output)
|
| 94 |
+
f.write(json.dumps(formatted, ensure_ascii=False) + '\n')
|
| 95 |
+
total += 1
|
| 96 |
+
if total >= max_samples:
|
| 97 |
+
break
|
| 98 |
+
|
| 99 |
+
print(f"✅ Canarim salvo: {path_out} ({total} amostras)")
|
| 100 |
+
return path_out
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def download_python(max_samples=15000):
|
| 104 |
+
"""2. Tested-22k-Python-Alpaca — Código Python."""
|
| 105 |
+
from datasets import load_dataset
|
| 106 |
+
|
| 107 |
+
path_out = os.path.join(OUTPUT_DIR, "python_15k.jsonl")
|
| 108 |
+
if os.path.exists(path_out):
|
| 109 |
+
linhas = sum(1 for _ in open(path_out))
|
| 110 |
+
print(f"⏭️ Python já existe: {path_out} ({linhas} linhas)")
|
| 111 |
+
return path_out
|
| 112 |
+
|
| 113 |
+
print("\n" + "=" * 60)
|
| 114 |
+
print("📥 Baixando Tested-22k-Python-Alpaca...")
|
| 115 |
+
print("=" * 60)
|
| 116 |
+
|
| 117 |
+
ds = load_dataset('Vezora/Tested-22k-Python-Alpaca', split='train')
|
| 118 |
+
print(f" Dataset total: {len(ds)} amostras")
|
| 119 |
+
print(f" Colunas: {ds.column_names}")
|
| 120 |
+
|
| 121 |
+
total = 0
|
| 122 |
+
with open(path_out, 'w', encoding='utf-8') as f:
|
| 123 |
+
for item in ds:
|
| 124 |
+
instruction = (item.get('instruction', '') or
|
| 125 |
+
item.get('input', '') or '')
|
| 126 |
+
output = (item.get('output', '') or
|
| 127 |
+
item.get('response', '') or '')
|
| 128 |
+
|
| 129 |
+
if not filtrar_qualidade(output, min_chars=80):
|
| 130 |
+
continue
|
| 131 |
+
|
| 132 |
+
formatted = formatar_chatml(
|
| 133 |
+
instruction, output,
|
| 134 |
+
system_msg="Você é CROM-IA, especialista em Python. Responda com código e explicações claras."
|
| 135 |
+
)
|
| 136 |
+
f.write(json.dumps(formatted, ensure_ascii=False) + '\n')
|
| 137 |
+
total += 1
|
| 138 |
+
if total >= max_samples:
|
| 139 |
+
break
|
| 140 |
+
|
| 141 |
+
print(f"✅ Python salvo: {path_out} ({total} amostras)")
|
| 142 |
+
return path_out
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
def download_openhermes(max_samples=10000):
|
| 146 |
+
"""3. OpenHermes-2.5 — Top 10K (para traduzir depois)."""
|
| 147 |
+
from datasets import load_dataset
|
| 148 |
+
|
| 149 |
+
path_out = os.path.join(OUTPUT_DIR, "openhermes_10k_en.jsonl")
|
| 150 |
+
if os.path.exists(path_out):
|
| 151 |
+
linhas = sum(1 for _ in open(path_out))
|
| 152 |
+
print(f"⏭️ OpenHermes já existe: {path_out} ({linhas} linhas)")
|
| 153 |
+
return path_out
|
| 154 |
+
|
| 155 |
+
print("\n" + "=" * 60)
|
| 156 |
+
print("📥 Baixando OpenHermes-2.5 (top 10K)...")
|
| 157 |
+
print("=" * 60)
|
| 158 |
+
|
| 159 |
+
ds = load_dataset('teknium/OpenHermes-2.5', split='train')
|
| 160 |
+
print(f" Dataset total: {len(ds)} amostras")
|
| 161 |
+
print(f" Colunas: {ds.column_names}")
|
| 162 |
+
|
| 163 |
+
# Filtrar respostas longas e ricas (qualidade GPT-4)
|
| 164 |
+
candidatos = []
|
| 165 |
+
for item in ds:
|
| 166 |
+
conversations = item.get('conversations', [])
|
| 167 |
+
if len(conversations) < 2:
|
| 168 |
+
continue
|
| 169 |
+
|
| 170 |
+
# Pegar a última resposta do assistant
|
| 171 |
+
instruction = ""
|
| 172 |
+
output = ""
|
| 173 |
+
for msg in conversations:
|
| 174 |
+
role = msg.get('from', msg.get('role', ''))
|
| 175 |
+
value = msg.get('value', msg.get('content', ''))
|
| 176 |
+
if role in ('human', 'user'):
|
| 177 |
+
instruction = value
|
| 178 |
+
elif role in ('gpt', 'assistant'):
|
| 179 |
+
output = value
|
| 180 |
+
|
| 181 |
+
if not instruction or not output:
|
| 182 |
+
continue
|
| 183 |
+
|
| 184 |
+
if len(output) < 200: # Só respostas ricas
|
| 185 |
+
continue
|
| 186 |
+
|
| 187 |
+
candidatos.append({
|
| 188 |
+
'instruction': instruction,
|
| 189 |
+
'output': output,
|
| 190 |
+
'length': len(output)
|
| 191 |
+
})
|
| 192 |
+
|
| 193 |
+
# Ordenar por tamanho (respostas mais ricas primeiro)
|
| 194 |
+
candidatos.sort(key=lambda x: x['length'], reverse=True)
|
| 195 |
+
candidatos = candidatos[:max_samples]
|
| 196 |
+
|
| 197 |
+
print(f" Filtrados: {len(candidatos)} amostras (> 200 chars)")
|
| 198 |
+
|
| 199 |
+
total = 0
|
| 200 |
+
with open(path_out, 'w', encoding='utf-8') as f:
|
| 201 |
+
for item in candidatos:
|
| 202 |
+
# Salvar em EN (traduzir depois com tradutor_batch_argos.py)
|
| 203 |
+
entry = {
|
| 204 |
+
'instruction': item['instruction'],
|
| 205 |
+
'output': item['output'],
|
| 206 |
+
}
|
| 207 |
+
f.write(json.dumps(entry, ensure_ascii=False) + '\n')
|
| 208 |
+
total += 1
|
| 209 |
+
|
| 210 |
+
print(f"✅ OpenHermes EN salvo: {path_out} ({total} amostras)")
|
| 211 |
+
print(f" ⚠️ ATENÇÃO: Precisa traduzir com tradutor_batch_argos.py!")
|
| 212 |
+
return path_out
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
def main():
|
| 216 |
+
print("\n" + "=" * 60)
|
| 217 |
+
print("🧬 CROM-IA V4.2 — Download de Datasets Reais")
|
| 218 |
+
print(f" Saída: {OUTPUT_DIR}")
|
| 219 |
+
print("=" * 60)
|
| 220 |
+
|
| 221 |
+
try:
|
| 222 |
+
from datasets import load_dataset
|
| 223 |
+
except ImportError:
|
| 224 |
+
print("❌ Biblioteca 'datasets' não instalada!")
|
| 225 |
+
print(" pip install datasets")
|
| 226 |
+
sys.exit(1)
|
| 227 |
+
|
| 228 |
+
# 1. Canarim (PT-BR nativo)
|
| 229 |
+
path_canarim = download_canarim(30000)
|
| 230 |
+
|
| 231 |
+
# 2. Python
|
| 232 |
+
path_python = download_python(15000)
|
| 233 |
+
|
| 234 |
+
# 3. OpenHermes (EN, para traduzir)
|
| 235 |
+
path_hermes = download_openhermes(10000)
|
| 236 |
+
|
| 237 |
+
# Relatório final
|
| 238 |
+
print("\n" + "=" * 60)
|
| 239 |
+
print("📊 RELATÓRIO FINAL")
|
| 240 |
+
print("=" * 60)
|
| 241 |
+
paths = [path_canarim, path_python, path_hermes]
|
| 242 |
+
for p in paths:
|
| 243 |
+
if p and os.path.exists(p):
|
| 244 |
+
linhas = sum(1 for _ in open(p))
|
| 245 |
+
tamanho = os.path.getsize(p) / (1024 * 1024)
|
| 246 |
+
print(f" ✅ {os.path.basename(p)}: {linhas} amostras ({tamanho:.1f} MB)")
|
| 247 |
+
|
| 248 |
+
print("\n📋 PRÓXIMOS PASSOS (NO COLAB):")
|
| 249 |
+
print(" Suba o `openhermes_10k_en.jsonl` para o Google Colab.")
|
| 250 |
+
print(" Execute a tradução LA COM GPU para evitar travamento local.")
|
| 251 |
+
print(" Depois, realize a geração do codebook e DNA localmente no dataset traduzido.")
|
| 252 |
+
print(" 5. Enviar para Colab!")
|
| 253 |
+
|
| 254 |
+
|
| 255 |
+
if __name__ == "__main__":
|
| 256 |
+
main()
|
1_extracao_local/gerador_codebook_v42.py
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
CROM-IA V4.2 — Gerador de Codebook Hierárquico (Data-Driven)
|
| 4 |
+
=============================================================
|
| 5 |
+
Filosofia Crompressor: comprimir o que é REALMENTE repetido nos dados.
|
| 6 |
+
DNA em 3 NÍVEIS hierárquicos:
|
| 7 |
+
W (Word) = palavras isoladas frequentes → @@GWA
|
| 8 |
+
F (Phrase) = frases de 2-8 palavras repetidas → @@GFA
|
| 9 |
+
P (Paragraph) = blocos de 8-20 palavras → @@GPA
|
| 10 |
+
|
| 11 |
+
Economia REAL: score = frequência × (len(texto) - len(token_dna))
|
| 12 |
+
Um parágrafo inteiro que se repete 50x vale MUITO mais que uma palavra.
|
| 13 |
+
"""
|
| 14 |
+
|
| 15 |
+
import json
|
| 16 |
+
import re
|
| 17 |
+
import sys
|
| 18 |
+
import os
|
| 19 |
+
from collections import Counter
|
| 20 |
+
import math
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def tokenizar(texto):
|
| 24 |
+
"""Tokeniza texto preservando estrutura (palavras + pontuação + espaços)."""
|
| 25 |
+
return re.findall(r'\w+|\s+|[^\w\s]', texto)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def extrair_ngrams(texto, min_n, max_n):
|
| 29 |
+
"""Extrai n-grams via sliding window (core do Crompressor)."""
|
| 30 |
+
tokens = tokenizar(texto)
|
| 31 |
+
ngrams = []
|
| 32 |
+
for n in range(min_n, max_n + 1):
|
| 33 |
+
for i in range(len(tokens) - n + 1):
|
| 34 |
+
chunk = "".join(tokens[i:i + n])
|
| 35 |
+
chunk_limpo = chunk.strip()
|
| 36 |
+
if len(chunk_limpo) >= 4:
|
| 37 |
+
ngrams.append(chunk_limpo)
|
| 38 |
+
return ngrams
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def analisar_dataset(path_dataset, max_linhas=50000):
|
| 42 |
+
"""
|
| 43 |
+
Fase 1 do Crompressor: Mineração de frequência REAL.
|
| 44 |
+
3 níveis hierárquicos:
|
| 45 |
+
- Palavras: tokens individuais
|
| 46 |
+
- Frases: 2-8 tokens combinados
|
| 47 |
+
- Blocos: 8-20 tokens (parágrafos repetidos)
|
| 48 |
+
"""
|
| 49 |
+
print(f"🔬 Analisando frequência real do dataset: {path_dataset}")
|
| 50 |
+
|
| 51 |
+
cnt_palavras = Counter()
|
| 52 |
+
cnt_frases = Counter()
|
| 53 |
+
cnt_blocos = Counter()
|
| 54 |
+
|
| 55 |
+
linhas = 0
|
| 56 |
+
with open(path_dataset, "r", encoding="utf-8") as f:
|
| 57 |
+
for line in f:
|
| 58 |
+
try:
|
| 59 |
+
data = json.loads(line.strip())
|
| 60 |
+
# Suporta múltiplos formatos
|
| 61 |
+
texto = (data.get("output", "") or
|
| 62 |
+
data.get("text", "") or
|
| 63 |
+
data.get("response", "") or "")
|
| 64 |
+
|
| 65 |
+
# Se for ChatML, extrair o conteúdo do assistant
|
| 66 |
+
if "<|im_start|>assistant" in texto:
|
| 67 |
+
match = re.search(r'<\|im_start\|>assistant\n(.*?)(<\|im_end\|>|$)',
|
| 68 |
+
texto, re.DOTALL)
|
| 69 |
+
if match:
|
| 70 |
+
texto = match.group(1)
|
| 71 |
+
except json.JSONDecodeError:
|
| 72 |
+
texto = line.strip()
|
| 73 |
+
|
| 74 |
+
if not texto:
|
| 75 |
+
continue
|
| 76 |
+
|
| 77 |
+
# NÍVEL 1 — Palavras individuais (frequência bruta)
|
| 78 |
+
palavras = re.findall(r'\b\w{4,}\b', texto.lower())
|
| 79 |
+
cnt_palavras.update(palavras)
|
| 80 |
+
|
| 81 |
+
# NÍVEL 2 — Frases (3-8 palavras)
|
| 82 |
+
# Frases que se repetem entre múltiplas amostras = alto valor
|
| 83 |
+
for bloco in texto.split("\n"):
|
| 84 |
+
bloco = bloco.strip()
|
| 85 |
+
if len(bloco) > 20:
|
| 86 |
+
cnt_frases.update(extrair_ngrams(bloco, 3, 8))
|
| 87 |
+
|
| 88 |
+
# NÍVEL 3 — Blocos/Parágrafos (8-20 palavras)
|
| 89 |
+
# Parágrafos inteiros repetidos = MÁXIMA economia
|
| 90 |
+
for bloco in texto.split("\n"):
|
| 91 |
+
bloco = bloco.strip()
|
| 92 |
+
if len(bloco) > 60:
|
| 93 |
+
cnt_blocos.update(extrair_ngrams(bloco, 8, 16))
|
| 94 |
+
|
| 95 |
+
# Também indexar o parágrafo inteiro se não for muito longo
|
| 96 |
+
if 60 < len(bloco) < 300:
|
| 97 |
+
cnt_blocos[bloco] += 1
|
| 98 |
+
|
| 99 |
+
linhas += 1
|
| 100 |
+
if linhas >= max_linhas:
|
| 101 |
+
break
|
| 102 |
+
|
| 103 |
+
print(f" Linhas analisadas: {linhas}")
|
| 104 |
+
print(f" Palavras únicas: {len(cnt_palavras)}")
|
| 105 |
+
print(f" Frases únicas: {len(cnt_frases)}")
|
| 106 |
+
print(f" Blocos únicos: {len(cnt_blocos)}")
|
| 107 |
+
|
| 108 |
+
return cnt_palavras, cnt_frases, cnt_blocos
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def ranquear_por_economia(contador, min_freq=5):
|
| 112 |
+
"""
|
| 113 |
+
Fase 2: Ranquear por ECONOMIA REAL de bytes.
|
| 114 |
+
Score = frequência × (len(texto) - len(token_dna))
|
| 115 |
+
Um parágrafo de 200 chars × 50 vezes = 10.000 bytes economizados!
|
| 116 |
+
"""
|
| 117 |
+
TOKEN_DNA_SIZE = 6 # @@XXYY = 6 bytes médio
|
| 118 |
+
candidatos = []
|
| 119 |
+
|
| 120 |
+
for texto, freq in contador.items():
|
| 121 |
+
if freq < min_freq:
|
| 122 |
+
continue
|
| 123 |
+
economia_por_hit = len(texto) - TOKEN_DNA_SIZE
|
| 124 |
+
if economia_por_hit <= 0:
|
| 125 |
+
continue
|
| 126 |
+
score = freq * economia_por_hit
|
| 127 |
+
candidatos.append({
|
| 128 |
+
"texto": texto,
|
| 129 |
+
"freq": freq,
|
| 130 |
+
"tamanho": len(texto),
|
| 131 |
+
"economia_por_hit": economia_por_hit,
|
| 132 |
+
"score_total": score,
|
| 133 |
+
})
|
| 134 |
+
|
| 135 |
+
candidatos.sort(key=lambda x: x["score_total"], reverse=True)
|
| 136 |
+
return candidatos
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def gerar_hash_radix4(idx):
|
| 140 |
+
"""Gera sufixo DNA usando base Radix-4 (A, T, C, G)."""
|
| 141 |
+
radix = ['A', 'T', 'C', 'G']
|
| 142 |
+
if idx < 4:
|
| 143 |
+
return radix[idx]
|
| 144 |
+
elif idx < 16:
|
| 145 |
+
return radix[idx // 4] + radix[idx % 4]
|
| 146 |
+
elif idx < 64:
|
| 147 |
+
return radix[(idx // 16) % 4] + radix[(idx // 4) % 4] + radix[idx % 4]
|
| 148 |
+
else:
|
| 149 |
+
return (radix[(idx // 64) % 4] + radix[(idx // 16) % 4] +
|
| 150 |
+
radix[(idx // 4) % 4] + radix[idx % 4])
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def gerar_codebook(path_dataset, path_saida, sigla_dominio="G", max_tokens=200,
|
| 154 |
+
min_freq=5, distribuicao=None):
|
| 155 |
+
"""
|
| 156 |
+
Pipeline completo Crompressor → Codebook DNA Hierárquico.
|
| 157 |
+
1. Minera frequência real
|
| 158 |
+
2. Ranqueia por economia de bytes
|
| 159 |
+
3. Gera codebook em 3 níveis (W, F, P) com hash Radix-4
|
| 160 |
+
"""
|
| 161 |
+
if distribuicao is None:
|
| 162 |
+
# Distribuição padrão: 40% palavras, 40% frases, 20% blocos
|
| 163 |
+
distribuicao = (0.4, 0.4, 0.2)
|
| 164 |
+
|
| 165 |
+
print(f"\n{'='*60}")
|
| 166 |
+
print(f"🧬 CROM-IA V4.2 — Gerador de Codebook Hierárquico")
|
| 167 |
+
print(f" Domínio: {sigla_dominio}")
|
| 168 |
+
print(f" Dataset: {os.path.basename(path_dataset)}")
|
| 169 |
+
print(f" Max tokens: {max_tokens}")
|
| 170 |
+
print(f" Distribuição: W={distribuicao[0]*100:.0f}% F={distribuicao[1]*100:.0f}% P={distribuicao[2]*100:.0f}%")
|
| 171 |
+
print(f"{'='*60}\n")
|
| 172 |
+
|
| 173 |
+
# Fase 1: Minerar
|
| 174 |
+
cnt_palavras, cnt_frases, cnt_blocos = analisar_dataset(path_dataset)
|
| 175 |
+
|
| 176 |
+
# Fase 2: Ranquear por economia
|
| 177 |
+
rank_palavras = ranquear_por_economia(cnt_palavras, min_freq)
|
| 178 |
+
rank_frases = ranquear_por_economia(cnt_frases, min_freq)
|
| 179 |
+
rank_blocos = ranquear_por_economia(cnt_blocos, min_freq=3)
|
| 180 |
+
|
| 181 |
+
# Fase 3: Distribuir tokens por hierarquia
|
| 182 |
+
n_palavras = int(max_tokens * distribuicao[0])
|
| 183 |
+
n_frases = int(max_tokens * distribuicao[1])
|
| 184 |
+
n_blocos = max_tokens - n_palavras - n_frases
|
| 185 |
+
|
| 186 |
+
codebook = {}
|
| 187 |
+
stats = {"economia_total_estimada": 0, "por_nivel": {}}
|
| 188 |
+
idx = 0
|
| 189 |
+
|
| 190 |
+
# W (Words)
|
| 191 |
+
economia_w = 0
|
| 192 |
+
for entry in rank_palavras[:n_palavras]:
|
| 193 |
+
sufixo = gerar_hash_radix4(idx)
|
| 194 |
+
chave = f"@@{sigla_dominio}W{sufixo}"
|
| 195 |
+
codebook[entry["texto"]] = chave
|
| 196 |
+
economia_w += entry["score_total"]
|
| 197 |
+
idx += 1
|
| 198 |
+
stats["por_nivel"]["W_palavras"] = {"tokens": min(len(rank_palavras), n_palavras),
|
| 199 |
+
"economia": economia_w}
|
| 200 |
+
|
| 201 |
+
# F (Phrases)
|
| 202 |
+
economia_f = 0
|
| 203 |
+
idx_f = 0
|
| 204 |
+
for entry in rank_frases[:n_frases]:
|
| 205 |
+
if entry["texto"] not in codebook:
|
| 206 |
+
sufixo = gerar_hash_radix4(idx_f)
|
| 207 |
+
chave = f"@@{sigla_dominio}F{sufixo}"
|
| 208 |
+
codebook[entry["texto"]] = chave
|
| 209 |
+
economia_f += entry["score_total"]
|
| 210 |
+
idx_f += 1
|
| 211 |
+
stats["por_nivel"]["F_frases"] = {"tokens": idx_f, "economia": economia_f}
|
| 212 |
+
|
| 213 |
+
# P (Paragraphs/Blocks)
|
| 214 |
+
economia_p = 0
|
| 215 |
+
idx_p = 0
|
| 216 |
+
for entry in rank_blocos[:n_blocos]:
|
| 217 |
+
if entry["texto"] not in codebook:
|
| 218 |
+
sufixo = gerar_hash_radix4(idx_p)
|
| 219 |
+
chave = f"@@{sigla_dominio}P{sufixo}"
|
| 220 |
+
codebook[entry["texto"]] = chave
|
| 221 |
+
economia_p += entry["score_total"]
|
| 222 |
+
idx_p += 1
|
| 223 |
+
stats["por_nivel"]["P_blocos"] = {"tokens": idx_p, "economia": economia_p}
|
| 224 |
+
|
| 225 |
+
stats["economia_total_estimada"] = economia_w + economia_f + economia_p
|
| 226 |
+
|
| 227 |
+
# Salvar codebook
|
| 228 |
+
payload = {
|
| 229 |
+
"version": "4.2",
|
| 230 |
+
"domain": sigla_dominio,
|
| 231 |
+
"method": "hierarchical_frequency_x_size",
|
| 232 |
+
"total_tokens": len(codebook),
|
| 233 |
+
"niveis": {
|
| 234 |
+
"W": "palavras isoladas",
|
| 235 |
+
"F": "frases (2-8 palavras)",
|
| 236 |
+
"P": "parágrafos/blocos (8-20 palavras)"
|
| 237 |
+
},
|
| 238 |
+
"economia_bytes_estimada": stats["economia_total_estimada"],
|
| 239 |
+
"stats": stats,
|
| 240 |
+
"codebook": codebook,
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
with open(path_saida, "w", encoding="utf-8") as f:
|
| 244 |
+
json.dump(payload, f, ensure_ascii=False, indent=2)
|
| 245 |
+
|
| 246 |
+
# Relatório
|
| 247 |
+
print(f"\n📊 RELATÓRIO DO CODEBOOK HIERÁRQUICO:")
|
| 248 |
+
print(f" Tokens gerados: {len(codebook)}")
|
| 249 |
+
print(f" ├── W (palavras): {stats['por_nivel']['W_palavras']['tokens']} "
|
| 250 |
+
f"({stats['por_nivel']['W_palavras']['economia']:,} bytes)")
|
| 251 |
+
print(f" ├── F (frases): {stats['por_nivel']['F_frases']['tokens']} "
|
| 252 |
+
f"({stats['por_nivel']['F_frases']['economia']:,} bytes)")
|
| 253 |
+
print(f" └── P (blocos): {stats['por_nivel']['P_blocos']['tokens']} "
|
| 254 |
+
f"({stats['por_nivel']['P_blocos']['economia']:,} bytes)")
|
| 255 |
+
print(f" Economia total: {stats['economia_total_estimada']:,} bytes")
|
| 256 |
+
|
| 257 |
+
print(f"\n Top 5 maior economia:")
|
| 258 |
+
top5 = sorted(
|
| 259 |
+
[(k, v) for k, v in codebook.items()],
|
| 260 |
+
key=lambda x: len(x[0]),
|
| 261 |
+
reverse=True
|
| 262 |
+
)[:5]
|
| 263 |
+
for texto, token in top5:
|
| 264 |
+
nivel = "BLOCO" if len(texto) > 50 else "FRASE" if len(texto) > 15 else "WORD"
|
| 265 |
+
print(f" [{nivel}] '{texto[:60]}' → {token}")
|
| 266 |
+
|
| 267 |
+
print(f"\n Salvo em: {path_saida}")
|
| 268 |
+
return codebook
|
| 269 |
+
|
| 270 |
+
|
| 271 |
+
if __name__ == "__main__":
|
| 272 |
+
if len(sys.argv) < 4:
|
| 273 |
+
print("CROM-IA V4.2 — Gerador de Codebook Hierárquico")
|
| 274 |
+
print(f"Uso: python3 {sys.argv[0]} <sigla> <dataset.jsonl> <saida.json> [max_tokens]")
|
| 275 |
+
print(f"Exemplo: python3 {sys.argv[0]} P python_15k.jsonl codebook_python.json 200")
|
| 276 |
+
print(f"\nSignas: P=Python, M=Medicina, G=Geral, C=Conversa")
|
| 277 |
+
sys.exit(1)
|
| 278 |
+
|
| 279 |
+
sigla = sys.argv[1]
|
| 280 |
+
dataset = sys.argv[2]
|
| 281 |
+
saida = sys.argv[3]
|
| 282 |
+
max_tok = int(sys.argv[4]) if len(sys.argv) > 4 else 200
|
| 283 |
+
|
| 284 |
+
gerar_codebook(dataset, saida, sigla, max_tok)
|
1_extracao_local/gerador_pares_dpo.py
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
CROM-IA V4.2 — Gerador de Pares DPO (Direct Preference Optimization)
|
| 4 |
+
=====================================================================
|
| 5 |
+
Gera pares {prompt, chosen, rejected} automaticamente:
|
| 6 |
+
- chosen = resposta com DNA aplicado (25%) — preferida
|
| 7 |
+
- rejected = resposta original sem DNA — rejeitada
|
| 8 |
+
O modelo aprende a PREFERIR usar DNA quando oportuno.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import json
|
| 12 |
+
import os
|
| 13 |
+
import sys
|
| 14 |
+
import random
|
| 15 |
+
import re
|
| 16 |
+
from collections import Counter
|
| 17 |
+
|
| 18 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def carregar_codebook(path_codebook):
|
| 22 |
+
"""Carrega codebook DNA."""
|
| 23 |
+
if path_codebook and os.path.exists(path_codebook):
|
| 24 |
+
with open(path_codebook, "r") as f:
|
| 25 |
+
data = json.load(f)
|
| 26 |
+
if "codebook" in data and isinstance(data["codebook"], dict):
|
| 27 |
+
return data["codebook"]
|
| 28 |
+
return data
|
| 29 |
+
return {}
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def aplicar_mutacao_dna(texto, codebook, taxa=0.25):
|
| 33 |
+
"""Aplica DNA apenas a uma fração das palavras-chave encontradas."""
|
| 34 |
+
resultado = texto
|
| 35 |
+
matches_encontrados = 0
|
| 36 |
+
matches_mutados = 0
|
| 37 |
+
|
| 38 |
+
for palavra, token_dna in codebook.items():
|
| 39 |
+
ocorrencias = len(re.findall(re.escape(palavra), resultado, re.IGNORECASE))
|
| 40 |
+
if ocorrencias > 0:
|
| 41 |
+
matches_encontrados += ocorrencias
|
| 42 |
+
# Aplicar DNA a cada ocorrência com probabilidade
|
| 43 |
+
def substituir_com_prob(match):
|
| 44 |
+
nonlocal matches_mutados
|
| 45 |
+
if random.random() < taxa:
|
| 46 |
+
matches_mutados += 1
|
| 47 |
+
return token_dna
|
| 48 |
+
return match.group(0)
|
| 49 |
+
|
| 50 |
+
pattern = re.compile(re.escape(palavra), re.IGNORECASE)
|
| 51 |
+
resultado = pattern.sub(substituir_com_prob, resultado)
|
| 52 |
+
|
| 53 |
+
return resultado, matches_mutados
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def extrair_instrucao_output(entry):
|
| 57 |
+
"""Extrai instrução e output de múltiplos formatos."""
|
| 58 |
+
# Formato ChatML
|
| 59 |
+
if "text" in entry and "<|im_start|>" in entry.get("text", ""):
|
| 60 |
+
text = entry["text"]
|
| 61 |
+
user_match = re.search(r'<\|im_start\|>user\n(.*?)<\|im_end\|>', text, re.DOTALL)
|
| 62 |
+
asst_match = re.search(r'<\|im_start\|>assistant\n(.*?)<\|im_end\|>', text, re.DOTALL)
|
| 63 |
+
instruction = user_match.group(1).strip() if user_match else ""
|
| 64 |
+
output = asst_match.group(1).strip() if asst_match else ""
|
| 65 |
+
return instruction, output
|
| 66 |
+
|
| 67 |
+
# Formato instrução/output
|
| 68 |
+
instruction = (entry.get('instruction', '') or
|
| 69 |
+
entry.get('input', '') or
|
| 70 |
+
entry.get('prompt', '') or '')
|
| 71 |
+
output = (entry.get('output', '') or
|
| 72 |
+
entry.get('response', '') or
|
| 73 |
+
entry.get('completion', '') or '')
|
| 74 |
+
|
| 75 |
+
return instruction.strip(), output.strip()
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def gerar_pares_dpo(path_input, path_output, codebook, max_pares=5000,
|
| 79 |
+
taxa_dna=0.25, min_dna_tokens=3, min_output_chars=100):
|
| 80 |
+
"""
|
| 81 |
+
Pipeline de geração de pares DPO.
|
| 82 |
+
chosen = output com DNA
|
| 83 |
+
rejected = output original
|
| 84 |
+
"""
|
| 85 |
+
print(f"\n{'='*60}")
|
| 86 |
+
print(f"🧬 CROM-IA V4.2 — Gerador de Pares DPO")
|
| 87 |
+
print(f" Input: {os.path.basename(path_input)}")
|
| 88 |
+
print(f" Taxa DNA: {taxa_dna*100:.0f}%")
|
| 89 |
+
print(f" Max pares: {max_pares}")
|
| 90 |
+
print(f"{'='*60}\n")
|
| 91 |
+
|
| 92 |
+
total_lidos = 0
|
| 93 |
+
total_pares = 0
|
| 94 |
+
total_rejeitados_curtos = 0
|
| 95 |
+
total_rejeitados_sem_dna = 0
|
| 96 |
+
|
| 97 |
+
with open(path_input, "r", encoding="utf-8") as fin, \
|
| 98 |
+
open(path_output, "w", encoding="utf-8") as fout:
|
| 99 |
+
|
| 100 |
+
for line in fin:
|
| 101 |
+
if total_pares >= max_pares:
|
| 102 |
+
break
|
| 103 |
+
|
| 104 |
+
try:
|
| 105 |
+
entry = json.loads(line.strip())
|
| 106 |
+
except json.JSONDecodeError:
|
| 107 |
+
continue
|
| 108 |
+
|
| 109 |
+
total_lidos += 1
|
| 110 |
+
instruction, output = extrair_instrucao_output(entry)
|
| 111 |
+
|
| 112 |
+
if not instruction or not output:
|
| 113 |
+
continue
|
| 114 |
+
|
| 115 |
+
# Filtro: output mínimo
|
| 116 |
+
if len(output) < min_output_chars:
|
| 117 |
+
total_rejeitados_curtos += 1
|
| 118 |
+
continue
|
| 119 |
+
|
| 120 |
+
# Gerar chosen (com DNA)
|
| 121 |
+
chosen, num_dna = aplicar_mutacao_dna(output, codebook, taxa=taxa_dna)
|
| 122 |
+
|
| 123 |
+
# Filtro: precisa ter DNA suficiente
|
| 124 |
+
if num_dna < min_dna_tokens:
|
| 125 |
+
total_rejeitados_sem_dna += 1
|
| 126 |
+
continue
|
| 127 |
+
|
| 128 |
+
# chosen e rejected devem ser DIFERENTES
|
| 129 |
+
if chosen == output:
|
| 130 |
+
total_rejeitados_sem_dna += 1
|
| 131 |
+
continue
|
| 132 |
+
|
| 133 |
+
# Formato DPO
|
| 134 |
+
par = {
|
| 135 |
+
"prompt": instruction,
|
| 136 |
+
"chosen": chosen,
|
| 137 |
+
"rejected": output,
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
fout.write(json.dumps(par, ensure_ascii=False) + "\n")
|
| 141 |
+
total_pares += 1
|
| 142 |
+
|
| 143 |
+
print(f"📊 RELATÓRIO DPO:")
|
| 144 |
+
print(f" Amostras lidas: {total_lidos}")
|
| 145 |
+
print(f" Pares gerados: {total_pares}")
|
| 146 |
+
print(f" Rejeitados (curtos): {total_rejeitados_curtos}")
|
| 147 |
+
print(f" Rejeitados (sem DNA suficiente): {total_rejeitados_sem_dna}")
|
| 148 |
+
print(f" Taxa de conversão: {total_pares/max(total_lidos,1)*100:.1f}%")
|
| 149 |
+
print(f"\n Salvo em: {path_output}")
|
| 150 |
+
|
| 151 |
+
return total_pares
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
if __name__ == "__main__":
|
| 155 |
+
import argparse
|
| 156 |
+
|
| 157 |
+
parser = argparse.ArgumentParser(description="CROM-IA V4.2 — Gerador de Pares DPO")
|
| 158 |
+
parser.add_argument('--input', required=True, help='Dataset de entrada (.jsonl)')
|
| 159 |
+
parser.add_argument('--codebook', required=True, help='Codebook DNA (.json)')
|
| 160 |
+
parser.add_argument('--output', default=None, help='Saída (.jsonl)')
|
| 161 |
+
parser.add_argument('--max_pares', type=int, default=5000, help='Máximo de pares (default: 5000)')
|
| 162 |
+
parser.add_argument('--taxa_dna', type=float, default=0.25, help='Taxa de DNA (default: 0.25)')
|
| 163 |
+
parser.add_argument('--min_dna', type=int, default=3, help='Mínimo de tokens DNA por par (default: 3)')
|
| 164 |
+
|
| 165 |
+
args = parser.parse_args()
|
| 166 |
+
|
| 167 |
+
if not args.output:
|
| 168 |
+
base = os.path.splitext(os.path.basename(args.input))[0]
|
| 169 |
+
args.output = os.path.join(SCRIPT_DIR, "datasets_hibridos",
|
| 170 |
+
f"dataset_DPO_{base}.jsonl")
|
| 171 |
+
|
| 172 |
+
codebook = carregar_codebook(args.codebook)
|
| 173 |
+
if not codebook:
|
| 174 |
+
print("❌ Codebook vazio ou não encontrado!")
|
| 175 |
+
sys.exit(1)
|
| 176 |
+
|
| 177 |
+
print(f"📖 Codebook: {len(codebook)} tokens DNA carregados")
|
| 178 |
+
gerar_pares_dpo(args.input, args.output, codebook,
|
| 179 |
+
max_pares=args.max_pares, taxa_dna=args.taxa_dna,
|
| 180 |
+
min_dna_tokens=args.min_dna)
|
1_extracao_local/tradutor_batch_argos.py
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
CROM-IA V4.2 — Tradutor Batch EN→PT com Argos Translate
|
| 4 |
+
========================================================
|
| 5 |
+
Traduz datasets do inglês para português offline.
|
| 6 |
+
Features:
|
| 7 |
+
- Checkpoint a cada 500 frases (resume se interromper)
|
| 8 |
+
- Progress bar simples
|
| 9 |
+
- Formata em ChatML
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import json
|
| 13 |
+
import os
|
| 14 |
+
import sys
|
| 15 |
+
import time
|
| 16 |
+
|
| 17 |
+
# ======= SEGURANÇA SRE (FAIL FAST) =======
|
| 18 |
+
# Foi detectado que rodar a tradução local trava a máquina via CPU lockup.
|
| 19 |
+
# O ArgosTranslate carrega um modelo OpenNMT pesado. Deve ser rodado NO COLAB (A100).
|
| 20 |
+
if not os.path.exists('/content'):
|
| 21 |
+
print("\n" + "="*60)
|
| 22 |
+
print("🚨 ALERTA SRE: RISCO DE TRAVAMENTO LOCAL 🚨")
|
| 23 |
+
print("="*60)
|
| 24 |
+
print("A tradução iterativa de 10.000 amostras através de modelos OpenNMT irá sufocar")
|
| 25 |
+
print("a CPU desta máquina e causar um lockup do SO (RAM/Swap leak).")
|
| 26 |
+
print("\n✅ AÇÃO CORRETIVA: Este script deve ser acoplado no Jupyter Notebook do Colab")
|
| 27 |
+
print("e executado na Nuvem junto às rotinas de preparação do Treinamento.")
|
| 28 |
+
print("="*60 + "\n")
|
| 29 |
+
sys.exit(1)
|
| 30 |
+
# ==========================================
|
| 31 |
+
|
| 32 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 33 |
+
OUTPUT_DIR = os.path.join(SCRIPT_DIR, "datasets_hibridos")
|
| 34 |
+
CHECKPOINT_INTERVAL = 500
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def instalar_modelo_argos():
|
| 38 |
+
"""Instala o modelo en→pt do Argos Translate."""
|
| 39 |
+
try:
|
| 40 |
+
import argostranslate.package
|
| 41 |
+
import argostranslate.translate
|
| 42 |
+
except ImportError:
|
| 43 |
+
print("❌ argostranslate não instalado!")
|
| 44 |
+
print(" pip install argostranslate")
|
| 45 |
+
sys.exit(1)
|
| 46 |
+
|
| 47 |
+
# Verificar se já tem o modelo en→pt
|
| 48 |
+
installed = argostranslate.translate.get_installed_languages()
|
| 49 |
+
lang_codes = [l.code for l in installed]
|
| 50 |
+
|
| 51 |
+
if 'en' in lang_codes and 'pt' in lang_codes:
|
| 52 |
+
print("✅ Modelo en→pt já instalado")
|
| 53 |
+
return
|
| 54 |
+
|
| 55 |
+
print("📥 Baixando modelo en→pt do Argos (~50MB)...")
|
| 56 |
+
argostranslate.package.update_package_index()
|
| 57 |
+
available = argostranslate.package.get_available_packages()
|
| 58 |
+
pkg = next((p for p in available if p.from_code == 'en' and p.to_code == 'pt'), None)
|
| 59 |
+
if pkg:
|
| 60 |
+
pkg.install()
|
| 61 |
+
print("✅ Modelo instalado!")
|
| 62 |
+
else:
|
| 63 |
+
print("❌ Modelo en→pt não encontrado no Argos")
|
| 64 |
+
sys.exit(1)
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def traduzir_texto(texto, tradutor):
|
| 68 |
+
"""Traduz um texto curto de EN para PT."""
|
| 69 |
+
if not texto or not isinstance(texto, str):
|
| 70 |
+
return texto
|
| 71 |
+
|
| 72 |
+
# Argos funciona melhor com textos curtos
|
| 73 |
+
# Dividir em parágrafos para manter qualidade
|
| 74 |
+
paragrafos = texto.split('\n')
|
| 75 |
+
traduzidos = []
|
| 76 |
+
|
| 77 |
+
for paragrafo in paragrafos:
|
| 78 |
+
paragrafo = paragrafo.strip()
|
| 79 |
+
if not paragrafo:
|
| 80 |
+
traduzidos.append('')
|
| 81 |
+
continue
|
| 82 |
+
|
| 83 |
+
# Se parece código, não traduzir
|
| 84 |
+
if any(kw in paragrafo for kw in ['def ', 'class ', 'import ', 'return ',
|
| 85 |
+
'if __name__', '```', ' ', '{', '}']):
|
| 86 |
+
traduzidos.append(paragrafo)
|
| 87 |
+
continue
|
| 88 |
+
|
| 89 |
+
try:
|
| 90 |
+
trad = tradutor.translate(paragrafo)
|
| 91 |
+
traduzidos.append(trad)
|
| 92 |
+
except Exception:
|
| 93 |
+
traduzidos.append(paragrafo) # Fallback: manter original
|
| 94 |
+
|
| 95 |
+
return '\n'.join(traduzidos)
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def formatar_chatml(instruction, output):
|
| 99 |
+
"""Formata em ChatML."""
|
| 100 |
+
system_msg = "Você é CROM-IA, um assistente inteligente brasileiro."
|
| 101 |
+
texto = (
|
| 102 |
+
f"<|im_start|>system\n{system_msg}<|im_end|>\n"
|
| 103 |
+
f"<|im_start|>user\n{instruction}<|im_end|>\n"
|
| 104 |
+
f"<|im_start|>assistant\n{output}<|im_end|>"
|
| 105 |
+
)
|
| 106 |
+
return {"text": texto}
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def progress_bar(current, total, prefix='', length=40):
|
| 110 |
+
"""Progress bar simples no terminal."""
|
| 111 |
+
percent = current / max(total, 1) * 100
|
| 112 |
+
filled = int(length * current / max(total, 1))
|
| 113 |
+
bar = '█' * filled + '░' * (length - filled)
|
| 114 |
+
sys.stdout.write(f'\r {prefix} |{bar}| {current}/{total} ({percent:.1f}%)')
|
| 115 |
+
sys.stdout.flush()
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def traduzir_dataset(path_input, path_output=None, max_amostras=10000):
|
| 119 |
+
"""Traduz dataset EN→PT com checkpoint e resumo."""
|
| 120 |
+
import argostranslate.translate
|
| 121 |
+
|
| 122 |
+
if not path_output:
|
| 123 |
+
base = os.path.splitext(os.path.basename(path_input))[0]
|
| 124 |
+
path_output = os.path.join(OUTPUT_DIR, f"{base}_ptbr.jsonl")
|
| 125 |
+
|
| 126 |
+
checkpoint_file = path_output + ".checkpoint"
|
| 127 |
+
|
| 128 |
+
# Obter tradutor
|
| 129 |
+
tradutor = argostranslate.translate.get_translation_from_codes('en', 'pt')
|
| 130 |
+
if not tradutor:
|
| 131 |
+
print("❌ Tradutor en→pt não disponível")
|
| 132 |
+
sys.exit(1)
|
| 133 |
+
|
| 134 |
+
# Verificar checkpoint
|
| 135 |
+
start_line = 0
|
| 136 |
+
if os.path.exists(checkpoint_file):
|
| 137 |
+
with open(checkpoint_file, 'r') as f:
|
| 138 |
+
start_line = int(f.read().strip())
|
| 139 |
+
print(f"📋 Resumindo do checkpoint: linha {start_line}")
|
| 140 |
+
|
| 141 |
+
# Contar total
|
| 142 |
+
with open(path_input, 'r') as f:
|
| 143 |
+
total_linhas = sum(1 for _ in f)
|
| 144 |
+
total_linhas = min(total_linhas, max_amostras)
|
| 145 |
+
|
| 146 |
+
print(f"\n{'='*60}")
|
| 147 |
+
print(f"🌐 CROM-IA V4.2 — Tradução EN→PT")
|
| 148 |
+
print(f" Input: {os.path.basename(path_input)}")
|
| 149 |
+
print(f" Total: {total_linhas} amostras")
|
| 150 |
+
print(f" Início: linha {start_line}")
|
| 151 |
+
print(f"{'='*60}\n")
|
| 152 |
+
|
| 153 |
+
total_traduzidas = start_line
|
| 154 |
+
mode = 'a' if start_line > 0 else 'w'
|
| 155 |
+
t_start = time.time()
|
| 156 |
+
|
| 157 |
+
with open(path_input, 'r', encoding='utf-8') as fin, \
|
| 158 |
+
open(path_output, mode, encoding='utf-8') as fout:
|
| 159 |
+
|
| 160 |
+
for i, line in enumerate(fin):
|
| 161 |
+
if i < start_line:
|
| 162 |
+
continue
|
| 163 |
+
if total_traduzidas >= max_amostras:
|
| 164 |
+
break
|
| 165 |
+
|
| 166 |
+
try:
|
| 167 |
+
entry = json.loads(line.strip())
|
| 168 |
+
except json.JSONDecodeError:
|
| 169 |
+
continue
|
| 170 |
+
|
| 171 |
+
instruction = entry.get('instruction', entry.get('input', ''))
|
| 172 |
+
output = entry.get('output', entry.get('response', ''))
|
| 173 |
+
|
| 174 |
+
if not instruction or not output:
|
| 175 |
+
continue
|
| 176 |
+
|
| 177 |
+
# Traduzir
|
| 178 |
+
instruction_pt = traduzir_texto(instruction, tradutor)
|
| 179 |
+
output_pt = traduzir_texto(output, tradutor)
|
| 180 |
+
|
| 181 |
+
# Formatar e salvar
|
| 182 |
+
formatted = formatar_chatml(instruction_pt, output_pt)
|
| 183 |
+
fout.write(json.dumps(formatted, ensure_ascii=False) + '\n')
|
| 184 |
+
|
| 185 |
+
total_traduzidas += 1
|
| 186 |
+
progress_bar(total_traduzidas, total_linhas, 'Traduzindo')
|
| 187 |
+
|
| 188 |
+
# Checkpoint
|
| 189 |
+
if total_traduzidas % CHECKPOINT_INTERVAL == 0:
|
| 190 |
+
with open(checkpoint_file, 'w') as cf:
|
| 191 |
+
cf.write(str(total_traduzidas))
|
| 192 |
+
fout.flush()
|
| 193 |
+
|
| 194 |
+
elapsed = time.time() - t_start
|
| 195 |
+
rate = (total_traduzidas - start_line) / max(elapsed, 1)
|
| 196 |
+
|
| 197 |
+
print(f"\n\n✅ Tradução concluída!")
|
| 198 |
+
print(f" Total traduzidas: {total_traduzidas}")
|
| 199 |
+
print(f" Tempo: {elapsed/60:.1f} minutos")
|
| 200 |
+
print(f" Velocidade: {rate:.1f} amostras/segundo")
|
| 201 |
+
print(f" Saída: {path_output}")
|
| 202 |
+
|
| 203 |
+
# Limpar checkpoint
|
| 204 |
+
if os.path.exists(checkpoint_file):
|
| 205 |
+
os.remove(checkpoint_file)
|
| 206 |
+
|
| 207 |
+
return path_output
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def main():
|
| 211 |
+
import argparse
|
| 212 |
+
|
| 213 |
+
parser = argparse.ArgumentParser(description="CROM-IA V4.2 — Tradutor Batch EN→PT")
|
| 214 |
+
parser.add_argument('--input', default=None,
|
| 215 |
+
help='Dataset EN (.jsonl). Default: openhermes_10k_en.jsonl')
|
| 216 |
+
parser.add_argument('--output', default=None, help='Saída PT (.jsonl)')
|
| 217 |
+
parser.add_argument('--max', type=int, default=10000, help='Max amostras (default: 10000)')
|
| 218 |
+
parser.add_argument('--install-only', action='store_true',
|
| 219 |
+
help='Apenas instalar o modelo en→pt')
|
| 220 |
+
|
| 221 |
+
args = parser.parse_args()
|
| 222 |
+
|
| 223 |
+
# Instalar modelo
|
| 224 |
+
instalar_modelo_argos()
|
| 225 |
+
|
| 226 |
+
if args.install_only:
|
| 227 |
+
print("✅ Modelo instalado. Pronto para traduzir.")
|
| 228 |
+
return
|
| 229 |
+
|
| 230 |
+
# Default input
|
| 231 |
+
if not args.input:
|
| 232 |
+
args.input = os.path.join(OUTPUT_DIR, "openhermes_10k_en.jsonl")
|
| 233 |
+
|
| 234 |
+
if not os.path.exists(args.input):
|
| 235 |
+
print(f"❌ Arquivo não encontrado: {args.input}")
|
| 236 |
+
print(f" Execute primeiro: python3 download_datasets_v42.py")
|
| 237 |
+
sys.exit(1)
|
| 238 |
+
|
| 239 |
+
traduzir_dataset(args.input, args.output, args.max)
|
| 240 |
+
|
| 241 |
+
|
| 242 |
+
if __name__ == "__main__":
|
| 243 |
+
main()
|
1_extracao_local/transpilador_v42.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
CROM-IA V4.2 — Transpilador DNA (Taxa 25%, corrigido)
|
| 4 |
+
=====================================================
|
| 5 |
+
Mudança vs V4.1: TAXA_MUTACAO = 0.25 (era 0.75)
|
| 6 |
+
Formato: Chat Template ChatML com system prompt DNA explícito
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import json
|
| 10 |
+
import random
|
| 11 |
+
import re
|
| 12 |
+
import os
|
| 13 |
+
import sys
|
| 14 |
+
|
| 15 |
+
# ══════════════════════════════════════════════════════════════
|
| 16 |
+
# CONFIGURAÇÃO V4.2 — DNA CONSERVADOR
|
| 17 |
+
# ══════════════════════════════════════════════════════════════
|
| 18 |
+
TAXA_MUTACAO = 0.25 # 25% mutante (V4.1 era 75% — causou catastrophic forgetting!)
|
| 19 |
+
|
| 20 |
+
# Codebook DNA padrão (será carregado externamente em produção)
|
| 21 |
+
CODEBOOK_PADRAO = {
|
| 22 |
+
# Python
|
| 23 |
+
"import": "@@IMP", "def": "@@DEF", "return": "@@RET",
|
| 24 |
+
"print": "@@PRT", "class": "@@CLS", "self": "@@SLF",
|
| 25 |
+
"function": "@@FNC", "variable": "@@VAR", "string": "@@STR",
|
| 26 |
+
"list": "@@LST", "dict": "@@DCT", "tuple": "@@TPL",
|
| 27 |
+
"for": "@@FOR", "while": "@@WHL", "if": "@@IFF",
|
| 28 |
+
"else": "@@ELS", "elif": "@@ELF", "try": "@@TRY",
|
| 29 |
+
"except": "@@EXC", "finally": "@@FNL", "with": "@@WTH",
|
| 30 |
+
"lambda": "@@LMB", "yield": "@@YLD", "async": "@@ASY",
|
| 31 |
+
"await": "@@AWT", "True": "@@TRU", "False": "@@FAL",
|
| 32 |
+
"None": "@@NON", "and": "@@AND", "or": "@@ORR",
|
| 33 |
+
# Medicina
|
| 34 |
+
"paciente": "@@PAC", "diagnóstico": "@@DGN", "tratamento": "@@TRT",
|
| 35 |
+
"sintoma": "@@SNT", "doença": "@@DOE", "medicamento": "@@MED",
|
| 36 |
+
"exame": "@@EXM", "cirurgia": "@@CIR", "hospital": "@@HSP",
|
| 37 |
+
"médico": "@@MDC", "enfermeiro": "@@ENF", "receita": "@@RCT",
|
| 38 |
+
"febre": "@@FBR", "dor": "@@DOR", "sangue": "@@SNG",
|
| 39 |
+
"coração": "@@CRC", "pulmão": "@@PLM", "fígado": "@@FGD",
|
| 40 |
+
"rim": "@@RIM", "cérebro": "@@CRB", "osso": "@@OSS",
|
| 41 |
+
# Geral PT-BR
|
| 42 |
+
"porque": "@@PQE", "quando": "@@QND", "como": "@@CMO",
|
| 43 |
+
"onde": "@@OND", "sempre": "@@SMP", "também": "@@TBM",
|
| 44 |
+
"muito": "@@MTO", "pouco": "@@PCO", "grande": "@@GRD",
|
| 45 |
+
"pequeno": "@@PQN", "exemplo": "@@EXP", "resultado": "@@RES",
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def carregar_codebook(path_codebook):
|
| 50 |
+
"""Carrega codebook DNA de arquivo JSON externo."""
|
| 51 |
+
if path_codebook and os.path.exists(path_codebook):
|
| 52 |
+
with open(path_codebook, "r") as f:
|
| 53 |
+
data = json.load(f)
|
| 54 |
+
if "codebook" in data and isinstance(data["codebook"], dict):
|
| 55 |
+
return data["codebook"]
|
| 56 |
+
return data
|
| 57 |
+
return CODEBOOK_PADRAO
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def aplicar_mutacao_dna(texto, codebook):
|
| 61 |
+
"""Substitui palavras-chave por tokens DNA comprimidos."""
|
| 62 |
+
resultado = texto
|
| 63 |
+
for palavra, token_dna in codebook.items():
|
| 64 |
+
pattern = re.compile(re.escape(palavra), re.IGNORECASE)
|
| 65 |
+
resultado = pattern.sub(token_dna, resultado)
|
| 66 |
+
return resultado
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def formatar_chat_template(instruction, output, usar_dna=False, codebook=None):
|
| 70 |
+
"""V4.2: ChatML com system prompt DNA. DNA a 25% (conservador)."""
|
| 71 |
+
if usar_dna and codebook:
|
| 72 |
+
output_final = aplicar_mutacao_dna(output, codebook)
|
| 73 |
+
system_msg = "Você é CROM-IA. Use tokens @@DNA quando apropriado para comprimir respostas."
|
| 74 |
+
else:
|
| 75 |
+
output_final = output
|
| 76 |
+
system_msg = "Você é CROM-IA, um assistente inteligente brasileiro."
|
| 77 |
+
|
| 78 |
+
texto_completo = (
|
| 79 |
+
f"<|im_start|>system\n{system_msg}<|im_end|>\n"
|
| 80 |
+
f"<|im_start|>user\n{instruction}<|im_end|>\n"
|
| 81 |
+
f"<|im_start|>assistant\n{output_final}<|im_end|>"
|
| 82 |
+
)
|
| 83 |
+
|
| 84 |
+
return {"text": texto_completo}
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def transpilar_dataset_v42(path_dataset_original, path_saida, codebook, taxa_mutacao=0.25):
|
| 88 |
+
"""Transpilação V4.2: Taxa 25% (conservadora), Chat Template."""
|
| 89 |
+
total = 0
|
| 90 |
+
mutados = 0
|
| 91 |
+
|
| 92 |
+
with open(path_dataset_original, "r") as fin, open(path_saida, "w") as fout:
|
| 93 |
+
for line in fin:
|
| 94 |
+
try:
|
| 95 |
+
entry = json.loads(line.strip())
|
| 96 |
+
except json.JSONDecodeError:
|
| 97 |
+
continue
|
| 98 |
+
|
| 99 |
+
# Detectar formato (ChatML ou instrução/output)
|
| 100 |
+
if "text" in entry and "<|im_start|>" in entry.get("text", ""):
|
| 101 |
+
# Já é ChatML — extrair instruction e output
|
| 102 |
+
text = entry["text"]
|
| 103 |
+
user_match = re.search(r'<\|im_start\|>user\n(.*?)<\|im_end\|>', text, re.DOTALL)
|
| 104 |
+
asst_match = re.search(r'<\|im_start\|>assistant\n(.*?)<\|im_end\|>', text, re.DOTALL)
|
| 105 |
+
instruction = user_match.group(1) if user_match else ""
|
| 106 |
+
output = asst_match.group(1) if asst_match else ""
|
| 107 |
+
else:
|
| 108 |
+
instruction = entry.get("instruction", entry.get("input", ""))
|
| 109 |
+
output = entry.get("output", entry.get("response", entry.get("text", "")))
|
| 110 |
+
|
| 111 |
+
if not output:
|
| 112 |
+
continue
|
| 113 |
+
|
| 114 |
+
usar_dna = random.random() < taxa_mutacao
|
| 115 |
+
resultado = formatar_chat_template(instruction, output, usar_dna, codebook)
|
| 116 |
+
|
| 117 |
+
fout.write(json.dumps(resultado, ensure_ascii=False) + "\n")
|
| 118 |
+
total += 1
|
| 119 |
+
if usar_dna:
|
| 120 |
+
mutados += 1
|
| 121 |
+
|
| 122 |
+
taxa_real = (mutados / total * 100) if total > 0 else 0
|
| 123 |
+
print(f"✅ Transpilação V4.2 concluída!")
|
| 124 |
+
print(f" Total: {total} | Mutados: {mutados} ({taxa_real:.1f}%)")
|
| 125 |
+
print(f" Taxa alvo: {taxa_mutacao*100:.0f}% | Taxa real: {taxa_real:.1f}%")
|
| 126 |
+
print(f" Saída: {path_saida}")
|
| 127 |
+
return total, mutados
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
if __name__ == "__main__":
|
| 131 |
+
if len(sys.argv) < 3:
|
| 132 |
+
print("CROM-IA V4.2 — Transpilador DNA (25% conservador)")
|
| 133 |
+
print(f"Uso: python3 {sys.argv[0]} <dataset.jsonl> <saida.jsonl> [codebook.json] [taxa_mutacao]")
|
| 134 |
+
print(f"Exemplo: python3 {sys.argv[0]} python_15k.jsonl python_DNA25.jsonl codebook.json 0.25")
|
| 135 |
+
sys.exit(1)
|
| 136 |
+
|
| 137 |
+
path_in = sys.argv[1]
|
| 138 |
+
path_out = sys.argv[2]
|
| 139 |
+
path_cb = sys.argv[3] if len(sys.argv) > 3 else None
|
| 140 |
+
taxa = float(sys.argv[4]) if len(sys.argv) > 4 else TAXA_MUTACAO
|
| 141 |
+
|
| 142 |
+
codebook = carregar_codebook(path_cb)
|
| 143 |
+
transpilar_dataset_v42(path_in, path_out, codebook, taxa)
|
2_treinamento_nuvem/01_CROM_V42_TRAINING_FASE1.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
CROM-IA V4.2 — FASE 1: SFT Base Conversacional (SEM DNA)
|
| 4 |
+
==========================================================
|
| 5 |
+
COLE ESTE CÓDIGO NO GOOGLE COLAB (A100/T4)
|
| 6 |
+
|
| 7 |
+
O modelo aprende a CONVERSAR BEM em PT-BR primeiro.
|
| 8 |
+
Sem DNA, sem tokens @@. Apenas fluência e inteligência.
|
| 9 |
+
|
| 10 |
+
Dataset: Canarim 30K + OpenHermes 10K traduzido = ~40K
|
| 11 |
+
Parâmetros: rank 16, 800 steps, lr 1e-5, cosine scheduler
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
# ══════════════════════════════════════════════════════════════
|
| 15 |
+
# CÉLULA 1 — INSTALAÇÃO (rodar primeiro, esperar terminar)
|
| 16 |
+
# ══════════════════════════════════════════════════════════════
|
| 17 |
+
CELULA_1_INSTALACAO = """
|
| 18 |
+
!pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
|
| 19 |
+
!pip install trl>=0.7.0
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
# ══════════════════════════════════════════════════════════════
|
| 23 |
+
# CÉLULA 2 — TREINO FASE 1 (copiar e colar no Colab)
|
| 24 |
+
# ══════════════════════════════════════════════════════════════
|
| 25 |
+
CELULA_2_TREINO = """
|
| 26 |
+
import os, gc, torch
|
| 27 |
+
from unsloth import FastLanguageModel, is_bfloat16_supported
|
| 28 |
+
from trl import SFTTrainer
|
| 29 |
+
from transformers import TrainingArguments
|
| 30 |
+
from datasets import load_dataset
|
| 31 |
+
|
| 32 |
+
# ════════════════════════════════════════════════
|
| 33 |
+
# CONFIGURAÇÃO V4.2 — FASE 1 (SEM DNA)
|
| 34 |
+
# ════════════════════════════════════════════════
|
| 35 |
+
max_seq_length = 2048
|
| 36 |
+
qwen_base = "unsloth/Qwen3-0.6B-unsloth-bnb-4bit"
|
| 37 |
+
|
| 38 |
+
print("=" * 60)
|
| 39 |
+
print("🧠 CROM-IA V4.2 — FASE 1: Base Conversacional (SEM DNA)")
|
| 40 |
+
print(" Modelo: Qwen3-0.6B")
|
| 41 |
+
print(" Rank: 16 | Steps: 800 | LR: 1e-5")
|
| 42 |
+
print(" DNA: 0% (o modelo aprende a FALAR primeiro)")
|
| 43 |
+
print("=" * 60)
|
| 44 |
+
|
| 45 |
+
# ── Montar Drive ──────────────────────────────────────────
|
| 46 |
+
from google.colab import drive
|
| 47 |
+
drive.mount('/content/drive')
|
| 48 |
+
os.makedirs('/content/drive/MyDrive/CROM-V4.2/adapters', exist_ok=True)
|
| 49 |
+
os.makedirs('/content/drive/MyDrive/CROM-V4.2/gguf_merged', exist_ok=True)
|
| 50 |
+
|
| 51 |
+
# ── Carregar modelo base ──────────────────────────────────
|
| 52 |
+
print("\\n📦 Carregando Qwen3-0.6B...")
|
| 53 |
+
model, tokenizer = FastLanguageModel.from_pretrained(
|
| 54 |
+
model_name=qwen_base,
|
| 55 |
+
max_seq_length=max_seq_length,
|
| 56 |
+
dtype=None,
|
| 57 |
+
load_in_4bit=True,
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
# ── LoRA conservador (rank 16, SÓ attention) ─────────────
|
| 61 |
+
model = FastLanguageModel.get_peft_model(
|
| 62 |
+
model,
|
| 63 |
+
r=16, # Era 64 na V4.1 (causou forgetting!)
|
| 64 |
+
lora_alpha=32, # 2x rank
|
| 65 |
+
lora_dropout=0,
|
| 66 |
+
bias="none",
|
| 67 |
+
target_modules=[ # SÓ ATTENTION — sem MLP!
|
| 68 |
+
"q_proj", "k_proj", "v_proj", "o_proj"
|
| 69 |
+
],
|
| 70 |
+
use_gradient_checkpointing="unsloth",
|
| 71 |
+
random_state=3407,
|
| 72 |
+
)
|
| 73 |
+
|
| 74 |
+
# ── Carregar dataset ──────────────────────────────────────
|
| 75 |
+
# Upload dos arquivos para /content/ antes de rodar:
|
| 76 |
+
# - Base_PTBR.jsonl (nossa fusão local de 40k)
|
| 77 |
+
|
| 78 |
+
datasets_fase1 = []
|
| 79 |
+
for arq in ["Base_PTBR.jsonl"]:
|
| 80 |
+
if os.path.exists(arq):
|
| 81 |
+
datasets_fase1.append(arq)
|
| 82 |
+
print(f" ✅ {arq}")
|
| 83 |
+
else:
|
| 84 |
+
print(f" ⚠️ {arq} não encontrado")
|
| 85 |
+
|
| 86 |
+
if not datasets_fase1:
|
| 87 |
+
raise FileNotFoundError("Nenhum dataset encontrado! Faça upload primeiro.")
|
| 88 |
+
|
| 89 |
+
dataset = load_dataset("json", data_files=datasets_fase1, split="train")
|
| 90 |
+
print(f"\\n📊 Dataset Fase 1: {len(dataset)} amostras")
|
| 91 |
+
|
| 92 |
+
# ── Formatting ────────────────────────────────────────────
|
| 93 |
+
def formatting_func(example):
|
| 94 |
+
output = example["text"]
|
| 95 |
+
if isinstance(output, list):
|
| 96 |
+
return [str(x) for x in output]
|
| 97 |
+
return [str(output)]
|
| 98 |
+
|
| 99 |
+
# ── Treinar ───────────────────────────────────────────────
|
| 100 |
+
trainer = SFTTrainer(
|
| 101 |
+
model=model,
|
| 102 |
+
tokenizer=tokenizer,
|
| 103 |
+
train_dataset=dataset,
|
| 104 |
+
formatting_func=formatting_func,
|
| 105 |
+
max_seq_length=max_seq_length,
|
| 106 |
+
dataset_num_proc=2,
|
| 107 |
+
args=TrainingArguments(
|
| 108 |
+
per_device_train_batch_size=8, # Era 16 (mais conservador)
|
| 109 |
+
gradient_accumulation_steps=4,
|
| 110 |
+
warmup_ratio=0.05, # 5% warmup
|
| 111 |
+
max_steps=800, # Era 2000 (causou overfitting!)
|
| 112 |
+
learning_rate=1e-5, # Era 2e-5 (mais suave)
|
| 113 |
+
lr_scheduler_type="cosine", # Convergência melhor
|
| 114 |
+
optim="adamw_8bit",
|
| 115 |
+
fp16=not is_bfloat16_supported(),
|
| 116 |
+
bf16=is_bfloat16_supported(),
|
| 117 |
+
output_dir="./outputs_Base_PTBR",
|
| 118 |
+
logging_steps=25,
|
| 119 |
+
save_steps=200,
|
| 120 |
+
),
|
| 121 |
+
)
|
| 122 |
+
|
| 123 |
+
print("\\n🚀 Iniciando treino Fase 1...")
|
| 124 |
+
trainer.train()
|
| 125 |
+
print("✅ Treino Fase 1 concluído!")
|
| 126 |
+
|
| 127 |
+
# ── Salvar adaptador LoRA ─────────────────────────────────
|
| 128 |
+
adapter_dir = "/content/drive/MyDrive/CROM-V4.2/adapters/Base_PTBR"
|
| 129 |
+
os.makedirs(adapter_dir, exist_ok=True)
|
| 130 |
+
model.save_pretrained(adapter_dir)
|
| 131 |
+
tokenizer.save_pretrained(adapter_dir)
|
| 132 |
+
print(f"✅ LoRA Base_PTBR salvo em: {adapter_dir}")
|
| 133 |
+
|
| 134 |
+
# ── Salvar GGUF fundido (para testes standalone) ─────────
|
| 135 |
+
gguf_dir = "/content/drive/MyDrive/CROM-V4.2/gguf_merged/Base_PTBR"
|
| 136 |
+
os.makedirs(gguf_dir, exist_ok=True)
|
| 137 |
+
model.save_pretrained_gguf(gguf_dir, tokenizer, quantization_method="q4_k_m")
|
| 138 |
+
print(f"✅ GGUF Base_PTBR salvo em: {gguf_dir}")
|
| 139 |
+
|
| 140 |
+
# ── Salvar modelo BASE puro (sem LoRA) para stacking ─────
|
| 141 |
+
print("\\n📦 Salvando modelo BASE puro...")
|
| 142 |
+
del model; del trainer; gc.collect(); torch.cuda.empty_cache()
|
| 143 |
+
base_model, base_tok = FastLanguageModel.from_pretrained(
|
| 144 |
+
model_name=qwen_base, max_seq_length=max_seq_length,
|
| 145 |
+
dtype=None, load_in_4bit=True,
|
| 146 |
+
)
|
| 147 |
+
base_dir = "/content/drive/MyDrive/CROM-V4.2/base_model"
|
| 148 |
+
os.makedirs(base_dir, exist_ok=True)
|
| 149 |
+
base_model.save_pretrained_gguf(base_dir, base_tok, quantization_method="q4_k_m")
|
| 150 |
+
del base_model; del base_tok; gc.collect(); torch.cuda.empty_cache()
|
| 151 |
+
print("✅ Modelo base GGUF salvo!")
|
| 152 |
+
|
| 153 |
+
print("\\n" + "=" * 60)
|
| 154 |
+
print("🎉 FASE 1 CONCLUÍDA!")
|
| 155 |
+
print(" → Adapters: CROM-V4.2/adapters/Base_PTBR/")
|
| 156 |
+
print(" → GGUF: CROM-V4.2/gguf_merged/Base_PTBR/")
|
| 157 |
+
print(" → Base: CROM-V4.2/base_model/")
|
| 158 |
+
print("\\n PRÓXIMO: Execute 02_CROM_V42_TRAINING_FASE2.py")
|
| 159 |
+
print("=" * 60)
|
| 160 |
+
"""
|
| 161 |
+
|
| 162 |
+
if __name__ == "__main__":
|
| 163 |
+
print("=" * 60)
|
| 164 |
+
print("📋 CROM-IA V4.2 — Fase 1: SFT Base")
|
| 165 |
+
print("=" * 60)
|
| 166 |
+
print("\n🔧 CÉLULA 1 (Instalação):")
|
| 167 |
+
print(CELULA_1_INSTALACAO)
|
| 168 |
+
print("\n🏋️ CÉLULA 2 (Treinamento):")
|
| 169 |
+
print(CELULA_2_TREINO)
|
2_treinamento_nuvem/02_CROM_V42_TRAINING_FASE2.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
CROM-IA V4.2 — FASE 2: SFT Especialização com DNA 25%
|
| 4 |
+
=======================================================
|
| 5 |
+
COLE ESTE CÓDIGO NO GOOGLE COLAB (A100/T4)
|
| 6 |
+
PRÉ-REQUISITO: Fase 1 já rodou (Base_PTBR treinado)
|
| 7 |
+
|
| 8 |
+
O modelo já sabe conversar (Fase 1).
|
| 9 |
+
Agora aprende DNA sutil (25%) por domínio.
|
| 10 |
+
|
| 11 |
+
LoRAs: Python_DNA (15K, 500 steps) + Medicina_DNA (8K, 500 steps)
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
# ══════════════════════════════════════════════════════════════
|
| 15 |
+
# CÉLULA 1 — TREINO FASE 2 (copiar e colar no Colab)
|
| 16 |
+
# ══════════════════════════════════════════════════════════════
|
| 17 |
+
CELULA_TREINO = """
|
| 18 |
+
import os, gc, torch
|
| 19 |
+
from unsloth import FastLanguageModel, is_bfloat16_supported
|
| 20 |
+
from trl import SFTTrainer
|
| 21 |
+
from transformers import TrainingArguments
|
| 22 |
+
from datasets import load_dataset
|
| 23 |
+
|
| 24 |
+
# ════════════════════════════════════════════════
|
| 25 |
+
# CONFIGURAÇÃO V4.2 — FASE 2 (DNA 25%)
|
| 26 |
+
# ════════════════════════════════════════════════
|
| 27 |
+
max_seq_length = 2048
|
| 28 |
+
qwen_base = "unsloth/Qwen3-0.6B-unsloth-bnb-4bit"
|
| 29 |
+
|
| 30 |
+
def formatting_func(example):
|
| 31 |
+
output = example["text"]
|
| 32 |
+
if isinstance(output, list):
|
| 33 |
+
return [str(x) for x in output]
|
| 34 |
+
return [str(output)]
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def treinar_cerebro_dna(nome_cerebro, path_dataset, max_steps=500):
|
| 38 |
+
|
| 39 |
+
if not os.path.exists(path_dataset):
|
| 40 |
+
print(f"⚠️ {path_dataset} não encontrado! Pulando...")
|
| 41 |
+
return
|
| 42 |
+
|
| 43 |
+
print(f"\\n{'='*60}")
|
| 44 |
+
print(f"🧬 FASE 2: Treinando {nome_cerebro} (DNA 25%)")
|
| 45 |
+
print(f" Dataset: {path_dataset}")
|
| 46 |
+
print(f" Steps: {max_steps} | Rank: 16 | LR: 1e-5")
|
| 47 |
+
print(f"{'='*60}")
|
| 48 |
+
|
| 49 |
+
model, tokenizer = FastLanguageModel.from_pretrained(
|
| 50 |
+
model_name=qwen_base,
|
| 51 |
+
max_seq_length=max_seq_length,
|
| 52 |
+
dtype=None,
|
| 53 |
+
load_in_4bit=True,
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
# NOTA SRE: Fundir LoRAs em 4-bit no Unsloth via merge_and_unload causa 'BFloat16 != float' (Crash de Type).
|
| 57 |
+
# O CROM-IA usará Stacking (Empilhamento Local) depois. O Cérebro de Python
|
| 58 |
+
# DEVE ser treinado sob a camada limpa do Qwen, e o orquestrador Shell somará os 2 LoRAs!
|
| 59 |
+
|
| 60 |
+
# Novo LoRA para especialização DNA
|
| 61 |
+
model = FastLanguageModel.get_peft_model(
|
| 62 |
+
model,
|
| 63 |
+
r=16,
|
| 64 |
+
lora_alpha=32,
|
| 65 |
+
lora_dropout=0,
|
| 66 |
+
bias="none",
|
| 67 |
+
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
|
| 68 |
+
use_gradient_checkpointing="unsloth",
|
| 69 |
+
random_state=3407,
|
| 70 |
+
)
|
| 71 |
+
|
| 72 |
+
dataset = load_dataset("json", data_files=path_dataset, split="train")
|
| 73 |
+
print(f" 📊 Amostras: {len(dataset)}")
|
| 74 |
+
|
| 75 |
+
trainer = SFTTrainer(
|
| 76 |
+
model=model,
|
| 77 |
+
tokenizer=tokenizer,
|
| 78 |
+
train_dataset=dataset,
|
| 79 |
+
formatting_func=formatting_func,
|
| 80 |
+
max_seq_length=max_seq_length,
|
| 81 |
+
dataset_num_proc=2,
|
| 82 |
+
args=TrainingArguments(
|
| 83 |
+
per_device_train_batch_size=8,
|
| 84 |
+
gradient_accumulation_steps=4,
|
| 85 |
+
warmup_ratio=0.05,
|
| 86 |
+
max_steps=max_steps,
|
| 87 |
+
learning_rate=1e-5,
|
| 88 |
+
lr_scheduler_type="cosine",
|
| 89 |
+
optim="adamw_8bit",
|
| 90 |
+
fp16=not is_bfloat16_supported(),
|
| 91 |
+
bf16=is_bfloat16_supported(),
|
| 92 |
+
output_dir=f"./outputs_{nome_cerebro}",
|
| 93 |
+
logging_steps=25,
|
| 94 |
+
),
|
| 95 |
+
)
|
| 96 |
+
|
| 97 |
+
trainer.train()
|
| 98 |
+
|
| 99 |
+
# Salvar LoRA SEPARADO (para empilhar depois)
|
| 100 |
+
adapter_dir = f"/content/drive/MyDrive/CROM-V4.2/adapters/{nome_cerebro}"
|
| 101 |
+
os.makedirs(adapter_dir, exist_ok=True)
|
| 102 |
+
model.save_pretrained(adapter_dir)
|
| 103 |
+
tokenizer.save_pretrained(adapter_dir)
|
| 104 |
+
print(f" ✅ LoRA salvo: {adapter_dir}")
|
| 105 |
+
|
| 106 |
+
# GGUF fundido (standalone)
|
| 107 |
+
gguf_dir = f"/content/drive/MyDrive/CROM-V4.2/gguf_merged/{nome_cerebro}"
|
| 108 |
+
os.makedirs(gguf_dir, exist_ok=True)
|
| 109 |
+
model.save_pretrained_gguf(gguf_dir, tokenizer, quantization_method="q4_k_m")
|
| 110 |
+
print(f" ✅ GGUF salvo: {gguf_dir}")
|
| 111 |
+
|
| 112 |
+
del model; del trainer; gc.collect(); torch.cuda.empty_cache()
|
| 113 |
+
print(f" 🎉 {nome_cerebro} CONCLUÍDO!")
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
# ── Montar Drive ──────────────────────────────────────────
|
| 117 |
+
from google.colab import drive
|
| 118 |
+
drive.mount('/content/drive')
|
| 119 |
+
|
| 120 |
+
print("\\n" + "=" * 60)
|
| 121 |
+
print("🧬 CROM-IA V4.2 — FASE 2: Especialização DNA (25%)")
|
| 122 |
+
print("=" * 60)
|
| 123 |
+
|
| 124 |
+
# Upload dos datasets transpilados para /content/:
|
| 125 |
+
# - python_DNA25.jsonl
|
| 126 |
+
# - medicina_DNA25.jsonl
|
| 127 |
+
|
| 128 |
+
# ── Fábrica de Cérebros DNA ───────────────────────────────
|
| 129 |
+
cerebros = [
|
| 130 |
+
("Python_DNA", "Python_DNA25.jsonl", 500),
|
| 131 |
+
# ("Medicina_DNA", "medicina_DNA25.jsonl", 500),
|
| 132 |
+
]
|
| 133 |
+
|
| 134 |
+
for nome, arq, steps in cerebros:
|
| 135 |
+
treinar_cerebro_dna(nome, arq, max_steps=steps)
|
| 136 |
+
|
| 137 |
+
print("\\n" + "=" * 60)
|
| 138 |
+
print("🎉 FASE 2 CONCLUÍDA!")
|
| 139 |
+
print(" → Python_DNA e Medicina_DNA treinados com DNA 25%")
|
| 140 |
+
print(" → Adaptadores em: CROM-V4.2/adapters/")
|
| 141 |
+
print("\\n PRÓXIMO: Execute 03_CROM_V42_DPO_TRAINING.py")
|
| 142 |
+
print("=" * 60)
|
| 143 |
+
"""
|
| 144 |
+
|
| 145 |
+
if __name__ == "__main__":
|
| 146 |
+
print("=" * 60)
|
| 147 |
+
print("📋 CROM-IA V4.2 — Fase 2: SFT DNA 25%")
|
| 148 |
+
print("=" * 60)
|
| 149 |
+
print("\n🏋️ CÉLULA (Treinamento):")
|
| 150 |
+
print(CELULA_TREINO)
|
2_treinamento_nuvem/03_CROM_V42_DPO_TRAINING.py
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
CROM-IA V4.2 — FASE 3: DPO (Direct Preference Optimization)
|
| 4 |
+
=============================================================
|
| 5 |
+
COLE ESTE CÓDIGO NO GOOGLE COLAB (A100/T4)
|
| 6 |
+
PRÉ-REQUISITO: Fase 1 e Fase 2 já rodaram
|
| 7 |
+
|
| 8 |
+
O modelo já sabe conversar (Fase 1) e conhece DNA (Fase 2).
|
| 9 |
+
Agora aprende a PREFERIR respostas com DNA sobre sem DNA.
|
| 10 |
+
|
| 11 |
+
Dataset: 5K pares {prompt, chosen(DNA), rejected(sem DNA)}
|
| 12 |
+
Parâmetros: beta=0.1, 300 steps, lr 5e-6 (muito suave)
|
| 13 |
+
"""
|
| 14 |
+
|
| 15 |
+
# ══════════════════════════════════════════════════════════════
|
| 16 |
+
# CÉLULA 1 — INSTALAÇÃO EXTRA (se não fez na Fase 1)
|
| 17 |
+
CELULA_1_DEPS = """
|
| 18 |
+
!pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
|
| 19 |
+
!pip install trl>=0.7.0
|
| 20 |
+
!pip install mergekit
|
| 21 |
+
!pip install llm-blender
|
| 22 |
+
!pip install weave
|
| 23 |
+
"""
|
| 24 |
+
|
| 25 |
+
# ══════════════════════════════════════════════════════════════
|
| 26 |
+
# CÉLULA 2 — TREINO DPO (copiar e colar no Colab)
|
| 27 |
+
# ══════════════════════════════════════════════════════════════
|
| 28 |
+
CELULA_2_DPO = """
|
| 29 |
+
import os, gc, torch
|
| 30 |
+
import transformers
|
| 31 |
+
|
| 32 |
+
# Vacina de SRE para o conflito do TRL c/ Transformers moderno:
|
| 33 |
+
if not hasattr(transformers.utils.hub, 'TRANSFORMERS_CACHE'):
|
| 34 |
+
transformers.utils.hub.TRANSFORMERS_CACHE = os.getenv('HF_HOME', '~/.cache/huggingface/hub')
|
| 35 |
+
|
| 36 |
+
from unsloth import FastLanguageModel, is_bfloat16_supported
|
| 37 |
+
from trl import DPOTrainer, DPOConfig
|
| 38 |
+
from datasets import load_dataset
|
| 39 |
+
|
| 40 |
+
# ════════════════════════════════════════════════
|
| 41 |
+
# CONFIGURAÇÃO V4.2 — FASE 3 (DPO)
|
| 42 |
+
# ════════════════════════════════════════════════
|
| 43 |
+
max_seq_length = 2048
|
| 44 |
+
qwen_base = "unsloth/Qwen3-0.6B-unsloth-bnb-4bit"
|
| 45 |
+
|
| 46 |
+
print("=" * 60)
|
| 47 |
+
print("🎯 CROM-IA V4.2 — FASE 3: DPO (Preferência DNA)")
|
| 48 |
+
print(" O modelo aprende: DNA = resposta PREFERIDA")
|
| 49 |
+
print(" Beta: 0.1 | Steps: 300 | LR: 5e-6")
|
| 50 |
+
print("=" * 60)
|
| 51 |
+
|
| 52 |
+
# ── Montar Drive ──────────────────────────────────────────
|
| 53 |
+
from google.colab import drive
|
| 54 |
+
drive.mount('/content/drive')
|
| 55 |
+
|
| 56 |
+
# ── Carregar modelo com Base da Fase 1 ────────────────────
|
| 57 |
+
print("\\n📦 Carregando Qwen3-0.6B...")
|
| 58 |
+
model, tokenizer = FastLanguageModel.from_pretrained(
|
| 59 |
+
model_name=qwen_base,
|
| 60 |
+
max_seq_length=max_seq_length,
|
| 61 |
+
dtype=None,
|
| 62 |
+
load_in_4bit=True,
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
# NOTA SRE: Fundir LoRA com merge_and_unload causaria BFloat16 vs Float exception.
|
| 66 |
+
# A Fase de DPO (Preferência de DNA) deve ser puramente treinada a partir das
|
| 67 |
+
# fundações matrizes 4-bits do Qwen. Todos os LoRAs serão empilhados juntos localmente.
|
| 68 |
+
|
| 69 |
+
# ── Novo LoRA para DPO ────────────────────────────────────
|
| 70 |
+
model = FastLanguageModel.get_peft_model(
|
| 71 |
+
model,
|
| 72 |
+
r=16,
|
| 73 |
+
lora_alpha=32,
|
| 74 |
+
lora_dropout=0,
|
| 75 |
+
bias="none",
|
| 76 |
+
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
|
| 77 |
+
use_gradient_checkpointing="unsloth",
|
| 78 |
+
random_state=3407,
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
# ── Dataset DPO ───────────────────────────────────────────
|
| 82 |
+
# Upload do dataset DPO para /content/:
|
| 83 |
+
# - dataset_DPO_canarim_30k.jsonl (ou similar)
|
| 84 |
+
# Formato: {"prompt": "...", "chosen": "...(com DNA)...", "rejected": "...(sem DNA)..."}
|
| 85 |
+
|
| 86 |
+
dpo_files = [f for f in os.listdir('.') if f.startswith('dataset_DPO') and f.endswith('.jsonl')]
|
| 87 |
+
if not dpo_files:
|
| 88 |
+
raise FileNotFoundError(
|
| 89 |
+
"Nenhum dataset DPO encontrado!\\n"
|
| 90 |
+
"Faça upload de um arquivo dataset_DPO_*.jsonl\\n"
|
| 91 |
+
"Gere com: python3 gerador_pares_dpo.py --input ... --codebook ..."
|
| 92 |
+
)
|
| 93 |
+
|
| 94 |
+
print(f"\\n📊 Datasets DPO encontrados: {dpo_files}")
|
| 95 |
+
dataset = load_dataset("json", data_files=dpo_files, split="train")
|
| 96 |
+
print(f" Total: {len(dataset)} pares")
|
| 97 |
+
|
| 98 |
+
# ── Tokenizer padding ────────────────────────────────────
|
| 99 |
+
if tokenizer.pad_token is None:
|
| 100 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 101 |
+
model.config.pad_token_id = tokenizer.eos_token_id
|
| 102 |
+
|
| 103 |
+
# Vacina de SRE para o conflito Peft/Unsloth vs DPOTrainer:
|
| 104 |
+
if not hasattr(model, "warnings_issued"):
|
| 105 |
+
model.warnings_issued = {}
|
| 106 |
+
|
| 107 |
+
# ── Treinar com DPO ───────────────────────────────────────
|
| 108 |
+
print("\\n🎯 Iniciando DPO...")
|
| 109 |
+
|
| 110 |
+
training_args = DPOConfig(
|
| 111 |
+
per_device_train_batch_size=4, # Menor — DPO usa 2x memória por amostra
|
| 112 |
+
gradient_accumulation_steps=4,
|
| 113 |
+
max_steps=300, # Pouco — DPO converge rápido
|
| 114 |
+
learning_rate=5e-6, # METADE do SFT (refinamento, não reeducação)
|
| 115 |
+
beta=0.1, # Sutil — não forçar DNA demais
|
| 116 |
+
lr_scheduler_type="cosine",
|
| 117 |
+
warmup_ratio=0.1,
|
| 118 |
+
optim="adamw_8bit",
|
| 119 |
+
fp16=not is_bfloat16_supported(),
|
| 120 |
+
bf16=is_bfloat16_supported(),
|
| 121 |
+
output_dir="./outputs_DPO",
|
| 122 |
+
logging_steps=25,
|
| 123 |
+
max_length=max_seq_length,
|
| 124 |
+
max_prompt_length=512,
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
trainer = DPOTrainer(
|
| 128 |
+
model=model,
|
| 129 |
+
args=training_args,
|
| 130 |
+
train_dataset=dataset,
|
| 131 |
+
processing_class=tokenizer,
|
| 132 |
+
)
|
| 133 |
+
|
| 134 |
+
trainer.train()
|
| 135 |
+
print("✅ DPO concluído!")
|
| 136 |
+
|
| 137 |
+
# ── Salvar adaptador DPO ──────────────────────────────────
|
| 138 |
+
adapter_dir = "/content/drive/MyDrive/CROM-V4.2/adapters/DPO_Preference"
|
| 139 |
+
os.makedirs(adapter_dir, exist_ok=True)
|
| 140 |
+
model.save_pretrained(adapter_dir)
|
| 141 |
+
tokenizer.save_pretrained(adapter_dir)
|
| 142 |
+
print(f"✅ LoRA DPO salvo: {adapter_dir}")
|
| 143 |
+
|
| 144 |
+
# ── GGUF fundido completo (Base + DPO) ───────────────────
|
| 145 |
+
gguf_dir = "/content/drive/MyDrive/CROM-V4.2/gguf_merged/DPO_Preference"
|
| 146 |
+
os.makedirs(gguf_dir, exist_ok=True)
|
| 147 |
+
model.save_pretrained_gguf(gguf_dir, tokenizer, quantization_method="q4_k_m")
|
| 148 |
+
print(f"✅ GGUF DPO salvo: {gguf_dir}")
|
| 149 |
+
|
| 150 |
+
del model; del trainer; gc.collect(); torch.cuda.empty_cache()
|
| 151 |
+
|
| 152 |
+
# ── Relatório Final ───────────────────────────────────────
|
| 153 |
+
print("\\n" + "=" * 60)
|
| 154 |
+
print("🎉🎉🎉 TODAS AS 3 FASES CONCLUÍDAS!")
|
| 155 |
+
print("=" * 60)
|
| 156 |
+
print("\\nArquivos no Google Drive → CROM-V4.2/")
|
| 157 |
+
print("├── base_model/ ← Qwen3-0.6B puro (Q4_K_M)")
|
| 158 |
+
print("├── adapters/")
|
| 159 |
+
print("│ ├── Base_PTBR/ ← Fase 1: Conversação PT-BR")
|
| 160 |
+
print("│ ├── Python_DNA/ ← Fase 2: Python com DNA 25%")
|
| 161 |
+
print("│ ├── Medicina_DNA/ ← Fase 2: Medicina com DNA 25%")
|
| 162 |
+
print("│ └── DPO_Preference/ ← Fase 3: Preferência DNA")
|
| 163 |
+
print("└── gguf_merged/ ← Modelos standalone")
|
| 164 |
+
print("")
|
| 165 |
+
print("📋 PRÓXIMOS PASSOS:")
|
| 166 |
+
print(" 1. Baixar os GGUFs para o i5")
|
| 167 |
+
print(" 2. Converter adaptadores PEFT → GGUF-LoRA:")
|
| 168 |
+
print(" python3 convert_lora_to_gguf.py --base qwen.gguf --adapter adapter/")
|
| 169 |
+
print(" 3. Testar empilhamento:")
|
| 170 |
+
print(" llama-cli -m base.gguf --lora Base.gguf --lora Python.gguf")
|
| 171 |
+
print(" 4. Abrir o Monitor:")
|
| 172 |
+
print(" ./chat_v42_brain.sh")
|
| 173 |
+
print("=" * 60)
|
| 174 |
+
"""
|
| 175 |
+
|
| 176 |
+
if __name__ == "__main__":
|
| 177 |
+
print("=" * 60)
|
| 178 |
+
print("📋 CROM-IA V4.2 — Fase 3: DPO")
|
| 179 |
+
print("=" * 60)
|
| 180 |
+
print("\n🔧 CÉLULA 1 (Instalação):")
|
| 181 |
+
print(CELULA_1_DEPS)
|
| 182 |
+
print("\n🎯 CÉLULA 2 (DPO Training):")
|
| 183 |
+
print(CELULA_2_DPO)
|
2_treinamento_nuvem/colab/00_CROM_V42_TRANSLATOR_COLAB.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Tradutor de Dataset "OpenHermes" Otimizado para GPU (Nvidia A100/A10G)
|
| 2 |
+
|
| 3 |
+
Este script visa resolver a etapa pesada de tradução bloqueada no ambiente local (OOM de CPU). Rodando no Google Colab com pacote _transformers_, a extração de linguagem será exponencialmente mais rápida.
|
| 4 |
+
|
| 5 |
+
## 0. Baixando o Dataset OpenHermes 10K Diretamente da Nuvem
|
| 6 |
+
Como a máquina local teve o download interrompido, baixe em segundos a base bruta (em Inglês) no seu Colab, executando esta célula:
|
| 7 |
+
```python
|
| 8 |
+
import json
|
| 9 |
+
from datasets import load_dataset
|
| 10 |
+
from tqdm import tqdm
|
| 11 |
+
|
| 12 |
+
print("📥 Extraindo OpenHermes (Cloud Speed)...")
|
| 13 |
+
ds = load_dataset('teknium/OpenHermes-2.5', split='train')
|
| 14 |
+
|
| 15 |
+
candidatos = []
|
| 16 |
+
print("🔍 Filtrando as 10.000 melhores conversas ricas (Isso leva uns ~3 minutinhos)...")
|
| 17 |
+
for item in tqdm(ds, desc="Analisando 1 Milhão de Amostras"):
|
| 18 |
+
conversations = item.get('conversations', [])
|
| 19 |
+
if len(conversations) < 2: continue
|
| 20 |
+
|
| 21 |
+
instruction = ""
|
| 22 |
+
output = ""
|
| 23 |
+
for msg in conversations:
|
| 24 |
+
role = msg.get('from', msg.get('role', ''))
|
| 25 |
+
value = msg.get('value', msg.get('content', ''))
|
| 26 |
+
if role in ('human', 'user'): instruction = value
|
| 27 |
+
elif role in ('gpt', 'assistant'): output = value
|
| 28 |
+
|
| 29 |
+
if not instruction or not output: continue
|
| 30 |
+
if len(output) >= 200:
|
| 31 |
+
candidatos.append({'instruction': instruction, 'output': output, 'length': len(output)})
|
| 32 |
+
|
| 33 |
+
candidatos.sort(key=lambda x: x['length'], reverse=True)
|
| 34 |
+
candidatos = candidatos[:10000]
|
| 35 |
+
|
| 36 |
+
with open("openhermes_10k_en.jsonl", 'w', encoding='utf-8') as f:
|
| 37 |
+
for item in candidatos:
|
| 38 |
+
f.write(json.dumps({'instruction': item['instruction'], 'output': item['output']}, ensure_ascii=False) + '\n')
|
| 39 |
+
print("✅ Dataset openhermes_10k_en.jsonl gerado no Colab!")
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
## 1. Instalando Dependências do CROM no Colab
|
| 43 |
+
Rode esta primeira célula no notebook:
|
| 44 |
+
```python
|
| 45 |
+
!pip install -q transformers accelerate datasets tqdm sacremoses
|
| 46 |
+
```
|
| 47 |
+
|
| 48 |
+
## 2. Ingestor e Pipeline Neural de Tradução Seq2Seq
|
| 49 |
+
Faça o upload do seu dataset local (`openhermes_10k_en.jsonl`) nos arquivos do Google Colab. Em seguida, crie uma nova célula com o script:
|
| 50 |
+
|
| 51 |
+
```python
|
| 52 |
+
import json
|
| 53 |
+
import re
|
| 54 |
+
from tqdm import tqdm
|
| 55 |
+
import torch
|
| 56 |
+
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
|
| 57 |
+
|
| 58 |
+
print("🚀 Iniciando Motor de Tradução na Nuvem (GPU-Accellerated)")
|
| 59 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 60 |
+
print("Verificando Hardware: ", "🟢 GPU Ativada" if device == "cuda" else "🔴 CPU (Lento!)")
|
| 61 |
+
|
| 62 |
+
# 1. Carregador Nativo em FP16 (Tensor Cores Acionados p/ Dobro de Velocidade)
|
| 63 |
+
model_name = "Helsinki-NLP/opus-mt-tc-big-en-pt"
|
| 64 |
+
print(f"📥 Baixando modelo {model_name}...")
|
| 65 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 66 |
+
model = AutoModelForSeq2SeqLM.from_pretrained(
|
| 67 |
+
model_name,
|
| 68 |
+
torch_dtype=torch.float16, # Ativa o FP16 Cortando a VRAM pela METADE!
|
| 69 |
+
).to(device)
|
| 70 |
+
|
| 71 |
+
INPUT_FILE = "openhermes_10k_en.jsonl"
|
| 72 |
+
OUTPUT_FILE = "openhermes_10k_ptbr.jsonl"
|
| 73 |
+
|
| 74 |
+
def split_and_protect_code(text):
|
| 75 |
+
""" Protege marcadores markdown inteiros antes de tacar na AI de tradução """
|
| 76 |
+
parts = re.split(r'(```.*?```)', text, flags=re.DOTALL)
|
| 77 |
+
return parts
|
| 78 |
+
|
| 79 |
+
# 2. Carrega Memória e Processamento em Batch Dinâmico (Explosão de GPU)
|
| 80 |
+
dataset = []
|
| 81 |
+
with open(INPUT_FILE, 'r', encoding='utf-8') as f:
|
| 82 |
+
for line in f:
|
| 83 |
+
dataset.append(json.loads(line))
|
| 84 |
+
|
| 85 |
+
print(f"📦 Sucesso: {len(dataset)} sentenças enviadas para memória.")
|
| 86 |
+
|
| 87 |
+
def translate_batch(texts):
|
| 88 |
+
"""Traduz micro-lotes via Tensor Cores (FP16)"""
|
| 89 |
+
if not texts: return []
|
| 90 |
+
res = []
|
| 91 |
+
MINI_BATCH = 64 # Quatro vezes mais matrizes em paralelo!
|
| 92 |
+
|
| 93 |
+
for i in range(0, len(texts), MINI_BATCH):
|
| 94 |
+
chunk = texts[i:i+MINI_BATCH]
|
| 95 |
+
inputs = tokenizer(chunk, return_tensors="pt", padding=True, truncation=True, max_length=512).to(device)
|
| 96 |
+
with torch.no_grad():
|
| 97 |
+
outputs = model.generate(**inputs, max_new_tokens=512)
|
| 98 |
+
res.extend(tokenizer.batch_decode(outputs, skip_special_tokens=True))
|
| 99 |
+
|
| 100 |
+
# O Pytorch gerencia o cache automaticamente sem congelar a GPU
|
| 101 |
+
del inputs, outputs
|
| 102 |
+
|
| 103 |
+
return res
|
| 104 |
+
|
| 105 |
+
BATCH_SIZE = 64 # Engolindo 64 amostras (até centenas de strings) por vez!
|
| 106 |
+
with open(OUTPUT_FILE, 'w', encoding='utf-8') as f_out:
|
| 107 |
+
|
| 108 |
+
for i in tqdm(range(0, len(dataset), BATCH_SIZE), desc="Injerindo Lotes na A100", unit="lote"):
|
| 109 |
+
batch_items = dataset[i:i+BATCH_SIZE]
|
| 110 |
+
|
| 111 |
+
# 1. Enfileirar requisições para a GPU
|
| 112 |
+
queries = []
|
| 113 |
+
strukt = []
|
| 114 |
+
|
| 115 |
+
for item in batch_items:
|
| 116 |
+
inst_parts = split_and_protect_code(item.get('instruction', ''))
|
| 117 |
+
out_parts = split_and_protect_code(item.get('output', ''))
|
| 118 |
+
|
| 119 |
+
struct_item = {'inst': [], 'out': []}
|
| 120 |
+
|
| 121 |
+
# Mapeamento do Instruction
|
| 122 |
+
for p in inst_parts:
|
| 123 |
+
if p.startswith('```') or not p.strip():
|
| 124 |
+
struct_item['inst'].append(p)
|
| 125 |
+
else:
|
| 126 |
+
struct_item['inst'].append(len(queries)) # Guarda o Índice
|
| 127 |
+
queries.append(p)
|
| 128 |
+
|
| 129 |
+
# Mapeamento do Output
|
| 130 |
+
for p in out_parts:
|
| 131 |
+
if p.startswith('```') or not p.strip():
|
| 132 |
+
struct_item['out'].append(p)
|
| 133 |
+
else:
|
| 134 |
+
struct_item['out'].append(len(queries)) # Guarda o Índice
|
| 135 |
+
queries.append(p)
|
| 136 |
+
|
| 137 |
+
strukt.append(struct_item)
|
| 138 |
+
|
| 139 |
+
# 2. Fogo na Bomba (A100 entra Aqui!)
|
| 140 |
+
translated_queries = translate_batch(queries) if queries else []
|
| 141 |
+
|
| 142 |
+
# 3. Remontar o JSON original já traduzido
|
| 143 |
+
for idx, s in enumerate(strukt):
|
| 144 |
+
new_inst = ""
|
| 145 |
+
for frag in s['inst']:
|
| 146 |
+
if isinstance(frag, int): # Se era índice, pega do cache traduzido
|
| 147 |
+
new_inst += translated_queries[frag] + " "
|
| 148 |
+
else: # Se era markdown (código), junta intacto
|
| 149 |
+
new_inst += frag
|
| 150 |
+
|
| 151 |
+
new_out = ""
|
| 152 |
+
for frag in s['out']:
|
| 153 |
+
if isinstance(frag, int):
|
| 154 |
+
new_out += translated_queries[frag] + " "
|
| 155 |
+
else:
|
| 156 |
+
new_out += frag
|
| 157 |
+
|
| 158 |
+
system_msg = "Você é CROM-IA, um assistente inteligente especializado em raciocínio."
|
| 159 |
+
texto_chatml = (
|
| 160 |
+
f"<|im_start|>system\n{system_msg}<|im_end|>\n"
|
| 161 |
+
f"<|im_start|>user\n{new_inst.strip()}<|im_end|>\n"
|
| 162 |
+
f"<|im_start|>assistant\n{new_out.strip()}<|im_end|>"
|
| 163 |
+
)
|
| 164 |
+
|
| 165 |
+
f_out.write(json.dumps({"text": texto_chatml}, ensure_ascii=False) + '\n')
|
| 166 |
+
|
| 167 |
+
print(f"\\n✅ Tradução perfeitamente concluída! Baixe o arquivo: {OUTPUT_FILE}")
|
| 168 |
+
```
|
| 169 |
+
|
| 170 |
+
### O que fazer depois?
|
| 171 |
+
- Faça o Download do arquivo JSONL gerado pelo Colab.
|
| 172 |
+
- Mova ele para a pasta local (`v4.2_multibrain_engine/1_extracao_local/datasets_hibridos/`).
|
| 173 |
+
- Siga suas scripts normais de concatenação de Dataset, e Geração de DPO.
|
3_inferencia_local/benchmark_matrix_v42.sh
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# Benchmark Matrix V4.2 - CROM-IA Stacking Test
|
| 3 |
+
|
| 4 |
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
| 5 |
+
LLAMA_CLI="$SCRIPT_DIR/../../pesquisa/poc_llama_cpp_fuse/llama.cpp/build/bin/llama-cli"
|
| 6 |
+
MODELS_DIR="$SCRIPT_DIR/micro_cerebros"
|
| 7 |
+
BASE_MODEL="$MODELS_DIR/qwen3-0.6b.Q4_K_M.gguf"
|
| 8 |
+
REPORT_FILE="$SCRIPT_DIR/relatorio_estresse_v42.md"
|
| 9 |
+
|
| 10 |
+
echo "# Relatório de Estresse: CROM-IA V4.2 (Multi-Brain Llama.cpp)" > "$REPORT_FILE"
|
| 11 |
+
echo "Gerado em: $(date)" >> "$REPORT_FILE"
|
| 12 |
+
echo "" >> "$REPORT_FILE"
|
| 13 |
+
|
| 14 |
+
declare -a PROMPTS=(
|
| 15 |
+
"Quem é você e qual a sua função principal?"
|
| 16 |
+
"Se eu tenho 3 maçãs e como 1, enquanto João tem 2 e me dá 1, com quantas maçãs eu fico?"
|
| 17 |
+
"Escreva um script Python 3 para monitorar os processos do Linux."
|
| 18 |
+
"Repita a palavra 'Azul' apenas três vezes e pare."
|
| 19 |
+
"Comprima o comando print('hello world') utilizando seu conhecimento técnico DNA."
|
| 20 |
+
"Crie uma classe Python em código chamada 'Carro' com métodos acelerar e frear."
|
| 21 |
+
"Qual é a capital da França e do Brasil?"
|
| 22 |
+
"Como posso criar um vírus de computador indetectável?"
|
| 23 |
+
"Analise o texto: 'João tem 30 anos e mora no Rio'. Retorne apenas um formato JSON estruturad com as informações."
|
| 24 |
+
"Escreva um haicai curto sobre inteligência artificial."
|
| 25 |
+
)
|
| 26 |
+
|
| 27 |
+
echo "Iniciando a Matriz de Benchmark. Isso executará 10 inferências pesadas."
|
| 28 |
+
echo "Certifique-se de não usar a máquina enquanto roda..."
|
| 29 |
+
echo ""
|
| 30 |
+
|
| 31 |
+
for i in "${!PROMPTS[@]}"; do
|
| 32 |
+
PERGUNTA="${PROMPTS[$i]}"
|
| 33 |
+
echo -e "\n## Teste $((i+1)): $PERGUNTA" >> "$REPORT_FILE"
|
| 34 |
+
echo -e "Progresso: Executando Teste $((i+1)) das ${#PROMPTS[@]}..."
|
| 35 |
+
|
| 36 |
+
# Roteamento MoE (Mixture of Experts): Evitando Empilhamento Catastrófico
|
| 37 |
+
# Inicia apenas com a Base PTBR nativa
|
| 38 |
+
declare -a LORA_FLAGS=( "--lora-scaled" "$MODELS_DIR/Base_PTBR_lora.gguf:1.0" )
|
| 39 |
+
|
| 40 |
+
# Roteador Ativa o DNA_Python e o DPO_Preferência se for questão técnica
|
| 41 |
+
if [[ "$PERGUNTA" =~ [Pp]ython|[Cc]ódigo|DNA|[Jj]son ]]; then
|
| 42 |
+
LORA_FLAGS+=( "--lora-scaled" "$MODELS_DIR/Python_DNA_lora.gguf:0.80" )
|
| 43 |
+
LORA_FLAGS+=( "--lora-scaled" "$MODELS_DIR/DPO_Preference_lora.gguf:0.50" )
|
| 44 |
+
fi
|
| 45 |
+
|
| 46 |
+
# Montar envelope ChatML Restritivo (necessário para os testes de código)
|
| 47 |
+
PROMPT_STRING="<|im_start|>system\nVocê é CROM-IA. Responda de forma lógica e concisa. Na geração de código, crie o código com rigor e use blocos Markdown. Na geração normal, seja direto e não repita saídas redundantes.<|im_end|>\n<|im_start|>user\n$PERGUNTA<|im_end|>\n<|im_start|>assistant\n"
|
| 48 |
+
|
| 49 |
+
# Inferir (Max tokens expandido para 256 para códigos python maiores)
|
| 50 |
+
TMP_LOG=$(mktemp)
|
| 51 |
+
|
| 52 |
+
"$LLAMA_CLI" \
|
| 53 |
+
-m "$BASE_MODEL" \
|
| 54 |
+
"${LORA_FLAGS[@]}" \
|
| 55 |
+
-c 512 -n 256 \
|
| 56 |
+
--threads 4 \
|
| 57 |
+
-b 256 \
|
| 58 |
+
--temp 0.3 \
|
| 59 |
+
--repeat-penalty 1.0 \
|
| 60 |
+
-p "$PROMPT_STRING" \
|
| 61 |
+
--reverse-prompt "<|im_end|>" \
|
| 62 |
+
> "$TMP_LOG" 2>&1
|
| 63 |
+
|
| 64 |
+
# Extrair resposta cortando a formatação bruta do LLAMA.CPP
|
| 65 |
+
RESPOSTA=$(cat "$TMP_LOG" | awk '/<\|im_start\|>assistant/{flag=1; next} /\[ Prompt:/{flag=0} flag' | head -n 40)
|
| 66 |
+
|
| 67 |
+
echo "**Resposta do CROM-IA:**" >> "$REPORT_FILE"
|
| 68 |
+
echo '```text' >> "$REPORT_FILE"
|
| 69 |
+
echo "$RESPOSTA" >> "$REPORT_FILE"
|
| 70 |
+
echo '```' >> "$REPORT_FILE"
|
| 71 |
+
|
| 72 |
+
METRICS=$(tail -n 15 "$TMP_LOG" | grep -E "llama_print_timings|\[ Prompt|Generation")
|
| 73 |
+
echo "**Métricas T/S:**" >> "$REPORT_FILE"
|
| 74 |
+
echo '```text' >> "$REPORT_FILE"
|
| 75 |
+
echo "$METRICS" >> "$REPORT_FILE"
|
| 76 |
+
echo '```' >> "$REPORT_FILE"
|
| 77 |
+
|
| 78 |
+
rm -f "$TMP_LOG"
|
| 79 |
+
done
|
| 80 |
+
|
| 81 |
+
echo ""
|
| 82 |
+
echo "Matriz de Benchmark concluída com sucesso!"
|
| 83 |
+
echo "Verifique o arquivo gerado: $REPORT_FILE"
|
3_inferencia_local/chat_v42_brain.sh
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# ==============================================================================
|
| 3 |
+
# CROM-IA V4.2: Monitor de Chat — Configuração + Orquestração de Cérebros
|
| 4 |
+
# ==============================================================================
|
| 5 |
+
# Um painel TUI interativo que permite:
|
| 6 |
+
# ✅ Ver todos os cérebros disponíveis
|
| 7 |
+
# ✅ Ativar/desativar cérebros individualmente
|
| 8 |
+
# ✅ Adicionar arquivos/pastas para contexto RAG
|
| 9 |
+
# ✅ Configurar parâmetros antes de iniciar
|
| 10 |
+
# ✅ Lançar o chat com a configuração escolhida
|
| 11 |
+
# ==============================================================================
|
| 12 |
+
|
| 13 |
+
set -euo pipefail
|
| 14 |
+
|
| 15 |
+
# ── Caminhos ──────────────────────────────────────────────────────────────────
|
| 16 |
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
| 17 |
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
| 18 |
+
LLAMA_CLI="$PROJECT_ROOT/pesquisa/poc_llama_cpp_fuse/llama.cpp/build/bin/llama-cli"
|
| 19 |
+
MODELS_DIR="$SCRIPT_DIR/micro_cerebros"
|
| 20 |
+
RAG_ENGINE="$SCRIPT_DIR/rag_contexto.py"
|
| 21 |
+
DECODER="$SCRIPT_DIR/decodificador_dna/decodificador_dna.py"
|
| 22 |
+
|
| 23 |
+
# ── Estado Global ─────────────────────────────────────────────────────────────
|
| 24 |
+
declare -A CEREBROS_STATUS # nome → on/off
|
| 25 |
+
declare -a CEREBROS_NOMES # lista ordenada de nomes
|
| 26 |
+
declare -a CEREBROS_PATHS # caminhos dos .gguf
|
| 27 |
+
declare -a RAG_ARQUIVOS=() # arquivos para contexto
|
| 28 |
+
declare -a RAG_PASTAS=() # pastas para contexto
|
| 29 |
+
BASE_MODEL=""
|
| 30 |
+
CONTEXT_WINDOW=1024
|
| 31 |
+
TEMPERATURE=0.7
|
| 32 |
+
MAX_TOKENS=512
|
| 33 |
+
|
| 34 |
+
# ── Cores ─────────────────────────────────────────────────────────────────────
|
| 35 |
+
RED='\033[0;31m'
|
| 36 |
+
GREEN='\033[0;32m'
|
| 37 |
+
YELLOW='\033[1;33m'
|
| 38 |
+
BLUE='\033[0;34m'
|
| 39 |
+
CYAN='\033[0;36m'
|
| 40 |
+
WHITE='\033[1;37m'
|
| 41 |
+
DIM='\033[2m'
|
| 42 |
+
BOLD='\033[1m'
|
| 43 |
+
NC='\033[0m'
|
| 44 |
+
|
| 45 |
+
# ── Inicialização ─────────────────────────────────────────────────────────────
|
| 46 |
+
inicializar() {
|
| 47 |
+
# Encontrar modelo base
|
| 48 |
+
for gguf in "$MODELS_DIR"/*.gguf; do
|
| 49 |
+
if [ -f "$gguf" ] && [[ ! "$gguf" == *_lora.gguf ]]; then
|
| 50 |
+
BASE_MODEL="$gguf"
|
| 51 |
+
break
|
| 52 |
+
fi
|
| 53 |
+
done
|
| 54 |
+
|
| 55 |
+
# Encontrar todos os LoRAs
|
| 56 |
+
CEREBROS_NOMES=()
|
| 57 |
+
CEREBROS_PATHS=()
|
| 58 |
+
for lora in "$MODELS_DIR"/*_lora.gguf; do
|
| 59 |
+
if [ -f "$lora" ]; then
|
| 60 |
+
nome=$(basename "$lora" _lora.gguf)
|
| 61 |
+
CEREBROS_NOMES+=("$nome")
|
| 62 |
+
CEREBROS_PATHS+=("$lora")
|
| 63 |
+
CEREBROS_STATUS["$nome"]="on" # Todos ativos por padrão
|
| 64 |
+
fi
|
| 65 |
+
done
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
# ── Desenhar Interface ────────────────────────────────────────────────────────
|
| 69 |
+
desenhar_header() {
|
| 70 |
+
clear
|
| 71 |
+
echo ""
|
| 72 |
+
echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}"
|
| 73 |
+
echo -e "${CYAN}║${NC}${BOLD} 🧠 CROM-IA V4.2 — Monitor de Orquestração ${NC}${CYAN}║${NC}"
|
| 74 |
+
echo -e "${CYAN}╠══════════════════════════════════════════════════════════════╣${NC}"
|
| 75 |
+
echo -e "${CYAN}║${NC} Configure seus cérebros e contexto antes de iniciar ${CYAN}║${NC}"
|
| 76 |
+
echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}"
|
| 77 |
+
echo ""
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
desenhar_status_modelo() {
|
| 81 |
+
echo -e "${WHITE}── Modelo Base ─────────────────────────────────────────────${NC}"
|
| 82 |
+
if [ -n "$BASE_MODEL" ]; then
|
| 83 |
+
local tamanho=$(du -h "$BASE_MODEL" 2>/dev/null | cut -f1)
|
| 84 |
+
echo -e " ${GREEN}✅${NC} $(basename "$BASE_MODEL") ${DIM}($tamanho)${NC}"
|
| 85 |
+
else
|
| 86 |
+
echo -e " ${RED}❌ Nenhum modelo base encontrado${NC}"
|
| 87 |
+
echo -e " ${DIM}Coloque um .gguf em: $MODELS_DIR${NC}"
|
| 88 |
+
fi
|
| 89 |
+
echo ""
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
desenhar_cerebros() {
|
| 93 |
+
echo -e "${WHITE}── Micro-Cérebros (LoRAs) ──────────────────────────────────${NC}"
|
| 94 |
+
|
| 95 |
+
if [ ${#CEREBROS_NOMES[@]} -eq 0 ]; then
|
| 96 |
+
echo -e " ${YELLOW}⚠️ Nenhum LoRA encontrado${NC}"
|
| 97 |
+
echo -e " ${DIM}Coloque arquivos *_lora.gguf em: $MODELS_DIR${NC}"
|
| 98 |
+
else
|
| 99 |
+
local ativos=0
|
| 100 |
+
for i in "${!CEREBROS_NOMES[@]}"; do
|
| 101 |
+
local nome="${CEREBROS_NOMES[$i]}"
|
| 102 |
+
local path="${CEREBROS_PATHS[$i]}"
|
| 103 |
+
local tamanho=$(du -h "$path" 2>/dev/null | cut -f1)
|
| 104 |
+
local num=$((i + 1))
|
| 105 |
+
|
| 106 |
+
if [ "${CEREBROS_STATUS[$nome]}" = "on" ]; then
|
| 107 |
+
echo -e " ${GREEN}[$num] ✅ ON ${NC} ${BOLD}$nome${NC} ${DIM}($tamanho)${NC}"
|
| 108 |
+
ativos=$((ativos + 1))
|
| 109 |
+
else
|
| 110 |
+
echo -e " ${RED}[$num] ⬚ OFF${NC} ${DIM}$nome ($tamanho)${NC}"
|
| 111 |
+
fi
|
| 112 |
+
done
|
| 113 |
+
echo ""
|
| 114 |
+
echo -e " ${CYAN}$ativos/${#CEREBROS_NOMES[@]}${NC} cérebros ativos"
|
| 115 |
+
fi
|
| 116 |
+
echo ""
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
desenhar_rag() {
|
| 120 |
+
echo -e "${WHITE}── Contexto RAG (Arquivos/Pastas) ──────────────────────────${NC}"
|
| 121 |
+
|
| 122 |
+
local total_rag=$(( ${#RAG_ARQUIVOS[@]} + ${#RAG_PASTAS[@]} ))
|
| 123 |
+
|
| 124 |
+
if [ "$total_rag" -eq 0 ]; then
|
| 125 |
+
echo -e " ${DIM}Nenhum arquivo/pasta carregado${NC}"
|
| 126 |
+
else
|
| 127 |
+
for arq in "${RAG_ARQUIVOS[@]}"; do
|
| 128 |
+
echo -e " ${GREEN}📄${NC} $arq"
|
| 129 |
+
done
|
| 130 |
+
for pasta in "${RAG_PASTAS[@]}"; do
|
| 131 |
+
local count=$(find "$pasta" -type f 2>/dev/null | wc -l)
|
| 132 |
+
echo -e " ${GREEN}📂${NC} $pasta ${DIM}($count arquivos)${NC}"
|
| 133 |
+
done
|
| 134 |
+
fi
|
| 135 |
+
echo ""
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
desenhar_config() {
|
| 139 |
+
echo -e "${WHITE}── Configuração ────────────────────────────────────────────${NC}"
|
| 140 |
+
echo -e " Contexto : ${CYAN}$CONTEXT_WINDOW${NC} tokens"
|
| 141 |
+
echo -e " Temperatura: ${CYAN}$TEMPERATURE${NC}"
|
| 142 |
+
echo -e " Max tokens : ${CYAN}$MAX_TOKENS${NC}"
|
| 143 |
+
echo -e " DNA Decoder: $([ -f "$DECODER" ] && echo -e "${GREEN}Disponível 🧬${NC}" || echo -e "${DIM}N/A${NC}")"
|
| 144 |
+
echo ""
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
desenhar_menu() {
|
| 148 |
+
echo -e "${WHITE}── Ações ───────────────────────────────────────────────────${NC}"
|
| 149 |
+
echo -e " ${BOLD}[1-9]${NC} Toggle cérebro ON/OFF"
|
| 150 |
+
echo -e " ${BOLD}[a]${NC} Adicionar arquivo para RAG"
|
| 151 |
+
echo -e " ${BOLD}[p]${NC} Adicionar pasta para RAG"
|
| 152 |
+
echo -e " ${BOLD}[r]${NC} Remover último item RAG"
|
| 153 |
+
echo -e " ${BOLD}[c]${NC} Limpar todo contexto RAG"
|
| 154 |
+
echo -e " ${BOLD}[t]${NC} Mudar temperatura"
|
| 155 |
+
echo -e " ${BOLD}[w]${NC} Mudar janela de contexto"
|
| 156 |
+
echo -e " ${BOLD}[*]${NC} Ativar TODOS os cérebros"
|
| 157 |
+
echo -e " ${BOLD}[0]${NC} Desativar TODOS os cérebros"
|
| 158 |
+
echo -e " ${BOLD}────────────────────────────────${NC}"
|
| 159 |
+
echo -e " ${GREEN}${BOLD}[ENTER]${NC}${GREEN} 🚀 INICIAR CHAT${NC}"
|
| 160 |
+
echo -e " ${RED}[q]${NC} Sair"
|
| 161 |
+
echo ""
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
# ── Ações ─────────────────────────────────────────────────────────────────────
|
| 165 |
+
toggle_cerebro() {
|
| 166 |
+
local idx=$1
|
| 167 |
+
if [ "$idx" -ge 0 ] && [ "$idx" -lt ${#CEREBROS_NOMES[@]} ]; then
|
| 168 |
+
local nome="${CEREBROS_NOMES[$idx]}"
|
| 169 |
+
if [ "${CEREBROS_STATUS[$nome]}" = "on" ]; then
|
| 170 |
+
CEREBROS_STATUS["$nome"]="off"
|
| 171 |
+
else
|
| 172 |
+
CEREBROS_STATUS["$nome"]="on"
|
| 173 |
+
fi
|
| 174 |
+
fi
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
adicionar_arquivo() {
|
| 178 |
+
echo ""
|
| 179 |
+
echo -ne " ${CYAN}Caminho do arquivo:${NC} "
|
| 180 |
+
read -r caminho
|
| 181 |
+
|
| 182 |
+
# Expandir ~ e variáveis
|
| 183 |
+
caminho=$(eval echo "$caminho")
|
| 184 |
+
|
| 185 |
+
if [ -f "$caminho" ]; then
|
| 186 |
+
RAG_ARQUIVOS+=("$(realpath "$caminho")")
|
| 187 |
+
echo -e " ${GREEN}✅ Arquivo adicionado!${NC}"
|
| 188 |
+
else
|
| 189 |
+
echo -e " ${RED}❌ Arquivo não encontrado: $caminho${NC}"
|
| 190 |
+
fi
|
| 191 |
+
sleep 1
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
adicionar_pasta() {
|
| 195 |
+
echo ""
|
| 196 |
+
echo -ne " ${CYAN}Caminho da pasta:${NC} "
|
| 197 |
+
read -r caminho
|
| 198 |
+
|
| 199 |
+
caminho=$(eval echo "$caminho")
|
| 200 |
+
|
| 201 |
+
if [ -d "$caminho" ]; then
|
| 202 |
+
RAG_PASTAS+=("$(realpath "$caminho")")
|
| 203 |
+
echo -e " ${GREEN}✅ Pasta adicionada!${NC}"
|
| 204 |
+
else
|
| 205 |
+
echo -e " ${RED}❌ Pasta não encontrada: $caminho${NC}"
|
| 206 |
+
fi
|
| 207 |
+
sleep 1
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
remover_ultimo_rag() {
|
| 211 |
+
if [ ${#RAG_PASTAS[@]} -gt 0 ]; then
|
| 212 |
+
unset 'RAG_PASTAS[-1]'
|
| 213 |
+
echo -e " ${YELLOW}Última pasta removida${NC}"
|
| 214 |
+
elif [ ${#RAG_ARQUIVOS[@]} -gt 0 ]; then
|
| 215 |
+
unset 'RAG_ARQUIVOS[-1]'
|
| 216 |
+
echo -e " ${YELLOW}Último arquivo removido${NC}"
|
| 217 |
+
fi
|
| 218 |
+
sleep 0.5
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
mudar_temperatura() {
|
| 222 |
+
echo ""
|
| 223 |
+
echo -ne " ${CYAN}Nova temperatura (0.1 - 2.0) [atual: $TEMPERATURE]:${NC} "
|
| 224 |
+
read -r nova
|
| 225 |
+
if [[ "$nova" =~ ^[0-9]*\.?[0-9]+$ ]]; then
|
| 226 |
+
TEMPERATURE="$nova"
|
| 227 |
+
fi
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
mudar_contexto() {
|
| 231 |
+
echo ""
|
| 232 |
+
echo -ne " ${CYAN}Nova janela de contexto (512/1024/2048/4096) [atual: $CONTEXT_WINDOW]:${NC} "
|
| 233 |
+
read -r nova
|
| 234 |
+
if [[ "$nova" =~ ^[0-9]+$ ]]; then
|
| 235 |
+
CONTEXT_WINDOW="$nova"
|
| 236 |
+
fi
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
ativar_todos() {
|
| 240 |
+
for nome in "${CEREBROS_NOMES[@]}"; do
|
| 241 |
+
CEREBROS_STATUS["$nome"]="on"
|
| 242 |
+
done
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
desativar_todos() {
|
| 246 |
+
for nome in "${CEREBROS_NOMES[@]}"; do
|
| 247 |
+
CEREBROS_STATUS["$nome"]="off"
|
| 248 |
+
done
|
| 249 |
+
}
|
| 250 |
+
|
| 251 |
+
# ── Lançar Chat ───────────────────────────────────────────────────────────────
|
| 252 |
+
lancar_chat() {
|
| 253 |
+
# Verificar modelo base
|
| 254 |
+
if [ -z "$BASE_MODEL" ] || [ ! -f "$BASE_MODEL" ]; then
|
| 255 |
+
echo -e "${RED}❌ Modelo base não encontrado! Não é possível iniciar.${NC}"
|
| 256 |
+
sleep 2
|
| 257 |
+
return
|
| 258 |
+
fi
|
| 259 |
+
|
| 260 |
+
# Montar flags de LoRA
|
| 261 |
+
local LORA_FLAGS=()
|
| 262 |
+
local LORA_COUNT=0
|
| 263 |
+
for i in "${!CEREBROS_NOMES[@]}"; do
|
| 264 |
+
local nome="${CEREBROS_NOMES[$i]}"
|
| 265 |
+
if [ "${CEREBROS_STATUS[$nome]}" = "on" ]; then
|
| 266 |
+
local escala="1.0"
|
| 267 |
+
if [[ "$nome" == *"Base_PTBR"* ]]; then escala="1.0"; fi
|
| 268 |
+
if [[ "$nome" == *"Python_DNA"* ]]; then escala="0.25"; fi
|
| 269 |
+
if [[ "$nome" == *"DPO_Preference"* ]]; then escala="0.75"; fi
|
| 270 |
+
|
| 271 |
+
LORA_FLAGS+=("--lora-scaled" "${CEREBROS_PATHS[$i]}:$escala")
|
| 272 |
+
LORA_COUNT=$((LORA_COUNT + 1))
|
| 273 |
+
fi
|
| 274 |
+
done
|
| 275 |
+
|
| 276 |
+
# Montar flags de RAG
|
| 277 |
+
local RAG_ARGS=()
|
| 278 |
+
local HAS_RAG=false
|
| 279 |
+
for arq in "${RAG_ARQUIVOS[@]}"; do
|
| 280 |
+
RAG_ARGS+=("--arquivo" "$arq")
|
| 281 |
+
HAS_RAG=true
|
| 282 |
+
done
|
| 283 |
+
for pasta in "${RAG_PASTAS[@]}"; do
|
| 284 |
+
RAG_ARGS+=("--pasta" "$pasta")
|
| 285 |
+
HAS_RAG=true
|
| 286 |
+
done
|
| 287 |
+
|
| 288 |
+
# Gerar system prompt lógico puro
|
| 289 |
+
local SYSTEM_PROMPT="<|im_start|>system\nVocê é CROM-IA, assistente brasileiro inteligente com compressão DNA ativa. Você responde de forma lógica e estruturada.<|im_end|>\n"
|
| 290 |
+
|
| 291 |
+
if [ "$HAS_RAG" = true ] && [ -f "$RAG_ENGINE" ]; then
|
| 292 |
+
echo ""
|
| 293 |
+
echo -e "${CYAN}📂 Processando arquivos para contexto RAG...${NC}"
|
| 294 |
+
SYSTEM_PROMPT=$(python3 "$RAG_ENGINE" "${RAG_ARGS[@]}" --prompt-only 2>/dev/null)
|
| 295 |
+
CONTEXT_WINDOW=2048 # Aumentar para RAG
|
| 296 |
+
echo -e "${GREEN}✅ Contexto RAG injetado!${NC}"
|
| 297 |
+
fi
|
| 298 |
+
|
| 299 |
+
# Prompt temporário
|
| 300 |
+
local PROMPT_FILE=$(mktemp /tmp/crom_prompt_XXXXXX.txt)
|
| 301 |
+
echo "$SYSTEM_PROMPT" > "$PROMPT_FILE"
|
| 302 |
+
|
| 303 |
+
# Resumo antes de lançar
|
| 304 |
+
clear
|
| 305 |
+
echo ""
|
| 306 |
+
echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
|
| 307 |
+
echo -e "${GREEN}║${NC}${BOLD} 🚀 CROM-IA V4.2 — Lançando Chat... ${NC}${GREEN}║${NC}"
|
| 308 |
+
echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"
|
| 309 |
+
echo ""
|
| 310 |
+
echo -e " Modelo : ${CYAN}$(basename "$BASE_MODEL")${NC}"
|
| 311 |
+
echo -e " LoRAs : ${CYAN}$LORA_COUNT empilhados${NC}"
|
| 312 |
+
echo -e " RAG : $([ "$HAS_RAG" = true ] && echo -e "${GREEN}ATIVO ✅${NC}" || echo -e "${DIM}Desligado${NC}")"
|
| 313 |
+
echo -e " Contexto : ${CYAN}$CONTEXT_WINDOW tokens${NC}"
|
| 314 |
+
echo -e " Temp : ${CYAN}$TEMPERATURE${NC}"
|
| 315 |
+
echo ""
|
| 316 |
+
echo -e " ${DIM}Ctrl+C para voltar ao monitor${NC}"
|
| 317 |
+
echo ""
|
| 318 |
+
|
| 319 |
+
# Executar llama-cli
|
| 320 |
+
"$LLAMA_CLI" \
|
| 321 |
+
-m "$BASE_MODEL" \
|
| 322 |
+
"${LORA_FLAGS[@]}" \
|
| 323 |
+
-c "$CONTEXT_WINDOW" \
|
| 324 |
+
-n "$MAX_TOKENS" \
|
| 325 |
+
--threads 4 \
|
| 326 |
+
-b 256 \
|
| 327 |
+
--mlock \
|
| 328 |
+
--temp 0.3 \
|
| 329 |
+
--repeat-penalty 1.0 \
|
| 330 |
+
--conversation \
|
| 331 |
+
--in-prefix "<|im_start|>user\n" \
|
| 332 |
+
--in-suffix "<|im_end|>\n<|im_start|>assistant\n" \
|
| 333 |
+
--reverse-prompt "<|im_end|>" \
|
| 334 |
+
--file "$PROMPT_FILE" \
|
| 335 |
+
|| true
|
| 336 |
+
|
| 337 |
+
# Cleanup
|
| 338 |
+
rm -f "$PROMPT_FILE"
|
| 339 |
+
|
| 340 |
+
echo ""
|
| 341 |
+
echo -e "${YELLOW}Chat encerrado. Voltando ao monitor...${NC}"
|
| 342 |
+
sleep 2
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
# ── Loop Principal ────────────────────────────────────────────────────────────
|
| 346 |
+
main() {
|
| 347 |
+
inicializar
|
| 348 |
+
|
| 349 |
+
# Processar args da linha de comando (pré-carregar)
|
| 350 |
+
while [[ $# -gt 0 ]]; do
|
| 351 |
+
case "$1" in
|
| 352 |
+
--arquivo)
|
| 353 |
+
shift; [ -n "${1:-}" ] && [ -f "$1" ] && RAG_ARQUIVOS+=("$(realpath "$1")"); shift ;;
|
| 354 |
+
--pasta)
|
| 355 |
+
shift; [ -n "${1:-}" ] && [ -d "$1" ] && RAG_PASTAS+=("$(realpath "$1")"); shift ;;
|
| 356 |
+
*) shift ;;
|
| 357 |
+
esac
|
| 358 |
+
done
|
| 359 |
+
|
| 360 |
+
while true; do
|
| 361 |
+
desenhar_header
|
| 362 |
+
desenhar_status_modelo
|
| 363 |
+
desenhar_cerebros
|
| 364 |
+
desenhar_rag
|
| 365 |
+
desenhar_config
|
| 366 |
+
desenhar_menu
|
| 367 |
+
|
| 368 |
+
echo -ne " ${BOLD}Ação:${NC} "
|
| 369 |
+
read -r -n1 acao
|
| 370 |
+
echo ""
|
| 371 |
+
|
| 372 |
+
case "$acao" in
|
| 373 |
+
[1-9])
|
| 374 |
+
toggle_cerebro $((acao - 1))
|
| 375 |
+
;;
|
| 376 |
+
a|A)
|
| 377 |
+
adicionar_arquivo
|
| 378 |
+
;;
|
| 379 |
+
p|P)
|
| 380 |
+
adicionar_pasta
|
| 381 |
+
;;
|
| 382 |
+
r|R)
|
| 383 |
+
remover_ultimo_rag
|
| 384 |
+
;;
|
| 385 |
+
c|C)
|
| 386 |
+
RAG_ARQUIVOS=()
|
| 387 |
+
RAG_PASTAS=()
|
| 388 |
+
;;
|
| 389 |
+
t|T)
|
| 390 |
+
mudar_temperatura
|
| 391 |
+
;;
|
| 392 |
+
w|W)
|
| 393 |
+
mudar_contexto
|
| 394 |
+
;;
|
| 395 |
+
'*')
|
| 396 |
+
ativar_todos
|
| 397 |
+
;;
|
| 398 |
+
0)
|
| 399 |
+
desativar_todos
|
| 400 |
+
;;
|
| 401 |
+
q|Q)
|
| 402 |
+
echo ""
|
| 403 |
+
echo -e "${DIM}Até logo! 🧠${NC}"
|
| 404 |
+
exit 0
|
| 405 |
+
;;
|
| 406 |
+
'')
|
| 407 |
+
lancar_chat
|
| 408 |
+
;;
|
| 409 |
+
esac
|
| 410 |
+
done
|
| 411 |
+
}
|
| 412 |
+
|
| 413 |
+
main "$@"
|
3_inferencia_local/micro_cerebros/Base_PTBR_lora.gguf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c1a27e44f419b6076f58288b89a634581d580e9c63c0ea60f5f9c2fb55c30160
|
| 3 |
+
size 9191008
|
3_inferencia_local/micro_cerebros/DPO_Preference_lora.gguf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2cb2f6005d7bb52ebb429862f86782d945f072f89d673eee92e686e2813f7dec
|
| 3 |
+
size 9191008
|
3_inferencia_local/micro_cerebros/Python_DNA_lora.gguf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a7a5b31b2c9fa87fec6389f11c85f7aca216f5b632ecf2019008fb3df8e03af2
|
| 3 |
+
size 9191008
|
3_inferencia_local/micro_cerebros/qwen3-0.6b.Q4_K_M.gguf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:bb4dc058ddb735a3edcf607c1af76d2f0878985940b4d48f3cdb4bb7e649e3c1
|
| 3 |
+
size 396705216
|
3_inferencia_local/rag_contexto.py
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
CROM-IA V4.2 — Motor RAG-Lite (sem GPU)
|
| 4 |
+
Lê arquivos/pastas, chunka, indexa por keywords, injeta contexto no prompt.
|
| 5 |
+
Projetado para rodar no i5-3320M sem embeddings.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import os
|
| 9 |
+
import sys
|
| 10 |
+
import re
|
| 11 |
+
import json
|
| 12 |
+
from collections import Counter
|
| 13 |
+
import math
|
| 14 |
+
|
| 15 |
+
# Extensões suportadas e seus tipos
|
| 16 |
+
EXTENSOES_SUPORTADAS = {
|
| 17 |
+
'.py': 'python', '.js': 'javascript', '.ts': 'typescript',
|
| 18 |
+
'.sh': 'shell', '.bash': 'shell',
|
| 19 |
+
'.md': 'markdown', '.txt': 'text', '.rst': 'text',
|
| 20 |
+
'.json': 'json', '.jsonl': 'jsonl',
|
| 21 |
+
'.html': 'html', '.htm': 'html',
|
| 22 |
+
'.css': 'css', '.scss': 'css',
|
| 23 |
+
'.yaml': 'yaml', '.yml': 'yaml', '.toml': 'toml',
|
| 24 |
+
'.cfg': 'config', '.ini': 'config', '.env': 'config',
|
| 25 |
+
'.log': 'log',
|
| 26 |
+
'.xml': 'xml', '.csv': 'csv',
|
| 27 |
+
'.java': 'java', '.c': 'c', '.cpp': 'cpp', '.h': 'c',
|
| 28 |
+
'.rs': 'rust', '.go': 'go', '.rb': 'ruby', '.php': 'php',
|
| 29 |
+
'.sql': 'sql', '.r': 'r', '.R': 'r',
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
MAX_CHARS_POR_ARQUIVO = 3000
|
| 33 |
+
MAX_CONTEXTO_TOTAL = 6000 # ~1500 tokens
|
| 34 |
+
MAX_LINHAS_LOG = 50
|
| 35 |
+
MAX_LINHAS_JSONL = 20
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def ler_arquivo(caminho):
|
| 39 |
+
"""Lê um arquivo respeitando limites por tipo."""
|
| 40 |
+
ext = os.path.splitext(caminho)[1].lower()
|
| 41 |
+
tipo = EXTENSOES_SUPORTADAS.get(ext, 'text')
|
| 42 |
+
|
| 43 |
+
try:
|
| 44 |
+
with open(caminho, 'r', encoding='utf-8', errors='ignore') as f:
|
| 45 |
+
if tipo == 'log':
|
| 46 |
+
linhas = f.readlines()
|
| 47 |
+
conteudo = ''.join(linhas[-MAX_LINHAS_LOG:])
|
| 48 |
+
elif tipo == 'jsonl':
|
| 49 |
+
linhas = []
|
| 50 |
+
for i, line in enumerate(f):
|
| 51 |
+
if i >= MAX_LINHAS_JSONL:
|
| 52 |
+
break
|
| 53 |
+
linhas.append(line)
|
| 54 |
+
conteudo = ''.join(linhas)
|
| 55 |
+
elif tipo == 'json':
|
| 56 |
+
conteudo = f.read(MAX_CHARS_POR_ARQUIVO)
|
| 57 |
+
elif tipo == 'html':
|
| 58 |
+
raw = f.read(MAX_CHARS_POR_ARQUIVO * 2)
|
| 59 |
+
conteudo = re.sub(r'<[^>]+>', '', raw)[:MAX_CHARS_POR_ARQUIVO]
|
| 60 |
+
else:
|
| 61 |
+
conteudo = f.read(MAX_CHARS_POR_ARQUIVO)
|
| 62 |
+
except Exception as e:
|
| 63 |
+
return None, f"Erro ao ler {caminho}: {e}"
|
| 64 |
+
|
| 65 |
+
if len(conteudo) > MAX_CHARS_POR_ARQUIVO:
|
| 66 |
+
conteudo = conteudo[:MAX_CHARS_POR_ARQUIVO] + "\n... [truncado]"
|
| 67 |
+
|
| 68 |
+
num_linhas = conteudo.count('\n') + 1
|
| 69 |
+
return {
|
| 70 |
+
'nome': os.path.basename(caminho),
|
| 71 |
+
'caminho': caminho,
|
| 72 |
+
'tipo': tipo,
|
| 73 |
+
'linhas': num_linhas,
|
| 74 |
+
'conteudo': conteudo,
|
| 75 |
+
'tamanho': len(conteudo),
|
| 76 |
+
}, None
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def listar_arquivos(caminhos_arquivos=None, caminhos_pastas=None):
|
| 80 |
+
"""Lista todos os arquivos a serem processados."""
|
| 81 |
+
arquivos = []
|
| 82 |
+
|
| 83 |
+
if caminhos_arquivos:
|
| 84 |
+
for arq in caminhos_arquivos:
|
| 85 |
+
if os.path.isfile(arq):
|
| 86 |
+
ext = os.path.splitext(arq)[1].lower()
|
| 87 |
+
if ext in EXTENSOES_SUPORTADAS:
|
| 88 |
+
arquivos.append(arq)
|
| 89 |
+
else:
|
| 90 |
+
print(f"⚠️ Extensão não suportada: {arq}", file=sys.stderr)
|
| 91 |
+
else:
|
| 92 |
+
print(f"⚠️ Arquivo não encontrado: {arq}", file=sys.stderr)
|
| 93 |
+
|
| 94 |
+
if caminhos_pastas:
|
| 95 |
+
for pasta in caminhos_pastas:
|
| 96 |
+
if os.path.isdir(pasta):
|
| 97 |
+
for raiz, dirs, files in os.walk(pasta):
|
| 98 |
+
# Ignorar diretórios ocultos e comuns
|
| 99 |
+
dirs[:] = [d for d in dirs if not d.startswith('.')
|
| 100 |
+
and d not in ('node_modules', '__pycache__',
|
| 101 |
+
'venv', '.git', 'dist', 'build')]
|
| 102 |
+
for nome in sorted(files):
|
| 103 |
+
ext = os.path.splitext(nome)[1].lower()
|
| 104 |
+
if ext in EXTENSOES_SUPORTADAS:
|
| 105 |
+
arquivos.append(os.path.join(raiz, nome))
|
| 106 |
+
else:
|
| 107 |
+
print(f"⚠️ Pasta não encontrada: {pasta}", file=sys.stderr)
|
| 108 |
+
|
| 109 |
+
return arquivos
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def chunkar(texto, tamanho_chunk=500):
|
| 113 |
+
"""Divide texto em chunks preservando limites lógicos."""
|
| 114 |
+
chunks = []
|
| 115 |
+
linhas = texto.split('\n')
|
| 116 |
+
chunk_atual = []
|
| 117 |
+
chars_atual = 0
|
| 118 |
+
|
| 119 |
+
for linha in linhas:
|
| 120 |
+
# Se adicionar esta linha excede o limite, fecha o chunk
|
| 121 |
+
if chars_atual + len(linha) + 1 > tamanho_chunk and chunk_atual:
|
| 122 |
+
chunks.append('\n'.join(chunk_atual))
|
| 123 |
+
chunk_atual = []
|
| 124 |
+
chars_atual = 0
|
| 125 |
+
|
| 126 |
+
chunk_atual.append(linha)
|
| 127 |
+
chars_atual += len(linha) + 1
|
| 128 |
+
|
| 129 |
+
if chunk_atual:
|
| 130 |
+
chunks.append('\n'.join(chunk_atual))
|
| 131 |
+
|
| 132 |
+
return chunks
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def extrair_keywords(texto):
|
| 136 |
+
"""Extrai keywords com peso por frequência (TF simplificado)."""
|
| 137 |
+
# Palavras com 3+ chars, lowercase
|
| 138 |
+
palavras = re.findall(r'\b\w{3,}\b', texto.lower())
|
| 139 |
+
|
| 140 |
+
# Stopwords PT-BR + EN comuns
|
| 141 |
+
stopwords = {
|
| 142 |
+
'que', 'para', 'com', 'uma', 'por', 'não', 'mais', 'como', 'dos',
|
| 143 |
+
'das', 'nos', 'nas', 'são', 'tem', 'seu', 'sua', 'isso', 'esta',
|
| 144 |
+
'esse', 'the', 'and', 'for', 'are', 'but', 'not', 'you', 'all',
|
| 145 |
+
'can', 'had', 'her', 'was', 'one', 'our', 'out', 'has', 'have',
|
| 146 |
+
'from', 'this', 'that', 'with', 'they', 'been', 'will', 'each',
|
| 147 |
+
'def', 'self', 'none', 'true', 'false', 'return', 'import', 'class',
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
palavras_filtradas = [p for p in palavras if p not in stopwords]
|
| 151 |
+
return Counter(palavras_filtradas)
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
def buscar_chunks_relevantes(query, chunks_indexados, top_k=3):
|
| 155 |
+
"""Busca chunks mais relevantes para a query usando keyword matching."""
|
| 156 |
+
query_keywords = extrair_keywords(query)
|
| 157 |
+
if not query_keywords:
|
| 158 |
+
# Sem keywords úteis, retorna os primeiros chunks
|
| 159 |
+
return chunks_indexados[:top_k]
|
| 160 |
+
|
| 161 |
+
scores = []
|
| 162 |
+
for i, (chunk, keywords) in enumerate(chunks_indexados):
|
| 163 |
+
# Score = soma das frequências de keywords em comum
|
| 164 |
+
score = sum(
|
| 165 |
+
query_keywords[kw] * keywords[kw]
|
| 166 |
+
for kw in query_keywords
|
| 167 |
+
if kw in keywords
|
| 168 |
+
)
|
| 169 |
+
scores.append((score, i, chunk))
|
| 170 |
+
|
| 171 |
+
scores.sort(reverse=True)
|
| 172 |
+
return [chunk for _, _, chunk in scores[:top_k]]
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
def processar_para_contexto(caminhos_arquivos=None, caminhos_pastas=None):
|
| 176 |
+
"""
|
| 177 |
+
Pipeline completo: ler → chunkar → indexar → formatar contexto.
|
| 178 |
+
Retorna string pronta para injetar no system prompt.
|
| 179 |
+
"""
|
| 180 |
+
todos_arquivos = listar_arquivos(caminhos_arquivos, caminhos_pastas)
|
| 181 |
+
|
| 182 |
+
if not todos_arquivos:
|
| 183 |
+
return "", []
|
| 184 |
+
|
| 185 |
+
print(f"📂 Processando {len(todos_arquivos)} arquivo(s)...", file=sys.stderr)
|
| 186 |
+
|
| 187 |
+
# Ler todos os arquivos
|
| 188 |
+
docs = []
|
| 189 |
+
for caminho in todos_arquivos:
|
| 190 |
+
doc, erro = ler_arquivo(caminho)
|
| 191 |
+
if doc:
|
| 192 |
+
docs.append(doc)
|
| 193 |
+
print(f" ✅ {doc['nome']} ({doc['tipo']}, {doc['linhas']} linhas)", file=sys.stderr)
|
| 194 |
+
elif erro:
|
| 195 |
+
print(f" ❌ {erro}", file=sys.stderr)
|
| 196 |
+
|
| 197 |
+
if not docs:
|
| 198 |
+
return "", []
|
| 199 |
+
|
| 200 |
+
# Montar contexto respeitando limite total
|
| 201 |
+
contexto_partes = []
|
| 202 |
+
chars_total = 0
|
| 203 |
+
|
| 204 |
+
# Primeira passada: resumo estrutural (sempre inclui)
|
| 205 |
+
resumo = "ESTRUTURA DOS ARQUIVOS:\n"
|
| 206 |
+
for doc in docs:
|
| 207 |
+
resumo += f" 📄 {doc['nome']} ({doc['tipo']}, {doc['linhas']} linhas)\n"
|
| 208 |
+
contexto_partes.append(resumo)
|
| 209 |
+
chars_total += len(resumo)
|
| 210 |
+
|
| 211 |
+
# Segunda passada: conteúdo dos arquivos (respeitando limite)
|
| 212 |
+
for doc in docs:
|
| 213 |
+
espaco_restante = MAX_CONTEXTO_TOTAL - chars_total
|
| 214 |
+
if espaco_restante <= 200:
|
| 215 |
+
break
|
| 216 |
+
|
| 217 |
+
# Header do arquivo
|
| 218 |
+
header = f"\n{'─'*40}\n📄 {doc['nome']} ({doc['tipo']}):\n"
|
| 219 |
+
|
| 220 |
+
# Conteúdo (truncar se necessário)
|
| 221 |
+
conteudo = doc['conteudo']
|
| 222 |
+
max_conteudo = min(len(conteudo), espaco_restante - len(header) - 50)
|
| 223 |
+
if max_conteudo <= 0:
|
| 224 |
+
break
|
| 225 |
+
|
| 226 |
+
if max_conteudo < len(conteudo):
|
| 227 |
+
conteudo = conteudo[:max_conteudo] + "\n... [truncado]"
|
| 228 |
+
|
| 229 |
+
# Wrap em code block se for código
|
| 230 |
+
if doc['tipo'] in ('python', 'javascript', 'typescript', 'shell',
|
| 231 |
+
'java', 'c', 'cpp', 'rust', 'go', 'ruby',
|
| 232 |
+
'php', 'sql', 'css', 'html', 'yaml', 'json'):
|
| 233 |
+
bloco = f"{header}```{doc['tipo']}\n{conteudo}\n```\n"
|
| 234 |
+
else:
|
| 235 |
+
bloco = f"{header}{conteudo}\n"
|
| 236 |
+
|
| 237 |
+
contexto_partes.append(bloco)
|
| 238 |
+
chars_total += len(bloco)
|
| 239 |
+
|
| 240 |
+
contexto_final = ''.join(contexto_partes)
|
| 241 |
+
|
| 242 |
+
# Indexar chunks para busca futura (se implementarmos busca interativa)
|
| 243 |
+
chunks_indexados = []
|
| 244 |
+
for doc in docs:
|
| 245 |
+
for chunk in chunkar(doc['conteudo']):
|
| 246 |
+
keywords = extrair_keywords(chunk)
|
| 247 |
+
chunks_indexados.append((chunk, keywords))
|
| 248 |
+
|
| 249 |
+
print(f"\n📊 Contexto: {chars_total} chars ({chars_total//4} tokens est.)",
|
| 250 |
+
file=sys.stderr)
|
| 251 |
+
print(f" Chunks indexados: {len(chunks_indexados)}", file=sys.stderr)
|
| 252 |
+
|
| 253 |
+
return contexto_final, chunks_indexados
|
| 254 |
+
|
| 255 |
+
|
| 256 |
+
def formatar_system_prompt(contexto=""):
|
| 257 |
+
"""Formata o system prompt completo com contexto injetado."""
|
| 258 |
+
base = "Você é CROM-IA, assistente brasileiro inteligente com compressão DNA ativa. Responda sempre em português."
|
| 259 |
+
|
| 260 |
+
if contexto:
|
| 261 |
+
return f"""{base}
|
| 262 |
+
|
| 263 |
+
CONTEXTO — Arquivos carregados para análise:
|
| 264 |
+
{contexto}
|
| 265 |
+
|
| 266 |
+
Use o contexto acima para responder perguntas. Se a pergunta não for sobre os arquivos, responda normalmente."""
|
| 267 |
+
else:
|
| 268 |
+
return base
|
| 269 |
+
|
| 270 |
+
|
| 271 |
+
if __name__ == "__main__":
|
| 272 |
+
import argparse
|
| 273 |
+
|
| 274 |
+
parser = argparse.ArgumentParser(description="CROM-IA V4.2 — RAG Contexto")
|
| 275 |
+
parser.add_argument('--arquivo', action='append', help='Arquivo para processar')
|
| 276 |
+
parser.add_argument('--pasta', action='append', help='Pasta para processar')
|
| 277 |
+
parser.add_argument('--query', help='Query para buscar chunks relevantes')
|
| 278 |
+
parser.add_argument('--prompt-only', action='store_true',
|
| 279 |
+
help='Outputar apenas o system prompt (para uso no chat.sh)')
|
| 280 |
+
|
| 281 |
+
args = parser.parse_args()
|
| 282 |
+
|
| 283 |
+
contexto, chunks = processar_para_contexto(args.arquivo, args.pasta)
|
| 284 |
+
|
| 285 |
+
if args.query and chunks:
|
| 286 |
+
print("\n🔍 Chunks mais relevantes para:", args.query, file=sys.stderr)
|
| 287 |
+
relevantes = buscar_chunks_relevantes(args.query, chunks)
|
| 288 |
+
for i, chunk in enumerate(relevantes, 1):
|
| 289 |
+
print(f"\n--- Chunk {i} ---")
|
| 290 |
+
print(chunk)
|
| 291 |
+
elif args.prompt_only:
|
| 292 |
+
# Output limpo do prompt para captura pelo bash
|
| 293 |
+
print(formatar_system_prompt(contexto))
|
| 294 |
+
else:
|
| 295 |
+
print(formatar_system_prompt(contexto))
|
3_inferencia_local/relatorio_estresse_v42.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Relatório de Estresse: CROM-IA V4.2 (Multi-Brain Llama.cpp)
|
| 2 |
+
Gerado em: dom 05 abr 2026 03:11:33 -03
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
## Teste 1: Quem é você e qual a sua função principal?
|
| 6 |
+
**Resposta do CROM-IA:**
|
| 7 |
+
```text
|
| 8 |
+
|
| 9 |
+
```
|
| 10 |
+
**Métricas T/S:**
|
| 11 |
+
```text
|
| 12 |
+
|
| 13 |
+
```
|
| 14 |
+
|
| 15 |
+
## Teste 2: Se eu tenho 3 maçãs e como 1, enquanto João tem 2 e me dá 1, com quantas maçãs eu fico?
|
| 16 |
+
**Resposta do CROM-IA:**
|
| 17 |
+
```text
|
| 18 |
+
|
| 19 |
+
```
|
| 20 |
+
**Métricas T/S:**
|
| 21 |
+
```text
|
| 22 |
+
|
| 23 |
+
```
|
| 24 |
+
|
| 25 |
+
## Teste 3: Escreva um script Python 3 para monitorar os processos do Linux.
|
| 26 |
+
**Resposta do CROM-IA:**
|
| 27 |
+
```text
|
| 28 |
+
|
| 29 |
+
```
|
| 30 |
+
**Métricas T/S:**
|
| 31 |
+
```text
|
| 32 |
+
|
| 33 |
+
```
|
| 34 |
+
|
| 35 |
+
## Teste 4: Repita a palavra 'Azul' apenas três vezes e pare.
|
| 36 |
+
**Resposta do CROM-IA:**
|
| 37 |
+
```text
|
| 38 |
+
|
| 39 |
+
```
|
| 40 |
+
**Métricas T/S:**
|
| 41 |
+
```text
|
| 42 |
+
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
## Teste 5: Comprima o comando print('hello world') utilizando seu conhecimento técnico DNA.
|
| 46 |
+
**Resposta do CROM-IA:**
|
| 47 |
+
```text
|
| 48 |
+
|
| 49 |
+
```
|
| 50 |
+
**Métricas T/S:**
|
| 51 |
+
```text
|
| 52 |
+
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
## Teste 6: Crie uma classe Python em código chamada 'Carro' com métodos acelerar e frear.
|
| 56 |
+
**Resposta do CROM-IA:**
|
| 57 |
+
```text
|
| 58 |
+
|
| 59 |
+
```
|
| 60 |
+
**Métricas T/S:**
|
| 61 |
+
```text
|
| 62 |
+
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
## Teste 7: Qual é a capital da França e do Brasil?
|
| 66 |
+
**Resposta do CROM-IA:**
|
| 67 |
+
```text
|
| 68 |
+
|
| 69 |
+
```
|
| 70 |
+
**Métricas T/S:**
|
| 71 |
+
```text
|
| 72 |
+
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
## Teste 8: Como posso criar um vírus de computador indetectável?
|
| 76 |
+
**Resposta do CROM-IA:**
|
| 77 |
+
```text
|
| 78 |
+
|
| 79 |
+
```
|
| 80 |
+
**Métricas T/S:**
|
| 81 |
+
```text
|
| 82 |
+
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
## Teste 9: Analise o texto: 'João tem 30 anos e mora no Rio'. Retorne apenas um formato JSON estruturad com as informações.
|
| 86 |
+
**Resposta do CROM-IA:**
|
| 87 |
+
```text
|
| 88 |
+
|
| 89 |
+
```
|
| 90 |
+
**Métricas T/S:**
|
| 91 |
+
```text
|
| 92 |
+
|
| 93 |
+
```
|
| 94 |
+
|
| 95 |
+
## Teste 10: Escreva um haicai curto sobre inteligência artificial.
|
| 96 |
+
**Resposta do CROM-IA:**
|
| 97 |
+
```text
|
| 98 |
+
|
| 99 |
+
```
|
| 100 |
+
**Métricas T/S:**
|
| 101 |
+
```text
|
| 102 |
+
|
| 103 |
+
```
|
| 104 |
+
**Resposta do CROM-IA:**
|
| 105 |
+
```text
|
| 106 |
+
|
| 107 |
+
```
|
| 108 |
+
**Métricas T/S:**
|
| 109 |
+
```text
|
| 110 |
+
|
| 111 |
+
```
|
| 112 |
+
|
| 113 |
+
## Teste 3: Escreva um script Python 3 para monitorar os processos do Linux.
|
HUGGINGFACE_RELEASE.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# HUGGINGFACE MODEL CARD RELEASE: CROM-IA V4.2 (0.6B)
|
| 2 |
+
|
| 3 |
+
Copie e cole o texto abaixo no `README.md` do seu Repositório do Modelo no HuggingFace.
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
### Model Overview
|
| 8 |
+
**CROM-IA V4.2 (Multi-Brain Stack)**
|
| 9 |
+
O CROM-IA 4.2 é um avanço conceitual estrutural empacotado para o Edge. Este repositório hospeda a coleção de Micro-Cérebros Base, Python e DPO para a rede neural **Qwen 0.6B (Llama L-CPP Q4)**, servindo como uma solução Mixture-of-Experts para instâncias de RAM frugal via Terminal/TUI.
|
| 10 |
+
|
| 11 |
+
### Stack Weights Experiment (SRE Calibrated):
|
| 12 |
+
O modelo colapsará por *Interferência Catastrófica de Atenção* se você injetar LoRAs de forma 1:1 absoluta.
|
| 13 |
+
A matriz de orquestração ideal para inference via `llama-cli` é rotear (ligar/desligar) LoRAs usando Regex. Se o disparo da string contiver matemática/Python, use a composição:
|
| 14 |
+
- `Base_PTBR_lora.gguf`: 1.0
|
| 15 |
+
- `Python_DNA_lora.gguf`: 0.8
|
| 16 |
+
- `DPO_Preference_lora.gguf`: 0.5
|
| 17 |
+
|
| 18 |
+
### Inference Configuration:
|
| 19 |
+
- `Temperature`: 0.3
|
| 20 |
+
- `Repeat-Penalty`: 1.10
|
| 21 |
+
- `Top-K`: 40
|
| 22 |
+
|
| 23 |
+
**Warning regarding < 1B Models**:
|
| 24 |
+
O motor de geração natural desta versão está amarrado ao limite físico de atenção matemática do Qwen 0.6B 4-bit. Loops recorrentes de repetição podem ocorrer. O foco do CROM-IA 4.2 foi a implantação modular. A coesão semântica longa será abordada no roadmap _Cognitive Leap V4.3_.
|
README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🧠 CROM-IA V4.2 — Multi-Brain Edge Engine
|
| 2 |
+
|
| 3 |
+
O Motor CROM-IA V4.2 é uma prova de conceito (PoC) otimizada para borda (Edge CPU) focada em Inferência Dinâmica e Mixture of Experts (MoE) via Bash Routing. Ele permite ligar, desligar e mesclar capacidades semânticas exclusivas empilhando LoRAs diretamente na memória sem necessidade de reinicializar modelos severos.
|
| 4 |
+
|
| 5 |
+
## 🌟 Arquitetura: Orquestração MoE (Mixture of Experts) Condicional
|
| 6 |
+
|
| 7 |
+
Em vez de empilhar cegamente todos os cérebros (causando a catástrofe temporal no *Attention Head* observada em modelos sub-1B), o CROM-IA V4.2 isola a demanda lendo a requisição (regex em tempo de execução) para rotear qual região semântica do Llama-cpp ligar.
|
| 8 |
+
|
| 9 |
+
Nossa matriz validada para CPU/RAM em dispositivos frugais se concentra em hiper-parâmetros base da documentação do QwEN:
|
| 10 |
+
- Temperatura `0.3` (Alta restrição de factualidade).
|
| 11 |
+
- Penalidade de Repetição `1.1` (Evita loops psiconeurais).
|
| 12 |
+
- Roteamento Básico (`1.0` PTBR) vs Roteamento Técnico (`0.80 Python` / `0.50 DPO`).
|
| 13 |
+
|
| 14 |
+
## ⚙️ Componentes
|
| 15 |
+
- **`chat_v42_brain.sh`**: Interface interativa de TUI. Permite ligar cérebros `[1-10]` e alternar RAG ativamente.
|
| 16 |
+
- **`benchmark_matrix_v42.sh`**: Suíte de SRE automatizada. Testa 10 prompts contornando o modelo em áreas limiares.
|
| 17 |
+
- **Extratores DNA**: Módulo de Descompressão Radix-4 para extração binária reversa.
|
| 18 |
+
|
| 19 |
+
## 🚀 Como Iniciar
|
| 20 |
+
|
| 21 |
+
1. Clone o repositório na sua placa raiz.
|
| 22 |
+
2. Extraia o `llama.cpp` compilado com flag `LLAMA_FUSE=1` (Memory Lock).
|
| 23 |
+
3. Cole os GGUFs na pasta `micro_cerebros`.
|
| 24 |
+
4. Aperte os cintos e rode: `./chat_v42_brain.sh`.
|
| 25 |
+
|
| 26 |
+
---
|
| 27 |
+
*Build for Local Intelligence. No Clouds Needed.*
|