Skip to content

Repository files navigation

docpipe

Pipeline de extração de documentos com LLM. Recebe um documento (PDF/imagem), classifica o tipo, extrai dados estruturados com LLM, valida a saída e expõe tudo via API documentada — com fila, revisão humana e testes. Produção em miniatura, não um script.

CI

Status: 🚧 etapas 1–3 concluídas + página de demo no ar em / (upload com drag & drop, polling de status, JSON extraído com confidences e métricas). Falta fechar a etapa 4: deploy — ver Roteiro.

docpipe demo

Arquitetura

flowchart LR
  U[Upload API] --> S[(MinIO / S3)]
  U --> Q[[Fila: RabbitMQ]]
  Q --> W[Worker]
  W --> C[1. Classifica<br/>LLM: saída enum]
  W --> E[2. Extrai<br/>LLM: JSON estruturado]
  W --> V[3. Valida<br/>Zod — reprova → retry c/ feedback]
  W --> P[(Postgres via Prisma)]
  API[GET /documents/:id] --> P
  R[POST /documents/:id/review] --> P
Loading
  • API (apps/api): HTTP + Swagger. Recebe upload, enfileira, consulta status/resultado.
  • Worker (apps/worker): consome a fila e roda o pipeline (classifica → extrai → valida → persiste).
  • libs/: código compartilhado atrás de portas isoladas — prisma, queue (trocável RabbitMQ→SQS), storage (MinIO→S3).

Stack

NestJS · Prisma + PostgreSQL · RabbitMQ · MinIO (S3-compatible) · OpenAI (structured outputs) · Zod · Docker Compose · pnpm.

Requisitos

  • Node 22+ (há um .nvmrc; nvm use)
  • pnpm (corepack enable pnpm)
  • Docker + Docker Compose

Quickstart

# 1. Infra local (Postgres, RabbitMQ, MinIO)
docker compose up -d

# 2. Dependências
pnpm install

# 3. Variáveis de ambiente
cp .env.example .env   # defina OPENAI_API_KEY — sem ela o worker boota, mas
                       # todo documento falha com erro explicativo

# 4. Gera o Prisma Client
pnpm prisma:generate

# 5. Builda o front-end da demo (React/Vite → apps/web/dist, servido pela API)
pnpm build:web

# 6. Sobe a API (demo em http://localhost:3000, Swagger em /api)
pnpm start:dev

# 7. (outro terminal) sobe o worker
pnpm start:worker:dev

# Desenvolvimento do front com HMR: pnpm dev:web (http://localhost:5173, proxy pra API)

Endpoints de infra:

Serviço URL
Demo (upload + status) http://localhost:3000
API / Swagger http://localhost:3000/api
Health http://localhost:3000/health
RabbitMQ (painel) http://localhost:15672 — docpipe / docpipe
MinIO (console) http://localhost:9001 — docpipe / docpipe123

API

Sem autenticação — é uma demo; em produção entraria auth de verdade na borda.

Rota O que faz
POST /documents Upload (multipart, campo file: PDF/JPEG/PNG/WebP até 10 MB) → armazena no MinIO, registra no Postgres e enfileira. Idempotente por sha256: reenviar o mesmo arquivo devolve o registro existente com deduplicated: true.
GET /documents Histórico (mais recentes primeiro; ?limit=1–100, default 20), com extração incluída.
GET /documents/:id Status (QUEUED → PROCESSING → DONE/FAILED), tipo classificado, dados extraídos (extraction.data), confidences por atributo, flag needsReview, tokens usados e motivo de falha (error).
POST /documents/:id/review Correção humana: valida o body contra o mesmo schema Zod da extração, guarda o par original/corrigido (auditável) e limpa o needsReview.
GET /metrics Documentos por status/tipo, pendências de revisão, tokens totais e custo estimado (USD).
curl -F "file=@nota.pdf" http://localhost:3000/documents
# → {"id":"…","status":"QUEUED","deduplicated":false,…}

Layout do monorepo

docpipe/
├─ apps/
│  ├─ api/        # HTTP + Swagger (serve o build do web na raiz)
│  ├─ web/        # front-end da demo (React + Vite + TS)
│  └─ worker/     # consumidor da fila (pipeline)
├─ libs/
│  ├─ contracts/  # schemas zod: mensagens da fila + classificação + extração por tipo
│  ├─ llm/        # adapter LLM atrás de porta (OpenAI structured outputs)
│  ├─ prisma/     # PrismaModule/Service
│  ├─ queue/      # adapter de fila atrás de porta (RabbitMQ → SQS)
│  └─ storage/    # adapter de storage atrás de porta (MinIO → S3)
├─ prisma/        # schema + migrations
├─ docker-compose.yml
└─ .github/workflows/ci.yml

Scripts

Comando O que faz
pnpm start:dev API em watch mode
pnpm start:worker:dev Worker em watch mode
pnpm dev:web Front-end com HMR (Vite, proxy pra API)
pnpm build Compila api + worker
pnpm build:web Typecheck + build do front-end
pnpm lint ESLint (--fix)
pnpm test Testes unitários (Jest)
pnpm eval Roda o golden set contra o pipeline real e mede acurácia (requer API+worker+OPENAI_API_KEY)
pnpm prisma:migrate Cria/aplica migration
pnpm prisma:studio UI do banco

Design decisions

  1. Saída estruturada + validação + retry ✅ — o LLM responde sob JSON Schema strict (structured outputs); a resposta ainda passa pelo Zod do tipo (validação semântica: datas ISO, moeda ISO 4217). Reprovou → reenvia uma vez com os erros de validação no prompt; reprovou de novo → FAILED. Nada de parsear texto solto.
  2. Idempotência ✅ — sha256 do arquivo como chave única (com tratamento da corrida P2002); redelivery da fila também é idempotente (doc DONE não reprocessa).
  3. Custo/observabilidade ✅ — tokens de prompt/completion somados (classificação + extração) persistidos por documento; GET /metrics agrega contagens, tokens e custo estimado (preços por 1M configuráveis).
  4. Confiança ✅ — o LLM devolve confidence (0–1) por atributo; qualquer uma abaixo de CONFIDENCE_THRESHOLD (default 0.7) → needsReview: true, limpo pela revisão humana.
  5. Golden set ✅ — 12 documentos sintéticos (sem dados reais) em eval/golden-set.json; pnpm eval gera os PDFs, roda o pipeline real e mede a acurácia campo a campo.
  6. Schema pro LLM ≠ schema de validação — o structured output vai sem regex/formats (suporte irregular no modo strict); a validação semântica (datas ISO, moeda ISO 4217) roda no nosso Zod — e é a reprovação dela que alimenta o retry com feedback.

What I'd do differently at scale

Batching de requisições ao LLM · cache de resultados por hash · DLQ para falhas · multi-tenant + auth real · storage/fila gerenciados (S3 + SQS). (discussão, não implementado na v1)

Roteiro

Etapa Entrega Status
0 Setup: monorepo + Compose + API/worker bootados + Swagger
1 Upload → S3 → fila (idempotência, worker consumindo, testes unit)
2 Worker: classificação + extração + Zod + retry c/ feedback + persistência (recibo ponta a ponta)
3 Outros 2 tipos, confidence/needs_review, review, /metrics, golden set + eval
4 Página de demo ✅ · README com GIF ✅ · badge CI ✅ · deploy (Railway/Fly.io) ⬜ 🔶

Licença

MIT

About

Pipeline de extracao de documentos com LLM (NestJS + Prisma + RabbitMQ + MinIO + OpenAI)

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages