CommunityImagegithub.com

claudejaune/gemma-embed-search

Indexez un dossier d'images, d'audio ou de texte avec un modèle d'embedding multimodal local et recherchez-le en langage naturel. Construit un index vectoriel reprenable via tout serveur compatible OpenAI /v1/embeddings acceptant des parties multimodales, comme llama.cpp's llama-server exécutant EmbeddingGemma 2, puis classe les fichiers par similarité sémantique avec filtrage par couleur, requêtes AND multi-facettes, sortie JSON, et planche contact HTML…

Qu'est-ce que gemma-embed-search ?

Cette compétence permet d'indexer localement des dossiers d'images, fichiers audio ou documents texte en utilisant un modèle d'embedding multimodal (EmbeddingGemma 2) exécuté sur le matériel de l'utilisateur via un serveur compatible OpenAI (par exemple llama.cpp). L'utilisateur peut ensuite rechercher ces fichiers par requête en langage naturel, obtenant un classement par similarité sémantique. Elle prend en charge le filtrage par couleur (basé sur les pixels), les requêtes AND multi-facettes (--must), les synonymes (--also), la sortie JSON pour intégration dans des pipelines, et génère des planches contact HTML avec miniatures intégrées en base64 pour une revue visuelle. L'index est incrémental et reprenable, ce qui permet de traiter de grands volumes sans tout recommencer en cas d'interruption. Le script s'interface avec tout serveur exposant une API /v1/embeddings, garantissant que les données ne quittent jamais la machine de l'utilisateur. Particulièrement utile pour les développeurs travaillant avec des corpus multimodaux locaux, elle offre un contrôle fin via des options en ligne de commande et une documentation détaillée sur les pièges courants (limites de contexte audio, différences de quantification, etc.).

Compatible avec✓Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/claudejaune/gemma-embed-search/tree/HEAD

Installed? Explore more Image skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Gemma Embed Search

Récupérez des fichiers locaux par leur sens. Un seul espace d'embedding contient des images, de l'audio et du texte, de sorte qu'une requête tapée renvoie les images, clips ou documents correspondants. Le modèle s'exécute sur le matériel de l'utilisateur via un serveur local ; rien n'est téléchargé ailleurs.

scripts/embed_search.py fait quatre choses : doctor vérifie le serveur, init enregistre la connexion, index intègre les fichiers dans un cache, et search les classe par rapport à une requête.

Configuration locale

Les paramètres se trouvent dans config.json, jamais dans ce fichier :

  • Linux et macOS : ~/.config/gemma-embed-search/config.json
  • Windows : %USERPROFILE%\.config\gemma-embed-search\config.json

Lisez d'abord ce fichier. S'il contient url et model, toutes les commandes ultérieures fonctionneront sans indicateurs de connexion et vous pouvez passer l'étape 2.

S'il est manquant ou incomplet, demandez à l'utilisateur l'URL du serveur et le dossier à indexer, exécutez doctor pour lister les modèles que le serveur propose réellement, puis exécutez init pour écrire le fichier. init fusionne, donc ajouter un paramètre à la fois est sûr. Ne devinez jamais un nom de modèle.

Copier config.example.json de ce dossier vers ce chemin et le modifier fait le même travail que init, pour un utilisateur qui préfère éditer le fichier directement. Ajoutez "api_key" uniquement si le serveur en a besoin.

Ne sauvegardez jamais les paramètres dans le dossier de la compétence lui-même. La mise à jour de la compétence remplace tous les fichiers qu'elle contient, et tout ce qui y est écrit est perdu.

Liste de vérification pour la configuration

Progression :

  • Étape 1 : Confirmer le serveur et choisir un nom de modèle (doctor)
  • Étape 2 : Sauvegarder la connexion (init)
  • Étape 3 : Indexer un pilote de 20 fichiers et examiner une requête
  • Étape 4 : Indexer tout le dossier
  • Étape 5 : Répondre à la requête réelle de l'utilisateur, avec --html pour qu'il puisse voir les résultats

Sautez l'étape 2 si config.json contient déjà url et model.

Exécutez le script avec uv run scripts/embed_search.py (installe Pillow à partir des métadonnées en ligne du script) ou python3 scripts/embed_search.py si Pillow est déjà importable.

Étape 1 — trouver le serveur et le nom du modèle. Ne devinez jamais le nom du modèle ; lisez-le depuis le serveur.

uv run scripts/embed_search.py --url http://127.0.0.1:1235 doctor

doctor affiche les modèles proposés par le serveur et teste un embedding. Si l'utilisateur n'a pas encore démarré de serveur, lisez references/setup.md et donnez-lui la commande pour son modèle.

Étape 2 — enregistrez-le pour que les appels ultérieurs n'aient besoin d'aucun indicateur. Passez --api-key uniquement si le serveur en nécessite un ; il est écrit dans le fichier de configuration avec le mode 0600. Passez --root sur n'importe quelle commande ultérieure pour travailler sur un dossier différent sans modifier ce qui est sauvegardé.

uv run scripts/embed_search.py --url http://127.0.0.1:1235 --model <nom-du-doctor> init --root <dossier>
uv run scripts/embed_search.py index --limit 20

Étape 3 — pilote avant la longue exécution. L'indexation est l'étape coûteuse : environ 0,25 s par image sur un GPU de bureau, donc 10 000 fichiers prennent environ 40 minutes. Indexez 20 fichiers, exécutez une requête et confirmez que les résultats semblent corrects avant de vous engager dans le passage complet.

Étape 4 — indexation complète. Réexécuter index n'intègre que les fichiers nouveaux ou modifiés, donc une exécution interrompue reprend d'elle-même.

uv run scripts/embed_search.py index

Étape 5 — recherche.

uv run scripts/embed_search.py search "un labrador noir sur une plage" --top 20 --html hits.html

Livre de recettes des requêtes

IntentionCommande
Recherche sémantique simplesearch "un marché de nuit bondé"
Deux facettes qui doivent toutes deux être vraiessearch "une femme" --must "la couleur jaune"
Synonymes pour qu'une formulation ne domine passearch "une femme" --also "une fille" --also "portrait féminin"
Trouver chaque image contenant Xsearch "personnages aux cheveux roux" --top 60 --html hits.html
Sujet plus une contrainte de couleur réellesearch "une femme" --color jaune --min-color 0.05
Images principalement monochromes ou sombressearch "n'importe quelle image" --max-color bleu --modality image
Un seul type de fichiersearch "sons de sirène" --modality audio
Lisible par machine pour un travail ultérieursearch "..." --json --top 50
Plus rapide, score légèrement moins précissearch "..." --dims 256

--also moyenne les vecteurs de paraphrase en une seule requête. --must conserve le score de la facette la plus faible, ce qui est la façon d'exprimer un ET. Utilisez --also pour les synonymes et --must pour les conditions indépendantes.

Lecture de la sortie

La sortie simple est score [modality] chemin, meilleur d'abord. Les exécutions de couleur insèrent le rapport de pixels après le score. --json émet {"query", "index", "total", "filtered_out", "results": [{"rank", "score", "color", "modality", "path"}]} sur stdout ; toutes les progressions vont sur stderr, donc stdout se canalise toujours proprement dans jq.

Les scores cosinus de cette famille de modèles se situent entre environ 0,3 et 0,8. Le nombre absolu signifie peu ; l'écart entre les résultats pertinents et les non pertinents compte. Si le haut de la liste est faux, la requête est fausse — reformulez-la plutôt que de faire confiance au classement. Ne présentez jamais une longue liste comme étant également bonne : nommez où s'arrêtent les résultats confiants et où commencent les suppositions.

Une courte liste n'est pas la réponse complète. Chaque fichier indexé obtient un score, donc le total dans la sortie compte l'ensemble du corpus et ne vous dit jamais combien de résultats sont plausibles. Trouvez plutôt la falaise — le point où les scores cessent de chuter fortement. Si la liste que vous avez montrée se termine avant, dites que les résultats sont tronqués et proposez une exécution plus longue : un --top plus grand coûte une planche contact de plus, pas une autre indexation. Honorez un nombre nommé par l'utilisateur, et indiquez toujours la limite que vous avez appliquée. Ne prétendez jamais "il n'y en a pas" sans une liste élargie, --top 100 ou plus, que quelqu'un a réellement regardée.

Pour une revue visuelle, proposez toujours --html : il écrit une planche contact de miniatures avec les scores et les noms de fichiers que l'utilisateur peut ouvrir dans un navigateur. Un --html simple écrit hits.html dans le répertoire de travail ; --html FICHIER définit le chemin. Les miniatures sont intégrées en base64, donc la planche est autonome et se déplace seule. La planche intègre de vraies miniatures des fichiers correspondants, donc traitez-la comme une copie de cette partie de la bibliothèque : gardez-la hors du contrôle de version et de tout ce que vous transmettez. Elles mesurent 512 px de large par défaut ; augmentez --thumb-width pour une inspection rapprochée des détails.

Pièges

  • Un mot de couleur dans le texte de la requête est un indice doux, pas un filtre. "une femme avec un thème jaune" classe une femme en veste orange en premier. Utilisez --color jaune --min-color 0.05 pour une contrainte réelle ; elle est calculée à partir des pixels, pas du modèle.
  • Un mot de style est aussi un indice doux, et plus faible. "une femme photoréaliste aux cheveux roux" classe une illustration à l'encre d'une femme aux cheveux roux en premier, car les noms du sujet l'emportent sur le style. Déplacez le style dans --must pour qu'il soit noté comme sa propre facette et fixez l'attribut visuel avec --color. Ni l'un ni l'autre n'est un vrai filtre : --must prend le minimum entre les facettes, donc insister sur l'un échange l'autre.
  • Plusieurs sujets dans une seule image se fondent en un seul vecteur, donc l'image obtient un score moins bon pour une requête à sujet unique qu'une image dédiée à ce sujet : un portrait d'une femme aux cheveux roux à côté d'un homme peut se situer loin dans une recherche "femme aux cheveux roux" tout en étant en haut de "personnages aux cheveux roux". Les synonymes de la même idée singulière n'aident pas ; la forme plurielle ou collective le fait. Élargissez --top lorsque la question est "trouver tout ce qui contient X".
  • --color a besoin que l'index contienne des statistiques de couleur, que seul index calcule. Un index construit avec une version plus ancienne signale 0,0 pour tout : réindexez avec --force si le filtrage par couleur exclut silencieusement tous les fichiers.
  • L'index et la requête doivent utiliser le même modèle. Changer --model mélange silencieusement des vecteurs incompatibles ; réindexez avec --force après tout changement de modèle et notez le modèle dans stats.
  • Le serveur doit exécuter le modèle d'embedding avec un pooling moyen et son projecteur de vision (--mmproj) chargé. Sans le projecteur, les requêtes d'image échouent ou renvoient un vecteur qui ignore l'image. doctor prouve que le texte fonctionne ; exécutez une requête d'image pour prouver la vision.
  • Les images sont ré-encodées en JPEG avec le côté le plus long à 1536 avant d'être envoyées. Le ré-encodage est obligatoire, pas cosmétique : les serveurs rejettent couramment les fichiers WebP, 16 bits ou mal étiquetés, et Pillow les lit à la place. Le modèle n'a pas de limite de pixels — le serveur ré-échantillonne chaque image à un budget de jetons de vision fixe — donc --resize échange la taille d'envoi contre la fidélité, pas l'exactitude. Les chiffres mesurés et les détails se trouvent dans references/setup.md.
  • Les formats HEIC et raw d'appareil photo ne sont pas lus à moins que Pillow n'ait été construit avec le plugin. Le script enregistre skip <fichier> : cannot identify image file et continue ; vérifiez skipped_errors dans le résumé de l'index plutôt que de supposer une couverture complète.
  • search sur un dossier qui n'a jamais été indexé se termine avec le code 4 et un message. Ne traitez pas une liste de résultats vide comme "aucune correspondance" tant que le nombre d'index dans stats ne semble pas correct.
  • L'audio est limité par le contexte du serveur : environ 5,5 minutes par clip à 25 jetons par seconde. Les fichiers plus longs échouent comme une erreur de requête, pas comme une mauvaise correspondance.
  • Les scores ne sont pas comparables entre corpus ou entre quantifications. Ne promettez jamais de seuil ; ajustez --min-color et --top en fonction de ce que l'utilisateur voit.

Référence du script

doctor                       Vérifie le serveur, liste les modèles, teste un embedding
init [--root DOSSIER]            Sauvegarde l'URL, le modèle, la clé et le dossier par défaut dans le fichier de configuration
index   --root DOSSIER            Intègre les fichiers nouveaux et modifiés (incrémental, reprenable)
        [--modality auto|image|audio|text] [--include '*.png,sub/*.jpg']
        [--exclude-dir node_modules,.git] [--limit N] [--batch 16] [--resize 1536]
        [--force] [--compact]
search  "requête"              Classe les fichiers indexés ; affiche le score, la modalité, le chemin
        [--also P]... [--must P]... [--color NOM --min-color F | --max-color F]
        [--modality image] [--dims 512|256|128] [--top 20] [--offset 0]
        [--json] [--html [FICHIER]] [--thumb-width 512]
stats                        Nombre d'entrées, répartition des modalités, modèle, taille de l'index

Codes de sortie : 0 succès, 2 erreur d'utilisation, 3 serveur injoignable ou authentification rejetée, 4 index manquant, 5 rien à faire, 6 erreur serveur en cours d'exécution. Exécutez scripts/embed_search.py <commande> --help pour la documentation complète des indicateurs.

La résolution de la configuration est : indicateur > environnement (EMBED_SEARCH_URL, EMBED_SEARCH_MODEL, EMBED_SEARCH_API_KEY, EMBED_SEARCH_ROOT) > fichier de configuration à ~/.config/gemma-embed-search/config.json. L'index par défaut est ~/.cache/gemma-embed-search/<dossier>-<hash>.jsonl, un enregistrement JSON par fichier, donc il est sûr de conserver plusieurs index pour différents dossiers.

Plus de détails

  • references/setup.md — démarrer un serveur, modèle et indicateurs requis, ce que signifie doctor
  • references/query-guide.md — construction de requêtes, logique de facettes, seuils de couleur, réglage par rapport aux résultats réels
  • references/errors.md — chaque code de sortie et la correction pour chaque mode d'échec

Skills associés