- Entendendo RAG: O Que É Isso?
- A Tecnologia: Como Funciona?
- Pré-requisitos: O Que Você Precisa Antes de Começar
- Guia de Configuração Passo a Passo
- Usando a Aplicação
- Entendendo o Código
- Guia de Solução de Problemas
- Deploy em Produção
- Recursos Adicionais
Digamos que você trabalha em uma empresa com milhares de documentos: contratos, atas de reunião, relatórios, vídeos de treinamento e mais. Um dia, alguém pergunta:
"O que combinamos no contrato Smith sobre prazos de entrega?"
Sem um sistema RAG, você precisaria:
- Lembrar em qual pasta está o contrato Smith
- Abrir o documento
- Procurar manualmente pelas páginas para encontrar a seção de entrega
- Ler e entender o que encontrou
- Formular uma resposta
Isso pode levar de 5 a 30 minutos. E se você receber 50 perguntas assim por dia?
Com um sistema RAG como o MegaRAG, você:
- Digita sua pergunta
- Recebe uma resposta em segundos, com a fonte exata destacada
Retrieval-Augmented Generation (Geração Aumentada por Recuperação)
Vamos detalhar:
- Retrieval (Recuperação): Encontrar informações relevantes nos seus documentos
- Augmented (Aumentada): O conhecimento da IA é "aumentado" (aprimorado) com seus documentos específicos
- Generation (Geração): A IA gera uma resposta em linguagem natural
Pense no RAG como um bibliotecário muito inteligente:
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ │
│ IA TRADICIONAL (como ChatGPT sozinho) │
│ ═════════════════════════════════════ │
│ │
│ Você: "O que está no contrato Smith?" │
│ IA: "Não tenho acesso aos seus documentos. Só posso usar meu conhecimento geral." │
│ │
│ A IA é inteligente, mas ela não leu SEUS documentos. │
│ │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ SISTEMA RAG (IA + Seus Documentos) │
│ ══════════════════════════════════ │
│ │
│ Você: "O que está no contrato Smith?" │
│ │
│ RAG Passo 1 (Recuperação): │
│ "Deixe-me buscar nos seus documentos algo sobre 'contrato Smith'..." │
│ → Encontrado: Seção 4.2 do smith_contrato.pdf menciona prazos de entrega │
│ │
│ RAG Passo 2 (Geração Aumentada): │
│ "Baseado na Seção 4.2 do seu contrato Smith, o prazo de entrega é..." │
│ │
│ Agora a IA pode responder perguntas sobre SEUS documentos específicos! │
│ │
└─────────────────────────────────────────────────────────────────────────────────────┘
Aqui está exatamente o que acontece quando você usa o MegaRAG:
Passo 1: UPLOAD
═══════════════
Você arrasta um PDF para o app.
📄 relatorio_trimestral.pdf
│
▼
┌─────────────────┐
│ MegaRAG │
│ recebe arquivo │
└─────────────────┘
Passo 2: ARMAZENAR O ARQUIVO
════════════════════════════
O arquivo original é salvo no Supabase Storage (como Google Drive, mas para nosso app).
📄 relatorio_trimestral.pdf
│
▼
┌──────────────────────────────────┐
│ Supabase Storage │
│ ════════════════ │
│ │
│ 📁 documents/ │
│ └── relatorio_trimestral.pdf │
│ │
│ (Arquivo salvo com segurança) │
└──────────────────────────────────┘
Passo 3: EXTRAIR CONTEÚDO
═════════════════════════
A IA lê o arquivo e extrai todo o conteúdo.
Para um PDF, isso significa:
• Todo texto de cada página
• Tabelas convertidas em texto estruturado
• Descrições de imagens e gráficos
📄 relatorio_trimestral.pdf
│
▼
┌────────────────────────────────┐
│ Google Gemini AI │
│ ═════════════════ │
│ │
│ "Vejo que este PDF tem 15 │
│ páginas. Página 1 é a capa...│
│ Página 4 tem tabela de │
│ receita..." │
│ │
│ SAÍDA: Todo texto extraído │
└────────────────────────────────┘
Passo 4: DIVIDIR O CONTEÚDO EM CHUNKS
═════════════════════════════════════
O texto extraído é dividido em pedaços menores chamados "chunks".
Por que chunks?
• Modelos de IA têm limites de quanto texto podem processar de uma vez
• Pedaços menores são mais fáceis de pesquisar
• Recuperamos apenas os chunks RELEVANTES, não o documento inteiro
Texto Completo do Documento (10.000 palavras)
│
▼
┌──────────────────────────────────────────────┐
│ Processo de Chunking │
│ ════════════════════ │
│ │
│ Dividido em pedaços de ~800 palavras │
│ com sobreposição │
│ │
│ Chunk 1: "Relatório Q3 2024. Resumo │
│ Executivo: Receita cresceu 15%..."│
│ │
│ Chunk 2: "...continuação do anterior. │
│ O mercado norte-americano..." │
│ │
│ Chunk 3: "...despesas diminuíram devido │
│ a eficiências operacionais..." │
│ │
│ (12 chunks no total) │
└──────────────────────────────────────────────┘
Passo 5: CRIAR EMBEDDINGS (A Mágica)
════════════════════════════════════
Cada chunk é convertido em números que representam seu significado.
O que são embeddings?
Computadores não entendem significado. Para um computador, "cachorro" e "cão"
são sequências de caracteres completamente diferentes, mesmo significando
a mesma coisa.
EMBEDDINGS convertem texto em números que capturam o significado:
┌────────────────────────────────────────────────────────────────────┐
│ │
│ "Eu amo cachorros" → [0.21, 0.85, 0.12, 0.53, 0.77, ...] │
│ (768 números) │
│ │
│ "Eu adoro filhotes" → [0.22, 0.84, 0.11, 0.55, 0.76, ...] │
│ (768 números - MUITO SIMILARES!) │
│ │
│ "Eu odeio vegetais" → [0.89, 0.12, 0.76, 0.23, 0.11, ...] │
│ (768 números - MUITO DIFERENTES!) │
│ │
└────────────────────────────────────────────────────────────────────┘
Note como "cachorros" e "filhotes" têm números similares? Isso porque
têm significados similares! É assim que a IA "entende" texto.
Por que 768 números?
É o tamanho que o modelo de embedding do Google usa. Mais números =
entendimento mais detalhado do significado. Pense nisso como coordenadas
em um espaço de 768 dimensões onde significados similares ficam próximos.
Passo 6: ARMAZENAR TUDO
═══════════════════════
Os chunks e seus embeddings são salvos no banco de dados.
┌──────────────────────────────────────────────────────────────────┐
│ Banco de Dados Supabase (PostgreSQL + pgvector) │
│ ════════════════════════════════════════════ │
│ │
│ tabela documents: │
│ ┌─────┬───────────────────────────┬────────┬───────────┐ │
│ │ id │ file_name │ status │ chunks │ │
│ ├─────┼───────────────────────────┼────────┼───────────┤ │
│ │ abc │ relatorio_trimestral.pdf │ pronto │ 12 │ │
│ └─────┴───────────────────────────┴────────┴───────────┘ │
│ │
│ tabela chunks: │
│ ┌─────┬─────────────────────┬───────────────────────────┐ │
│ │ id │ content │ content_vector │ │
│ ├─────┼─────────────────────┼───────────────────────────┤ │
│ │ 001 │ "Relatório Q3..." │ [0.21, 0.85, 0.12, ...] │ │
│ │ 002 │ "Norte-americano..."│ [0.33, 0.67, 0.45, ...] │ │
│ │ ... │ ... │ ... │ │
│ └─────┴─────────────────────┴───────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
Passo 7: FAZER UMA PERGUNTA
═══════════════════════════
Você digita: "Qual foi a receita do Q3?"
┌─────────────────────────┐
│ │
│ Sua Pergunta │
│ ═════════════ │
│ │
│ "Qual foi a │
│ receita do Q3?" │
│ │
└───────────┬─────────────┘
│
▼
Passo 8: CONVERTER PERGUNTA EM EMBEDDING
════════════════════════════════════════
Sua pergunta é convertida no mesmo formato de 768 números.
"Qual foi a receita do Q3?"
│
▼
┌────────────────────────────────────────┐
│ Modelo de Embedding Google Gemini │
│ ══════════════════════════════════ │
│ │
│ Entrada: "Qual foi a receita do Q3?" │
│ Saída: [0.19, 0.82, 0.15, 0.51, ...] │
│ (768 números) │
│ │
└────────────────────────────────────────┘
Passo 9: BUSCAR CHUNKS SIMILARES (Busca Vetorial)
═════════════════════════════════════════════════
Comparamos o embedding da sua pergunta com todos os embeddings dos chunks.
┌────────────────────────────────────────────────────────────────────┐
│ Busca por Similaridade Vetorial │
│ ═══════════════════════════════ │
│ │
│ Sua pergunta: [0.19, 0.82, 0.15, 0.51, ...] │
│ │
│ Comparar com cada chunk: │
│ │
│ Chunk 001: [0.21, 0.85, 0.12, 0.53, ...] │
│ Similaridade: 94% ✅ ALTA CORRESPONDÊNCIA! │
│ Conteúdo: "Receita Q3 2024 foi R$50 milhões..." │
│ │
│ Chunk 002: [0.33, 0.67, 0.45, 0.89, ...] │
│ Similaridade: 67% │
│ Conteúdo: "O departamento de marketing..." │
│ │
│ Chunk 003: [0.88, 0.12, 0.95, 0.11, ...] │
│ Similaridade: 23% │
│ Conteúdo: "Móveis do escritório foram trocados..." │
│ │
│ Resultado: Retornar os 5 chunks mais similares │
│ │
└────────────────────────────────────────────────────────────────────┘
Passo 10: GERAR RESPOSTA
════════════════════════
A IA lê os chunks relevantes e escreve uma resposta.
┌────────────────────────────────────────────────────────────────────┐
│ Google Gemini AI │
│ ═══════════════ │
│ │
│ PROMPT ENVIADO PARA IA: │
│ ════════════════════════ │
│ │
│ "Você é um assistente útil. Responda a pergunta do usuário │
│ baseado APENAS nas seguintes fontes. Cite suas fontes. │
│ │
│ FONTE 1: Receita Q3 2024 foi R$50 milhões, representando │
│ aumento de 15% em relação ao Q2... │
│ │
│ FONTE 2: A divisão por região mostra que América do Norte │
│ contribuiu R$30 milhões... │
│ │
│ PERGUNTA: Qual foi a receita do Q3?" │
│ │
│ RESPOSTA DA IA: │
│ ════════════════ │
│ │
│ "Baseado no Relatório Q3 2024, a receita foi R$50 milhões, │
│ um aumento de 15% em relação ao Q2 [Fonte 1]. América do Norte │
│ foi o maior contribuidor com R$30 milhões [Fonte 2]." │
│ │
└────────────────────────────────────────────────────────────────────┘
Passo 11: EXIBIR RESPOSTA COM FONTES
════════════════════════════════════
Você vê a resposta com referências de fonte clicáveis.
┌────────────────────────────────────────────────────────────────────┐
│ Interface de Chat │
│ ═════════════════ │
│ │
│ Você: Qual foi a receita do Q3? │
│ │
│ Assistente: Baseado no Relatório Q3 2024, a receita foi │
│ R$50 milhões, um aumento de 15% em relação ao Q2 [Fonte 1]. │
│ América do Norte foi o maior contribuidor com R$30 milhões │
│ [Fonte 2]. │
│ │
│ Fontes: │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ [1] relatorio_trimestral.pdf (94% correspondência) │ │
│ │ "Receita Q3 2024 foi R$50 milhões, representando..." │ │
│ ├────────────────────────────────────────────────────────────┤ │
│ │ [2] relatorio_trimestral.pdf (89% correspondência) │ │
│ │ "A divisão por região mostra América do Norte..." │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────┘
A maioria dos sistemas RAG só funciona com documentos de texto. O MegaRAG funciona com tudo:
| Tipo de Arquivo | O Que o MegaRAG Faz | Como Funciona |
|---|---|---|
| Extrai texto, tabelas, imagens | IA lê cada página e descreve conteúdo visual | |
| Word (.docx) | Extrai todo texto e formatação | Parser de documento extrai conteúdo |
| PowerPoint (.pptx) | Extrai conteúdo dos slides | Cada slide se torna texto pesquisável |
| Excel (.xlsx) | Extrai dados das células | Tabelas convertidas em texto pesquisável |
| Imagens | Descreve o que está na imagem | IA Vision analisa: "Um gráfico de barras mostrando vendas por região..." |
| Vídeos | Analisa conteúdo do vídeo ao longo do tempo | IA assiste em intervalos: "Aos 0:30, o apresentador discute..." |
| Áudio | Transcreve fala para texto | IA ouve e converte fala em texto pesquisável |
| Arquivos texto | Lê diretamente | Extração direta de texto |
Aqui está cada peça de tecnologia no MegaRAG e por que a usamos:
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ │
│ SEU NAVEGADOR WEB │
│ ═════════════════ │
│ │
│ O quê: Chrome, Firefox, Safari ou Edge │
│ Por quê: Você interage com o MegaRAG através de um app web │
│ │
│ Você vê: │
│ • Página de upload de documentos │
│ • Interface de chat │
│ • Resultados de busca │
│ │
└────────────────────────────────────────────┬────────────────────────────────────────┘
│
│ Requisições HTTP (como carregar página)
│
▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ │
│ APLICAÇÃO NEXT.JS │
│ ═════════════════ │
│ │
│ O quê: Um framework React que lida com frontend e backend │
│ Por quê: Uma base de código para tudo, ótima experiência de desenvolvimento │
│ │
│ ┌─────────────────────────────────┐ ┌─────────────────────────────────┐ │
│ │ FRONTEND (React) │ │ BACKEND (Rotas API) │ │
│ │ ═════════════════ │ │ ═════════════════════ │ │
│ │ │ │ │ │
│ │ • src/app/page.tsx │ │ • src/app/api/upload/ │ │
│ │ (Página inicial) │ │ (Gerencia uploads) │ │
│ │ │ │ │ │
│ │ • src/app/dashboard/ │ │ • src/app/api/query/ │ │
│ │ (Aplicação principal) │ │ (Gerencia perguntas) │ │
│ │ │ │ │ │
│ │ • src/components/ │ │ • src/app/api/documents/ │ │
│ │ (Partes de UI reutilizáveis) │ │ (Listar, deletar docs) │ │
│ │ │ │ │ │
│ │ Escrito em: TypeScript │ │ Escrito em: TypeScript │ │
│ │ Estilização: Tailwind CSS │ │ Roda em: Servidor Node.js │ │
│ └─────────────────────────────────┘ └─────────────────────────────────┘ │
│ │
└────────────┬────────────────────────────────────────────────────────┬───────────────┘
│ │
│ Queries do banco │ Chamadas API IA
│ Armazenamento de arquivos │
▼ ▼
┌─────────────────────────────────────────┐ ┌─────────────────────────────────────────┐
│ │ │ │
│ SUPABASE │ │ GOOGLE GEMINI │
│ ════════ │ │ ═════════════ │
│ │ │ │
│ O quê: "Backend as a Service" │ │ O quê: Modelo de IA do Google │
│ Por quê: Não precisamos gerenciar │ │ Por quê: Melhor custo-benefício │
│ servidores │ │ │
│ │ │ Fornece: │
│ Fornece: │ │ ┌───────────────────────────────┐ │
│ ┌───────────────────────────────┐ │ │ │ Entendimento de Texto │ │
│ │ Banco PostgreSQL │ │ │ │ ════════════════════ │ │
│ │ ════════════════ │ │ │ │ │ │
│ │ │ │ │ │ • Ler e entender PDFs │ │
│ │ Armazena todos os dados: │ │ │ │ • Descrever imagens │ │
│ │ • Metadados de documentos │ │ │ │ • Analisar conteúdo vídeo │ │
│ │ • Chunks de texto │ │ │ │ • Transcrever áudio │ │
│ │ • Embeddings (vetores) │ │ │ │ • Gerar respostas │ │
│ │ • Entidades e relações │ │ │ │ │ │
│ │ • Histórico de chat │ │ │ ├───────────────────────────────┤ │
│ │ │ │ │ │ Geração de Embedding │ │
│ │ Com extensão pgvector: │ │ │ │ ══════════════════════ │ │
│ │ • Armazena vetores 768-dim │ │ │ │ │ │
│ │ • Busca rápida por similar. │ │ │ │ • Converte texto em números │ │
│ │ │ │ │ │ • Vetores 768 dimensões │ │
│ ├───────────────────────────────┤ │ │ │ • Entendimento semântico │ │
│ │ Armazenamento de Arquivos │ │ │ │ │ │
│ │ ═══════════════════════ │ │ │ ├───────────────────────────────┤ │
│ │ │ │ │ │ File API │ │
│ │ Armazena arquivos originais:│ │ │ │ ════════ │ │
│ │ • PDFs │ │ │ │ │ │
│ │ • Vídeos │ │ │ │ • Upload arquivos grandes │ │
│ │ • Imagens │ │ │ │ • Processa vídeos (até 1GB) │ │
│ │ • Áudio │ │ │ │ • Processa áudio │ │
│ └───────────────────────────────┘ │ │ └───────────────────────────────┘ │
│ │ │ │
│ Tier grátis: 500MB banco, 1GB storage │ │ Tier grátis: 15 req/min, 1M tokens/dia│
│ │ │ │
└─────────────────────────────────────────┘ └─────────────────────────────────────────┘
PostgreSQL (o banco de dados) é ótimo para armazenar e buscar dados normais. Mas não suporta nativamente busca por similaridade.
Por exemplo, busca normal em banco:
-- Encontra correspondência exata: só retorna "Contrato Smith"
SELECT * FROM documents WHERE name = 'Contrato Smith';Mas com embeddings, precisamos de busca por similaridade:
-- Encontra documentos SIMILARES a "acordo Smith"
-- Deveria retornar: "Contrato Smith", "Acordo J. Smith", "Contrato com Smith Inc."
SELECT * FROM documents
ORDER BY embedding <=> query_embedding -- Encontra mais similares
LIMIT 5;pgvector é uma extensão que adiciona essa capacidade:
- Tipo de dado
VECTOR(768): Armazena vetores de 768 dimensões - Operador
<=>: Calcula distância cosseno entre vetores - Índice
HNSW: Torna busca por similaridade rápida (sem ele, compararíamos com cada linha)
HNSW significa "Hierarchical Navigable Small World" (Mundo Pequeno Navegável Hierárquico).
Sem entrar muito em detalhes técnicos, é uma forma de organizar vetores para encontrar similares rapidamente:
Sem HNSW (lento):
══════════════════
Embedding da pergunta: [0.1, 0.2, 0.3, ...]
Comparar com chunk 1... 45% similar
Comparar com chunk 2... 23% similar
Comparar com chunk 3... 87% similar ← Encontrou um bom!
Comparar com chunk 4... 12% similar
Comparar com chunk 5... 67% similar
... comparar com TODOS os 10.000 chunks (lento!)
Com HNSW (rápido):
══════════════════
Embedding da pergunta: [0.1, 0.2, 0.3, ...]
Começa em ponto aleatório, pula para vizinhos mais próximos:
Chunk 500 (45%) → Chunk 234 (67%) → Chunk 891 (89%) → Encontrado!
Só comparou ~50 chunks em vez de 10.000 (rápido!)
Quando comparamos dois embeddings, usamos "similaridade de cosseno":
Vetor A: [0.5, 0.5] (apontando nordeste)
Vetor B: [0.6, 0.7] (também apontando nordeste-ish)
Vetor C: [-0.5, 0.5] (apontando noroeste)
Similaridade de cosseno mede o ÂNGULO entre vetores:
A e B: Ângulo pequeno = ALTA similaridade (0.98)
A e C: Ângulo grande = BAIXA similaridade (0.0)
B
/
/
/ ângulo pequeno
/
A────────────
\
\ ângulo grande
\
C
Isso funciona independente do "comprimento" dos vetores,
o que é perfeito para comparar embeddings de texto.
Antes de poder rodar o MegaRAG, você precisa configurar algumas coisas. Esta seção guia você por cada uma.
O que é Node.js? Node.js permite que seu computador execute JavaScript fora de um navegador web. Como o MegaRAG é construído com JavaScript/TypeScript, você precisa do Node.js para rodá-lo.
Como instalar Node.js:
Opção A: Baixar do Site (Mais Fácil)
- Vá para nodejs.org
- Você verá dois botões de download:
- LTS (Long Term Support) - Escolha este!
- Current - Tem recursos mais novos mas menos estável
- Clique no botão LTS para baixar
- Execute o instalador:
- Windows: Dê duplo clique no arquivo
.msi, clique Próximo pelo assistente - Mac: Dê duplo clique no arquivo
.pkg, siga os prompts
- Windows: Dê duplo clique no arquivo
- Reinicie seu terminal/prompt de comando
Opção B: Usando nvm (Recomendado para desenvolvedores)
nvm (Node Version Manager) permite trocar facilmente entre versões do Node.js.
Mac/Linux:
# Instalar nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# Reinicie o terminal, depois instale Node.js
nvm install 18
nvm use 18Windows: Baixe e instale nvm-windows
Verificar se Node.js está instalado:
Abra Terminal (Mac) ou Prompt de Comando (Windows) e execute:
node --versionO que você deve ver:
v18.17.0
(ou qualquer versão 18.x ou superior)
Se você ver um erro:
- "node is not recognized" - Node.js não está instalado ou não está no seu PATH
- Tente reiniciar seu terminal
- Se usar Windows, certifique-se de reiniciar o Prompt de Comando após instalação
O que é Git? Git é uma ferramenta que permite baixar código do GitHub e rastrear alterações no seu próprio código.
Como instalar Git:
Windows
- Vá para git-scm.com/download/windows
- O download deve começar automaticamente
- Execute o instalador com configurações padrão (continue clicando Próximo)
Mac
Git vem pré-instalado na maioria dos Macs. Se não:
# Usando Homebrew (se você tiver)
brew install git
# Ou será solicitada instalação do Xcode Command Line Tools
git --versionLinux
# Ubuntu/Debian
sudo apt-get install git
# Fedora
sudo dnf install gitVerificar se Git está instalado:
git --versionO que você deve ver:
git version 2.39.0
(ou qualquer versão 2.x)
O que é Supabase? Supabase é um "Backend as a Service" que fornece:
- Um banco PostgreSQL (onde armazenamos todos os dados)
- Armazenamento de arquivos (onde armazenamos documentos enviados)
- Geração automática de API
- Extensão pgvector (para busca semântica)
Por que Supabase?
- Tier grátis é muito generoso (500MB banco, 1GB armazenamento)
- Serviço gerenciado (você não precisa configurar servidores)
- Tem pgvector pré-instalado
- Dashboard fácil de usar
Como criar uma conta Supabase:
- Vá para supabase.com
- Clique "Start your project" (canto superior direito)
- Clique "Sign up with GitHub" (mais fácil) ou use email
- Se usar GitHub:
- Clique "Authorize Supabase"
- Pode ser necessário verificar seu email
- Você chegará no Dashboard do Supabase
- Não crie um projeto ainda - faremos isso nos passos de configuração
O que você deve ver: O Dashboard do Supabase com um botão "New project".
O que é a Google AI API? É como acessamos os modelos Gemini AI do Google programaticamente. Gemini é a IA que:
- Lê e entende seus documentos
- Cria embeddings (os vetores de 768 números)
- Gera respostas para suas perguntas
Por que Gemini?
- Excelente qualidade pelo preço
- Pode lidar com imagens, vídeo e áudio
- Tier grátis generoso (15 requisições/minuto, 1 milhão tokens/dia)
- Fácil de configurar
Como obter uma chave API Google AI:
- Vá para aistudio.google.com/apikey
- Faça login com sua conta Google (Gmail)
- Pode aparecer uma tela de boas-vindas - clique para continuar
- Clique "Create API key"
- Clique "Create API key in new project" (ou selecione projeto existente)
- Copie a chave API imediatamente!
- Começa com
AIza - Tem cerca de 40 caracteres
- Exemplo:
AIzaSyC1234567890abcdefghijklmnopqrstuvwx
- Começa com
- Salve esta chave em lugar seguro (app de Notas, gerenciador de senhas, etc.)
- Você não poderá ver novamente no dashboard do Google
- Se perder, precisará criar uma nova
O que você deve ver: Uma página mostrando sua chave API com botão "Copy".
Notas importantes:
- Esta chave é secreta - não compartilhe publicamente nem faça commit no GitHub
- O tier grátis tem limites, mas são generosos para uso pessoal
- Se atingir limites de taxa, espere um minuto e tente novamente
Antes de prosseguir, certifique-se de ter:
- Node.js instalado (execute
node --versionpara verificar) - Git instalado (execute
git --versionpara verificar) - Conta Supabase criada (você deve ver o dashboard)
- Chave API Google AI copiada e salva em lugar seguro
Agora vamos configurar tudo. Siga estes passos na ordem.
O que é um terminal? Um terminal (também chamado linha de comando ou prompt de comando) é uma interface baseada em texto para seu computador. Em vez de clicar botões, você digita comandos.
Como abrir o terminal:
- Mac: Pressione
Cmd + Espaço, digite "Terminal", pressione Enter - Windows: Pressione
Win + R, digite "cmd", pressione Enter (ou busque "Prompt de Comando" ou "PowerShell") - Linux: Pressione
Ctrl + Alt + T
Você deve ver uma janela com um cursor piscando, algo como:
seu-usuario@seu-computador ~ %
Quando você baixa código, ele vai para sua pasta atual. Vamos colocar em algum lugar adequado.
Opção A: Usar seu diretório home (mais simples)
# Ir para seu diretório home
cd ~Opção B: Usar uma pasta específica
# Exemplo: Colocar em uma pasta "Projetos"
cd ~/Projetos
# Se a pasta Projetos não existir, crie primeiro:
mkdir -p ~/Projetos
cd ~/ProjetosComo verificar onde você está:
pwdIsso imprime seu diretório atual. Você deve ver algo como:
- Mac:
/Users/seunomeou/Users/seunome/Projetos - Windows:
C:\Users\seunomeouC:\Users\seunome\Projetos
"Clonar" significa baixar uma cópia do código do GitHub.
git clone https://github.com/inematds/MegaRAG.gitO que você deve ver:
Cloning into 'MegaRAG'...
remote: Enumerating objects: 150, done.
remote: Counting objects: 100% (150/150), done.
remote: Compressing objects: 100% (100/100), done.
remote: Total 150 (delta 45), reused 140 (delta 35)
Receiving objects: 100% (150/150), 250.00 KiB | 2.50 MiB/s, done.
Resolving deltas: 100% (45/45), done.
Se você ver um erro:
git: command not found- Git não está instalado. Volte aos Pré-requisitos.Repository not found- Verifique erros de digitação na URLPermission denied- Pode ser necessário autenticar no GitHub
cd MegaRAGAgora você está dentro da pasta do projeto. Verifique:
pwdDeve mostrar: /Users/seunome/MegaRAG ou similar
Projetos JavaScript usam "pacotes" (bibliotecas de código pré-escritas) para tarefas comuns. O arquivo package.json lista todos os pacotes que o MegaRAG precisa. O comando npm install baixa todos eles.
npm installO que você deve ver:
npm warn deprecated some-package@1.0.0: ...
(Alguns avisos são normais, não se preocupe)
added 285 packages, and audited 286 packages in 15s
72 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Se você ver erros:
npm: command not found- Node.js não está instalado corretamenteEACCES: permission denied- No Mac/Linux, tente:sudo npm install- Erros de rede - Verifique sua conexão de internet
O que acabou de acontecer?
- npm leu
package.jsonpara ver quais pacotes precisamos - Baixou ~285 pacotes para uma pasta chamada
node_modules - Esta pasta é grande (~200MB) mas você nunca precisa olhar dentro
Vamos garantir que tudo foi baixado corretamente:
ls -laO que você deve ver:
drwxr-xr-x node_modules/
drwxr-xr-x public/
drwxr-xr-x src/
-rw-r--r-- .env.example
-rw-r--r-- .gitignore
-rw-r--r-- next.config.mjs
-rw-r--r-- package.json
-rw-r--r-- package-lock.json
-rw-r--r-- README.md
-rw-r--r-- tsconfig.json
...
Se você não vir node_modules, execute npm install novamente.
- Abra seu navegador
- Vá para supabase.com
- Clique "Dashboard" (canto superior direito) ou faça login
- Clique o grande botão "New project"
- Preencha o formulário:
- Organization: Selecione sua organização pessoal (ou crie uma)
- Name:
megarag(ou qualquer nome que goste) - Database Password: Clique "Generate a password"
- IMPORTANTE: Copie esta senha e salve em algum lugar! Você não verá novamente.
- Region: Escolha a mais próxima de você
- Se você está no Brasil:
sa-east-1 - Se está nos EUA:
us-east-1ouus-west-1 - Se está na Europa:
eu-west-1oueu-central-1
- Se você está no Brasil:
- Pricing Plan: Tier grátis está bom
- Clique "Create new project"
- Espere 2-3 minutos enquanto o Supabase configura seu banco
O que você deve ver: Uma tela de progresso dizendo "Setting up project..." seguida do Dashboard do Projeto.
Uma vez que seu projeto está pronto:
- Clique no ícone Settings (engrenagem ⚙️) na barra lateral esquerda
- Clique API em "Project Settings"
- Você verá uma página com suas credenciais
Encontre e copie estes três valores:
| Campo | Onde encontrar | Como parece |
|---|---|---|
| Project URL | Em "Project URL" | https://abcd1234.supabase.co |
| anon public | Em "Project API keys" | eyJhbGciOiJIUzI1... (JWT mais curto) |
| service_role | Em "Project API keys" (clique "Reveal") | eyJhbGciOiJIUzI1... (JWT mais longo) |
IMPORTANTE:
- Mantenha a chave service_role SECRETA. Ela tem acesso total ao banco.
- A chave anon é segura para usar no código do navegador (tem permissões limitadas)
Anote ou cole em um app de notas. Você precisará em breve.
Agora precisamos criar as tabelas e funções que o MegaRAG usa.
- No Dashboard do Supabase, clique SQL Editor na barra lateral esquerda
- Você verá uma janela de query em branco
- É aqui que executaremos comandos SQL
Como executar SQL no Supabase:
- Copie o código SQL abaixo
- Cole no Editor SQL
- Clique o botão verde "Run" (ou pressione Cmd/Ctrl + Enter)
- Verifique a mensagem de sucesso na parte inferior
- Repita para o próximo bloco SQL
Execute estes comandos SQL na ordem:
-- ═══════════════════════════════════════════════════════════════════════════════
-- Habilitar extensão pgvector
-- ═══════════════════════════════════════════════════════════════════════════════
--
-- O que isso faz:
-- pgvector é uma extensão PostgreSQL que nos permite armazenar e buscar embeddings
-- (aqueles arrays de 768 números que representam significado). Sem esta extensão,
-- PostgreSQL não saberia o que fazer com dados vetoriais.
--
-- O que acontece:
-- Após executar, PostgreSQL ganha novas capacidades:
-- • Tipo de dado VECTOR(768) - pode armazenar arrays de 768 números de ponto flutuante
-- • Operador <=> - pode calcular distância entre dois vetores
-- • Tipo de índice HNSW - pode criar índices de busca por similaridade rápidos
CREATE EXTENSION IF NOT EXISTS vector;O que você deve ver:
Success. No rows returned
-- ═══════════════════════════════════════════════════════════════════════════════
-- Criar tabela documents
-- ═══════════════════════════════════════════════════════════════════════════════
--
-- O que isso faz:
-- Esta tabela armazena metadados sobre cada arquivo enviado. Pense nela como o
-- "catálogo de fichas" que rastreia quais arquivos existem e seu status de processamento.
--
-- O que cada coluna significa:
-- • id: Um identificador único para cada documento (geramos isso)
-- • file_name: O nome original do arquivo como "relatorio_trimestral.pdf"
-- • file_type: A extensão como "pdf", "mp4", "png"
-- • file_size: O tamanho do arquivo em bytes
-- • file_path: Onde o arquivo está armazenado no Supabase Storage
-- • status: Onde estamos no processamento: pending → processing → processed → (ou failed)
-- • chunks_count: Quantos chunks de texto foram criados deste documento
-- • error_message: Se o processamento falhou, o que deu errado
-- • metadata: Campo JSON flexível para dados extras
-- • created_at/updated_at: Quando o registro foi criado/modificado
CREATE TABLE IF NOT EXISTS documents (
id VARCHAR(255) PRIMARY KEY,
workspace VARCHAR(255) DEFAULT 'default',
file_name VARCHAR(1024) NOT NULL,
file_type VARCHAR(50) NOT NULL,
file_size BIGINT,
file_path TEXT,
status VARCHAR(64) DEFAULT 'pending',
chunks_count INTEGER DEFAULT 0,
error_message TEXT,
metadata JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Índices tornam queries mais rápidas pré-organizando os dados
-- Pense neles como o índice no final de um livro
CREATE INDEX IF NOT EXISTS idx_documents_status ON documents(status);
CREATE INDEX IF NOT EXISTS idx_documents_file_type ON documents(file_type);
CREATE INDEX IF NOT EXISTS idx_documents_created_at ON documents(created_at);O que você deve ver:
Success. No rows returned
-- ═══════════════════════════════════════════════════════════════════════════════
-- Criar tabela chunks
-- ═══════════════════════════════════════════════════════════════════════════════
--
-- O que isso faz:
-- Esta é a tabela MAIS IMPORTANTE. Ela armazena o conteúdo real dos seus
-- documentos, dividido em pedaços pesquisáveis, junto com seus embeddings.
--
-- Por que "chunks"?
-- Documentos podem ser muito longos (100+ páginas). Não podemos pesquisar a coisa
-- toda de uma vez. Em vez disso, dividimos em pedaços menores (~800 palavras cada) e
-- pesquisamos esses. Quando você faz uma pergunta, encontramos os chunks mais
-- relevantes, não documentos inteiros.
--
-- O que cada coluna significa:
-- • id: Identificador único para este chunk
-- • document_id: De qual documento este chunk veio (liga à tabela documents)
-- • chunk_order_index: A ordem deste chunk (1º, 2º, 3º pedaço do doc)
-- • content: O conteúdo de texto real deste chunk
-- • content_vector: O embedding - 768 números representando o significado
-- • tokens: Quantos tokens (aproximadamente palavras) estão neste chunk
-- • chunk_type: Que tipo de conteúdo: text, image, table, video_segment, audio
-- • page_idx: De qual página isso veio (para PDFs)
-- • timestamp_start/end: Intervalo de tempo (para vídeo/áudio)
--
-- A cláusula REFERENCES cria uma "chave estrangeira":
-- • Significa que document_id DEVE existir na tabela documents
-- • ON DELETE CASCADE significa: se deletarmos um documento, deletamos seus chunks também
CREATE TABLE IF NOT EXISTS chunks (
id VARCHAR(255) PRIMARY KEY,
workspace VARCHAR(255) DEFAULT 'default',
document_id VARCHAR(255) REFERENCES documents(id) ON DELETE CASCADE,
chunk_order_index INTEGER,
content TEXT NOT NULL,
content_vector VECTOR(768),
tokens INTEGER,
chunk_type VARCHAR(50) DEFAULT 'text',
page_idx INTEGER,
timestamp_start FLOAT,
timestamp_end FLOAT,
metadata JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Índice para encontrar rapidamente todos os chunks de um documento
CREATE INDEX IF NOT EXISTS idx_chunks_document_id ON chunks(document_id);
CREATE INDEX IF NOT EXISTS idx_chunks_type ON chunks(chunk_type);
-- Índice HNSW para busca rápida por similaridade vetorial
-- Esta é a mágica que torna a busca semântica rápida
-- Sem ele, teríamos que comparar cada chunk (lento!)
-- Com ele, podemos encontrar chunks similares em milissegundos
--
-- Parâmetros:
-- • vector_cosine_ops: Usa similaridade de cosseno (mede ângulo entre vetores)
-- • m = 16: Número de conexões por nó (maior = mais preciso, mais memória)
-- • ef_construction = 64: Qualidade de construção (maior = melhor índice, construção mais lenta)
CREATE INDEX IF NOT EXISTS idx_chunks_vector ON chunks
USING hnsw (content_vector vector_cosine_ops) WITH (m = 16, ef_construction = 64);O que você deve ver:
Success. No rows returned
-- ═══════════════════════════════════════════════════════════════════════════════
-- Criar tabela entities
-- ═══════════════════════════════════════════════════════════════════════════════
--
-- O que isso faz:
-- Esta tabela armazena "entidades" extraídas dos seus documentos. Entidades são
-- coisas notáveis como pessoas, empresas, lugares, conceitos, etc.
--
-- Por que entidades?
-- Entidades permitem busca mais inteligente. Em vez de apenas encontrar texto
-- que corresponde à sua query, podemos entender SOBRE O QUE você está perguntando.
--
-- Exemplo:
-- Documento menciona "Tim Cook" múltiplas vezes em diferentes chunks.
-- Criamos UMA entidade para "Tim Cook" com tipo "PERSON" e descrição
-- como "CEO da Apple Inc., mencionado no contexto de anúncios de produtos."
--
-- O que cada coluna significa:
-- • id: Identificador único
-- • entity_name: O nome como "Tim Cook" ou "Apple Inc."
-- • entity_type: Categoria: PERSON, ORGANIZATION, LOCATION, EVENT, CONCEPT, etc.
-- • description: Contexto sobre esta entidade dos documentos
-- • content_vector: Embedding da descrição (para busca semântica)
-- • source_chunk_ids: Quais chunks mencionam esta entidade (array JSON)
CREATE TABLE IF NOT EXISTS entities (
id VARCHAR(255) PRIMARY KEY,
workspace VARCHAR(255) DEFAULT 'default',
entity_name VARCHAR(512) NOT NULL,
entity_type VARCHAR(128),
description TEXT,
content_vector VECTOR(768),
source_chunk_ids JSONB DEFAULT '[]'::jsonb,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_entities_name ON entities(entity_name);
CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(entity_type);
CREATE INDEX IF NOT EXISTS idx_entities_vector ON entities
USING hnsw (content_vector vector_cosine_ops) WITH (m = 16, ef_construction = 64);O que você deve ver:
Success. No rows returned
-- ═══════════════════════════════════════════════════════════════════════════════
-- Criar tabela relations
-- ═══════════════════════════════════════════════════════════════════════════════
--
-- O que isso faz:
-- Esta tabela armazena RELACIONAMENTOS entre entidades. Isso é o que faz
-- do MegaRAG um sistema de "grafo de conhecimento".
--
-- Exemplos de relacionamentos:
-- • "Tim Cook" --[CEO_DE]--> "Apple Inc."
-- • "iPhone 15" --[FABRICADO_POR]--> "Apple Inc."
-- • "WWDC 2024" --[SEDIADO_POR]--> "Apple Inc."
--
-- Por que relacionamentos?
-- Eles permitem queries complexas que seguem conexões:
-- P: "Quem lidera empresas que fazem smartphones?"
-- → Encontrar entidades "smartphone"
-- → Encontrar relacionamentos onde smartphones são alvos
-- → Encontrar entidades fonte com relacionamentos "CEO" ou "lidera"
-- → Retornar essas pessoas
--
-- O que cada coluna significa:
-- • source_entity_id: A entidade onde o relacionamento começa ("Tim Cook")
-- • target_entity_id: A entidade para onde o relacionamento aponta ("Apple Inc.")
-- • relation_type: O tipo de relacionamento ("CEO_DE")
-- • description: Mais contexto sobre este relacionamento
-- • content_vector: Embedding para busca semântica em relacionamentos
CREATE TABLE IF NOT EXISTS relations (
id VARCHAR(255) PRIMARY KEY,
workspace VARCHAR(255) DEFAULT 'default',
source_entity_id VARCHAR(512),
target_entity_id VARCHAR(512),
relation_type VARCHAR(256),
description TEXT,
content_vector VECTOR(768),
source_chunk_ids JSONB DEFAULT '[]'::jsonb,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_relations_source ON relations(source_entity_id);
CREATE INDEX IF NOT EXISTS idx_relations_target ON relations(target_entity_id);
CREATE INDEX IF NOT EXISTS idx_relations_type ON relations(relation_type);
CREATE INDEX IF NOT EXISTS idx_relations_vector ON relations
USING hnsw (content_vector vector_cosine_ops) WITH (m = 16, ef_construction = 64);O que você deve ver:
Success. No rows returned
-- ═══════════════════════════════════════════════════════════════════════════════
-- Criar tabelas de sessão de chat e mensagens
-- ═══════════════════════════════════════════════════════════════════════════════
--
-- O que isso faz:
-- Estas tabelas armazenam seu histórico de conversas para que você possa ter
-- chats de múltiplos turnos e voltar a conversas anteriores.
--
-- chat_sessions: Uma linha por thread de conversa
-- chat_messages: Uma linha por mensagem (tanto perguntas do usuário quanto respostas da IA)
CREATE TABLE IF NOT EXISTS chat_sessions (
id VARCHAR(255) PRIMARY KEY,
workspace VARCHAR(255) DEFAULT 'default',
title VARCHAR(512) DEFAULT 'Novo Chat',
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS chat_messages (
id VARCHAR(255) PRIMARY KEY,
session_id VARCHAR(255) REFERENCES chat_sessions(id) ON DELETE CASCADE,
role VARCHAR(50) NOT NULL, -- 'user' ou 'assistant'
content TEXT NOT NULL,
sources JSONB DEFAULT '[]'::jsonb, -- Referências de fonte para respostas da IA
metadata JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_chat_sessions_updated ON chat_sessions(updated_at);
CREATE INDEX IF NOT EXISTS idx_chat_messages_session ON chat_messages(session_id);O que você deve ver:
Success. No rows returned
-- ═══════════════════════════════════════════════════════════════════════════════
-- Criar tabela de cache LLM
-- ═══════════════════════════════════════════════════════════════════════════════
--
-- O que isso faz:
-- Faz cache de respostas da IA para evitar chamar a API repetidamente para a mesma pergunta.
-- Se você perguntar "Qual foi a receita do Q3?" duas vezes, retornamos a resposta em cache
-- instantaneamente em vez de pagar por outra chamada de API.
--
-- Entradas de cache expiram após 24 horas por padrão (configurável).
CREATE TABLE IF NOT EXISTS llm_cache (
id VARCHAR(255) PRIMARY KEY,
prompt_hash VARCHAR(64) NOT NULL, -- Hash do prompt completo
response TEXT NOT NULL, -- A resposta da IA em cache
model VARCHAR(128), -- Qual modelo gerou isso
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX IF NOT EXISTS idx_llm_cache_hash ON llm_cache(prompt_hash);
CREATE INDEX IF NOT EXISTS idx_llm_cache_expires ON llm_cache(expires_at);O que você deve ver:
Success. No rows returned
-- ═══════════════════════════════════════════════════════════════════════════════
-- Criar funções de busca
-- ═══════════════════════════════════════════════════════════════════════════════
--
-- O que fazem:
-- Estas são funções reutilizáveis que executam busca por similaridade. Em vez de
-- escrever queries SQL complexas no nosso código, chamamos estas funções.
--
-- Como funcionam:
-- 1. Recebem um query_embedding (sua pergunta convertida em 768 números)
-- 2. Encontram linhas onde o embedding é similar (acima de match_threshold)
-- 3. Retornam as mais similares (até match_count)
--
-- O operador <=> calcula distância de cosseno:
-- • 0 = vetores idênticos
-- • 2 = vetores opostos
-- Convertemos para similaridade fazendo: 1 - distância
-- Então similaridade de 0.9 significa 90% similar
-- Buscar chunks por similaridade semântica
CREATE OR REPLACE FUNCTION search_chunks(
query_embedding VECTOR(768),
match_threshold FLOAT DEFAULT 0.3,
match_count INT DEFAULT 10
) RETURNS TABLE (
id VARCHAR,
document_id VARCHAR,
content TEXT,
chunk_type VARCHAR,
similarity FLOAT
) LANGUAGE plpgsql AS $$
BEGIN
RETURN QUERY
SELECT
c.id,
c.document_id,
c.content,
c.chunk_type,
(1 - (c.content_vector <=> query_embedding))::FLOAT AS similarity
FROM chunks c
WHERE c.content_vector IS NOT NULL
AND 1 - (c.content_vector <=> query_embedding) > match_threshold
ORDER BY c.content_vector <=> query_embedding
LIMIT match_count;
END;
$$;
-- Buscar entidades por similaridade semântica
CREATE OR REPLACE FUNCTION search_entities(
query_embedding VECTOR(768),
match_threshold FLOAT DEFAULT 0.3,
match_count INT DEFAULT 20
) RETURNS TABLE (
id VARCHAR,
entity_name VARCHAR,
entity_type VARCHAR,
description TEXT,
similarity FLOAT
) LANGUAGE plpgsql AS $$
BEGIN
RETURN QUERY
SELECT
e.id,
e.entity_name,
e.entity_type,
e.description,
(1 - (e.content_vector <=> query_embedding))::FLOAT AS similarity
FROM entities e
WHERE e.content_vector IS NOT NULL
AND 1 - (e.content_vector <=> query_embedding) > match_threshold
ORDER BY e.content_vector <=> query_embedding
LIMIT match_count;
END;
$$;
-- Buscar relações por similaridade semântica
CREATE OR REPLACE FUNCTION search_relations(
query_embedding VECTOR(768),
match_threshold FLOAT DEFAULT 0.3,
match_count INT DEFAULT 20
) RETURNS TABLE (
id VARCHAR,
source_entity_id VARCHAR,
target_entity_id VARCHAR,
relation_type VARCHAR,
description TEXT,
similarity FLOAT
) LANGUAGE plpgsql AS $$
BEGIN
RETURN QUERY
SELECT
r.id,
r.source_entity_id,
r.target_entity_id,
r.relation_type,
r.description,
(1 - (r.content_vector <=> query_embedding))::FLOAT AS similarity
FROM relations r
WHERE r.content_vector IS NOT NULL
AND 1 - (r.content_vector <=> query_embedding) > match_threshold
ORDER BY r.content_vector <=> query_embedding
LIMIT match_count;
END;
$$;O que você deve ver:
Success. No rows returned
Vamos garantir que tudo funcionou. Execute este SQL:
-- Listar todas as tabelas que acabamos de criar
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
ORDER BY table_name;O que você deve ver:
table_name
-----------
chat_messages
chat_sessions
chunks
documents
entities
llm_cache
relations
Se alguma estiver faltando, volte e execute aquele comando SQL novamente.
O banco armazena texto e metadados. Mas os arquivos reais (PDFs, vídeos, etc.) precisam ir para outro lugar. Supabase Storage é esse lugar.
- No Dashboard do Supabase, clique Storage na barra lateral esquerda
- Clique o botão "New bucket"
- Preencha o formulário:
- Name:
documents(exatamente assim, minúsculo) - Public bucket: Deixe OFF (queremos privado)
- Allowed MIME types: Deixe vazio (permitir todos os tipos)
- File size limit:
104857600(isso é 100MB em bytes)
- Name:
- Clique "Create bucket"
O que você deve ver: Um novo bucket chamado "documents" na sua lista de armazenamento.
Agora precisamos dizer ao MegaRAG como conectar ao Supabase e Gemini.
Volte para seu terminal (certifique-se de estar na pasta megarag):
# Criar .env.local copiando o exemplo
cp .env.example .env.localO que isso faz:
Cria um novo arquivo chamado .env.local que é uma cópia de .env.example. A parte .local diz ao Git para ignorar este arquivo (para você não commitar acidentalmente seus segredos).
Abra .env.local em um editor de texto:
Usando VS Code (recomendado):
code .env.localUsando nano (editor de terminal):
nano .env.localNo Windows, você pode:
notepad .env.localSubstitua os valores placeholder pelas suas credenciais reais:
# ═══════════════════════════════════════════════════════════════════════════════
# CONFIGURAÇÃO SUPABASE
# ═══════════════════════════════════════════════════════════════════════════════
#
# Obtenha estes de: Dashboard Supabase → Settings → API
#
# Sua URL do projeto parece: https://abcdefghijkl.supabase.co
# A parte "abcdefghijkl" é o ID único do seu projeto
NEXT_PUBLIC_SUPABASE_URL=https://seu-project-id.supabase.co
# A chave "anon" é segura para expor no código do navegador
# Ela tem permissões limitadas baseadas em regras de Row Level Security
# Encontre em "Project API keys" → "anon public"
NEXT_PUBLIC_SUPABASE_ANON_KEY=sua-chave-anon-aqui
# A chave "service role" é SECRETA - nunca exponha publicamente!
# Ela ignora todas as regras de segurança - use apenas no servidor
# Encontre em "Project API keys" → "service_role" (clique "Reveal")
SUPABASE_SERVICE_ROLE_KEY=sua-chave-service-role-aqui
# ═══════════════════════════════════════════════════════════════════════════════
# CONFIGURAÇÃO GOOGLE AI
# ═══════════════════════════════════════════════════════════════════════════════
#
# Obtenha de: aistudio.google.com/apikey
# Começa com "AIza" e tem cerca de 40 caracteres
GOOGLE_AI_API_KEY=AIzaSySuaChaveApiAquiVamos garantir que os valores estão definidos. Execute:
# Isso deve imprimir sua URL do Supabase (não um placeholder)
grep "NEXT_PUBLIC_SUPABASE_URL" .env.localO que você deve ver:
NEXT_PUBLIC_SUPABASE_URL=https://abcd1234.supabase.co
(Com seu ID de projeto real, não "abcd1234")
Erros comuns:
- Não inclua aspas ao redor dos valores
- Não adicione espaços ao redor do sinal
= - Certifique-se de não haver espaços no final
- A URL deve começar com
https://
npm run devO que você deve ver:
▲ Next.js 14.2.x
- Local: http://localhost:3000
- Environments: .env.local
✓ Starting...
✓ Ready in 2.3s
Se você ver erros:
Port 3000 is in use: Outro app está usando a porta 3000. Feche-o ou rode o MegaRAG em porta diferente:npm run dev -- -p 3001Missing environment variables: Verifique seu arquivo.env.localModule not found: Executenpm installnovamente
- Abra seu navegador web (Chrome, Firefox, Safari, Edge)
- Vá para: http://localhost:3000
O que você deve ver: A página inicial do MegaRAG com um botão "Get Started".
- Clique "Get Started" ou vá para http://localhost:3000/dashboard
O que você deve ver: O Dashboard com:
- Uma área de upload à direita
- Uma lista de documentos vazia à esquerda
- Um link "Chat" na barra lateral
Vamos testar o fluxo completo:
-
Faça upload de um arquivo de teste:
- Baixe qualquer PDF simples ou crie um arquivo de texto
- Arraste e solte na área de upload
- Você deve vê-lo aparecer na lista de documentos com status "Processing"
-
Espere o processamento:
- O status deve mudar para "Ready" (✓) após 10-60 segundos
- Se disser "Failed", verifique os logs do Supabase por erros
-
Teste o chat:
- Clique "Chat" na barra lateral
- Digite uma pergunta sobre seu documento
- Você deve receber uma resposta com citações de fonte
Parabéns! O MegaRAG está rodando! 🎉
Esta é sua base para gerenciar documentos.
Método 1: Arrastar e Soltar
- Encontre um arquivo no seu computador
- Arraste-o para a área de upload
- Solte para fazer upload
Método 2: Clicar para Navegar
- Clique na área de upload
- Selecione um arquivo no diálogo
- Clique "Abrir" para fazer upload
Método 3: Upload em Massa
- Selecione múltiplos arquivos (Ctrl/Cmd + clique)
- Arraste todos de uma vez
- Eles serão processados em paralelo
| Status | Ícone | Significado |
|---|---|---|
| Pending | ⏳ | Arquivo enviado, aguardando processamento |
| Processing | 🔄 | IA está lendo e dividindo o documento |
| Ready | ✓ | Documento processado e pesquisável |
| Failed | Algo deu errado (passe o mouse para detalhes) |
Deletar um documento:
- Passe o mouse sobre um documento
- Clique no ícone de lixeira (🗑️)
- Você tem 5 segundos para clicar "Desfazer"
Filtrar por status:
- Use o dropdown para mostrar apenas documentos Ready, Processing ou Failed
Buscar por nome:
- Pressione
Cmd/Ctrl + Kou clique na barra de busca - Digite para filtrar documentos por nome
Aqui é onde você faz perguntas sobre seus documentos.
- Digite sua pergunta na caixa de entrada
- Pressione Enter ou clique Enviar
- Espere a IA responder
- As fontes aparecerão abaixo da resposta
Clique no seletor de modo para escolher como o MegaRAG busca:
| Modo | O Que Faz | Melhor Para |
|---|---|---|
| Mix (padrão) | Usa todos os métodos de busca | Perguntas gerais |
| Naive | Só busca chunks de texto | Perguntas de palavras-chave simples |
| Local | Busca entidades primeiro | "Quem é X?" "O que é Y?" |
| Global | Segue relacionamentos | "Como X se relaciona com Y?" |
| Hybrid | Combina Local + Global | Perguntas complexas |
Iniciar novo chat:
- Clique "New Chat" na barra lateral
Renomear um chat:
- Passe o mouse sobre um chat na barra lateral
- Clique no ícone de lápis (✏️)
- Digite um novo nome
- Pressione Enter
Deletar um chat:
- Passe o mouse sobre um chat
- Clique no ícone de lixeira (🗑️)
Alternar entre chats:
- Clique em qualquer chat na barra lateral
- Seu histórico de conversa é preservado
Mostra o que o MegaRAG "sabe" dos seus documentos.
Chunks:
- Mostra todos os pedaços de texto dos seus documentos
- Clique para expandir e ver o conteúdo completo
- Mostra de qual documento cada chunk veio
Entities:
- Mostra todas as entidades extraídas (pessoas, empresas, etc.)
- Mostra o tipo e descrição
- Mostra quais documentos mencionam esta entidade
Relations:
- Mostra relacionamentos entre entidades
- Formato: Origem → [Tipo de Relação] → Destino
- Exemplo: "Tim Cook" → [CEO_DE] → "Apple Inc."
O que isso significa: Alguns pacotes não instalaram corretamente.
Solução:
# Deletar node_modules e reinstalar
rm -rf node_modules
rm package-lock.json
npm installO que isso significa: Sua chave API do Google AI está errada, expirada ou não definida.
Solução:
- Vá para aistudio.google.com/apikey
- Verifique se sua chave ainda é válida (não deletada)
- Se necessário, crie uma nova chave
- Atualize
GOOGLE_AI_API_KEYem.env.local - Reinicie o servidor dev: Pare com
Ctrl+C, depois executenpm run devnovamente
O que isso significa: As tabelas do banco não foram criadas.
Solução:
- Vá para o Editor SQL do Supabase
- Execute todos os comandos SQL do Passo 3 novamente
- Certifique-se de que cada um mostra "Success"
O que isso significa: O processamento começou mas não completou. Pode ser:
- Problemas de chave API
- Arquivo muito grande
- Processamento travou
Solução:
- Verifique o console do navegador (F12 → Console) por erros
- Verifique logs do Supabase (Dashboard → Logs)
- Verifique se seu
.env.localtem valores corretos - Para arquivos grandes (vídeos), certifique-se de que estão abaixo de 1GB
- Tente deletar o documento e reenviar
O que isso significa: Erro de Cross-Origin Resource Sharing. O navegador está bloqueando requisições.
Solução:
- Certifique-se de que
NEXT_PUBLIC_SUPABASE_URLcorresponde exatamente à URL do seu projeto - Inclua
https://no início - Não inclua barra no final
O que isso significa: Ou:
- Nenhum documento está processado
- Embeddings não foram gerados
- A query não corresponde a nenhum conteúdo
Solução:
- No Supabase, vá para Table Editor → chunks
- Verifique se há linhas com
content_vectornão nulo - Se vetores são nulos, reprocesse os documentos
- Certifique-se de que sua
GOOGLE_AI_API_KEYé válida
O que isso significa: Você atingiu o limite de taxa (15 requisições/minuto no tier grátis).
Solução:
- Espere 1 minuto e tente novamente
- Processe menos documentos de uma vez
- Faça upgrade para tier pago se precisar mais capacidade
O que isso significa: O tema não está sendo aplicado corretamente.
Solução:
- Limpe o cache do navegador
- Verifique se
ThemeProviderenvolve seu app emlayout.tsx - Tente clicar no alternador de tema múltiplas vezes
Se nenhuma dessas soluções funcionar:
-
Verifique o console por erros:
- Navegador: Pressione F12, clique "Console"
- Servidor: Olhe no terminal onde
npm run devestá rodando
-
Verifique logs do Supabase:
- Dashboard → Logs → Postgres Logs
-
Abra uma issue no GitHub:
- Vá para github.com/inematds/MegaRAG/issues
- Inclua: mensagem de erro, passos para reproduzir, seu ambiente
Vercel é a empresa que faz o Next.js, então o deploy é perfeito.
-
Envie seu código para o GitHub
git init git add . git commit -m "Commit inicial" git remote add origin https://github.com/seuusuario/seu-repo.git git push -u origin main
-
Crie conta na Vercel
- Vá para vercel.com
- Clique "Sign Up" → "Continue with GitHub"
-
Importe seu projeto
- Clique "New Project"
- Selecione seu repositório
- Clique "Import"
-
Configure variáveis de ambiente
- Clique "Environment Variables"
- Adicione cada variável do seu
.env.local:NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEYGOOGLE_AI_API_KEY
-
Deploy
- Clique "Deploy"
- Espere 1-2 minutos
- Você receberá uma URL como
https://seu-projeto.vercel.app
Ou use este botão:
MegaRAG funciona em qualquer plataforma que suporta Node.js:
- Vá para railway.app
- "New Project" → "Deploy from GitHub"
- Adicione variáveis de ambiente
- Deploy
- Vá para render.com
- "New" → "Web Service"
- Conecte repo do GitHub
- Adicione variáveis de ambiente
- Deploy
# Build para produção
npm run build
# Iniciar servidor de produção
npm start
# Roda na porta 3000 por padrão
# Use um proxy reverso (nginx) para HTTPSAntes de ir ao ar:
- Todas as variáveis de ambiente definidas em produção
-
SUPABASE_SERVICE_ROLE_KEYmantida secreta (não em logs) - Backup do banco configurado (Supabase faz isso automaticamente)
- Domínio configurado com HTTPS
- Testado com documentos reais
- ARCHITECTURE.md - Arquitetura do sistema com diagramas
- API_DOCUMENTATION.md - Documentação completa da API
- O que é RAG? - Explicação excelente da Pinecone
- Embeddings Explicados - Explicação visual no YouTube
- Documentação Next.js - O framework React
- Documentação Supabase - Banco de dados e armazenamento
- Guia pgvector - Extensão de busca vetorial
- Documentação Google AI - Modelos Gemini AI
- Manual TypeScript - Aprenda TypeScript
- Documentação React - Aprenda React
Encontrou um bug? Quer adicionar uma funcionalidade?
- Faça fork do repositório
- Crie uma branch:
git checkout -b minha-funcionalidade - Faça suas alterações
- Teste localmente
- Envie um Pull Request
Licença MIT - Use este código como quiser!