MODULO 3.5

Upload Multimodal

Seu SaaS nao pode aceitar so texto. PDFs, imagens, video, audio. Aqui voce aprende a processar cada tipo de arquivo, construir um sistema de upload profissional com drag-and-drop, e implementar chunking e indexacao para RAG.

6
Topicos
50 min
Duracao
Intermediario
Nivel
Pratica
Tipo
1

Tipos de Upload: PDF, Imagem, Video, Audio

Cada formato de arquivo tem requisitos diferentes para processamento por IA. Um PDF precisa de extracao de texto. Uma imagem precisa de um vision model. Um video precisa de extracao de frames + transcricao de audio. Entender essas diferencas antes de codar evita retrabalho e decisoes de arquitetura ruins.

🎯 Conceito Principal

Todo upload segue o mesmo fluxo basico: receber > armazenar > processar > disponibilizar para IA. O que muda entre formatos e a etapa de processamento. A estrategia de storage tambem varia por tamanho e frequencia de acesso.

📁 Os 4 Formatos e Seus Pipelines

📄

PDF

Texto + layout

  • Pipeline: Upload > pdf-parse > texto > chunking > IA
  • Libs: pdf-parse, pdfjs-dist, Apache Tika
  • Limite: ~100 paginas antes de precisar chunking
  • OCR: Tesseract para PDFs escaneados
🖼️

Imagem

Visual + texto

  • Pipeline: Upload > compress > vision model > descricao
  • Models: GPT-4o Vision, Claude Vision
  • Formatos: PNG, JPEG, WebP, GIF
  • Limite: 20MB por imagem (GPT-4o)
🎬

Video

Frames + audio

  • Pipeline: Upload > extrair frames + audio > Whisper + Vision
  • Libs: FFmpeg, Whisper API
  • Estrategia: 1 frame a cada 5-10s + transcricao completa
  • Complexidade: Alta. Recomendado para v2+
🎤

Audio

Voz + som

  • Pipeline: Upload > Whisper > texto > IA
  • Models: Whisper (OpenAI), Deepgram
  • Formatos: MP3, WAV, M4A, OGG
  • Limite: 25MB por arquivo (Whisper API)

📊 Custos de Processamento por Formato

  • PDF (10 paginas): ~5000 tokens de texto extraido. Custo de processamento: $0.01-0.05 dependendo do modelo. Extracao local, so paga na chamada ao LLM
  • Imagem (1 foto): ~$0.003 por imagem 512x512 no GPT-4o. $0.01-0.04 para imagens maiores. Claude Vision incluso no custo por token
  • Audio (1 minuto): ~$0.006 via Whisper API. Transcricao vira texto que entra no pipeline normal. Custo total: transcricao + LLM call
  • Video (1 minuto): ~$0.006 (audio) + $0.03-0.10 (6-12 frames analisados). O formato mais caro. Reserve para features premium

💡 Dica Pratica

Para o MVP, suporte PDF + imagens. Sao os dois formatos que 90% dos usuarios vao enviar. Audio e simples de adicionar depois (Whisper API e uma chamada). Video e complexo e caro. Deixe para quando tiver usuarios pagando.

2

Processamento de PDF

PDF e o formato mais comum que usuarios vao enviar. Contratos, relatorios, artigos, faturas. O desafio e que PDFs nao sao texto puro. Eles tem layout, tabelas, imagens embutidas e as vezes sao escaneados (imagem pura sem texto selecionavel). Cada caso precisa de uma estrategia diferente.

🎯 Conceito Principal

O pipeline de processamento de PDF tem 4 etapas: parsing (extrair texto bruto), limpeza (remover headers/footers/ruido), chunking (dividir em pedacos) e metadata (titulo, autor, numero de paginas).

  • pdf-parse (Node.js): Mais simples. Extrai texto basico. Bom para PDFs com texto selecionavel. Nao lida bem com tabelas ou layouts complexos
  • pdfjs-dist (Mozilla): Mais robusto. Extrai texto com posicionamento. Pode reconstruir tabelas. Usado internamente pelo Firefox
  • OCR (Tesseract): Para PDFs escaneados. Converte imagem em texto. Qualidade depende da resolucao do scan. Adiciona 2-5 segundos por pagina
  • Claude PDF nativo: Claude 3.5+ aceita PDFs diretamente na API. Ate 100 paginas. Mais caro mas nao precisa de parsing local

💻 PDF Parsing com pdf-parse

import pdfParse from 'pdf-parse'
import { readFileSync } from 'fs'
async function processPDF(filePath: string) {
const buffer = readFileSync(filePath)
const data = await pdfParse(buffer)
// Metadata
console.log('Paginas:', data.numpages)
console.log('Titulo:', data.info?.Title)
console.log('Autor:', data.info?.Author)
// Texto completo
const fullText = data.text
// Limpar texto
const cleaned = fullText
.replace(/\n{3,}/g, '\n\n') // remove linhas extras
.replace(/\s{2,}/g, ' ') // normaliza espacos
.trim()
return {
text: cleaned,
pages: data.numpages,
metadata: data.info
}
}

✂️ Estrategias de Chunking para PDF

1

Fixed-size chunks

Dividir a cada N tokens (ex: 1000). Simples mas pode cortar frases no meio. Sempre use overlap de 100-200 tokens.

2

Paragraph-based chunks

Dividir por paragrafos (double newline). Respeita a estrutura semantica. Tamanho varia. Melhor qualidade de retrieval.

3

Page-based chunks

Uma pagina = um chunk. Simples de implementar. Bom quando cada pagina tem conteudo distinto (relatorios, apresentacoes).

✓ O que FAZER

  • Detectar se o PDF e texto ou imagem (scanned)
  • Implementar chunking com overlap para docs grandes
  • Extrair e preservar metadata (titulo, autor, paginas)

✗ O que NAO fazer

  • Enviar PDF de 200 paginas inteiro para a API
  • Assumir que todo PDF tem texto selecionavel
  • Ignorar limpeza de texto (headers repetidos, footers)
3

Processamento de Imagens

Vision models mudaram o jogo. Em vez de extrair texto com OCR e perder contexto visual, GPT-4o e Claude Vision "enxergam" a imagem e descrevem, analisam ou extraem informacao diretamente. O processamento de imagens no seu SaaS precisa lidar com compressao, formatos, e envio eficiente para a API.

🎯 Conceito Principal

Existem duas abordagens para processar imagens com IA: enviar diretamente para um vision model (mais rico, mais caro) ou usar OCR para extrair texto (mais barato, perde contexto visual). Para a maioria dos SaaS, vision models sao a escolha certa.

  • GPT-4o Vision: Aceita PNG, JPEG, GIF, WebP. Ate 20MB. Suporta multiplas imagens por request. Custo baseado em resolucao (low/high detail)
  • Claude Vision: Ate 5 imagens por request. 20MB cada. Excelente em analise de documentos e graficos. Custo incluido no pricing por token
  • Base64 encoding: A forma de enviar imagens via API. Converte bytes em string ASCII. Aumenta o tamanho em ~33%. Alternativa: enviar URL publica da imagem
  • Compressao pre-envio: Reduzir resolucao para 1024x1024 antes de enviar. Corta custo sem perder qualidade significativa para analise. Use sharp (Node.js) para isso

💻 Enviando Imagem para GPT-4o Vision

import sharp from 'sharp'
import { readFileSync } from 'fs'
async function processImage(filePath: string) {
// 1. Comprimir e redimensionar
const compressed = await sharp(filePath)
.resize(1024, 1024, { fit: 'inside' })
.jpeg({ quality: 85 })
.toBuffer()
// 2. Converter para base64
const base64 = compressed.toString('base64')
const dataUrl = `data:image/jpeg;base64,${base64}`
// 3. Enviar para vision model
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{
role: 'user',
content: [
{ type: 'text', text: 'Analise esta imagem.' },
{ type: 'image_url', image_url: {
url: dataUrl,
detail: 'high' // 'low' = barato, 'high' = detalhado
}}
]
}]
})
return response.choices[0].message.content
}

📊 Resolucao vs Custo

  • Low detail (512x512): ~85 tokens. $0.003. Bom para classificacao simples, deteccao de tipo de documento
  • High detail (ate 2048x2048): ~765-1105 tokens. $0.01-0.04. Necessario para leitura de texto em imagens, analise de graficos
  • EXIF data: Imagens de camera tem metadata (data, localizacao, orientacao). Extraia com exifr (Node.js) antes de comprimir. Pode ser util como contexto

💡 Dica Pratica

Gere thumbnails no upload. Quando o usuario envia uma imagem de 8MB, gere um thumbnail de 200x200 para mostrar no chat e guarde o original no storage. O frontend carrega rapido, a API recebe o original comprimido para analise.

4

Upload UX Patterns

Upload ruim = usuario frustrado. Upload bom = usuario nem percebe a complexidade. Os patterns de UX para upload sao bem estabelecidos: drag-and-drop, progress bar, validacao em tempo real, preview e estados de erro claros. Implementar isso direito faz seu SaaS parecer profissional.

🎯 Conceito Principal

Um sistema de upload profissional tem 5 componentes essenciais: drop zone visual, validacao client-side, progress indicator, preview/thumbnail e error handling. Cada componente resolve um ponto de frustacao do usuario.

  • Drag-and-drop zone: Area visual onde o usuario pode arrastar arquivos. Muda de cor quando o arquivo esta sobre ela. Tambem aceita click para abrir file picker
  • Client-side validation: Validar tipo (MIME type), tamanho (max MB) e quantidade ANTES do upload. Feedback instantaneo: "Arquivo muito grande" ou "Formato nao suportado"
  • Progress bar: Indicador visual de progresso do upload. Usa XMLHttpRequest ou fetch com ReadableStream. Mostra porcentagem e velocidade estimada
  • Preview thumbnails: Para imagens, mostrar preview imediato (FileReader API). Para PDFs, mostrar icone + nome + tamanho. Confirma visualmente que o arquivo certo foi selecionado
  • Error states: Mensagens claras para cada tipo de erro (network, tamanho, formato, timeout). Sempre oferecer opcao de tentar novamente

🖥️ Os 4 Estados da Upload Zone

📂

Idle

"Arraste um arquivo ou clique para selecionar"

Drag Over

Borda muda de cor, fundo highlight

Uploading

Progress bar + porcentagem + preview

Complete

Thumbnail + nome + opcao de remover

💻 Upload com Supabase Storage

// Frontend: upload direto para Supabase Storage
async function uploadFile(file: File, userId: string) {
// Validacao client-side
const allowedTypes = ['application/pdf', 'image/png', 'image/jpeg']
if (!allowedTypes.includes(file.type)) {
throw new Error('Formato nao suportado')
}
if (file.size > 10 * 1024 * 1024) { // 10MB
throw new Error('Arquivo muito grande (max 10MB)')
}
// Upload para Supabase
const path = `${userId}/${Date.now()}-${file.name}`
const { data, error } = await supabase.storage
.from('uploads')
.upload(path, file, {
contentType: file.type,
upsert: false
})
if (error) throw error
// Obter URL publica
const { data: { publicUrl } } = supabase.storage
.from('uploads')
.getPublicUrl(path)
return { path, publicUrl }
}

✓ O que FAZER

  • Validar tipo e tamanho no client ANTES do upload
  • Mostrar progress bar com porcentagem real
  • Gerar preview imediato com FileReader para imagens

✗ O que NAO fazer

  • Aceitar qualquer tipo de arquivo sem validacao
  • Mostrar spinner generico sem progresso real
  • Guardar uploads no filesystem do servidor (nao escala)
5

Chunking e Indexacao para RAG

Quando um usuario envia um documento de 50 paginas e faz uma pergunta, voce nao pode enviar tudo para o LLM. E caro, lento e o modelo pode perder informacao no meio do texto enorme. RAG (Retrieval Augmented Generation) resolve isso: divide o documento em pedacos, indexa com embeddings e busca so os trechos relevantes para a pergunta.

🎯 Conceito Principal

O pipeline RAG tem 3 fases: indexacao (acontece no upload), retrieval (acontece na pergunta) e generation (o LLM responde com o contexto recuperado).

  • Chunking: Dividir o documento em pedacos de 500-1500 tokens. Overlap de 100-200 tokens entre chunks adjacentes para nao perder contexto na fronteira
  • Embedding: Converter cada chunk em um vetor numerico (array de 1536 floats com text-embedding-3-small da OpenAI). Vetores similares ficam proximos no espaco
  • Vector Storage: Guardar os vetores num banco vetorial (Supabase pgvector, Pinecone, Chroma). Permite busca por similaridade semantica
  • Retrieval: Quando o usuario pergunta, gerar embedding da pergunta e buscar os N chunks mais similares. Esses chunks viram contexto para o LLM

🔄 Pipeline RAG Completo

📄

1. Upload

Receber documento do usuario

✂️

2. Chunk

Dividir em pedacos de ~1000 tokens

🧮

3. Embed

Gerar vetor para cada chunk

💾

4. Store

Salvar vetores no pgvector

🔍

5. Retrieve

Buscar chunks similares a pergunta

🤖

6. Generate

LLM responde com contexto

💻 Chunking + Embedding + Retrieval

// 1. Chunking com overlap
function chunkText(text: string, size = 1000, overlap = 200) {
const chunks: string[] = []
let start = 0
while (start < text.length) {
chunks.push(text.slice(start, start + size))
start += size - overlap
}
return chunks
}
// 2. Gerar embeddings
async function embedChunks(chunks: string[]) {
const response = await openai.embeddings.create({
model: 'text-embedding-3-small',
input: chunks
})
return response.data.map(d => d.embedding)
}
// 3. Buscar chunks relevantes (Supabase pgvector)
async function searchChunks(query: string, docId: string) {
const queryEmb = await embedChunks([query])
const { data } = await supabase.rpc('match_chunks', {
query_embedding: queryEmb[0],
match_count: 5,
filter_doc_id: docId
})
return data.map(d => d.content)
}

📊 Custos de Embedding

  • text-embedding-3-small: $0.02 por 1M tokens. Um livro de 300 paginas (~150k tokens) custa ~$0.003 para indexar. Baratissimo
  • text-embedding-3-large: $0.13 por 1M tokens. Melhor qualidade de retrieval. Use para aplicacoes que precisam de alta precisao
  • Supabase pgvector: Incluso no plano free ate 500MB de dados vetoriais. Suficiente para milhares de documentos. Sem custo adicional de infra

💡 Dica Pratica

Comece com chunking simples e retrieval top-5. Muita gente se perde otimizando chunk size, overlap e re-ranking antes de ter usuarios. Chunk de 1000 chars com overlap de 200 + top 5 results funciona surpreendentemente bem para 90% dos casos. Otimize depois com dados reais.

6

Exercicio: Sistema de Upload Completo

Neste exercicio voce vai construir um sistema de upload end-to-end: drag-and-drop no frontend, upload para Supabase Storage, processamento de PDF e imagem no backend, e analise pela IA. O resultado e um componente reutilizavel para qualquer SaaS com IA.

🛠️

Exercicio: Build Complete Upload System

Tempo estimado: 40-60 minutos

1

Criar a drop zone com drag-and-drop

Componente React com eventos onDragOver, onDragLeave, onDrop. Aceitar PDF e imagens. Mostrar estado visual para cada fase:

const handleDrop = (e: DragEvent) => {
e.preventDefault()
const file = e.dataTransfer.files[0]
if (!validateFile(file)) return showError()
setPreview(URL.createObjectURL(file))
uploadToSupabase(file)
}
2

Upload para Supabase Storage com progress

Criar bucket 'uploads' no Supabase. Configurar RLS (Row Level Security) para que cada usuario so acesse seus proprios arquivos. Implementar progress tracking com XMLHttpRequest.

3

Processar PDF: extrair texto + chunking

No backend, baixar o arquivo do storage, processar com pdf-parse, limpar texto e dividir em chunks:

const { text, pages } = await processPDF(filePath)
const chunks = chunkText(text, 1000, 200)
const embeddings = await embedChunks(chunks)
await storeInPgVector(docId, chunks, embeddings)
4

Processar imagem: comprimir + enviar para Vision

Comprimir com sharp, converter para base64, enviar para GPT-4o Vision ou Claude Vision. Guardar a descricao gerada como texto indexavel.

5

Integrar com o chat: "Pergunte sobre o documento"

Depois do upload processado, usuario pode fazer perguntas. Usar RAG: buscar chunks relevantes, injetar como contexto no system prompt, LLM responde baseado no documento.

Criterios de Sucesso

Drag-and-drop funcionando com preview
Validacao client-side (tipo + tamanho)
Upload com progress bar real
PDF processado e texto extraido
Imagem analisada pelo vision model
IA responde perguntas sobre o documento

🌟 Bonus

Implemente multi-file upload: o usuario envia 3 PDFs de uma vez, todos sao processados em paralelo (Promise.all), e a IA consegue responder perguntas cruzando informacao de todos os documentos. Adicione um indicador de "documentos carregados" no chat.

📋 Resumo do Modulo

4 formatos, 4 pipelines diferentes - PDF (text extraction), imagem (vision model), video (frames + audio), audio (transcricao). MVP = PDF + imagens.
PDF processing: parse > clean > chunk - pdf-parse para texto, Tesseract para OCR. Chunking com overlap para documentos grandes. Claude aceita PDF nativo.
Vision models > OCR para imagens - GPT-4o Vision e Claude Vision enxergam contexto visual. Comprimir com sharp antes de enviar. Low vs high detail.
Upload UX: 5 componentes essenciais - Drop zone, validacao client-side, progress bar, preview e error handling. Supabase Storage para armazenamento.
RAG: chunk > embed > store > retrieve > generate - Embeddings baratos ($0.02/1M tokens). pgvector no Supabase. Top-5 retrieval funciona pra maioria dos casos.
Sistema completo: upload > process > AI analysis - Drag-drop UI, Supabase Storage, PDF/image processing, RAG pipeline. Componente reutilizavel para qualquer SaaS.

Proximo Modulo:

Modulo 3.6 - Estados do Sistema, Historico e Deploy. Gerenciar estados visuais, persistir conversas e preparar para producao.