Indexando localmente um ano de vídeos em um MacBook de 2021 com Gemma4-31B (50GB de swap)
(blog.simbastack.com)- O gargalo de um arquivo de vídeos não era a ferramenta de edição, e sim a impossibilidade de busca; o foco foi transformar clipes sem rótulo em um índice consultável em inglês
- Com um design local-first, foram criados arquivos sidecar
.description.mdao lado de cada clipe, extraindo em uma única chamada de visão rating, iluminação, localização, transcrição, palavras-chave e descrição em prosa - O pipeline reúne
ffprobe,exiftool, Nominatim,ffmpeg, WhisperX,insightfacee um modelo de visão para gerar metadados, GPS, frames, transcrições e embeddings faciais - Um MacBook Pro de 16 polegadas de 2021 com M1 Max e 64GB rodou o Gemma 4 31B Q4 no LM Studio, e durante o processamento em lote o swap chegou a 50,89GB
- Um esquema estruturado e restrições com enum reduziram alucinações, e foi possível montar um fluxo em que a indexação em massa roda no 31B local e só os 10~20% mais difíceis são reavaliados por um modelo em nuvem
O ponto de partida do problema: busca, não edição
- Durante quase meio ano na Maasai Mara, vídeos gravados com iPhone, DJI Pocket, drone, Nikon Z8 e Ray-Ban Meta continuaram se acumulando, mas a maioria acabou ficando sem nunca mais ser aberta
- Os canais sociais da Mara Hilltop ficaram parados por 3 meses não por falta de conteúdo, mas por falta de tempo de edição
- Com Claude Code e Opus 4.5/4.6, o trabalho de desenvolvimento passou a permitir execução longa de agentes e tarefas paralelas, e isso, somado ao lançamento da primeira hospedagem paga do KaribuKit, reduziu ainda mais o tempo disponível para editar vídeo
- A primeira solução imaginada foi uma stack SaaS de US$ 140/mês combinando Eddie AI, Higgsfield MCP, Submagic e Buffer, mas isso não atacava o gargalo real
- Vídeo generativo por IA não combinava com uma marca de viagem real, e cenas de IA exibidas de forma incorreta poderiam prejudicar a confiança quando os hóspedes esperam ver o lugar de verdade
- A frequência de postagem realista era mais próxima de 2 a 3 por semana, não de 3 a 5, então o plano inicial provavelmente falharia já na segunda semana
- Como DaVinci Resolve Studio e os recursos IntelliSearch, Smart Bins e Voice to Subtitle do Resolve 21 já cobriam cerca de 70% do que o Eddie oferecia, a maior parte já estava disponível
- O que restava era uma estrutura em que o Claude Code controlaria o Resolve via o MCP open source do DaVinci Resolve e usaria ElevenLabs para voiceover apenas em clipes informativos, reduzindo o custo para US$ 22/mês
O gargalo real: antes de um editor com IA, era preciso um índice
- Os editores de vídeo com IA no mercado presumem que o vídeo já está rotulado, mas na prática o arquivo real estava espalhado com nomes como
IMG_*.mov,DJI_*.mp4eMara june 2024 backup final FINAL - O Eddie permitia busca por transcrição, mas não conseguia encontrar cenas como “elefantes no alto da colina na golden hour” em um arquivo sem rótulos
- Nome do arquivo, pasta pai, coordenadas GPS e texto da transcrição não são suficientes para saber o conteúdo visual de algo como “um plano aberto do nascer do sol com girafas no quadro”
- O verdadeiro ponto de alavancagem não estava acima do editor, mas antes dele: primeiro era necessário um índice que tornasse o arquivo consultável em inglês
Design do indexador local-first
- A estrutura geral era parecida com os builds AI-native que a SimbaStack faz para clientes, mas como a mesma pessoa era cliente e engenheiro, as decisões puderam ser tomadas rapidamente
-
Quatro restrições
- Precisava ser local-first
- O arquivo da Mara Hilltop estava em SSDs físicos e os vídeos pessoais no notebook, então enviar milhares de clipes de vários GB para a nuvem não fazia sentido nem em custo nem em privacidade
- Havia preferência por arquivos sidecar em vez de um banco central
- Um
.description.mdfoi colocado ao lado de cada clipe para permitir busca com grep em texto puro - Mesmo que o indexador quebrasse depois, os arquivos permaneceriam, e ao mover entre drives os dados iriam junto
- Um
- Era preciso extrair tudo o que importava em uma única chamada de visão
- Como o passo de visão sobre frames extraídos é caro, o esquema foi desenhado desde o início de forma ampla para já capturar também informações que poderiam ser úteis depois
- Isso incluía rating, qualidade técnica, iluminação, hora do dia, paleta de cores, qualidade do áudio, número de pessoas, palavras-chave, rostos, localização, transcrição e descrição em prosa
- Era necessário poder escolher entre três backends de visão
- O padrão era a CLI do Claude Max, já inclusa na assinatura e sem custo marginal
- Quando velocidade era prioridade, usava-se a API da Anthropic
- Para processamento em lote, foi usado um backend local apontando para o LM Studio, e esse backend local era a peça central
- Precisava ser local-first
Pipeline de processamento por clipe
ffprobelê os metadadosexiftoollê latitude, longitude e altitude do GPS, funcionando igualmente em vídeos de iPhone, DJI Pocket e drone- O Nominatim faz reverse geocoding; é gratuito, tem limite de taxa e não exige chave de API
ffmpegextrai 5 frames de 1920px em intervalos uniformes- WhisperX faz a transcrição com alinhamento por palavra e diarização de falantes com pyannote, com suporte a 97 idiomas, incluindo hindi, inglês e suaíli
insightfacedetecta rostos e salva embeddings ArcFace de 512 dimensões em um banco facial SQLite central para permitir busca por pessoas em todo o arquivo depois- O modelo de visão lê frames, partes da transcrição e o contexto da pasta, e retorna frontmatter em YAML e uma descrição em prosa
- O resultado final é gravado como um sidecar
.description.mdao lado do clipe - No clipe real
IMG_1103.MOVda Mara Hilltop, o nome do arquivo sozinho não dizia nada sobre o contexto, mas o sidecar gerado pelo Gemma incluía montagem de tenda de safári, um movimento de câmera do interior para a savana, tipo de plano e usos como reels de marketing e B-roll de vlog de viagem - No nível da pasta, além dos sidecars ao lado de cada clipe, também eram gerados
_INDEX.jsone_INDEX.mdpara grep rápido e envio para LLMs - A implementação toda ficou em cerca de 1.400 linhas de Python como uma skill do Claude Code; a maior parte foi escrita pelo próprio Claude Code, enquanto o papel humano ficou em arquitetura, prompts, design de esquema e triagem de bugs
Um modelo local 31B rodando em um MacBook antigo
- O MacBook Pro de 16 polegadas com M1 Max e 64GB de RAM comprado em 2021 não foi escolhido originalmente para LLMs, mas para rodar ao mesmo tempo abas do Chrome, DaVinci Resolve, Slack, Discord e Drive
- Cinco anos depois, o mesmo notebook rodou o Gemma 4 31B Q4 no LM Studio e processou um arquivo de vídeo de um ano inteiro
- No LM Studio, um modelo de 28,40GB foi carregado na memória, e a API REST ficou disponível em
127.0.0.1:1234 - Durante o processamento em lote, 64GB de RAM não foram suficientes, e o uso de swap no Activity Monitor chegou ao pico de 50,89GB
- Isso não era um estado para manter continuamente em um dia normal de trabalho, mas foi considerado aceitável para forçar a máquina durante um fim de semana
- O notebook esquentou, os ventiladores dispararam, mas continuou gerando sidecars enquanto outras tarefas eram feitas
- O MacBook Pro M1 Max de 16 polegadas mostrou margem para rodar um modelo de 31B parâmetros em velocidade utilizável mesmo em hardware de 5 anos, e se os LLMs locais ficarem mais eficientes, ainda deve servir por mais 3 a 5 anos
Quatro bugs e lições aprendidas
-
Mudança de API na diarização do WhisperX 3.8
- No WhisperX 3.8,
whisperx.DiarizationPipelinefoi movido para o submódulowhisperx.diarize - O argumento do construtor
use_auth_tokenfoi renomeado paratoken, acompanhando o pyannote 3.x - A solução foi introspecção de assinatura
- O script tenta primeiro
token=e, se o construtor lançarTypeError, faz fallback parause_auth_token= - Ao chamar bibliotecas de IA que mudam rápido, uma chamada defensiva ao construtor funciona como um seguro barato
- No WhisperX 3.8,
-
A CLI do Claude devolvia erro de permissão como se fosse resposta bem-sucedida
- No primeiro teste do backend da CLI, os 4 sidecars voltaram com o mesmo texto: “I need permission to read the image frames...”
- O código de saída era 0 e a saída não estava vazia, então o script considerou aquilo um sucesso
- Sem
--permission-mode bypassPermissionsno modo não interativo, a Claude CLI devolvia o texto de negação de permissão no corpo da resposta em vez do prompt - A solução foi adicionar essa flag e tratar respostas curtas contendo “I need permission” como erro, não como descrição
- Ao usar ferramentas de IA em scripts, fluxos de permissão não interativos podem esconder falhas silenciosas
-
O Gemma retornava
people_count: "many"- Como o prompt de visão instruía
integer or the string "many" if >10, o Gemma na verdade estava seguindo a instrução corretamente - O bug não estava no modelo, mas no design do esquema
- Depois da correção, passou-se a pedir uma estimativa inteira entre 0 e 99, e respostas antigas com
"many"passaram a ser convertidas à força pelo parser - Campos do esquema não devem ser definidos como union do tipo
int ou string específica; é melhor fixar sempre como inteiro ou sempre como string para simplificar o consumo downstream
- Como o prompt de visão instruía
-
Um clipe tremido de moto foi descartado por engano
- O prompt inicial de cull seguia mais um padrão de portfólio fotográfico, então motion blur pesado, foco suave e tremor recebiam nota
cull - Um clipe noturno handheld de uma viagem à Espanha, gravado na moto, também foi marcado para descarte, embora justamente esse desfoque carregasse a atmosfera da lembrança
- O critério de cull foi alterado de “filmagem imperfeita” para “algo que não é um registro real”
- Os descartes passaram a se restringir a clipes como tampa da lente, gravação dentro do bolso, testes de 2 segundos e exposição completamente estourada
- Arquivos de fotos podem ter cull agressivo, mas memórias em vídeo exigem um cull mais tolerante; mesmo com o mesmo esquema, os modos precisam ficar explícitos
- O prompt inicial de cull seguia mais um padrão de portfólio fotográfico, então motion blur pesado, foco suave e tremor recebiam nota
Conclusões com esquema estruturado e modelo local
-
Restrições com enum reduzem alucinações
- O Gemma 4 E4B descreveu uma foto noturna de um coworking como “brightly lit, abundant natural light, floor-to-ceiling windows”, embora do lado de fora estivesse completamente escuro
- Quando recebeu um esquema estruturado e teve que escolher entre
golden_hour | bright_daylight | overcast | dim_interior | nighttime | mixed | unclear, o 31B recuperounighttimetanto com thinking-off quanto com thinking-on - Em prosa aberta, o modelo pode inventar descrições falsas, mas em um enum ele não pode criar novos valores, só escolher o errado
- O esquema se mostrou mais seguro do que a instrução
-
Um 31B local com prompts estruturados reduz a distância para a nuvem
- O Gemma 4 31B Q4 em thinking-off, usando esquema estruturado, produziu em muitos clipes de teste saídas difíceis de distinguir das do Sonnet 4.6
- O prêmio dos modelos de nuvem estava nos 10~20% de clipes mais difíceis
- Para o trabalho em massa de indexar milhares de clipes durante a noite, fazia sentido rodar localmente e mandar para a nuvem apenas os clipes marcados como
reviewpelo modelo local, num fluxo de duas etapas escalável
-
Editores de vídeo com IA estão competindo em uma camada alta demais
- A camada realmente valiosa não era o editor, e sim um índice pesquisável
- Se for possível consultar em linguagem natural algo como “clipes handheld internos na Mara, golden hour, com pessoas e mais de 8 segundos”, o editor acima disso fica muito mais simples
- O mercado de editores de vídeo com IA está competindo em uma camada superficial sobre um índice que não existe, pulando justamente a pré-condição
Próximos passos e limitações
- O próximo trabalho é criar um editor usando o Claude Code como orquestrador, o DaVinci Resolve MCP para montar cortes e o ElevenLabs para adicionar voiceover em clipes informativos
- Há limites claros para clonagem de voz
- Ela será usada apenas em conteúdo utilitário, como orientações, descrição de quartos, versões multilíngues e informações factuais que a pessoa realmente diria
- Não será usada em avaliações nem em mensagens do fundador
- Em 2026, regras de divulgação obrigatória já são uma realidade plausível, e a confiança em uma marca de hospitalidade pode se perder facilmente
- Com o índice, dá para evitar scrub manual em 47GB de vídeos da DJI Pocket só para encontrar um plano aberto do nascer do sol
- Agora, no notebook de 5 anos, um ano inteiro de vídeos da Mara Hilltop já pode ser consultado em inglês, ao custo de um fim de semana e 50GB de swap
- Os anos restantes, ainda espalhados por SSDs antigos, são o próximo alvo de processamento
- Os canais sociais da Mara Hilltop ainda não voltaram à ativa
- O indexador resolve apenas o problema de encontrar os clipes certos
- A outra metade é o editor que transforme isso em reels prontos; se der certo, haverá um texto de continuação, e se falhar, o motivo do fracasso será abordado
- A resposta correta talvez seja contratar uma pessoa
- Encontrar um editor com o olhar caloroso e observador que combine com a Mara Hilltop pode ser mais difícil do que escrever mais uma skill
- Reels no estilo MTV, cortados em excesso, não são o que se quer
- O código foi publicado em github.com/Simbastack-hq/framedex e está aberto a PRs e issues
1 comentários
Comentários do Hacker News
Parece que o Claude escolheu a URL errada para compartilhar o post. A menos que a pasta home tenha sido exposta publicamente, não dá para acessar
~/.claude/skills/video-index/, então fiquei curioso se você poderia compartilhar os arquivos de SkillAtualização: criei este repositório às pressas - https://github.com/Simbastack-hq/framedex
A licença é MIT, e ainda não consegui testar tudo direito depois de generalizar o projeto. Vou revisar com calma em breve e adicionar mais atualizações
Os dois grandes itens do TODO são: 1) usar essa indexação com a ajuda do Claude para editar vídeo mais rápido no DaVinci Resolve, 2) por enquanto ele só processa vídeo, mas quero expandir para também entender os milhares de imagens estáticas da câmera
Não entendi bem por que tanto swap é necessário. Considerando a largura de banda de memória exigida, isso pode desgastar o SSD bem rápido
O modelo quantizado em 4 bits do Gemma 4 31B deveria ter algo em torno de 19GiB, não 28.4GiB [1]. Não costumo passar imagens com frequência, então não sei quanta memória extra isso exige no contexto, mas imagino que não passe de 10GiB
Pelo Monitor de Atividade, além do Handy e da máquina virtual do Claude Code que aparentemente carregaram o modelo, também havia vários apps Electron abertos, então parece que a causa real está mais aí. Quando o notebook começa a acessar o disco pesadamente, esses apps acabam travando e ficando inúteis
[1] https://huggingface.co/mlx-community/gemma-4-31b-it-4bit
Mesmo assim, achei impressionante que, embora tenha ficado um pouco engasgado, eu ainda conseguia continuar trabalhando com outras coisas mesmo com várias abas abertas no Brave
Fiquei curioso se você sabia que isso já existe, funciona bem e não consome 50GB de swap
https://github.com/iliashad/edit-mind
Muito legal. Queria ter RAM suficiente para rodar um modelo local. Nas últimas semanas fiz algo bem parecido, mas como um app local em Electron usando Whisper e ffmpeg, com busca semântica e embeddings para conversar com o vídeo
A análise visual, a tagueação e o chat com o vídeo se comunicam com o Claude. Fiquei curioso se este projeto envia só uma imagem. Eu encontro várias imagens diferentes por vídeo com um algoritmo de detecção de cena personalizado e envio tudo para o Claude em uma única requisição junto com as legendas. Sem dúvida essa é a parte mais cara. Usando Sonnet 4.6 para análise e Haiku para tagueação, sai por cerca de 1 dólar para 1 hora de vídeo, e localmente provavelmente seria lento
Só que a forma como escolho os frames é um ponto fraco. Detecção de cena certamente ajudaria e é minha prioridade número 1 no roadmap. Fiquei curioso se você poderia compartilhar como escolhe os frames na detecção de cena
Optei por não incluir busca vetorial e manter tudo simples com arquivos Markdown genéricos e mais portáveis. Se eu mover o SSD, o conhecimento vai junto com os arquivos, não há índice para sincronizar, e texto puro genérico tende a sobreviver mais do que ferramentas. Ainda assim, vale explorar a outra direção que você mencionou
Há outras opções boas também. O Gemini 3.1 Flash Lite é muito bom para esse tipo de tarefa. Só não o Gemini 3.5 Flash. Esse tem um custo-benefício ruim
https://openrouter.ai/google/gemma-4-31b-it
Tenho duas perguntas
description.mdhá itens comofaces -> cluster_id. Isso vem do índice facial do DaVinci Resolve? Em coleções de fotos, informações como rostos+nomes e localização são realmente importantes, e LLMs em geral não lidam bem com isso.description.mdcolocado ao lado do vídeo para cada clipeDepois, ao fazer brainstorming com o Claude sobre algo como “quero montar um vídeo dos quartos premium da pousada”, ele pode consultar os arquivos e descobrir quais vídeos seriam úteis
Também há um arquivo em nível de raiz da pasta reunindo descrições em texto para facilitar a busca. Coloquei uma imagem de exemplo no blog - https://blog.simbastack.com/_media/gvcycx2n.png
Os rostos vêm do insightface. Eu detecto com RetinaFace do pacote open source
buffalo_le rodo tudo localmente na CPU. Depois detecto e gero embeddings dos rostos a partir de frames de amostra de cada clipe e gravo linhas em~/.framedex/faces.dbSinceramente, essa parte eu ainda não testei direito; sei que está sendo acumulada num banco local, mas ainda não validei quão bem funciona. Vou verificar isso em breve
De forma mais ampla, é justamente por isso que o framedex intencionalmente não delega rostos nem localização ao LLM. Rostos são tratados com embeddings do insightface / ArcFace, o que permite comparação determinística entre clipes. O modelo visual só fornece uma contagem aproximada de pessoas, sem tentar identificar quem são
A localização é tratada com EXIF GPS via exiftool e geocodificação reversa com Nominatim/OpenStreetMap. Não é chute, é metadado sólido
O LLM faz só o que ele faz bem: descrição de cena, clima, tipo de tomada, palavras-chave e notas de arquivar/revisar/descartar. Essa parte final das notas é discutível
Tentei rodar o Gemma num ThinkPad de 2015 para fazer algo parecido. Felizmente consegui fazer upgrade de memória; sem isso teria sido bem sofrido
Não vou mentir: rodando llama.cpp, a ventoinha ficou no máximo. Mesmo assim funcionou e concluí o trabalho
Às vezes parece ser só uma metáfora para “está usando 100% dos recursos”, e provavelmente é isso aqui, mas em outros contextos também já vi gente falando disso como uma reclamação literal
Acho que a maioria dos anfitriões do Airbnb não concordaria com a frase “vídeo gerado por IA não tem lugar para uma marca de viagem de verdade”
E essa expressão “crucificação no TripAdvisor” também me faz pensar como anfitriões do Airbnb com anúncios falsos conseguem sobreviver
Por outro lado, vídeo real leva tempo e desacelera todo o processo
Vejo uma limitação estrutural em aplicações B2C de IA: é difícil criar contexto personalizado
Se modelos locais competentes conseguirem fazer coleta de contexto, pesquisa, tagueação etc. do zero em grande escala, isso pode ser um grande avanço
Você pode jogar várias capturas de tela nele, e ele tenta dar nomes inteligentes com base no conteúdo. O mesmo vale para vídeos, PDFs etc.
Mas, como você disse, nem tentei cobrar por isso porque parece o tipo de coisa que a Apple pode simplesmente adicionar como recurso
https://finalfinalreallyfinaluntitleddocumentv3.com/
Mas acho que é só uma questão de tempo até os agentes ficarem inteligentes o bastante para que amigos não técnicos possam apenas dizer “organize os vídeos desta pasta para que eu consiga entendê-los”, e isso aconteça automaticamente