ARCHITECTURE

Arquitetura

Três contêineres principais, mais um serviço mDNS, sem intermediário de mensagens separado nem serviços em nuvem obrigatórios. As fotos são enviadas ou importadas de pastas do NAS e depois processadas para extrair metadados, miniaturas, vetores semânticos, rostos e texto. O resultado é uma biblioteca de fotos pesquisável por linguagem natural, pessoa e lugar.

3 + 1contêineres

Backend em Go, serviço de IA e PostgreSQL, mais um serviço mDNS que anuncia o domínio local

5tipos de tarefa

metadata, thumbnail, clip, face, ocr

512–1024dimensões

Vetores imagem-texto do Chinese-CLIP (512, 768 ou 1024, conforme o nível de modelos); as características faciais do ArcFace têm 512 dimensões

HNSWíndice vetorial

Índice de distância cosseno do pgvector; busca e comparação de rostos acontecem no banco de dados

SYSTEM

Arquitetura do sistema

O navegador só conversa com o backend em Go, que cuida dos uploads, do agendamento de tarefas, das miniaturas e das permissões, envia as prévias ao serviço de IA para inferência e grava todos os resultados no PostgreSQL. O serviço de IA não guarda estado: nunca acessa o banco de dados nem armazena arquivos, então pode rodar numa máquina mais potente.

CLIENTESNavegador no computadorApp web embutido no binário GoNavegador no celulariPhone · Androidwanmory.localDomínio local, sem decorar IPHTTP :8080DOCKER COMPOSEBackend Go · serverAPI, uploads, fila de tarefas, miniaturas, permissões, webAPI RESTUploads tusWorkers de tarefasContas · AcessosMiniaturas libvipsMetadados ExifToolVídeo FFmpegGeocodificaçãoÁlbuns · InteligentesSequências · ParecidasEscolhas IA · Neste diaVarredura a cada 15 minmdnsAnuncia wanmory.localServiço de IA · mlFastAPI + ONNX Runtime / PyTorch, sem estadoDetecção SCRFDCaracterísticas ArcFaceChinese-CLIPTexto PP-OCRPostgreSQL 17 + pgvectorDados, fila de tarefas e vetores num só banco, sem Redisassetsfaces · peoplefila jobssettingsíndice HNSWSQL/predict · prévias 1440 pxARMAZENAMENTO · EXTENSÕES/dataOriginais enviados, miniaturas, prévias de 1440 px/photos/* (pode ser só leitura :ro)Pastas de fotos do NAS, quantas quiser./modelsArquivos de modelos, baixados pelas configurações webServiço de IA remoto (opcional)Mac (CoreML / MPS) · NVIDIA CUDAAutenticação por token; recebe só prévias de 1440 px, nunca originaisleitura/gravaçãovarredura · só leituracargaHTTP + token
O backend é um único binário Go

O app web vai embutido no binário, então a instalação não precisa de Node. As migrações do banco rodam sozinhas na inicialização, e atualizar é só trocar a imagem.

O serviço de IA pode ficar em outra máquina

O serviço de IA embutido roda na rede interna do Docker e processa na CPU. Informe um endereço remoto nas configurações web para passar a usar um PC com placa de vídeo ou um Mac de casa.

Um banco de dados para tudo

Informações das fotos, pessoas, configurações, fila de tarefas e vetores ficam todos no PostgreSQL, então os dados do app e o estado das tarefas podem ir juntos para o backup. Os arquivos de foto precisam de um backup separado.

PIPELINE

Pipeline de processamento de fotos

Depois da importação, cada foto primeiro tem os metadados extraídos e as miniaturas geradas; em seguida, vetores semânticos, rostos e texto são calculados em paralelo. Cada etapa entra na fila separadamente, então reiniciar ou perder o serviço de IA não perde trabalho: o processamento continua quando tudo volta.

01ingest
Importação
  • Uploads web via tus, retomam após quedas
  • Pastas /photos varridas a cada 15 minutos
  • Soma SHA-1 calculada e gravada em assets
Backend
02metadata
Metadados
  • ExifTool lê dimensões e data da foto
  • GPS, câmera, lente, abertura e obturador
  • Horários sem fuso usam o fuso configurado
Backend
03thumbnail
Miniaturas
  • libvips gera as miniaturas
  • E uma prévia de 1440 px
  • FFmpeg extrai quadros e converte vídeos
Backend
04clip
Vetores
  • Chinese-CLIP calcula vetores de 1024-d
  • Busca em linguagem natural, categorias
  • Nota estética, fotos parecidas
IA · em paralelo
05face
Rostos
  • SCRFD detecta e alinha por 5 pontos
  • ArcFace calcula características de 512-d
  • Agrupados em pessoas aos poucos
IA · em paralelo
06ocr
Texto
  • PP-OCR lê o texto das fotos
  • Buscar fotos pelo texto
  • Identifica documentos e capturas
IA · em paralelo
SCHEDULING

Agendamento de tarefas em segundo plano

Não há intermediário de mensagens separado: a fila de tarefas é uma tabela jobs no PostgreSQL, gravada na mesma transação que os dados da foto, então uma foto salva sempre tem suas tarefas na fila. Os workers pegam tarefas com SKIP LOCKED, arrendamentos evitam travamentos e as falhas são repetidas com espera quadrática.

pendingna filarunningpega por um workerdoneconcluídafailedtentativas esgotadaspegar com SKIP LOCKEDsucessorepetições esgotadasfalha: nova tentativa após n² × 30 sIA inacessível: tenta de novo em 15 s, sem contar como falhaArrendamento de 10 min: sem resultado a tempo, é recuperada a cada 30 s e volta a pending
jobs/worker.go · claim
-- Pegar uma tarefa (server/internal/jobs/worker.go)
UPDATE jobs SET status = 'running', attempts = attempts + 1,
       locked_by = $1, locked_until = now() + $2::interval
WHERE id = (
  SELECT id FROM jobs
  WHERE status = 'pending' AND run_after <= now() AND type = ANY($3)
  ORDER BY priority DESC, run_after
  FOR UPDATE SKIP LOCKED   -- workers simultâneos nunca pegam a mesma
  LIMIT 1
)
RETURNING id, type, asset_id, payload, attempts, max_attempts;
Regras de agendamento
  • Uma tarefa do mesmo tipo para a mesma foto nunca entra duas vezes na fila enquanto outra espera ou roda.
  • Com a fila vazia, a consulta é feita a cada segundo; as tarefas são pegas por prioridade (maior primeiro) e depois por prazo (mais cedo primeiro).
  • O arrendamento de cada tarefa (que também é o seu tempo-limite) é de 10 minutos; ao reiniciar, um processo devolve à fila as próprias tarefas inacabadas.
Dar passagem e limitar
  • Enquanto alguém envia fotos, nenhuma tarefa de IA é pega, para que a banda e a CPU fiquem primeiro com o upload.
  • Se o serviço de IA não responde, todo o worker de IA para e espera, em vez de pegar tarefas uma a uma só para falharem e gastarem repetições.
  • O nível "Automático" detecta primeiro o hardware do servidor de IA e escolhe modelos adequados antes de pegar tarefas, o que ajuda a evitar carregar num Raspberry Pi ou parecido modelos que excedam a memória disponível.
AI SCHEDULING

Agendamento da IA

O serviço de IA só recebe prévias e devolve rostos, vetores e texto. O backend decide o endereço do serviço, os modelos e o paralelismo; o serviço de IA escolhe CUDA, CoreML / MPS, OpenVINO ou CPU conforme o hardware.

Fila de tarefas de IAclip · face · ocrParalelismo conforme configuração, limite ajustávelBackend Go · cliente de IAEscolhe serviço e nível, confere model_ids· Verifica /health a cada 15 s· Sem conexão → tarefas esperam· Nível automático → pelo hardwarepegarServiço de IA embutidoRede interna do Docker · CPUServiço de IA remotoMac ou PC com GPU em casaNó de trabalho remotoPega tarefas sozinho (previsto)um dos doisCPUONNX RuntimeCoreML / MPS · CUDAEscolhe a aceleração disponívelOpenVINOGPU integrada Intel
Três níveis de modelos

No "Automático", o nível segue o hardware do servidor de IA: Alta precisão com placa de vídeo utilizável; só com CPU, Leve com menos de 6 GB de memória e Equilibrado com 6 GB ou mais.

NívelHardware indicadoRostosBusca semântica
quality · Alta precisãoMac com Apple Silicon, GPU NVIDIASCRFD-10G + ArcFace R100 (antelopev2)Chinese-CLIP ViT-H/14 · 1024-d
balanced · EquilibradoNAS classe Intel i5SCRFD-10G + ArcFace R100 (antelopev2)Chinese-CLIP ViT-L/14 · 768-d
lite · LeveN100, Raspberry Pi 5SCRFD + ArcFace R50 (buffalo_l)Chinese-CLIP ViT-B/16 · 512-d
API do serviço de IA · /predict
POST /predict   (multipart: image + tasks)
Authorization: Bearer <token>

tasks = {
  "face": {"model": "antelopev2", "min_score": 0.5},
  "clip": {"model": "chinese-clip-vit-h-14"},
  "ocr":  {}
}

→ {
  "face": [{"box": [x, y, w, h], "score": 0.93,
            "embedding": [512 números], "yaw": 0.12, "blur": 340}],
  "clip": {"embedding": [1024 números]},
  "ocr":  {"text": "...", "lines": [...]},
  "model_ids": {"face": "antelopev2", "clip": "chinese-clip-vit-h-14"}
}
ALGORITHMS

Algoritmos principais

Os modelos, algoritmos e limiares por trás da busca, das pessoas, das sequências e das escolhas da IA. Alguns dependem de modelos de IA; outros, de cálculo vetorial e regras.

Busca em linguagem natural

O Chinese-CLIP coloca fotos e texto no mesmo espaço vetorial. Os vetores de imagem são calculados na importação; na busca, uma frase como "terceiro aniversário do bebê" vira um vetor de texto, e as fotos mais próximas são encontradas por distância cosseno no índice HNSW do pgvector.

sim(q, p) = q · p / (‖q‖ ‖p‖)
  • Três fontes de resultados são combinadas: primeiro as fotos em que as palavras buscadas foram reconhecidas, depois as tiradas num lugar com esse nome e, por fim, as mais próximas em significado.
  • Só voltam correspondências claras: um resultado precisa estar quase tão perto quanto o melhor e claramente mais perto que uma foto qualquer. Isso ajuda a filtrar correspondências fracas em vez de devolver fotos pouco relacionadas.
  • Se a busca for exatamente o nome de uma categoria (paisagens, comida, capturas de tela…), essa categoria é devolvida diretamente.
Agrupamento de rostos

O SCRFD encontra cada rosto e seus 5 pontos de referência, alinha e recorta em 112×112, e o ArcFace calcula um vetor de 512 dimensões (após a normalização, o produto escalar é a similaridade cosseno). O agrupamento acontece aos poucos, a cada foto concluída, sem esperar a biblioteca inteira.

d(a, b) = 1 − a · b rosto bom d < 0.55 · borrado/perfil d < 0.45
  • Os "rostos bons", nítidos, de frente e grandes o bastante, procuram os mais parecidos: se alguns já pertencem a uma pessoa, entram nela por maioria; se nenhum está atribuído, mas pelo menos 3 se parecem, uma nova pessoa é criada.
  • Rostos borrados, de perfil ou pequenos demais nunca criam uma pessoa; só se juntam a alguém com quem se parecem muito. Quem aparece por acaso uma vez não é cadastrado.
  • Agrupamentos simultâneos usam o mesmo bloqueio consultivo do banco, então ninguém é criado em dobro. As capas preferem rostos únicos nítidos (variância do laplaciano), de frente (yaw) e grandes.
Sequências e fotos parecidas
mesma câmera Δt ≤ 2s ou Δt ≤ 60s e sim ≥ 0.93
  • Fotos seguidas da mesma cena costumam ter similaridade CLIP de 0,94 a 0,98, enquanto uma troca de cena ou de pose costuma ficar entre 0,7 e 0,89; um limiar de similaridade de 0,93 ajuda a identificar prováveis sequências.
  • A foto recomendada: com rostos, aquela em que eles estão nítidos, de olhos abertos e olhando para a câmera; sem rostos, o arquivo maior (com a mesma câmera e configuração, fotos tremidas têm menos detalhe e ficam menores após a compressão).
  • Várias cópias do mesmo arquivo vão para "Duplicadas", sem precisar escolher. "Manter" move o resto para "Apagadas recentemente", de onde pode ser restaurado até ser apagado definitivamente.
Nota estética das escolhas da IA

Nenhum modelo extra é executado; os vetores CLIP são reaproveitados. A média dos vetores de um conjunto de descrições de "obras fotográficas" menos a de um conjunto de "fotos do dia a dia" dá uma direção de "fica bonito". A projeção de uma foto nessa direção é a sua nota.

score(p) = p · (μ_obra − μ_cotidiana)
  • Serve só para ordenar, nunca como nota absoluta; o carrossel de destaques da tela inicial escolhe as fotos por ela.
  • Outro conjunto de descrições identifica as fotos que deram errado (tremidas, estouradas etc.), avaliadas à parte de quão bonita a foto é.
TECH STACK

Tecnologias usadas

Apenas componentes de código aberto maduros, sem serviços proprietários; cada peça tem alternativa.

BACKEND
  • Go
    API, fila de tarefas, agendamento de miniaturas
  • libvips
    Miniaturas e prévias
  • FFmpeg
    Quadros de vídeo, conversão
  • ExifTool
    Leitura e gravação de metadados
  • tus
    Uploads retomáveis
SERVIÇO DE IA
  • Python + FastAPI
    Serviço HTTP sem estado
  • ONNX Runtime
    Inferência de rostos e texto
  • PyTorch
    Chinese-CLIP
  • InsightFace
    SCRFD + ArcFace
  • RapidOCR
    Reconhecimento de texto PP-OCR
DADOS
  • PostgreSQL 17
    Dados do app e fila de tarefas
  • pgvector
    Armazenamento de vetores
  • HNSW
    Índice de distância cosseno
  • ip2region
    Local por IP no histórico de acessos (offline)
  • Nominatim
    Geocodificação reversa (pode ser desligada)
INTERFACE E IMPLANTAÇÃO
  • React + TypeScript
    App web
  • Vite + Tailwind CSS
    Build e estilos
  • MapLibre GL
    Globo por satélite
  • Docker Compose
    Imagens amd64 / arm64
  • mDNS
    Domínio local wanmory.local
PRIVACY

Privacidade e segurança

Por padrão, as fotos e os resultados da IA ficam dentro da sua rede privada. Se você configurar um serviço de IA remoto, as prévias são enviadas a esse servidor para processamento.

Dados mínimos

O serviço de IA só recebe prévias de 1440 pixels, não guarda nenhum arquivo e nunca toca no banco de dados, nos nomes ou nos originais.

Autenticação

O serviço de IA embutido só existe na rede interna do Docker e apenas o backend chega até ele; quando há um token definido para um serviço de IA remoto, toda requisição precisa levar um token Bearer.

Permissões

Os membros só podem apagar as fotos que enviaram, e os administradores cuidam de tudo; fotos ocultas só aparecem para quem as ocultou; o histórico de acessos mostra uma localização aproximada pelo IP.

Originais só para leitura

As pastas do NAS podem ser montadas só para leitura com :ro, assim o app não consegue alterar nem apagar os arquivos delas.

Funciona offline

Depois de baixar os modelos, o reconhecimento e a busca acontecem localmente; recursos que precisam de internet, como a geocodificação reversa e as imagens de satélite, podem ser desligados.

Licenças dos modelos

Os modelos faciais do InsightFace são só para uso não comercial; os modelos não vêm na imagem, e as configurações mostram a licença de cada um antes do download.