Indexer localement une année de vidéos avec Gemma 4 31B sur un MacBook de 2021 (50 Go de swap)
(blog.simbastack.com)- Le principal goulot d’étranglement d’une archive vidéo n’était pas le montage mais l’impossibilité de faire des recherches, et l’objectif était de transformer des clips non étiquetés en un index interrogeable en anglais
- Avec une conception local-first, des fichiers sidecar
.description.mdsont créés à côté de chaque clip, en extrayant en un seul appel de vision la note, l’éclairage, le lieu, la transcription, les mots-clés et une description en prose - Le pipeline assemble
ffprobe,exiftool, Nominatim,ffmpeg, WhisperX,insightfaceet un modèle de vision pour générer métadonnées, GPS, images, transcription et embeddings de visages - Un MacBook Pro 16 pouces 2021 M1 Max 64 Go faisait tourner Gemma 4 31B Q4 dans LM Studio, et le swap a culminé à 50,89 Go pendant le traitement de masse
- Un schéma structuré et des contraintes enum ont réduit les hallucinations, et il a été possible d’imaginer une configuration où le gros de l’indexation est traité en local avec un 31B, puis où seuls les 10 à 20 % de clips difficiles sont réévalués par un modèle cloud
Point de départ du problème : la recherche avant le montage
- Pendant près de six mois passés dans le Maasai Mara, des vidéos tournées avec un iPhone, un DJI Pocket, un drone, un Nikon Z8 et des Ray-Ban Meta se sont accumulées, mais la plupart sont restées sans jamais être rouvertes
- Les réseaux sociaux de Mara Hilltop étaient à l’arrêt depuis trois mois, non pas par manque de contenu mais par manque de temps de montage
- Avec Claude Code et Opus 4.5/4.6, le travail de développement permettait désormais de longues exécutions d’agents et du travail en parallèle, et avec le lancement du premier hébergement payant de KaribuKit, le temps disponible pour monter des vidéos a encore diminué
- La première solution envisagée consistait en une stack SaaS à 140 $/mois combinant Eddie AI, Higgsfield MCP, Submagic et Buffer, mais elle ne correspondait pas au vrai goulot d’étranglement
- La vidéo générative par IA ne correspondait pas à une vraie marque de voyage, et afficher par erreur des scènes générées par IA à des voyageurs qui s’attendent à voir le lieu réel pouvait nuire à la confiance
- Un rythme de publication réaliste était plus proche de 2 à 3 publications par semaine que de 3 à 5, ce qui rendait le plan initial voué à l’échec dès la deuxième semaine
- DaVinci Resolve Studio et les fonctions IntelliSearch, Smart Bins et Voice to Subtitle de Resolve 21 couvraient déjà environ 70 % de ce qu’Eddie apportait
- La configuration restante consistait à laisser Claude Code piloter Resolve via le MCP open source de DaVinci Resolve, et à n’utiliser ElevenLabs pour la voix off que sur les clips informatifs, ce qui faisait tomber le coût à 22 $/mois
Le vrai goulot d’étranglement : il faut un index avant un éditeur IA
- Les éditeurs vidéo IA du marché partent du principe que les vidéos sont déjà étiquetées, alors qu’en pratique l’archive réelle était dispersée sous des noms comme
IMG_*.mov,DJI_*.mp4ouMara june 2024 backup final FINAL - Eddie permet la recherche dans les transcriptions, mais ne pouvait pas retrouver dans une archive non étiquetée une scène comme « des éléphants sur une colline à l’heure dorée »
- Les noms de fichiers, le dossier parent, les coordonnées GPS et le texte transcrit ne suffisent pas à connaître le contenu visuel d’un plan comme « un plan large au lever du soleil avec une girafe dans le cadre »
- Le véritable levier n’était pas au niveau de l’éditeur mais en amont : il fallait d’abord un index capable de rendre l’archive interrogeable en anglais
Conception d’un indexeur local-first
- L’architecture générale ressemblait aux builds natifs IA que SimbaStack développe pour ses clients, mais ici les décisions ont été rapides parce que la même personne était à la fois cliente et ingénieure
-
Quatre contraintes
- Il fallait être local-first
- L’archive de Mara Hilltop était sur un SSD physique et les vidéos personnelles sur le portable, et envoyer des milliers de clips de plusieurs gigaoctets dans le cloud n’avait de sens ni en coût ni en confidentialité
- Il fallait des fichiers sidecar plutôt qu’une base centrale
- Chaque clip reçoit un
.description.mdà côté de lui, consultable en texte brut avec grep - Même si l’indexeur casse plus tard, les fichiers restent là, et ils se déplacent avec les données d’un disque à l’autre
- Chaque clip reçoit un
- Il fallait extraire en un seul appel de vision toutes les informations nécessaires
- Comme le passage vision sur les images extraites coûte cher, le schéma a été conçu large dès le départ pour récupérer, dès le premier appel, y compris les informations utiles plus tard
- Cela comprenait la note, la qualité technique, l’éclairage, le moment de la journée, la palette de couleurs, la qualité audio, le nombre de personnes, les mots-clés, les visages, le lieu, la transcription, une description en prose, etc.
- Il fallait pouvoir choisir entre trois backends vision
- La valeur par défaut était la CLI de l’abonnement Claude Max, sans coût marginal
- Quand la vitesse était nécessaire, l’API Anthropic était utilisée
- Pour le traitement en masse, un backend local pointant vers LM Studio était utilisé, et c’était ce backend local qui était central
- Il fallait être local-first
Pipeline de traitement par clip
ffprobelit les métadonnéesexiftoollit latitude, longitude et altitude GPS, avec le même fonctionnement sur les vidéos iPhone, DJI Pocket et drone- Un géocodage inverse est effectué avec Nominatim, gratuit, limité en débit et sans besoin de clé API
ffmpegextrait 5 images en 1920 px à intervalles réguliers- WhisperX réalise la transcription avec alignement mot à mot et séparation des locuteurs via pyannote, avec prise en charge de 97 langues dont l’hindi, l’anglais et le swahili
insightfacedétecte les visages et stocke des embeddings ArcFace 512 dimensions dans une base SQLite centrale des visages pour permettre plus tard la recherche de personnes dans toute l’archive- Le modèle de vision lit les images, une partie de la transcription et le contexte du dossier, puis renvoie un frontmatter YAML et une description en prose
- Le résultat final est enregistré dans un sidecar
.description.mdà côté du clip - Dans un clip réel de Mara Hilltop,
IMG_1103.MOV, le nom du fichier ne donnait aucun contexte, mais le sidecar généré par Gemma comprenait l’installation d’une tente de safari, un panoramique de la caméra allant de l’intérieur vers la savane, le type de plan et des usages possibles comme des reels marketing ou du B-roll de vlog de voyage - Au niveau du dossier, en plus des sidecars à côté de chaque clip, des fichiers
_INDEX.jsonet_INDEX.mdétaient générés en tête pour permettre des grep rapides et l’envoi aux LLM - L’implémentation complète tient dans environ 1 400 lignes de Python sous forme de skill Claude Code, écrit en grande partie par Claude Code, le rôle humain ayant porté sur l’architecture, les prompts, la conception du schéma et le triage des bugs
Un modèle local 31B sur un vieux MacBook
- Le MacBook Pro 16 pouces M1 Max 64 Go RAM acheté en 2021 n’avait pas été choisi pour les LLM, mais pour faire tourner en même temps des onglets Chrome, DaVinci Resolve, Slack, Discord et Drive
- Cinq ans plus tard, ce même portable traite une année d’archive vidéo avec Gemma 4 31B Q4 dans LM Studio
- Dans LM Studio, un modèle de 28,40 Go était chargé en mémoire et l’API REST tournait sur
127.0.0.1:1234 - Pendant le traitement de masse, les 64 Go de RAM ne suffisaient plus, et l’utilisation du swap a culminé à 50,89 Go selon Activity Monitor
- Ce n’était pas un état tenable pour une journée de travail ordinaire, mais cela restait acceptable pour pousser la machine pendant un week-end
- Le portable chauffait, les ventilateurs soufflaient fort, mais il continuait à générer des sidecars pendant que d’autres tâches tournaient
- Ce modèle de MacBook Pro M1 Max 16 pouces montrait qu’un matériel vieux de cinq ans pouvait encore exécuter un modèle à 31B paramètres à une vitesse exploitable, et si les LLM locaux deviennent plus efficaces, il pourrait probablement servir encore 3 à 5 ans
Quatre bugs et leçons retenues
-
Changement d’API de séparation des locuteurs dans WhisperX 3.8
- Dans WhisperX 3.8,
whisperx.DiarizationPipelinea été déplacé vers le sous-modulewhisperx.diarize - L’argument de constructeur
use_auth_tokena été renommé entoken, en suivant pyannote 3.x - La solution a été l’introspection de signature
- Le script essaie d’abord
token=, puis bascule suruse_auth_token=si le constructeur renvoie unTypeError - Quand on appelle des bibliothèques IA qui évoluent vite, des appels de constructeur défensifs sont une assurance peu coûteuse
- Dans WhisperX 3.8,
-
La CLI Claude renvoyait des erreurs de permission comme si c’étaient des succès
- Lors du premier test du backend CLI, les 4 sidecars sont revenus avec exactement le même texte : « I need permission to read the image frames... »
- Le code de sortie était 0 et la sortie n’était pas vide, donc la vérification de succès du script passait
- En mode non interactif, sans
--permission-mode bypassPermissions, la CLI Claude renvoie le texte de refus de permission dans le corps de réponse au lieu de répondre au prompt - La solution a consisté à ajouter ce flag et à traiter comme erreur toute réponse courte contenant « I need permission » au lieu de l’accepter comme description
- Quand on manipule des outils IA dans des scripts, les flux d’autorisation non interactifs cachent des échecs silencieux
-
Gemma renvoyait
people_count: "many"- Le prompt vision demandait « integer or the string "many" if >10 », donc Gemma suivait correctement l’instruction
- Le bug n’était pas dans le modèle mais dans la conception du schéma
- Après correction, il a été explicitement demandé d’estimer un entier de 0 à 99, et les anciennes réponses
"many"ont été converties de force dans le parseur - Les champs de schéma ne doivent pas être des unions du type
intou chaîne spécifique : il faut fixer le type, toujours entier ou toujours chaîne, pour simplifier les consommateurs downstream
-
Des clips de moto tremblants ont été écartés à tort
- Le prompt initial de culling était plus proche de critères de portfolio photo, et classait le fort flou de mouvement, la mise au point molle et les tremblements dans
cull - Un clip de moto de nuit filmé à main levée pendant un voyage en Espagne s’est donc retrouvé destiné au rejet, alors que ce flou faisait justement partie de l’atmosphère du souvenir
- Le critère de culling a été redéfini : non plus « prise de vue imparfaite », mais « ce n’est pas une vraie trace du moment »
- Les clips à rejeter ont été resserrés à des cas comme bouchon d’objectif, vidéo dans la poche, clip test de 2 secondes ou exposition complètement brûlée
- Une archive photo peut être cullée de manière agressive, tandis que des souvenirs vidéo doivent l’être avec plus de souplesse ; même avec le même schéma, il faut des modes bien distincts
- Le prompt initial de culling était plus proche de critères de portfolio photo, et classait le fort flou de mouvement, la mise au point molle et les tremblements dans
Conclusions tirées des schémas structurés et d’un modèle local
-
Les contraintes par énumération réduisent les hallucinations
- Gemma 4 E4B décrivait une photo d’espace de coworking prise de nuit comme « brightly lit, abundant natural light, floor-to-ceiling windows », alors qu’à l’extérieur des fenêtres il faisait complètement nuit
- En donnant au 31B un schéma structuré et en lui faisant choisir parmi
golden_hour | bright_daylight | overcast | dim_interior | nighttime | mixed | unclear, il revenait ànighttime, aussi bien avec thinking-off qu’avec thinking-on - Le modèle peut inventer de fausses descriptions dans un texte libre, mais avec un enum il ne peut pas inventer une nouvelle valeur, seulement se tromper dans son choix
- Le schéma s’est avéré plus sûr que de simples instructions
-
Un 31B local et des prompts structurés réduisent l’écart avec le cloud
- Gemma 4 31B Q4 en mode thinking-off, avec un schéma structuré, produisait sur beaucoup de clips de test des sorties difficiles à distinguer de celles de Sonnet 4.6
- La prime des modèles cloud valait surtout sur les 10 à 20 % de clips difficiles
- Pour un travail de masse consistant à indexer des milliers de clips pendant la nuit, une architecture à deux niveaux passait bien à l’échelle : exécution en local, puis réévaluation dans le cloud des seuls clips marqués
reviewpar le local
-
Les éditeurs vidéo IA se battent à une couche trop haute
- La couche qui a de la valeur n’était pas l’éditeur, mais un index consultable
- Si l’on peut interroger en langage naturel quelque chose comme « clips de Mara tournés à main levée en intérieur, à l’heure dorée, avec des personnes, de plus de 8 secondes », alors l’éditeur au-dessus devient simple
- Le marché des éditeurs vidéo IA se dispute une couche de surface posée sur un index inexistant, en sautant la condition préalable qu’est justement cet index
Étapes suivantes et limites
- La prochaine étape consiste à créer un éditeur avec Claude Code comme orchestrateur, DaVinci Resolve MCP pour faire les coupes, et des voix off ElevenLabs sur les clips informatifs
- Le voice cloning a des limites claires
- Il n’est utilisé que pour du contenu utilitaire : indications, descriptions de chambres, versions multilingues, informations factuelles qu’on pourrait dire soi-même
- Il n’est pas utilisé pour les avis ni pour les messages du fondateur
- En 2026, les obligations de divulgation seront une réalité, et la confiance dans une marque d’hospitalité se perd facilement
- Une fois l’index disponible, il devient inutile de scruber manuellement 47 Go de vidéos DJI Pocket pour trouver un plan large au lever du soleil
- Aujourd’hui, sur un portable vieux de cinq ans, une année de vidéos de Mara Hilltop est devenue interrogeable en anglais, au prix d’un week-end et de 50 Go de swap
- Les autres années encore stockées sur d’anciens SSD sont les prochaines à traiter
- Les réseaux sociaux de Mara Hilltop ne sont pas encore relancés
- L’indexeur ne résout que le problème de trouver les bons clips
- L’autre moitié est l’éditeur qui les transforme en reels finalisés ; si cela fonctionne, un billet de suivi sera écrit, sinon il expliquera pourquoi cela a échoué
- Il est possible que la bonne réponse soit d’embaucher quelqu’un
- Trouver un monteur avec une sensibilité chaleureuse et attentive adaptée à Mara Hilltop peut être plus difficile qu’écrire un autre skill
- L’objectif n’est pas de produire des reels façon MTV coupés de manière excessive
- Le code est open source sur github.com/Simbastack-hq/framedex, et les PR comme les issues sont bienvenues
1 commentaires
Commentaires Hacker News
On dirait que Claude a choisi le mauvais URL à partager en écrivant l’article. Sauf si le dossier personnel est exposé vers l’extérieur,
~/.claude/skills/video-index/n’est pas accessible, donc je me demande si tu pourrais partager le fichier SkillMise à jour : j’ai créé ce dépôt à la hâte - https://github.com/Simbastack-hq/framedex
La licence est MIT, et je n’ai pas encore pu le généraliser puis le tester correctement. Je vais bientôt tout reprendre sérieusement et ajouter d’autres mises à jour
Les deux gros points de la TODO sont : 1) accélérer le montage vidéo dans DaVinci Resolve en exploitant cet index et l’aide de Claude, 2) pour l’instant je n’ai traité que la vidéo, mais je veux aussi l’étendre pour comprendre les milliers d’images fixes présentes sur l’appareil photo
Je ne comprends pas très bien pourquoi il faut autant de swap. Vu la bande passante mémoire nécessaire, ça risque d’user le SSD assez vite
Le modèle quantifié en 4 bits de Gemma 4 31B devrait faire autour de 19 GiB, pas 28,4 GiB [1]. Je n’injecte pas souvent des images, donc je ne sais pas combien de mémoire supplémentaire il faut pour les mettre dans le contexte, mais ça ne devrait probablement pas dépasser 10 GiB
En regardant le moniteur d’activité, on voit aussi plusieurs applis Electron ouvertes en plus de Handy et de la machine virtuelle pour Claude Code, qui semblent avoir chargé le modèle, donc la vraie cause vient sans doute plutôt de là. Une fois que le portable se met à gratter le disque à fond, ce genre d’applis se figera de toute façon, donc elles ne serviront plus à grand-chose
[1] https://huggingface.co/mlx-community/gemma-4-31b-it-4bit
Cela dit, même si ça ramait un peu, j’ai trouvé impressionnant de pouvoir continuer à faire autre chose, même avec beaucoup d’onglets ouverts dans le navigateur Brave
Je me demande si tu savais que ça existe déjà, que c’est plutôt bien, et que ça n’avale pas 50 Go de swap
https://github.com/iliashad/edit-mind
Très cool. J’aimerais avoir assez de RAM pour faire tourner des modèles en local. J’ai construit quelque chose de très similaire ces dernières semaines, mais moi je l’ai fait comme une appli Electron locale avec Whisper et ffmpeg, en ajoutant de la recherche sémantique et des embeddings pour discuter avec les vidéos
L’analyse visuelle, le tagging et le chat vidéo communiquent avec Claude. Je me demande si ce projet envoie une seule image. Moi, avec un algorithme de détection de scènes personnalisé, je repère plusieurs images différentes par vidéo et je les envoie à Claude en une seule requête avec les sous-titres. C’est clairement la partie la plus coûteuse. Avec Sonnet 4.6 pour l’analyse et Haiku pour le tagging, ça revient à environ 1 dollar pour une heure de vidéo, et j’imagine que ce serait lent en local
En revanche, la façon de choisir les frames est le point faible. La détection de scènes aiderait clairement, et c’est la priorité n°1 de la feuille de route. Je serais curieux que tu partages comment tu choisis les frames dans la détection de scènes
Je n’ai pas ajouté de recherche vectorielle, et j’ai préféré garder quelque chose de simple avec des fichiers Markdown génériques plus portables. Même si on déplace le SSD, la connaissance se déplace avec les fichiers ; il n’y a pas d’index à synchroniser, et le texte brut a l’avantage de survivre plus longtemps que l’outil. Cela dit, l’autre direction que tu évoques mérite aussi d’être explorée
Il y a aussi d’autres options correctes. Gemini 3.1 Flash Lite est très bien pour ce genre de travail. En revanche, pas Gemini 3.5 Flash. Son tarif n’est pas intéressant
https://openrouter.ai/google/gemma-4-31b-it
J’ai deux questions
description.md, il y a des éléments commefaces -> cluster_id. Je me demande si ça vient de l’index des visages de DaVinci Resolve. Dans une collection photo, les infos comme visages+noms et lieux sont vraiment importantes, mais les LLM généralistes gèrent mal ce genre de choses.description.mden texte brut, placés à côté des vidéos pour chaque clipPlus tard, quand je brainstorme avec Claude en lui disant par exemple « je veux faire une vidéo sur les suites haut de gamme du lodge », il peut interroger ces fichiers et comprendre quelles vidéos seraient utiles
Il y a aussi, à la racine du dossier, un fichier qui rassemble les descriptions textuelles pour faciliter la recherche. J’ai mis une image d’exemple sur le blog - https://blog.simbastack.com/_media/gvcycx2n.png
Les visages viennent d’insightface. Ils sont détectés avec RetinaFace du pack open source
buffalo_l, exécuté en local sur CPU. Les visages sont détectés et encodés à partir de frames échantillonnées de chaque clip, puis une ligne est écrite dans~/.framedex/faces.dbHonnêtement, sur cette partie, je sais que ça s’accumule dans une base locale, mais je n’ai pas encore vraiment vérifié à quel point ça fonctionne bien. Je vais bientôt m’y pencher sérieusement
Plus largement, c’est pour cela que framedex évite délibérément de confier au LLM le traitement des visages ou des lieux. Les visages sont gérés avec des embeddings insightface / ArcFace, ce qui permet une comparaison déterministe entre clips. Le modèle visuel ne fournit qu’un nombre approximatif de personnes et n’essaie pas d’identifier qui c’est
Les lieux sont gérés via les GPS EXIF avec exiftool et le géocodage inverse de Nominatim/OpenStreetMap. Ce n’est pas une supposition, mais une métadonnée solide
Le LLM ne fait que ce qu’il sait bien faire : description de scène, ambiance, type de plan, mots-clés, notes pour archiver/réviser/jeter, ce genre de choses. La dernière partie sur la notation peut se discuter
J’ai essayé de faire quelque chose de similaire sur un ThinkPad de 2015 avec Gemma. Heureusement, j’ai pu upgrader la mémoire, sinon ça aurait été assez pénible
Je ne vais pas mentir : en faisant tourner llama.cpp, le ventilateur était à fond. Mais ça a fonctionné, et le travail a été fait
J’ai l’impression que c’est parfois utilisé comme métaphore pour dire « ça utilise 100 % des ressources », et c’est probablement le sens ici, mais dans d’autres contextes, c’est clairement exprimé comme une vraie plainte
Je ne pense pas que la majorité des hôtes Airbnb seraient d’accord avec l’idée que « la vidéo générée par IA n’a pas sa place pour une vraie marque de voyage »
Quant à « la crucifixion sur TripAdvisor », je ne comprends vraiment pas comment des hôtes Airbnb qui publient de faux hébergements arrivent encore à survivre
En même temps, faire de vraies vidéos prend du temps et ralentit tout le processus
Je pense que les applications IA B2C sont structurellement limitées parce qu’il est difficile d’y construire un contexte personnalisé
Si un modèle local compétent pouvait faire à grande échelle, depuis zéro, la collecte de contexte, la recherche, le tagging, etc., ce serait une vraie percée
Tu lui donnes plusieurs captures d’écran et elle essaie de leur attribuer intelligemment un nom en fonction de leur contenu. Pareil pour la vidéo, les PDF, etc.
Mais comme tu le dis, Apple risque simplement d’intégrer ça comme fonctionnalité, donc je n’ai même pas essayé de la vendre
https://finalfinalreallyfinaluntitleddocumentv3.com/
Mais à mon avis, ce n’est qu’une question de temps avant que les agents deviennent assez intelligents pour que même des amis non techniques puissent simplement dire « organise les vidéos de ce dossier pour que je puisse les comprendre » et obtenir exactement ça