# Guia de Configuração — Módulo AI

## Pré-requisitos

| Componente | Como obter | Status |
|---|---|---|
| **Ollama** (host) | `curl -fsSL https://ollama.com/install.sh \| sh` | Local, necessário |
| **qwen3-embedding** | `ollama pull qwen3-embedding:latest` | Modelo de embedding |
| **gemma4:12b** | `ollama pull gemma4:12b` | LLM para chat local |
| **DeepSeek API key** | [platform.deepseek.com](https://platform.deepseek.com) | LLM cloud (opcional) |
| **PostgreSQL + pgvector** | `docker compose up -d postgres` | Já configurado |
| **RabbitMQ** | `docker compose up -d rabbit-mq` | Já configurado |

## 1. Setup do Ollama (Host)

### Instalação

```bash
# Linux
curl -fsSL https://ollama.com/install.sh | sh

# Verificar se está rodando
ollama --version
curl http://localhost:11434/api/tags
```

### Download dos Modelos

```bash
# Embedding (4.7 GB)
ollama pull qwen3-embedding:latest

# Chat local (7.6 GB)
ollama pull gemma4:12b

# Alternativa menor para máquinas com pouca RAM (9.6 GB, MoE)
# ollama pull gemma4:e4b

# Verificar modelos instalados
ollama list
```

**Hardware recomendado**:

| Modelo | RAM mínima | RAM recomendada | GPU VRAM (opcional) |
|---|---|---|---|
| `qwen3-embedding:latest` (8B) | 8 GB | 16 GB | 6 GB |
| `gemma4:12b` | 10 GB | 16 GB | 8 GB |
| `gemma4:e4b` | 6 GB | 12 GB | 6 GB |

### Configuração do Ollama

Por padrão, o Ollama escuta em `localhost:11434`. Se precisar acessar de outro host:

```bash
# Editar /etc/systemd/system/ollama.service ou usar env var
export OLLAMA_HOST=0.0.0.0:11434
```

Para otimizar performance com GPU (se disponível):

```bash
# Verificar se GPU está sendo usada
ollama run gemma4:12b --verbose
# Saída: "total duration: ..." — procure por "eval rate: XX tokens/s"
```

## 2. Arquivo `.env`

Criar na raiz do projeto (`backend/.env`):

```bash
# ============================================================
# Decompile-AI — Environment Variables
# ============================================================

# --- LLM Providers ---

# DeepSeek API Key (obter em https://platform.deepseek.com)
DEEPSEEK_API_KEY=sk-your-api-key-here

# --- Override de modelos (opcional) ---

# Provedor padrão de chat: ollama | deepseek
AI_DEFAULT_CHAT_PROVIDER=ollama

# Modelo de chat Ollama (padrão: gemma4:12b)
# AI_CHAT_MODEL_OLLAMA=gemma4:12b

# Modelo de chat DeepSeek (padrão: deepseek-chat)
# AI_CHAT_MODEL_DEEPSEEK=deepseek-chat

# Modelo de embedding (padrão: qwen3-embedding:latest)
# AI_EMBEDDING_MODEL=qwen3-embedding:latest

# Dimensão do embedding (padrão: 1024, max 4096 para qwen3)
# AI_EMBEDDING_DIMENSION=1024

# --- Database ---

# Sobrescrever credenciais do Postgres se necessário
# SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/decompile_ai
# SPRING_DATASOURCE_USERNAME=decompile_ai
# SPRING_DATASOURCE_PASSWORD=decompile_ai
```

**Importante**: Adicione `.env` ao `.gitignore`:

```bash
echo ".env" >> .gitignore
```

## 3. Carregamento do `.env`

O Spring Boot precisa saber como carregar o `.env`. Opções:

### Opção A: `spring.config.import` (nativo Spring Boot)

Adicionar ao `application.yml`:

```yaml
spring:
  config:
    import: optional:file:.env[.properties]
```

Isso carrega o `.env` como um arquivo de propriedades. **Limitação**: não suporta substituição de variáveis inline como `${VAR}` dentro de outras variáveis no `.env`, mas funciona bem para definir valores.

### Opção B: Plugin `dotenv` (recomendado para desenvolvimento)

Adicionar dependência ao `pom.xml`:

```xml
<dependency>
  <groupId>me.paulschwarz</groupId>
  <artifactId>spring-dotenv</artifactId>
  <version>4.0.0</version>
</dependency>
```

Suporta interpolação de variáveis e convenção `.env` padrão.

### Opção C: Export manual (desenvolvimento)

```bash
set -a && source .env && set +a
./mvnw spring-boot:run
```

## 4. `application.yml` — Configuração do Módulo AI

### Blocos a adicionar ao arquivo existente

```yaml
spring:
  # ... configurações existentes (datasource, jpa, flyway, rabbitmq) ...

  ai:
    ollama:
      base-url: http://localhost:11434
      embedding:
        options:
          model: ${AI_EMBEDDING_MODEL:qwen3-embedding:latest}
      chat:
        options:
          model: ${AI_CHAT_MODEL_OLLAMA:gemma4:12b}
          temperature: 0.3     # respostas determinísticas para análise técnica
          top-p: 0.95
          top-k: 64
    openai:
      base-url: https://api.deepseek.com
      api-key: ${DEEPSEEK_API_KEY}
      chat:
        options:
          model: ${AI_CHAT_MODEL_DEEPSEEK:deepseek-chat}
          temperature: 0.3
          max-tokens: 4096

app:
  # ... configurações existentes (storage, rabbitmq, docker, die, engines) ...

  ai:
    # Provedor padrão de chat quando a sessão não especifica modelo
    default-chat-provider: ${AI_DEFAULT_CHAT_PROVIDER:ollama}

    # --- Configurações de Embedding ---
    embedding:
      # Dimensão do vetor (qwen3-embedding suporta 32-4096)
      # DEVE corresponder à coluna vector(N) na migration V008
      dimension: ${AI_EMBEDDING_DIMENSION:1024}
      # Tamanho máximo do chunk em caracteres
      chunk-max-chars: 3000
      # Quantas funções processar por batch na API de embedding
      batch-size: 20

    # --- Configurações de RAG ---
    rag:
      # Quantos chunks retornar na busca semântica
      top-k: 10
      # Similaridade mínima para incluir um chunk (0.0 a 1.0)
      similarity-threshold: 0.6
      # Máximo de tokens de contexto enviados à LLM
      max-context-tokens: 8000

    # --- Configurações de Chat ---
    chat:
      # Quantas mensagens de histórico incluir no prompt
      max-history-messages: 20
      # Temperatura padrão para geração
      temperature: 0.3
```

### Configuração completa do `application.yml` (após merge)

```yaml
spring:
  threads:
    virtual:
      enabled: true
  application:
    name: decompile-ai
  config:
    import: optional:file:.env[.properties]
  datasource:
    url: jdbc:postgresql://localhost:5432/decompile_ai
    username: decompile_ai
    password: decompile_ai
  jpa:
    hibernate:
      ddl-auto: validate
  flyway:
    enabled: true
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  servlet:
    multipart:
      max-file-size: 500MB
      max-request-size: 500MB
  ai:
    ollama:
      base-url: http://localhost:11434
      embedding:
        options:
          model: ${AI_EMBEDDING_MODEL:qwen3-embedding:latest}
      chat:
        options:
          model: ${AI_CHAT_MODEL_OLLAMA:gemma4:12b}
          temperature: 0.3
          top-p: 0.95
          top-k: 64
    openai:
      base-url: https://api.deepseek.com
      api-key: ${DEEPSEEK_API_KEY}
      chat:
        options:
          model: ${AI_CHAT_MODEL_DEEPSEEK:deepseek-chat}
          temperature: 0.3
          max-tokens: 4096

app:
  storage:
    upload-dir: ./uploads/binaries
  rabbitmq:
    exchange: decompile.jobs
    queue: decompile.jobs.queue
    routing-key: decompile.jobs.created
  docker:
    enabled: true
  die:
    image: decompile-ai/diec:latest
    timeout-seconds: 60
    docker-host: unix:///var/run/docker.sock
  engines:
    ida5:
      image: decompile-ai/ida5:latest
      timeout-seconds: 300
    ghidra:
      image: decompile-ai/ghidra:latest
      timeout-seconds: 600
  ai:
    default-chat-provider: ${AI_DEFAULT_CHAT_PROVIDER:ollama}
    embedding:
      dimension: ${AI_EMBEDDING_DIMENSION:1024}
      chunk-max-chars: 3000
      batch-size: 20
    rag:
      top-k: 10
      similarity-threshold: 0.6
      max-context-tokens: 8000
    chat:
      max-history-messages: 20
      temperature: 0.3

logging:
  level:
    org.springframework.modulith: DEBUG
    ai.decompile.ai: DEBUG           # Logs do módulo AI
    org.springframework.ai: INFO     # Logs do Spring AI
```

## 5. `docker-compose.yml` (sem alterações)

O `docker-compose.yml` atual já atende todos os requisitos:

```yaml
services:
  postgres:
    container_name: decompile-ai-postgres
    image: pgvector/pgvector:pg18    # PostgreSQL 18 + pgvector nativo
    environment:
      - POSTGRES_USER=decompile_ai
      - POSTGRES_PASSWORD=decompile_ai
      - POSTGRES_DB=decompile_ai
    ports:
      - "5432:5432"
    volumes:
      - postgres:/var/lib/postgresql
    networks:
      - decompile-ai-network

  rabbit-mq:
    container_name: decompile-ai-rabbitmq
    image: rabbitmq:4-management
    ports:
      - "5672:5672"
      - "15672:15672"
    networks:
      - decompile-ai-network

networks:
  decompile-ai-network:
    driver: bridge

volumes:
  postgres:
```

**Não adicionamos Ollama ao docker-compose** porque ele roda no host.

## 6. Startup

### Ordem de inicialização

```bash
# 1. Infraestrutura Docker
docker compose up -d postgres rabbit-mq

# 2. Verificar Ollama no host
ollama list
# Deve mostrar: qwen3-embedding:latest, gemma4:12b

# 3. Configurar .env
cp .env.example .env
# Editar com a DEEPSEEK_API_KEY

# 4. Iniciar o backend
./mvnw spring-boot:run

# 5. Verificar health
curl http://localhost:8080/actuator/health
```

### Verificação de saúde dos componentes AI

```bash
# Ollama
curl http://localhost:11434/api/tags | jq '.models[].name'

# Testar embedding
curl http://localhost:11434/api/embed -d '{
  "model": "qwen3-embedding:latest",
  "input": "test"
}' | jq '.embeddings[0] | length'
# Deve retornar 1024 (ou dimensão configurada)

# Testar chat local
curl http://localhost:11434/api/chat -d '{
  "model": "gemma4:12b",
  "messages": [{"role": "user", "content": "Hello"}],
  "stream": false
}' | jq '.message.content'
```

## 7. Troubleshooting

### Ollama não responde

```bash
# Verificar se está rodando
systemctl status ollama
# ou
ps aux | grep ollama

# Reiniciar se necessário
systemctl restart ollama
```

### Erro: "model not found"

```bash
# Listar modelos disponíveis
ollama list

# Baixar modelo faltante
ollama pull qwen3-embedding:latest
ollama pull gemma4:12b
```

### Erro: "DeepSeek API key not configured"

- Verificar se `.env` existe e contém `DEEPSEEK_API_KEY=sk-...`
- Verificar se `spring.config.import: optional:file:.env[.properties]` está no `application.yml`
- Alternativa: `export DEEPSEEK_API_KEY=sk-...` no terminal

### Erro: "relation 'vector_store' does not exist"

- Verificar se Flyway rodou a migration V008: `SELECT * FROM flyway_schema_history;`
- Rodar manualmente se necessário: `./mvnw flyway:migrate`

### Erro: "column 'embedding' type vector not supported"

- Verificar se a extensão pgvector está ativada: `SELECT * FROM pg_extension WHERE extname = 'vector';`
- Ativar manualmente: `CREATE EXTENSION IF NOT EXISTS vector;`

### Performance lenta nos embeddings

- Reduzir `batch-size` no `application.yml`
- Verificar se o Ollama está usando GPU: `ollama run qwen3-embedding --verbose` e checar `eval rate`
- Sem GPU, o modelo 8B pode ser lento para centenas de funções (esperar 2-5 minutos)

### Contexto da LLM estourando

- Reduzir `max-context-tokens` em `app.ai.rag`
- Reduzir `max-history-messages` em `app.ai.chat`
- Aumentar `chunk-max-chars` (para incluir menos chunks maiores)
