Files
SnapOtter/apps/docs/pt-BR/guide/architecture.md
T
SnapOtterandGitHub 4963ab3bbd feat(docs-i18n): translate all documentation into 20 languages
All 181 docs markdown files translated into 20 languages (apps/docs/<locale>/**). Companion to the i18n code PR; admin-merged because the file count exceeds GitHub's per-PR CI trigger limit. Validated by pnpm i18n:check (all surfaces, 0 stale/missing) and a clean all-locale docs build.
2026-07-11 13:52:47 +08:00

9.3 KiB

description, i18n_source_hash, i18n_provenance, i18n_output_hash
description i18n_source_hash i18n_provenance i18n_output_hash
Estrutura do monorepo, arquitetura de apps e pacotes, ciclo de vida das requisições e uso de recursos do SnapOtter. 9e8f80499a37 human 93555b8e15c0

Arquitetura

O SnapOtter é um monorepo gerenciado com pnpm workspaces e Turborepo. Ele é implantado como uma pilha Docker Compose de 3 contêineres: a imagem do app SnapOtter, o PostgreSQL 17 e o Redis 8.

Estrutura do projeto

snapotter/
├── apps/
│   ├── api/          # Fastify backend
│   ├── web/          # React + Vite frontend
│   └── docs/         # This VitePress site
├── packages/
│   ├── image-engine/ # Sharp-based image operations
│   ├── media-engine/ # FFmpeg spawn + progress parsing
│   ├── doc-engine/   # qpdf, LibreOffice, ghostscript wrappers
│   ├── ai/           # Python AI model bridge
│   └── shared/       # Types, constants, i18n
└── docker/           # Dockerfile and Compose config

Pacotes

@snapotter/image-engine

A biblioteca principal de processamento de imagem construída sobre o Sharp. Ela lida com todas as operações que não são de IA: redimensionar, recortar, girar, espelhar, converter, comprimir, remover metadados e ajustes de cor (brilho, contraste, saturação, escala de cinza, sépia, inversão, canais de cor).

Este pacote não tem dependências de rede e roda inteiramente em processo.

@snapotter/ai

Uma camada de ponte que chama scripts Python para operações de ML. No primeiro uso, a ponte inicia um processo de dispatcher Python persistente que pré-importa bibliotecas pesadas (PIL, NumPy, MediaPipe, rembg) para que as chamadas de IA subsequentes dispensem o custo de importação. Se o dispatcher ainda não estiver pronto, a ponte recorre a gerar um novo subprocesso Python por requisição.

Os modelos não são pré-carregados. Cada script de ferramenta carrega os pesos do seu modelo do disco no momento da requisição e os descarta quando a requisição termina. Consulte Uso de recursos para o perfil de memória completo.

Operações suportadas: remoção de fundo (rembg/BiRefNet), upscaling (RealESRGAN), desfoque de rostos (MediaPipe), aprimoramento de rostos (GFPGAN/CodeFormer), apagamento de objetos (LaMa ONNX), OCR (PaddleOCR/Tesseract), colorização (DDColor), remoção de ruído, remoção de olhos vermelhos, restauração de fotos, geração de foto de passaporte, correção de transparência (HR-matting do BiRefNet) e redimensionamento com reconhecimento de conteúdo (binário caire em Go).

Os scripts Python ficam em packages/ai/python/. A imagem Docker pré-baixa todos os pesos de modelo durante o build para que o contêiner funcione totalmente offline.

@snapotter/shared

Tipos TypeScript compartilhados, constantes (como APP_VERSION e as definições de ferramentas) e strings de tradução i18n usadas tanto pelo frontend quanto pelo backend.

Aplicações

API (apps/api)

Um servidor Fastify v5 que expõe 241 rotas de ferramentas em cinco modalidades (image, video, audio, PDF, file) e lida com:

  • Uploads de arquivos, gerenciamento de espaço de trabalho temporário e armazenamento persistente de arquivos
  • Biblioteca de arquivos do usuário com cadeias de versão (tabela user_files) - cada resultado processado remete de volta ao seu arquivo de origem e registra qual ferramenta foi aplicada, com miniaturas geradas automaticamente para a página Files
  • Execução de ferramentas (roteia cada requisição de ferramenta para o motor de imagem ou para a ponte de IA)
  • Orquestração de pipelines (encadeamento de várias ferramentas em sequência)
  • Processamento em lote com controle de concorrência via filas de jobs do BullMQ (pools: image, media, ai, docs, system)
  • Autenticação de usuários, RBAC (funções admin/user com um conjunto completo de permissões), gerenciamento de chaves de API e limitação de taxa
  • Gerenciamento de equipes - CRUD apenas para admin; os usuários são atribuídos a uma equipe por meio do campo team no seu perfil
  • Configurações de runtime - um armazenamento chave-valor na tabela settings que controla disabledTools, enableExperimentalTools, loginAttemptLimit e outros parâmetros operacionais sem reimplantar
  • Marca personalizada e preferências de runtime por meio de configurações respaldadas pelo banco de dados
  • Documentação Scalar/OpenAPI em /api/docs
  • Serviço do frontend compilado como uma SPA em produção

Dependências principais: Fastify, Drizzle ORM (pg-core, node-postgres), Sharp, BullMQ, ioredis, Zod para validação.

O servidor lida com o encerramento gracioso em SIGTERM/SIGINT: ele drena as conexões HTTP, para os workers do BullMQ, desliga o dispatcher Python e fecha a conexão com o banco de dados.

Web (apps/web)

Um app de página única em React 19 construído com Vite. Usa Zustand para gerenciamento de estado, Tailwind CSS v4 para estilização e Lucide para ícones. Comunica-se com a API por REST e SSE (para acompanhamento de progresso).

As páginas incluem um espaço de trabalho de ferramentas, uma página Files para gerenciar uploads e resultados persistentes, um construtor de automação/pipelines e um painel de configurações de admin.

O frontend compilado é servido pelo backend Fastify em produção, portanto não há um servidor web separado no contêiner Docker.

Docs (apps/docs)

Este site VitePress. Implantado no Cloudflare Pages automaticamente a cada push para main.

Como uma requisição flui

  1. O usuário escolhe uma ferramenta na interface web e envia um arquivo.
  2. O frontend envia um POST multipart para /api/v1/tools/:section/:toolId com o arquivo e as configurações.
  3. A rota da API valida a entrada com o Zod e depois despacha o processamento.
  4. Para ferramentas padrão, o job é enfileirado no pool BullMQ apropriado (image, media ou docs, conforme a modalidade). O worker BullMQ em processo orienta automaticamente a imagem com base nos metadados EXIF, executa a função de processamento da ferramenta e retorna o resultado.
  5. Para ferramentas de IA, a ponte TypeScript envia uma requisição ao dispatcher Python persistente (ou gera um novo subprocesso como fallback), aguarda a conclusão e lê o arquivo de saída.
  6. O progresso do job é persistido na tabela jobs no PostgreSQL, de modo que o estado sobrevive a reinícios do contêiner. As atualizações em tempo real são entregues via SSE em /api/v1/jobs/:jobId/progress.
  7. A API retorna um jobId e um downloadUrl. O usuário baixa o arquivo processado de /api/v1/download/:jobId/:filename.

Para pipelines, a API alimenta a saída de cada etapa como entrada da próxima, executando-as em sequência.

Para o processamento em lote, a API usa flows do BullMQ com jobs filhos por etapa e retorna um arquivo ZIP com todos os arquivos processados.

Uso de recursos

O SnapOtter foi projetado para baixo uso de memória em repouso. Nada é pré-carregado ou mantido aquecido na inicialização.

Em repouso

O processo Node.js/Fastify, o PostgreSQL e o Redis estão em execução. A RAM típica em repouso é de cerca de 200 a 300 MB entre os três contêineres (processo Node.js, Postgres e Redis). Sem processo Python, sem pesos de modelo na memória.

O que inicia, e quando

Componente Inicia quando Memória enquanto ativo
Servidor Fastify + Postgres + Redis Início do contêiner ~200-300 MB no total
Workers do BullMQ Início do contêiner (em processo) Um worker por pool (image, media, ai, docs, system)
Dispatcher Python Primeira requisição de ferramenta de IA Interpretador Python + bibliotecas pré-importadas (PIL, NumPy, MediaPipe, rembg) - sem pesos de modelo
Pesos de modelo de IA Durante a requisição da ferramenta específica Carregados do disco, liberados quando a requisição termina

Carregamento de modelos

Todos os arquivos de pesos de modelo (somando vários GB) ficam no disco em /opt/models/ o tempo todo. Cada script de ferramenta de IA carrega na memória apenas o(s) seu(s) próprio(s) modelo(s) durante uma requisição e depois os libera. Alguns scripts chamam explicitamente del model e torch.cuda.empty_cache() após a inferência para garantir que a memória seja devolvida imediatamente.

Não há cache de modelo entre requisições. Executar a mesma ferramenta de IA em sequência recarrega o modelo a cada vez. Isso mantém a memória em repouso próxima de zero, ao custo de um atraso de carregamento do modelo em cada requisição de IA.

Cold start da primeira requisição de IA

O dispatcher Python não está em execução quando o contêiner inicia. A primeira requisição de IA dispara duas coisas em paralelo: o dispatcher começa a aquecer em segundo plano e a própria requisição recorre a gerar um subprocesso Python único e avulso. Assim que o dispatcher sinaliza que está pronto, todas as requisições de IA subsequentes o usam diretamente e evitam o custo de gerar subprocessos.