# 🤖 **Programando IA com JavaScript - Guia Completo**




## **📌 ÍNDICE**
1. [Por Que JavaScript para IA?](#1-por-que-javascript-para-ia)
2. [Ambiente e Ferramentas](#2-ambiente-e-ferramentas)
3. [Fundamentos Matemáticos](#3-fundamentos-matemáticos)
4. [Redes Neurais do Zero](#4-redes-neurais-do-zero)
5. [Bibliotecas de IA/ML](#5-bibliotecas-de-ia-ml)
6. [TensorFlow.js](#6-tensorflowjs)
7. [Brain.js](#7-brainjs)
8. [IA no Navegador](#8-ia-no-navegador)
9. [IA no Node.js](#9-ia-no-nodejs)
10. [Projetos Práticos](#10-projetos-práticos)
11. [Deploy e Produção](#11-deploy-e-produção)

---

## **1. POR QUE JAVASCRIPT PARA IA?**

### **Vantagens:**
- 🌐 **Universalidade**: Funciona em navegador, servidor, mobile, desktop
- 🔄 **Tempo Real**: Ideal para aplicações interativas
- 🚀 **Performance WebGL**: GPU acceleration via WebGL
- 📱 **PWA/Offline**: IA funcionando offline
- 🔌 **Integração**: Fácil integração com web apps existentes

### **Limitações:**
- 🐢 **Performance**: Geralmente mais lento que Python/C++
- 📚 **Ecossistema Menor**: Menos bibliotecas que Python
- 🧮 **Computação Científica**: Bibliotecas matemáticas limitadas

### **Casos de Uso Ideais:**
- Aplicações web interativas com IA
- Prototipagem rápida
- Visualização de modelos de IA
- Edge computing no navegador
- Extensões de navegador inteligentes

---

## **2. AMBIENTE E FERRAMENTAS**

### **Setup Básico:**
```bash
# Node.js necessário
node --version  # Deve ser >= 14

# Iniciar projeto
mkdir ia-javascript
cd ia-javascript
npm init -y

# Instalar dependências básicas
npm install tensorflow @tensorflow/tfjs-node brain.js
npm install --save-dev parcel-bundler
```

### **Estrutura do Projeto:**
```
ia-javascript/
├── public/
│   ├── index.html
│   └── style.css
├── src/
│   ├── ia/          # Código de IA
│   ├── utils/       # Funções auxiliares
│   └── app.js       # Aplicação principal
├── package.json
└── README.md
```

### **Ferramentas Recomendadas:**
- **Node.js**: Ambiente de execução
- **Visual Studio Code**: Editor
- **Parcel/Webpack**: Bundlers
- **Jest/Mocha**: Testes
- **Chrome DevTools**: Debugging

---

## **3. FUNDAMENTOS MATEMÁTICOS**

### **Implementando Operações Básicas:**
```javascript
// math-utils.js

class MathUtils {
    // Multiplicação de matrizes
    static multiplyMatrices(a, b) {
        const rowsA = a.length;
        const colsA = a[0].length;
        const rowsB = b.length;
        const colsB = b[0].length;
        
        if (colsA !== rowsB) {
            throw new Error('Matrizes incompatíveis para multiplicação');
        }
        
        const result = new Array(rowsA);
        for (let i = 0; i < rowsA; i++) {
            result[i] = new Array(colsB).fill(0);
            for (let j = 0; j < colsB; j++) {
                for (let k = 0; k < colsA; k++) {
                    result[i][j] += a[i][k] * b[k][j];
                }
            }
        }
        return result;
    }
    
    // Transposição de matriz
    static transpose(matrix) {
        return matrix[0].map((_, colIndex) => 
            matrix.map(row => row[colIndex])
        );
    }
    
    // Função de ativação sigmoid
    static sigmoid(x) {
        return 1 / (1 + Math.exp(-x));
    }
    
    // Derivada da sigmoid
    static sigmoidDerivative(x) {
        const sig = this.sigmoid(x);
        return sig * (1 - sig);
    }
    
    // Função ReLU
    static relu(x) {
        return Math.max(0, x);
    }
    
    // Softmax
    static softmax(arr) {
        const maxVal = Math.max(...arr);
        const exps = arr.map(x => Math.exp(x - maxVal));
        const sumExps = exps.reduce((a, b) => a + b, 0);
        return exps.map(exp => exp / sumExps);
    }
    
    // Função de perda (MSE)
    static meanSquaredError(predictions, targets) {
        let sum = 0;
        for (let i = 0; i < predictions.length; i++) {
            sum += Math.pow(predictions[i] - targets[i], 2);
        }
        return sum / predictions.length;
    }
}

// Exemplo de uso
const matrizA = [[1, 2], [3, 4]];
const matrizB = [[5, 6], [7, 8]];

console.log('Multiplicação:', MathUtils.multiplyMatrices(matrizA, matrizB));
console.log('Sigmoid de 0:', MathUtils.sigmoid(0));
console.log('Softmax:', MathUtils.softmax([1, 2, 3]));
```

---

## **4. REDES NEURAIS DO ZERO**

### **Implementação de Perceptron:**
```javascript
// perceptron.js

class Perceptron {
    constructor(numInputs, learningRate = 0.1) {
        this.weights = new Array(numInputs);
        this.bias = Math.random() * 2 - 1; // Entre -1 e 1
        this.learningRate = learningRate;
        
        // Inicializar pesos aleatoriamente
        for (let i = 0; i < numInputs; i++) {
            this.weights[i] = Math.random() * 2 - 1;
        }
    }
    
    // Função de ativação (step function)
    activate(sum) {
        return sum >= 0 ? 1 : 0;
    }
    
    // Forward pass
    predict(inputs) {
        if (inputs.length !== this.weights.length) {
            throw new Error('Número de inputs incorreto');
        }
        
        let sum = this.bias;
        for (let i = 0; i < inputs.length; i++) {
            sum += inputs[i] * this.weights[i];
        }
        
        return this.activate(sum);
    }
    
    // Treinamento
    train(inputs, target, maxEpochs = 1000) {
        for (let epoch = 0; epoch < maxEpochs; epoch++) {
            // Forward pass
            const prediction = this.predict(inputs);
            const error = target - prediction;
            
            // Se estiver correto, para
            if (error === 0) break;
            
            // Atualizar pesos e bias
            for (let i = 0; i < this.weights.length; i++) {
                this.weights[i] += this.learningRate * error * inputs[i];
            }
            this.bias += this.learningRate * error;
            
            // Log a cada 100 épocas
            if (epoch % 100 === 0) {
                console.log(`Época ${epoch}: Erro = ${error}`);
            }
        }
    }
    
    // Treinamento com múltiplos exemplos
    trainBatch(trainingData, maxEpochs = 1000) {
        for (let epoch = 0; epoch < maxEpochs; epoch++) {
            let totalError = 0;
            
            for (const [inputs, target] of trainingData) {
                const prediction = this.predict(inputs);
                const error = target - prediction;
                totalError += Math.abs(error);
                
                // Atualizar pesos
                for (let i = 0; i < this.weights.length; i++) {
                    this.weights[i] += this.learningRate * error * inputs[i];
                }
                this.bias += this.learningRate * error;
            }
            
            // Se erro médio for 0, para
            const meanError = totalError / trainingData.length;
            if (meanError === 0) {
                console.log(`Treinamento concluído na época ${epoch}`);
                break;
            }
            
            if (epoch % 100 === 0) {
                console.log(`Época ${epoch}: Erro médio = ${meanError.toFixed(4)}`);
            }
        }
    }
}

// Exemplo: Porta lógica AND
function testarPerceptron() {
    // Dados de treino: [input1, input2], output esperado
    const trainingData = [
        [[0, 0], 0],
        [[0, 1], 0],
        [[1, 0], 0],
        [[1, 1], 1]
    ];
    
    // Criar e treinar perceptron
    const perceptron = new Perceptron(2, 0.1);
    console.log('Treinando perceptron para porta AND...');
    perceptron.trainBatch(trainingData, 1000);
    
    // Testar
    console.log('\nTestando perceptron:');
    console.log(`0 AND 0 = ${perceptron.predict([0, 0])}`);
    console.log(`0 AND 1 = ${perceptron.predict([0, 1])}`);
    console.log(`1 AND 0 = ${perceptron.predict([1, 0])}`);
    console.log(`1 AND 1 = ${perceptron.predict([1, 1])}`);
    
    // Mostrar pesos finais
    console.log('\nPesos finais:', perceptron.weights);
    console.log('Bias final:', perceptron.bias);
}

// Executar exemplo
testarPerceptron();
```

### **Rede Neural Multicamadas (MLP):**
```javascript
// mlp.js

class MLP {
    constructor(layerSizes, learningRate = 0.1) {
        this.layerSizes = layerSizes;
        this.learningRate = learningRate;
        this.weights = [];
        this.biases = [];
        
        // Inicializar pesos e biases
        for (let i = 0; i < layerSizes.length - 1; i++) {
            const rows = layerSizes[i + 1];
            const cols = layerSizes[i];
            
            // Inicialização Xavier/Glorot
            const stdDev = Math.sqrt(2 / (cols + rows));
            const weightMatrix = Array(rows)
                .fill()
                .map(() => Array(cols)
                    .fill()
                    .map(() => (Math.random() * 2 - 1) * stdDev)
                );
            
            this.weights.push(weightMatrix);
            this.biases.push(Array(rows).fill(0));
        }
    }
    
    // Função de ativação
    static sigmoid(x) {
        return 1 / (1 + Math.exp(-x));
    }
    
    static sigmoidDerivative(x) {
        return x * (1 - x);
    }
    
    // Forward pass
    forward(input) {
        let currentActivation = input;
        const activations = [input];
        const weightedSums = [];
        
        for (let i = 0; i < this.weights.length; i++) {
            // Calcular soma ponderada
            const weightedSum = this.weights[i].map((neuronWeights, neuronIndex) => {
                let sum = this.biases[i][neuronIndex];
                for (let j = 0; j < neuronWeights.length; j++) {
                    sum += neuronWeights[j] * currentActivation[j];
                }
                return sum;
            });
            
            weightedSums.push(weightedSum);
            
            // Aplicar ativação
            currentActivation = weightedSum.map(MLP.sigmoid);
            activations.push(currentActivation);
        }
        
        return { output: currentActivation, activations, weightedSums };
    }
    
    // Backward pass (backpropagation)
    backward(input, target) {
        const { output, activations, weightedSums } = this.forward(input);
        
        // Calcular erro
        const errors = [];
        const gradients = [];
        
        // Erro na camada de saída
        let outputError = output.map((pred, i) => pred - target[i]);
        errors.unshift(outputError);
        
        // Gradiente para camada de saída
        const outputGradient = outputError.map((err, i) => 
            err * MLP.sigmoidDerivative(output[i])
        );
        gradients.unshift(outputGradient);
        
        // Backpropagate
        for (let i = this.weights.length - 2; i >= 0; i--) {
            const currentWeights = this.weights[i + 1];
            const currentActivation = activations[i + 1];
            const nextGradient = gradients[0];
            
            // Calcular erro
            const layerError = Array(currentActivation.length).fill(0);
            for (let j = 0; j < nextGradient.length; j++) {
                for (let k = 0; k < currentActivation.length; k++) {
                    layerError[k] += nextGradient[j] * currentWeights[j][k];
                }
            }
            errors.unshift(layerError);
            
            // Calcular gradiente
            const layerGradient = layerError.map((err, idx) => 
                err * MLP.sigmoidDerivative(currentActivation[idx])
            );
            gradients.unshift(layerGradient);
        }
        
        // Atualizar pesos e biases
        for (let i = 0; i < this.weights.length; i++) {
            const currentGradient = gradients[i];
            const prevActivation = activations[i];
            
            for (let j = 0; j < this.weights[i].length; j++) {
                for (let k = 0; k < this.weights[i][j].length; k++) {
                    this.weights[i][j][k] -= this.learningRate * 
                        currentGradient[j] * prevActivation[k];
                }
                this.biases[i][j] -= this.learningRate * currentGradient[j];
            }
        }
        
        return {
            error: outputError.reduce((sum, err) => sum + Math.abs(err), 0) / output.length,
            prediction: output
        };
    }
    
    // Treinamento
    train(trainingData, epochs = 1000, logInterval = 100) {
        for (let epoch = 0; epoch < epochs; epoch++) {
            let totalError = 0;
            
            for (const [input, target] of trainingData) {
                const result = this.backward(input, target);
                totalError += result.error;
            }
            
            const meanError = totalError / trainingData.length;
            
            if (epoch % logInterval === 0) {
                console.log(`Época ${epoch}: Erro = ${meanError.toFixed(6)}`);
            }
            
            if (meanError < 0.001) {
                console.log(`Convergiu na época ${epoch}`);
                break;
            }
        }
    }
    
    // Predição
    predict(input) {
        return this.forward(input).output;
    }
}

// Exemplo: Problema XOR (não linearmente separável)
function testarMLP() {
    // Dados XOR: [input1, input2], [output]
    const trainingData = [
        [[0, 0], [0]],
        [[0, 1], [1]],
        [[1, 0], [1]],
        [[1, 1], [0]]
    ];
    
    // Criar MLP: 2 inputs, 4 neurônios ocultos, 1 output
    const mlp = new MLP([2, 4, 1], 0.5);
    
    console.log('Treinando MLP para resolver XOR...');
    mlp.train(trainingData, 10000, 1000);
    
    console.log('\nTestando MLP:');
    trainingData.forEach(([input, target]) => {
        const prediction = mlp.predict(input);
        console.log(`${input} → ${prediction[0].toFixed(4)} (esperado: ${target})`);
    });
}

testarMLP();
```

---

## **5. BIBLIOTECAS DE IA/ML EM JAVASCRIPT**

### **Comparativo das Principais:**

| Biblioteca | Melhor Para | Dificuldade | Browser/Node |
|------------|-------------|-------------|--------------|
| **TensorFlow.js** | Deep Learning | Média | Ambos |
| **Brain.js** | Redes Neurais Simples | Fácil | Principalmente Node |
| **Synaptic.js** | Arquiteturas Complexas | Média | Ambos |
| **ML5.js** | IA para Artistas | Fácil | Browser |
| **Keras.js** | Modelos Keras/TF | Média | Browser |

### **Instalação:**
```bash
# TensorFlow.js
npm install @tensorflow/tfjs           # Browser
npm install @tensorflow/tfjs-node      # Node.js (com C++ bindings)
npm install @tensorflow/tfjs-node-gpu  # Node.js com GPU

# Brain.js
npm install brain.js

# Synaptic.js
npm install synaptic

# ML5.js (via CDN no browser)
<script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script>
```

---

## **6. TENSORFLOW.JS**

### **Introdução aos Tensores:**
```javascript
// tensores.js
import * as tf from '@tensorflow/tfjs';

class TensorFlowIntro {
    static async run() {
        // 1. Criar tensores
        const scalar = tf.scalar(42);
        const vector = tf.tensor1d([1, 2, 3, 4]);
        const matrix = tf.tensor2d([[1, 2], [3, 4]]);
        
        console.log('Scalar:', await scalar.data());
        console.log('Vector:', await vector.data());
        console.log('Matrix:', await matrix.array());
        
        // 2. Operações matemáticas
        const a = tf.tensor2d([[1, 2], [3, 4]]);
        const b = tf.tensor2d([[5, 6], [7, 8]]);
        
        // Soma
        const soma = a.add(b);
        console.log('Soma:', await soma.array());
        
        // Multiplicação
        const multiplicacao = a.matMul(b);
        console.log('Multiplicação:', await multiplicacao.array());
        
        // 3. Redes neurais simples
        const model = tf.sequential();
        
        // Camada densa (fully connected)
        model.add(tf.layers.dense({
            inputShape: [2],
            units: 4,
            activation: 'relu'
        }));
        
        model.add(tf.layers.dense({
            units: 1,
            activation: 'sigmoid'
        }));
        
        // Compilar modelo
        model.compile({
            optimizer: tf.train.adam(0.1),
            loss: 'meanSquaredError',
            metrics: ['accuracy']
        });
        
        // Dados de treino (XOR)
        const xs = tf.tensor2d([[0, 0], [0, 1], [1, 0], [1, 1]]);
        const ys = tf.tensor2d([[0], [1], [1], [0]]);
        
        console.log('\nTreinando modelo XOR...');
        
        // Treinar
        await model.fit(xs, ys, {
            epochs: 500,
            batchSize: 4,
            verbose: 0,
            callbacks: {
                onEpochEnd: (epoch, logs) => {
                    if (epoch % 100 === 0) {
                        console.log(`Época ${epoch}: perda = ${logs.loss.toFixed(4)}`);
                    }
                }
            }
        });
        
        // Testar
        const predictions = model.predict(xs);
        console.log('\nPredições:', await predictions.data());
        
        // Limpar memória
        tf.dispose([scalar, vector, matrix, a, b, soma, multiplicacao, xs, ys, predictions]);
    }
}

// Executar
TensorFlowIntro.run();
```

### **Reconhecimento de Dígitos (MNIST) com TensorFlow.js:**
```javascript
// mnist-tfjs.js
import * as tf from '@tensorflow/tfjs';
import * as tfvis from '@tensorflow/tfjs-vis';

class MNISTClassifier {
    constructor() {
        this.model = null;
        this.data = null;
    }
    
    async loadData() {
        // Carregar dataset MNIST
        this.data = new MnistData();
        await this.data.load();
    }
    
    createModel() {
        // Criar modelo CNN
        this.model = tf.sequential();
        
        // Camada convolucional
        this.model.add(tf.layers.conv2d({
            inputShape: [28, 28, 1],
            kernelSize: 3,
            filters: 8,
            activation: 'relu'
        }));
        
        this.model.add(tf.layers.maxPooling2d({
            poolSize: 2,
            strides: 2
        }));
        
        // Segunda camada convolucional
        this.model.add(tf.layers.conv2d({
            kernelSize: 3,
            filters: 16,
            activation: 'relu'
        }));
        
        this.model.add(tf.layers.maxPooling2d({
            poolSize: 2,
            strides: 2
        }));
        
        // Flatten
        this.model.add(tf.layers.flatten());
        
        // Camadas densas
        this.model.add(tf.layers.dense({
            units: 128,
            activation: 'relu'
        }));
        
        this.model.add(tf.layers.dropout(0.2));
        
        // Camada de saída
        this.model.add(tf.layers.dense({
            units: 10,
            activation: 'softmax'
        }));
        
        // Compilar
        this.model.compile({
            optimizer: tf.train.adam(),
            loss: 'categoricalCrossentropy',
            metrics: ['accuracy']
        });
        
        return this.model;
    }
    
    async train() {
        const BATCH_SIZE = 512;
        const TRAIN_DATA_SIZE = 5500;
        const TEST_DATA_SIZE = 1000;
        
        const [trainXs, trainYs] = tf.tidy(() => {
            const d = this.data.nextTrainBatch(TRAIN_DATA_SIZE);
            return [
                d.xs.reshape([TRAIN_DATA_SIZE, 28, 28, 1]),
                d.labels
            ];
        });
        
        const [testXs, testYs] = tf.tidy(() => {
            const d = this.data.nextTestBatch(TEST_DATA_SIZE);
            return [
                d.xs.reshape([TEST_DATA_SIZE, 28, 28, 1]),
                d.labels
            ];
        });
        
        // Visualizar treinamento
        const surface = { name: 'Treinamento MNIST', tab: 'Training' };
        
        return this.model.fit(trainXs, trainYs, {
            batchSize: BATCH_SIZE,
            epochs: 20,
            validationData: [testXs, testYs],
            callbacks: tfvis.show.fitCallbacks(
                surface,
                ['loss', 'val_loss', 'acc', 'val_acc'],
                {
                    height: 300,
                    callbacks: ['onEpochEnd']
                }
            )
        });
    }
    
    async predict(imageTensor) {
        if (!this.model) {
            throw new Error('Modelo não treinado');
        }
        
        // Pré-processar
        const processed = imageTensor
            .reshape([1, 28, 28, 1])
            .div(255.0);
        
        const prediction = this.model.predict(processed);
        const values = await prediction.data();
        
        // Retornar classe com maior probabilidade
        return values.indexOf(Math.max(...values));
    }
}

// Para usar no browser
class MnistData {
    constructor() {
        this.dataset = null;
    }
    
    async load() {
        // Esta é uma implementação simplificada
        // Na prática, você baixaria o dataset MNIST
        console.log('Carregando dados MNIST...');
        // Implementação real precisaria de fetch dos arquivos
    }
    
    nextTrainBatch(batchSize) {
        // Retornar batch de treino
        return { xs: tf.zeros([batchSize, 784]), labels: tf.zeros([batchSize, 10]) };
    }
    
    nextTestBatch(batchSize) {
        // Retornar batch de teste
        return { xs: tf.zeros([batchSize, 784]), labels: tf.zeros([batchSize, 10]) };
    }
}

// Interface web simples
class MNISTApp {
    constructor() {
        this.classifier = new MNISTClassifier();
        this.canvas = null;
        this.ctx = null;
    }
    
    async init() {
        await this.classifier.loadData();
        this.classifier.createModel();
        
        // Criar canvas para desenhar dígitos
        this.setupCanvas();
        this.setupUI();
    }
    
    setupCanvas() {
        this.canvas = document.createElement('canvas');
        this.canvas.width = 280;
        this.canvas.height = 280;
        this.canvas.style.border = '1px solid black';
        this.ctx = this.canvas.getContext('2d');
        
        this.ctx.fillStyle = 'white';
        this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
        this.ctx.strokeStyle = 'black';
        this.ctx.lineWidth = 20;
        this.ctx.lineCap = 'round';
        
        document.body.appendChild(this.canvas);
        
        // Event listeners para desenho
        let isDrawing = false;
        
        this.canvas.addEventListener('mousedown', (e) => {
            isDrawing = true;
            this.ctx.beginPath();
            this.ctx.moveTo(e.offsetX, e.offsetY);
        });
        
        this.canvas.addEventListener('mousemove', (e) => {
            if (isDrawing) {
                this.ctx.lineTo(e.offsetX, e.offsetY);
                this.ctx.stroke();
            }
        });
        
        this.canvas.addEventListener('mouseup', () => {
            isDrawing = false;
        });
        
        this.canvas.addEventListener('mouseleave', () => {
            isDrawing = false;
        });
    }
    
    setupUI() {
        // Botão de treinamento
        const trainBtn = document.createElement('button');
        trainBtn.textContent = 'Treinar Modelo';
        trainBtn.onclick = () => this.train();
        document.body.appendChild(trainBtn);
        
        // Botão de predição
        const predictBtn = document.createElement('button');
        predictBtn.textContent = 'Reconhecer Dígito';
        predictBtn.onclick = () => this.predict();
        document.body.appendChild(predictBtn);
        
        // Botão para limpar canvas
        const clearBtn = document.createElement('button');
        clearBtn.textContent = 'Limpar';
        clearBtn.onclick = () => this.clearCanvas();
        document.body.appendChild(clearBtn);
        
        // Área para resultados
        this.resultDiv = document.createElement('div');
        this.resultDiv.style.marginTop = '20px';
        this.resultDiv.style.fontSize = '24px';
        document.body.appendChild(this.resultDiv);
    }
    
    async train() {
        this.resultDiv.textContent = 'Treinando... (pode demorar)';
        await this.classifier.train();
        this.resultDiv.textContent = 'Treinamento completo!';
    }
    
    async predict() {
        // Converter canvas para tensor
        const imageData = this.ctx.getImageData(0, 0, 280, 280);
        const tensor = tf.browser.fromPixels(imageData, 1);
        
        // Redimensionar para 28x28
        const resized = tf.image.resizeBilinear(tensor, [28, 28]);
        
        // Prever
        const prediction = await this.classifier.predict(resized);
        this.resultDiv.textContent = `Predição: ${prediction}`;
        
        // Limpar tensores
        tf.dispose([tensor, resized]);
    }
    
    clearCanvas() {
        this.ctx.fillStyle = 'white';
        this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
        this.resultDiv.textContent = '';
    }
}

// Inicializar app quando a página carregar
// window.onload = () => new MNISTApp().init();
```

---

## **7. BRAIN.JS**

### **Exemplos com Brain.js:**
```javascript
// brainjs-examples.js
const brain = require('brain.js');

class BrainJSExamples {
    // 1. Rede neural simples
    static async simpleNN() {
        const net = new brain.NeuralNetwork();
        
        // Dados de treino (XOR)
        const trainingData = [
            { input: [0, 0], output: [0] },
            { input: [0, 1], output: [1] },
            { input: [1, 0], output: [1] },
            { input: [1, 1], output: [0] }
        ];
        
        console.log('Treinando rede neural para XOR...');
        
        net.train(trainingData, {
            iterations: 20000,
            errorThresh: 0.005,
            log: true,
            logPeriod: 1000
        });
        
        console.log('\nTestando:');
        console.log(`0,0 → ${net.run([0, 0])}`);
        console.log(`0,1 → ${net.run([0, 1])}`);
        console.log(`1,0 → ${net.run([1, 0])}`);
        console.log(`1,1 → ${net.run([1, 1])}`);
        
        return net;
    }
    
    // 2. Análise de sentimentos
    static async sentimentAnalysis() {
        const net = new brain.recurrent.LSTM();
        
        const trainingData = [
            { input: "Adorei esse produto!", output: "positivo" },
            { input: "Odiei, muito ruim", output: "negativo" },
            { input: "Excelente serviço", output: "positivo" },
            { input: "Péssima experiência", output: "negativo" },
            { input: "Recomendo muito", output: "positivo" },
            { input: "Não comprem isso", output: "negativo" },
            { input: "Maravilhoso, amei", output: "positivo" },
            { input: "Horrível, devolvi", output: "negativo" }
        ];
        
        // Converter para formato brain.js
        const data = trainingData.map(item => ({
            input: item.input,
            output: item.output
        }));
        
        net.train(data, {
            iterations: 1000,
            log: true,
            errorThresh: 0.01
        });
        
        const testPhrases = [
            "Gostei bastante",
            "Não gostei nada",
            "Superou expectativas",
            "Muito decepcionante"
        ];
        
        console.log('\nAnálise de sentimentos:');
        testPhrases.forEach(phrase => {
            const output = net.run(phrase);
            console.log(`${phrase} → ${output}`);
        });
    }
    
    // 3. Reconhecimento de padrões temporais
    static async timeSeries() {
        const net = new brain.recurrent.LSTMTimeStep({
            inputSize: 1,
            hiddenLayers: [10, 10],
            outputSize: 1
        });
        
        // Dados: Série temporal simples (onda seno)
        const sineWave = [];
        for (let i = 0; i < 100; i++) {
            sineWave.push([Math.sin(i * 0.1)]);
        }
        
        console.log('Treinando para prever série temporal...');
        
        net.train([sineWave], {
            iterations: 2000,
            errorThresh: 0.005,
            log: true,
            logPeriod: 200
        });
        
        // Fazer previsão para próximo passo
        const forecast = net.forecast([
            [Math.sin(10 * 0.1)],
            [Math.sin(11 * 0.1)],
            [Math.sin(12 * 0.1)]
        ], 3);
        
        console.log('\nPrevisões para próximos 3 passos:');
        forecast.forEach((pred, i) => {
            const actual = Math.sin((13 + i) * 0.1);
            console.log(`Passo ${i + 1}: Previsto=${pred[0].toFixed(4)}, Real=${actual.toFixed(4)}`);
        });
    }
    
    // 4. Classificação de cores (RGB para nome de cor)
    static async colorClassifier() {
        const net = new brain.NeuralNetwork({
            hiddenLayers: [10, 10]
        });
        
        const trainingData = [
            // Vermelho
            { input: { r: 1, g: 0, b: 0 }, output: { red: 1 } },
            // Verde
            { input: { r: 0, g: 1, b: 0 }, output: { green: 1 } },
            // Azul
            { input: { r: 0, g: 0, b: 1 }, output: { blue: 1 } },
            // Amarelo
            { input: { r: 1, g: 1, b: 0 }, output: { yellow: 1 } },
            // Roxo
            { input: { r: 1, g: 0, b: 1 }, output: { purple: 1 } },
            // Ciano
            { input: { r: 0, g: 1, b: 1 }, output: { cyan: 1 } },
            // Branco
            { input: { r: 1, g: 1, b: 1 }, output: { white: 1 } },
            // Preto
            { input: { r: 0, g: 0, b: 0 }, output: { black: 1 } }
        ];
        
        net.train(trainingData, {
            iterations: 5000,
            errorThresh: 0.005,
            log: true,
            logPeriod: 500
        });
        
        console.log('\nClassificando cores:');
        
        const testColors = [
            { name: 'Vermelho Claro', rgb: { r: 0.9, g: 0.2, b: 0.2 } },
            { name: 'Verde Escuro', rgb: { r: 0, g: 0.5, b: 0 } },
            { name: 'Azul Médio', rgb: { r: 0.3, g: 0.3, b: 0.9 } },
            { name: 'Rosa', rgb: { r: 1, g: 0.5, b: 0.8 } }
        ];
        
        testColors.forEach(color => {
            const output = net.run(color.rgb);
            
            // Encontrar cor com maior probabilidade
            let maxKey = '';
            let maxValue = 0;
            
            for (const [key, value] of Object.entries(output)) {
                if (value > maxValue) {
                    maxValue = value;
                    maxKey = key;
                }
            }
            
            console.log(`${color.name} (${JSON.stringify(color.rgb)}) → ${maxKey} (${maxValue.toFixed(2)})`);
        });
    }
    
    // 5. Rede neural com GPU (se disponível)
    static async gpuExample() {
        // Brain.js suporta GPU via WebGL no navegador
        const net = new brain.N