CommunityImagengithub.com

gemma-embed-search

Indexa una carpeta de imágenes, audio o texto con un modelo local de embedding multimodal y búscala en lenguaje natural. Construye un índice vectorial reanudable a través de cualquier servidor compatible con OpenAI /v1/embeddings que acepte partes de contenido multimodal, como llama.cpp ejecutando EmbeddingGemma 2, luego clasifica archivos por similitud semántica con filtrado de color, consultas AND multifaceta, salida JSON y hoja de contacto HTML…

¿Qué es gemma-embed-search?

Gemma Embed Search es una habilidad de agente de IA que permite a los usuarios indexar y buscar archivos locales (imágenes, audio y texto) por su significado semántico, utilizando un modelo de embedding multimodal que se ejecuta completamente en el hardware del usuario a través de un servidor local como llama.cpp. La herramienta es útil porque evita cargar datos a servicios externos, garantizando privacidad, y ofrece capacidades avanzadas de búsqueda como filtrado por color, consultas AND multifaceta, sinónimos, y salida en múltiples formatos (texto plano, JSON, HTML). Está diseñada para plataformas como Claude Code, Cursor o Codex, y funciona ejecutando el script `embed_search.py` con subcomandos como `doctor`, `init`, `index` y `search`. El proceso incluye verificar el servidor, guardar la configuración, indexar archivos de forma incremental y reanudable, y finalmente ejecutar consultas en lenguaje natural, con soporte para --html que genera una hoja de contacto visual para revisión.

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

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

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Gemma Embed Search

Recupera archivos locales por su significado. Un único espacio de embedding alberga imágenes, audio y texto, de modo que una consulta escrita devuelve las imágenes, clips o documentos que coinciden. El modelo se ejecuta en el hardware del usuario a través de un servidor local; no se sube nada a ningún sitio.

scripts/embed_search.py realiza cuatro acciones: doctor verifica el servidor, init guarda la conexión, index incrusta archivos en una caché y search los clasifica según la consulta.

Configuración local

La configuración reside en config.json, nunca en este archivo:

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

Lee ese archivo primero. Si contiene url y model, todos los comandos posteriores funcionan sin necesidad de banderas de conexión y puedes saltarte el Paso 2.

Si falta o está incompleto, pide al usuario la URL del servidor y la carpeta a indexar, ejecuta doctor para listar los modelos que realmente ofrece el servidor, y luego ejecuta init para escribir el archivo. init fusiona, por lo que es seguro añadir una configuración a la vez. Nunca adivines un nombre de modelo.

Copiar config.example.json de esta carpeta a esa ruta y editarlo hace el mismo trabajo que init, para un usuario que prefiera editar el archivo directamente. Añade "api_key" allí solo si el servidor la necesita.

Nunca guardes la configuración dentro de la propia carpeta de la habilidad. Al actualizar la habilidad se reemplaza cada archivo en ella, y cualquier dato escrito allí se perderá.

Lista de verificación

Progreso:

  • Paso 1: Confirmar el servidor y elegir un nombre de modelo (doctor)
  • Paso 2: Guardar la conexión (init)
  • Paso 3: Indexar una prueba de 20 archivos y revisar una consulta
  • Paso 4: Indexar toda la carpeta
  • Paso 5: Responder a la consulta real del usuario, con --html para que pueda ver los resultados

Omite el Paso 2 si config.json ya tiene url y model.

Ejecuta el script con uv run scripts/embed_search.py (instala Pillow desde los metadatos en línea del script) o python3 scripts/embed_search.py si Pillow ya está disponible.

Paso 1 — encontrar el servidor y el nombre del modelo. Nunca adivines el nombre del modelo; lée la información del servidor.

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

doctor muestra los modelos que ofrece el servidor y prueba un embedding. Si el usuario aún no ha iniciado un servidor, lee references/setup.md y dale el comando para su modelo.

Paso 2 — guardarlo para que las llamadas posteriores no necesiten banderas. Pasa --api-key solo si el servidor lo requiere; se escribe en el archivo de configuración con modo 0600. Pasa --root en cualquier comando posterior para trabajar en una carpeta diferente sin cambiar lo guardado.

uv run scripts/embed_search.py --url http://127.0.0.1:1235 --model <nombre-del-doctor> init --root <carpeta>
uv run scripts/embed_search.py index --limit 20

Paso 3 — prueba antes del proceso largo. Indexar es el paso costoso: aproximadamente 0.25 s por imagen en una GPU de escritorio, por lo que 10 000 archivos son unos 40 minutos. Indexa 20 archivos, ejecuta una consulta y confirma que los resultados sean correctos antes de comprometerte con el proceso completo.

Paso 4 — indexación completa. Volver a ejecutar index solo incrusta archivos nuevos o modificados, por lo que una interrupción se reanuda automáticamente.

uv run scripts/embed_search.py index

Paso 5 — búsqueda.

uv run scripts/embed_search.py search "un labrador negro en una playa" --top 20 --html hits.html

Recetario de consultas

IntenciónComando
Búsqueda semántica simplesearch "un mercado nocturno concurrido"
Dos facetas que ambas deben cumplirsesearch "una mujer" --must "el color amarillo"
Sinónimos para que una frase no dominesearch "una mujer" --also "una niña" --also "retrato femenino"
Encontrar cada imagen que contenga Xsearch "personajes con pelo rojo" --top 60 --html hits.html
Sujeto más una restricción de color realsearch "una mujer" --color amarillo --min-color 0.05
Mayormente monocromático o fotogramas oscurossearch "cualquier imagen" --max-color azul --modality image
Solo un tipo de archivosearch "sonidos de sirena" --modality audio
Legible por máquina para trabajo posteriorsearch "..." --json --top 50
Más rápido, puntuación ligeramente menos precisasearch "..." --dims 256

--also promedia vectores de paráfrasis en una sola consulta. --must mantiene la puntuación de la faceta más débil, que es cómo se expresa AND. Usa --also para sinónimos y --must para condiciones independientes.

Interpretación de la salida

La salida simple es puntuación [modalidad] ruta, de la mejor a la peor. Las ejecuciones con color insertan la proporción de píxeles después de la puntuación. --json emite {"query", "index", "total", "filtered_out", "results": [{"rank", "score", "color", "modality", "path"}]} en stdout; todo el progreso va a stderr, por lo que stdout siempre se puede redirigir limpiamente a jq.

Las puntuaciones de coseno de esta familia de modelos se sitúan entre aproximadamente 0.3 y 0.8. El número absoluto importa poco; la brecha entre aciertos y fallos es lo que realmente cuenta. Si la parte superior de la lista es incorrecta, la consulta es incorrecta; reformúlala en lugar de confiar en la clasificación. Nunca presentes una lista larga como gualmente buena: indica dónde terminan los resultados fiables y comienzan las suposiciones.

Una lista corta no es la respuesta completa. Cada archivo indexado obtiene una puntuación, por lo que total en la salida cuenta todo el corpus y nunca te dice cuántos resultados son plausibles. Encuentra el escalón — el punto donde las puntuaciones dejan de caer abruptamente. Si la lista que mostraste termina antes de él, di que los resultados están truncados y ofrece una ejecución más larga: un --top más grande solo cuesta una hoja de contacto más, no otra indexación. Respeta un número que el usuario nombre, y aún así indica el límite que aplicaste. Nunca afirmes "no hay ninguno" sin una lista ampliada, --top 100 o más, que alguien realmente haya revisado.

Para una revisión visual, ofrece siempre --html: escribe una hoja de contacto de miniaturas con puntuaciones y nombres de archivo que el usuario puede abrir en el navegador. Un --html sin más escribe hits.html en el directorio de trabajo; --html ARCHIVO establece la ruta. Las miniaturas se incrustan como base64, por lo que la hoja es autónoma y se puede transportar por sí sola. La hoja incrusta miniaturas reales de los archivos coincidentes, por lo que trátala como una copia de esa parte de la biblioteca: mantenla fuera del control de versiones y de cualquier cosa que reenvíes. Tienen 512 px de ancho por defecto; aumenta --thumb-width para una inspección detallada.

Errores comunes

  • Una palabra de color dentro del texto de la consulta es una pista suave, no un filtro. "una mujer con tema amarillo" clasifica a una mujer con una chaqueta naranja primero. Usa --color amarillo --min-color 0.05 para una restricción real; se calcula a partir de píxeles, no del modelo.
  • Una palabra de estilo también es una pista suave, y más débil. "una mujer fotorrealista con pelo rojo" clasifica una ilustración a tinta de una mujer pelirroja primero, porque los sustantivos del sujeto predominan sobre el estilo. Mueve el estilo a --must para que se puntúe como su propia faceta y fija el atributo visual con --color. Ninguno es un filtro real: --must toma el mínimo entre las facetas, por lo que presionar mucho en una sacrifica la otra.
  • Varios sujetos en un solo fotograma se mezclan en un único vector, por lo que el fotograma obtiene peor puntuación en una consulta de un solo sujeto que un fotograma dedicado a ese sujeto: un retrato de una mujer pelirroja junto a un hombre puede estar muy abajo en una búsqueda de "mujer con pelo rojo" mientras se clasifica cerca de la parte superior de "personajes con pelo rojo". Los sinónimos de la misma idea singular no ayudan; la forma plural o colectiva sí lo hace. Amplía --top cuando la pregunta sea "encontrar todo lo que contenga X".
  • --color necesita que el índice contenga estadísticas de color, que solo index calcula. Un índice construido con una versión anterior informa 0.0 para todo: vuelve a indexar con --force si el filtrado de color excluye silenciosamente cada archivo.
  • La indexación y la consulta deben usar el mismo modelo. Cambiar --model mezcla silenciosamente vectores incompatibles; vuelve a indexar con --force después de cualquier cambio de modelo y anota el modelo en stats.
  • El servidor debe ejecutar el modelo de embedding con agrupación de media (mean pooling) y su proyector de visión (--mmproj) cargado. Sin el proyector, las solicitudes de imagen fallan o devuelven un vector que ignora la imagen. doctor verifica que el texto funciona; ejecuta una consulta de imagen para verificar la visión.
  • Las imágenes se recodifican a JPEG con el lado más largo de 1536 antes de enviarse. La recodificación es obligatoria, no cosmética: los servidores suelen rechazar WebP, archivos de 16 bits o mal etiquetados, y Pillow los lee en su lugar. El modelo no tiene límite de píxeles — el servidor remuestrea cada imagen a un presupuesto fijo de tokens de visión — por lo que --resize intercambia tamaño de subida por fidelidad, no corrección. Los números medidos y los detalles están en references/setup.md.
  • Los formatos HEIC y RAW de cámara no se leen a menos que Pillow se haya compilado con el complemento. El script registra skip <archivo>: cannot identify image file y continúa; comprueba skipped_errors en el resumen del índice en lugar de asumir una cobertura completa.
  • search en una carpeta que nunca se indexó sale con código 4 y un mensaje. No trates una lista de resultados vacía como "sin coincidencias" hasta que el recuento del índice en stats parezca correcto.
  • El audio está limitado por el contexto del servidor: aproximadamente 5.5 minutos por clip a 25 tokens por segundo. Los archivos más largos fallan como un error de solicitud, no como una falta de coincidencia.
  • Las puntuaciones no son comparables entre distintos corpus ni entre distintas cuantizaciones. Nunca prometas un umbral; ajusta --min-color y --top en función de lo que vea el usuario.

Referencia del script

doctor                       Verifica el servidor, lista modelos, prueba un embedding
init [--root DIR]            Guarda url, model, key y root por defecto en el archivo de configuración
index   --root DIR           Incrusta archivos nuevos y modificados (incremental, reanudable)
        [--modality auto|image|audio|text] [--include '*.png,sub/*.jpg']
        [--exclude-dir node_modules,.git] [--limit N] [--batch 16] [--resize 1536]
        [--force] [--compact]
search  "consulta"           Clasifica archivos indexados; imprime puntuación, modalidad, ruta
        [--also P]... [--must P]... [--color NOMBRE --min-color F | --max-color F]
        [--modality image] [--dims 512|256|128] [--top 20] [--offset 0]
        [--json] [--html [ARCHIVO]] [--thumb-width 512]
stats                        Recuento de entradas, mezcla de modalidades, modelo, tamaño del índice

Códigos de salida: 0 éxito, 2 error de uso, 3 servidor inalcanzable o autenticación rechazada, 4 índice faltante, 5 nada que hacer, 6 error del servidor durante la ejecución. Ejecuta scripts/embed_search.py <comando> --help para la documentación completa de banderas.

La resolución de configuración es: bandera > entorno (EMBED_SEARCH_URL, EMBED_SEARCH_MODEL, EMBED_SEARCH_API_KEY, EMBED_SEARCH_ROOT) > archivo de configuración en ~/.config/gemma-embed-search/config.json. El índice por defecto es ~/.cache/gemma-embed-search/<carpeta>-<hash>.jsonl, un registro JSON por archivo, por lo que es seguro mantener varios índices para diferentes carpetas.

Más información

Skills relacionados