Eu tenho mais de 47 mil fotos no celular. E eu levei 3 segundos pra achar uma específica de quatro anos atrás, num restaurante italiano cujo nome eu já esqueci, num feriado que eu nem lembrava direito que aconteceu.
Google e Apple gastam bilhões em IA pra organizar a sua galeria. Mesmo assim, achar aquela foto continua um inferno: você filtra pelo rosto de alguém, aparecem mil resultados, você rola por minutos e desiste no meio do caminho. Spoiler: no Google Photos é exatamente a mesma coisa.
Então eu fiz o que costumo fazer quando uma ferramenta me irrita o suficiente: construí o meu. Rodando local, sem mandar nenhuma foto pra fora do meu hardware, entendendo contexto de verdade — não só rosto e localização, mas o que está acontecendo na cena.
Esse post é o desenho completo do sistema: como eu pensei, o que eu escolhi, o que eu deixei de lado, e por quê.
O problema real (que ninguém admite)
A promessa do Google Photos e do Apple Photos é boa no marketing: "busca por qualquer coisa". A realidade do uso é outra. Você digita "praia" e recebe 8.000 fotos. Você filtra por rosto e recebe 2.000. Você lembra que era em dezembro e o filtro de data corta pra 400. Você ainda precisa rolar 400 fotos pra achar uma.
O problema não é falta de IA. É que esses sistemas foram desenhados pra todo mundo, com o privacy-floor mais conservador possível, rodando em escala planetária. O resultado é uma busca que entende categorias mas não entende contexto. Ela sabe que tem um café na foto. Não sabe que era o aniversário da sua namorada, que vocês estavam num bistrô em Vienna, e que isso aconteceu no segundo dia da viagem.
E tem o outro lado: você está mandando cada foto sua pra um servidor externo. Cada detalhe íntimo, cada documento fotografado, cada print de conversa, cada nudes que você não devia ter tirado mas tirou. Isso vive num bucket de algum lugar, sendo processado por modelos de uma empresa que ano que vem pode mudar de política e te avisar via email.
Eu queria os dois: busca por contexto e privacidade real. Não existia. Construí.
O fluxo, em uma frase
Antes de qualquer detalhe, a ideia inteira numa linha:
Celular → NAS → Worker no Mac → IA local → Banco → UI de buscaÉ isso. Cada foto que eu tiro entra nesse pipeline e sai do outro lado como um conjunto de sinais consultáveis — rosto, lugar, momento, cena, objetos, ação, humor, cor — em vez de "um JPEG num diretório".
Vamos por partes.
1. A camada física: o NAS como verdade
Toda foto que eu tiro em qualquer dispositivo vai automaticamente pro NAS. Isso é o ponto zero, e é importante pelo seguinte motivo: o NAS é a única fonte de verdade dos arquivos. O banco de dados é índice. Os thumbnails são cache. A IA é processamento. Se tudo isso der ruim e for deletado amanhã, as fotos continuam intactas no NAS.
Isso é uma decisão de design importante. Eu vi sistema demais que mistura "armazenamento" com "índice" e quando o índice corrompe, perde foto. Aqui o índice é descartável. Reconstruir o índice é caro em tempo, não em dados.
O upload do celular pro NAS usa o que já existe: Synology Photos, Immich self-hosted, ou um rsync agendado. Não reinventei essa parte porque ela não é o problema interessante. O problema interessante começa depois que a foto está no NAS.
2. O worker: o coração silencioso do sistema
Tem um Mac Studio M3 Ultra (com 96GB de memória unificada) que fica ligado 24/7 monitorando o NAS. Quando uma foto nova aparece, ele entra em ação.
O fluxo dele segue uma regra simples: sempre tenta a verificação mais barata primeiro. Antes de gastar IA em qualquer coisa, ele faz uma cascata de checks:
Já vi esse caminho antes? Se sim, ignora.
Já vi um arquivo com esse mesmo nome e tamanho? Se sim, ignora.
Já vi essa assinatura exata do arquivo (md5)? Se sim, é o mesmo arquivo num novo lugar — só anota o novo caminho.
É um screenshot? Tem caminho curto: salva metadados básicos, gera thumbnail, e segue. Não desperdiça IA descrevendo um print de conversa.
É foto "de verdade"? Aí sim entra o pipeline completo: EXIF, hash perceptual, rostos, descrição visual, embedding, geocoding.
Cada degrau evita o degrau seguinte. Isso é fundamental porque o pipeline completo tem custo real por foto, e 47 mil fotos viram muita hora de processamento se você for burro e fizer tudo do zero toda vez. Em produção, depois do primeiro backfill, 99% das fotos novas param nos primeiros checks em milissegundos.
Esse tipo de decisão é o que separa um sistema que funciona de um sistema que parece funcionar até você ligar pra valer.
3. O hash perceptual: o detector de quase-duplicatas
Hash de arquivo (tipo md5) mata duplicata exata. Não mata aquela foto que você editou, recortou, comprimiu, mandou pelo WhatsApp e salvou de novo. Pra isso existe hash perceptual: um fingerprint baseado no visual da imagem, não no byte. Imagens parecidas geram hashes próximos. Quanto mais próximos, mais idênticas.
Resultado prático: na minha biblioteca tinha foto repetida em 4-5 versões diferentes (original, edição, captura de tela do Instagram, reenvio pelo WhatsApp). Cada uma com nome e tamanho diferentes, mas todas visualmente a mesma coisa. O hash perceptual agrupou tudo. Caí de ~52k pra ~47k fotos limpas.
5 mil fotos lixo que eu nem sabia que tinha.
4. O VLM local: a parte que realmente entende a foto
Essa é a peça onde a maior parte das pessoas para. Rodar um VLM (Vision-Language Model — um modelo de IA que olha pra imagem e descreve em texto) decente localmente, em hardware de consumidor, com qualidade que se compara a API externa, é onde o trabalho começa a ficar interessante.
Hoje eu uso Qwen3.6-35B-A3B. É um modelo de visão recente da Alibaba com uma arquitetura inteligente: 35 bilhões de parâmetros totais, mas só ~3 bilhões ativos por token (é o que o "A3B" no nome significa — uma arquitetura chamada Mixture of Experts, onde o modelo seleciona dinamicamente um subconjunto pequeno de "especialistas" pra cada decisão).
Na prática isso quer dizer: a inteligência é de um modelo de 35B, mas o custo de rodar é mais perto de um modelo de 3B. É o melhor dos dois mundos. E ele roda confortável no Mac Studio M3 Ultra com 96GB de memória unificada que eu uso pra esse pipeline.
A diferença pra modelos menores não é sutil. Qwen3.6 escora ~82% no MMMU, que é o benchmark padrão de raciocínio visual multimodal — território que até pouco tempo era exclusivo de modelos proprietários da OpenAI e Anthropic. Quando ele descreve uma foto, a descrição é boa o suficiente pra eu confiar que a busca semântica em cima vai funcionar. Não é mais "IA local que dá pro gasto". É "IA local que entrega".
O que eu peço pra ele em cada foto é mais ou menos isso: descrição rica em 2-3 frases, lista de tags, objetos visíveis, frases curtas de ação ("tomando vinho", "rindo"), humor da cena, cores dominantes, contagem de pessoas, se é screenshot, e um score de NSFW. Tudo estruturado, pronto pra virar campo de banco.
Pra dar uma ideia concreta, o prompt que eu uso é mais ou menos o que está abaixo. Isso aqui é uma versão resumida e didática, não é o prompt original do meu pipeline — o real tem mais regras, exemplos, controles de formato e tratamento de borda. Eu coloco aqui só pra você entender o formato da ideia, o tipo de informação que dá pra extrair pedindo certo:
SYSTEM:
Você é um analisador de fotos pessoais. Sua saída é JSON estrito.
Para cada imagem, retorne:
- description: descrição rica em 2-3 frases (cena, contexto, ambiente)
- tags: 5-15 tags curtas em português
- objects: objetos visíveis
- actions: frases de ação curtas (ex: "tomando vinho", "rindo")
- mood: humor da cena (festivo, contemplativo, casual...)
- dominant_colors: 3 cores dominantes em nome humano
- people_count: número de pessoas visíveis
- nsfw_score: 0.0 a 1.0
- is_screenshot: bool
- setting: "indoor" | "outdoor" | "mixed" | "unknown"
USER (quando rostos já são conhecidos):
Pessoas conhecidas detectadas nesta foto: ["Júlia", "Gabriel"].
Use os nomes nas descrições e ações quando relevante.Tem um detalhe nesse prompt que merece atenção, porque é onde o sistema vira algo realmente diferente: o bloco "USER" quando rostos já são conhecidos.
O reconhecimento facial roda antes do VLM. Quando ele identifica gente que o sistema já conhece, esses nomes são injetados no prompt junto com a imagem. Por que isso importa tanto? Porque muda completamente o tipo de informação que o modelo gera.
Sem os nomes injetados, a descrição é genérica: "uma mulher de cabelos castanhos sorrindo num restaurante". É verdadeira, mas é inútil pra busca — você não vai digitar "mulher de cabelos castanhos no restaurante".
Com os nomes injetados, a descrição vira específica e relacional: "Júlia rindo num restaurante italiano enquanto enrola spaghetti no garfo, ao lado de Gabriel". Agora você tem nome de pessoa real, ligado a ação real, ligado a objeto/cena real, no mesmo texto. É isso que permite buscas do tipo:
"Júlia comendo massa" → encontra a foto via
Júlia + ação(comer) + objeto(spaghetti)"Gabriel rindo" → encontra qualquer foto onde a descrição menciona Gabriel associado à ação de rir
"eu e Júlia juntos" → encontra fotos onde os dois nomes aparecem na mesma descrição (não só na mesma imagem)
"Júlia segurando algo verde" → relaciona pessoa, ação e cor numa única busca semântica
É a diferença entre "o modelo viu uma pessoa" e "o modelo viu a Júlia fazendo X com Y". A primeira gera dado morto. A segunda gera relações consultáveis: pessoa → ação → objeto, pessoa → ação → pessoa, pessoa → ação → lugar. Esse é o encadeamento que faz a busca funcionar como funciona.
5. Reconhecimento facial: identificar sem catalogar manualmente
O reconhecimento facial usa FaceNet, o modelo do Google que transforma cada rosto numa espécie de impressão digital matemática. Rostos parecidos geram impressões parecidas. Comparar é matemática simples.
Mas o macete não é o modelo. O macete é o clustering progressivo.
Eu não vou catalogar todo mundo manualmente. Isso é trabalho de um domingo inteiro de psicopata. Em vez disso, o sistema agrupa automaticamente todos os rostos não identificados que pareçam ser a mesma pessoa, e quando um cluster fica grande o suficiente, ele me pergunta uma única vez: "essa pessoa que aparece em 47 fotos, quem é?".
Eu nomeio uma vez. A partir dali, qualquer rosto novo que apareça parecido com aquele já é automaticamente associado à pessoa.
Comecei com 0 pessoas catalogadas. Hoje tenho ~80. O esforço total foi de uns 20 minutos espalhados em uma semana. Não tem catalogação massiva. Tem o sistema te perguntando coisas óbvias na hora certa.
6. Embeddings: como a busca semântica funciona de verdade
Aqui é onde mora a mágica. Quando o VLM gera a descrição, ela vira um embedding — termo chique pra "representação matemática do significado daquela frase".
Pensa numa biblioteca. Livros parecidos normalmente ficam perto uns dos outros nas estantes. Embedding é exatamente isso, mas pro significado das coisas, num espaço matemático. "Jantar romântico" e "casal num restaurante italiano à noite" são frases diferentes, mas vivem perto uma da outra nesse espaço.
É isso que permite buscar do jeito que você pensa, não do jeito que você cataloga.
Quando você digita "comida italiana com a Júlia", a sua frase também vira embedding. O sistema procura quais fotos têm descrições com embeddings próximos do seu. As mais próximas aparecem primeiro. Não importa se a descrição da foto não tem nenhuma palavra que você digitou — importa que o significado bate.
É a diferença entre "o computador entende texto" e "o computador entende sentido".
7. Metadados: o sinal que vem de graça
Toda foto que você tira já vem cheia de dado escondido: data, hora, câmera, ISO, GPS (se você deixou ligado). Isso é dado de graça e é o sinal mais confiável que existe — não foi inferido por IA, foi gravado pelo próprio sensor da câmera.
Quando tem GPS, eu faço reverse geocoding (transformar lat/long em nome de lugar) e armazeno a hierarquia: país, estado, cidade, bairro, rua. Tudo isso usando um servidor de geocoding que roda local — porque obviamente eu não vou bater na API do Google só pra resolver coordenada.
Resultado: "fotos tiradas em Vienna", "fotos em Milão em 2024", "fotos no raio de 1km daquela igreja" — tudo vira filtro direto, sem precisar de IA.
8. Onde tudo isso vive
Tudo o que sai do worker — descrição, tags, rostos, lugares, embeddings, metadados — vai pra um banco de dados único. É ele que torna o sistema executável.
O ponto importante não é o banco em si. É o que ele permite: perguntar qualquer coisa sobre qualquer foto em milissegundos. Pessoa, lugar, data, câmera, objetos, semântica, similaridade visual — tudo na mesma camada, tudo combinável.
Isso é o que dá a sensação de "o sistema entende minhas fotos". Não entende. Ele tem uma versão estruturada de cada foto, e responde perguntas em cima dessa versão. A diferença é semântica, mas é a diferença que importa: o sistema não pensa, ele consulta — só que consulta um índice tão rico que parece pensamento.
A UI é só uma camada bonita por cima dessa consulta.
9. A busca: dois modos, um cérebro
Esse é o ponto onde eu vi muita gente errar: busca semântica pura é ruim. Se você manda toda query pra vetor, você perde precisão em filtros óbvios. "Fotos de 2023" não precisa de IA. "Fotos com a Júlia" também não. Mas "Júlia rindo com vinho" precisa.
Então a UI tem dois modos.
Modo estruturado (filtros e menções)
Quando você usa filtros ou @menções pra construir a busca, vira consulta direta no banco. Pessoa = Júlia, data = dezembro/2024, lugar = Vienna, tag = café. Filtro é filtro. Sem IA. Sem embedding. Sem latência.
Modo natural (texto livre)
Quando você digita uma frase, o sistema faz outra coisa.
Primeiro, ele manda a sua frase pra um LLM local (Qwen 2.5 7B) com um trabalho específico: decompor sua intenção. "Foto da Júlia com vinho num jantar em Milão ano passado" sai dali decomposta em pessoa (Júlia), lugar (Milão), data (2024), objetos (vinho), tema (jantar romântico).
Depois, aplica os filtros duros primeiro — pessoa, local, data. Isso corta o universo de 47k pra talvez 800 fotos. Só nesse subconjunto menor ele faz o ranqueamento por semântica: embeddings, tags, descrição, ações.
O insight é importante: busca semântica não substitui filtro estruturado, ela complementa. O filtro corta o espaço. A semântica ranqueia o que sobrou. Quem inverte essa ordem cria sistema lento e impreciso.
O que o sistema sabe sobre cada foto
Por trás dos panos, toda imagem deixa de ser "um JPEG no NAS" e vira esse conjunto de sinais:
CategoriaSinais extraídosOrigem Identidadehash do arquivo, hash perceptual, caminho, dimensõesArquivo Tempoquando foi tirada, dia da semana, horaEXIF Câmeramarca, modelo, lente, ISO, aberturaEXIF LugarGPS, país, estado, cidade, bairroEXIF + geocoding Tipofoto vs. screenshot, score de NSFWHeurística + VLM Conteúdo visualdescrição, tags, objetos, ações, humor, coresVLM local Pessoasnº de rostos, embedding facial, pessoa conhecidaFaceNet + cluster Semânticaembedding de texto da descriçãoEmbedding model
O que isso permite na prática
Tudo isso parece muito teórico até você ver o que vira possível. Algumas buscas reais que eu faço todo dia, divididas por tipo:
Busca por pessoa
"fotos da Júlia"
"Júlia e eu juntos"
"Júlia sozinha"
"Fabrício rindo"
"meus pais juntos"
"meu irmão criança"
Busca por lugar
"fotos em Vienna"
"fotos em Milão em 2024"
"fotos em Paris no inverno"
"fotos tiradas em aeroportos"
"fotos na praia, qualquer praia"
Busca por momento ou data
"dezembro de 2024"
"feriados de 2023"
"fim de semana passado"
"primeira foto que tirei daquela viagem"
Busca por cena, contexto e estética
"jantar romântico num restaurante italiano"
"café da manhã num hotel"
"vista de janela de avião"
"prédios antigos da Europa"
"obra de arte num museu"
"restaurante à noite com luz baixa"
"vinho na mesa"
"pratos vistos de cima"
Busca por atributo visual
"foto com vestido verde"
"fotos com céu azul"
"fotos em preto e branco"
"fotos com duas pessoas"
"fotos com mais de cinco pessoas"
Busca de gestão da biblioteca
"fotos sem EXIF" (geralmente prints ou downloads)
"fotos com rosto mas sem pessoa catalogada" (queue de revisão)
"conteúdo mais sensível"
"quase-duplicatas"
"screenshots de receitas"
"documentos fotografados"
O salto: filtros compostos com várias pessoas ao mesmo tempo
É aqui que o sistema deixa de ser "busca melhor" e vira algo que nenhum produto comercial faz direito hoje. Porque cada pessoa catalogada vira um filtro independente, eu consigo combinar várias delas numa mesma busca e perguntar quem aparece junto de quem, em qualquer combinação.
"eu, Fabrício e meus pais" — exatamente as quatro pessoas, juntas na mesma foto
"Júlia e minha mãe sem mim" — duas pessoas presentes, terceira ausente
"eu e Júlia em qualquer lugar fora do Brasil" — duas pessoas + filtro geográfico
"Fabrício comigo num restaurante" — duas pessoas + contexto de cena
"todas as fotos que existem do meu pai com a Júlia" — relação entre duas pessoas específicas
"qualquer foto com pelo menos 3 das pessoas que eu mais fotografo" — agregação
Esse último tipo de busca é o que nenhum álbum, nenhuma pasta, nenhuma tag manual jamais vai dar pra você. Você não consegue antecipar todas as combinações possíveis de pessoas que vão importar daqui a 5 anos. Mas se você indexou pessoa por pessoa, qualquer combinação delas vira uma pergunta válida.
É a diferença entre uma biblioteca organizada e uma biblioteca consultável. A primeira responde "onde está a foto que eu já sei que existe". A segunda responde "quais fotos existem que satisfazem essas condições" — inclusive condições que você nunca tinha pensado em formular antes.
Nenhuma dessas buscas seria possível com filtro tradicional. Nenhuma envia uma foto pra fora do meu hardware. Esse é o ponto.
Decisões controversas que eu fiz
Algumas escolhas que vão te incomodar e eu vou defender.
Não uso CLIP pra busca direta de imagem→texto
CLIP é o padrão da indústria pra busca de imagem por texto (você joga texto, ele te dá imagens parecidas direto). Eu testei. Funciona razoavelmente, mas falha exatamente onde eu mais precisava: contexto pessoal. CLIP foi treinado em legendas genéricas da internet. Ele não sabe quem é Júlia, não sabe que aquele restaurante é o nosso, não sabe que aquela cor é a do nosso sofá.
VLM gerando texto rico (que sabe quem é Júlia) + embedding sobre esse texto é mais lento na indexação, mas dá resultado muito superior na busca. Eu indexo uma vez. Eu busco mil vezes. Otimizei pra busca.
Tudo num só banco em vez de juntar várias ferramentas especializadas
Existe uma cultura de empilhar ferramenta especializada pra cada problema: um banco pro texto, outro pros vetores, outro pra geolocalização, outro pra cache. Eu fugi disso o quanto pude. Adicionar peça de infra pra ganhar marginalmente em performance que eu não preciso é over-engineering. Quanto menos servidor, menos lugar pra dar problema às 3 da manhã.
Por que não usar API externa, apesar de ser mais rápido
Essa seção merece existir sozinha porque é a pergunta que todo dev faz quando vê o post: "mas Gabriel, é muito mais simples mandar isso pro GPT-4o, Gemini, Claude. A descrição vai ser melhor, vai ser mais rápido, vai custar centavos por foto. Por que se complicar?".
Tudo isso é verdade. E mesmo assim eu escolhi não fazer. Vou te explicar exatamente por quê.
O que você está realmente mandando
Quando você usa uma API de visão de qualquer um desses provedores, cada foto sua é enviada inteira, em alta resolução, pelos servidores deles. Não é "um vetor numérico abstrato". Não é "um hash". É a imagem original, decodificada, processada por um modelo que mora num data center que você não controla, sob uma política de privacidade que pode mudar amanhã sem te avisar direito.
Pensa no que tem na sua galeria. Não na curadoria do Instagram. Tudo. Documento fotografado pra mandar pro contador. Print de conversa importante. Foto do filho na banheira que você mandou pra avó. Nudes que existem porque você confia em quem recebeu. Receita médica. Comprovante de endereço. A sua intimidade visual inteira.
Mandar isso pra API externa não é um problema teórico. É um problema concreto: você está, literalmente, terceirizando o acesso à sua vida visual completa pra uma empresa cuja política de uso é unilateralmente alterável.
"Mas eles dizem que não treinam com meus dados"
Hoje. Pra esse plano. Sob esse contrato. Com esse CEO. Naquele país. Qualquer uma dessas variáveis muda, o contrato muda com ela.
E tem o problema mais imediato: mesmo que ninguém treine com seus dados, eles existem em log em algum lugar pelo tempo de retenção definido por eles. Uma falha de segurança nesse log, uma intimação judicial num país que não é o seu, uma mudança de política — qualquer uma dessas coisas expõe o que estava lá.
O único dado que ninguém vaza é o dado que nunca saiu da sua máquina. Não tem outro caminho.
O custo real do "mais rápido"
Sim, GPT-4o descreve uma foto em ~1 segundo. Qwen3.6 local leva uns segundos a mais. Esse é o custo que aparece no benchmark. Mas tem custos que não aparecem:
Custo recorrente — uma API externa cobra por foto, sempre. Local cobra hardware uma vez.
Custo de dependência — se a OpenAI mudar preço, deprecar modelo, ou banir sua conta, seu pipeline morre. Local não morre.
Custo de latência de rede — API depende de internet boa. No meu fluxo, o worker roda 24/7 e nunca depende de conexão externa pra processar uma foto que apareceu no NAS.
Custo de auditabilidade — quando você roda local, você sabe exatamente o que entrou, o que saiu, e o que ficou guardado. Com API externa, você confia.
A pergunta certa não é "qual é mais rápido". A pergunta é "qual o custo total ao longo de 5 anos, considerando que minhas fotos são pra sempre". Local ganha por uma margem absurda.
Quando API externa faria sentido (sendo honesto)
Pra ser justo: existem cenários onde a balança vira.
Se você é uma empresa processando fotos de outras pessoas que já consentiram com o uso de IA externa, a discussão muda. Se você está prototipando uma ideia e quer validar a hipótese antes de comprar hardware, faz sentido começar pela API. Se o volume é baixíssimo (centenas de fotos, não dezenas de milhares), o custo marginal da API talvez não justifique o investimento em local.
Mas nenhum desses sou eu. Eu sou um indivíduo, processando minhas próprias fotos, num volume alto, pra uso eterno. Pra esse perfil, local é a única resposta racional.
O que eu ganho em troca da "complicação"
Privacidade real, não declarada. Custo zero por inferência. Independência de provedor. Disponibilidade offline. Auditabilidade total. E uma propriedade que ninguém fala: a tranquilidade mental de saber que esse problema está resolvido pra sempre. Não vai ter notícia de vazamento que me afete. Não vai ter mudança de política que me obrigue a migrar.
Eu paguei o custo de complexidade uma vez. Eu colho a paz de espírito todo dia.
Quanto tempo, quanto custou
Pessoas perguntam isso então vou responder:
Tempo de construção: 1 fim de semana pra MVP funcional. 3 semanas pra chegar onde está hoje (com clustering progressivo de rostos, modo natural com LLM, UI decente).
Hardware: Mac Studio M3 Ultra com 96GB de memória unificada — comprei pensando em rodar inferência local de forma séria. Synology DS923+ que eu já tinha.
Custo de inferência: R$ 0. Tudo local.
Backfill inicial das 47k fotos: 36 horas rodando em background.
Custo recorrente: energia da máquina ligada 24/7. ~R$ 30-40/mês.
Pra comparação: Google Photos no plano que comporta meu volume seria ~R$ 30/mês pra sempre. Aqui o hardware é meu, a IA é minha, e o break-even é questão de tempo — depois disso é puro upside.
O que ainda não está pronto
Honestidade: o sistema tem buracos.
Vídeo ainda não é tratado. Quero rodar IA em vários frames e gerar resumo temporal, mas hoje vídeo está fora do pipeline.
Eventos (agrupar fotos do mesmo dia/lugar/pessoas num "evento") existe só como heurística simples. Queria que fosse algo mais inteligente.
App mobile não tem. A UI é web. Funciona no celular, mas não é nativa. Provavelmente é o próximo projeto.
Backup precisa ser explícito. O NAS tem snapshot, o banco não roda no NAS, então eu mantenho um dump diário pra lá.
Por que você deveria construir o seu
Eu sei que esse post tem um problema: ele descreve algo complexo o suficiente pra parecer fora do alcance. Não é. Cada componente individual é coisa de fim de semana. A complexidade aparente vem da soma, não das partes.
Se você é dev e gostou da ideia, comece pequeno. Indexa um diretório de fotos, extrai EXIF, gera thumbnails. Depois plugue reconhecimento facial. Depois um VLM local. Depois embeddings. Depois a busca. Não tente tudo de uma vez. Cada peça precisa funcionar isolada antes de virar parte de um sistema.
E mesmo que você nunca construa nada disso: pelo menos saiba que é possível. Saiba que você não é refém da Apple ou do Google pra ter busca decente nas suas fotos. Saiba que existe uma alternativa onde sua vida visual não vive num servidor de uma corporação.
Perguntas frequentes
Isso funciona em Windows ou Linux?
Sim. Eu uso Mac por preferência e porque Apple Silicon tem inferência local muito boa via memória unificada. O mesmo desenho funciona em Linux com GPU NVIDIA (até melhor, se você tiver uma boa). Em Windows, o caminho é WSL2 + GPU NVIDIA.
Qual VLM você recomenda pra começar?
Depende do quanto de hardware você tem. Pra começar com pouco e validar a ideia, qualquer VLM da família Qwen3-VL menor (7B-8B) já entrega bem. Pra qualidade que se compara a API externa, Qwen3.6-35B-A3B é o que eu uso hoje e o que eu recomendo — é MoE, então o custo de rodar é muito mais baixo do que o tamanho sugere. Em Apple Silicon, MLX e Ollama já têm builds prontas.
Preciso de quanto de RAM?
Pra rodar Qwen3.6-35B-A3B junto com embeddings e reconhecimento facial sem apertar, recomendo 96GB de memória unificada (foi o que eu fiz). Dá pra apertar em menos, mas se você está montando hardware do zero pra esse uso, ir de 96GB é a decisão certa — sobra espaço pro modelo, pro pipeline e pro futuro.
E se eu não souber programar?
Honestamente: provavelmente esse não é o sistema pra você hoje. Mas as peças individuais estão se popularizando rápido. Immich (self-hosted) já tem reconhecimento facial e busca decente. PhotoPrism idem. Eles não chegam onde meu sistema chega em busca semântica, mas estão muito mais perto do que estavam há 2 anos. Em 2-3 anos vai existir produto pronto pra fazer 80% disso.
Você vai abrir o código?
Eventualmente. O sistema hoje está acoplado demais à minha infra pessoal. Quero passar mais 2-3 meses limpando até ele virar algo plug-and-play, e aí solto. Se você quer ser avisado, assina o feed do blog ou me segue.
Quanto custa rodar tudo isso?
Recapitulando: hardware uma vez (no meu caso, Mac Studio M3 Ultra + NAS — o investimento sério é a máquina de IA, que comprei pra rodar inferência local de forma séria, não só pra esse projeto), energia ~R$ 30-40/mês recorrente. Comparado ao Google One Premium pra meu volume, o break-even depende do uso, mas a vantagem real não é financeira: é independência e privacidade. O hardware fica seu.
Não é mais simples só pagar o Apple iCloud+?
Mais simples? Sim. Resolve o problema que esse post descreve? Não. iCloud te dá armazenamento, não busca semântica de verdade nem privacidade absoluta. São produtos resolvendo problemas diferentes.
O ponto final
Eu tenho 47 mil fotos. Eu acho qualquer uma em segundos. Eu não preciso lembrar onde a foto está — só preciso lembrar do momento.
Isso não é mágica. É um sistema com peças bem conhecidas, montadas com critério, rodando em hardware que eu controlo. É o tipo de coisa que vira commodity em 5 anos, mas que hoje ainda é território de quem está disposto a construir.
Se você se identifica com o problema, se você também ficou frustrado com a busca do Google Photos, se você também tem uma desconfiança crescente de que sua vida visual não devia viver num servidor de terceiros: esse é o caminho. Não é o único, mas é um que eu posso garantir que funciona, porque eu uso todo dia.
E honestamente: isso ainda é só o começo.
Se quiser acompanhar os próximos posts onde eu vou abrir cada peça desse sistema em detalhe (IA local em produção, clustering progressivo de rostos, busca semântica em escala), assine o feed e me segue.