vss-search-archive

Par nvidia-ai-blueprints · video-search-and-summarization

Utilisez cette skill pour effectuer une recherche de fusion VSS de haut niveau sur des vidéos archivées, ou pour ingérer des fichiers vidéo / flux RTSP en vue d'une recherche. Ne PAS utiliser pour des questions visuelles ad hoc (utilisez vss-ask-video), le sous-titrage en direct (utilisez vss-deploy-dense-captioning), ou la synthèse et les rapports vidéo (utilisez vss-summarize-video).

npx skills add https://github.com/nvidia-ai-blueprints/video-search-and-summarization --skill vss-search-archive

Objectif

Exécuter la recherche de fusion VSS au niveau supérieur sur les vidéos archivées, ingérer de nouveaux clips / flux RTSP pour la recherche, et supprimer les sources ingérées pour la recherche.

Prérequis

  • Déploiement VSS actif accessible sur $HOST_IP (voir vss-deploy-profile et references/).
  • Skill vss-manage-video-io-storage installée (utilisée pour lister et gérer les sources vidéo avant la recherche).
  • Identifiants NGC dans $NGC_CLI_API_KEY et $NVIDIA_API_KEY pour toute extraction d'images.
  • curl, jq, et Docker disponibles sur l'appelant.

Instructions

Suivez les tables de routage et les flux de travail étape par étape ci-dessous. Chaque section se terminant par workflow, quick start, ou flow est destinée à être exécutée de haut en bas. La documentation de référence détaillée se trouve dans references/.

Exemples

Des exemples fonctionnels de bout en bout sont conservés dans evals/ (chaque manifeste *.json contient un scénario exécutable) et en ligne dans les blocs curl par flux de travail ci-dessous. Exécutez une évaluation Tier-3 avec nv-base validate <this-skill-dir> --agent-eval pour les rejouer.

Limitations

  • Nécessite que le profil VSS / microservice correspondant soit déployé et accessible depuis l'appelant.
  • Les modèles hébergés sur NGC et les NIMs peuvent être soumis à des limites de débit, des exigences de mémoire GPU et des restrictions de licence.
  • Les limites de concurrence, de mémoire GPU et de stockage dépendent du matériel hôte et du fichier compose du profil.

Dépannage

  • Erreur : l'appel REST retourne connection refused. Cause : le microservice cible n'est pas en cours d'exécution. Solution : sondez /docs ou /health ; redéployez via vss-deploy-profile ou la skill vss-deploy-* correspondante.
  • Erreur : HTTP 401/403 depuis les extractions NGC. Cause : NGC_CLI_API_KEY manquante/expirée. Solution : docker login nvcr.io et réexportez la clé avant de réessayer.
  • Erreur : OOM du conteneur ou le modèle ne se charge pas. Cause : mémoire GPU insuffisante pour le profil sélectionné. Solution : basculez vers une variante plus petite ou libérez les GPUs via docker compose down.

Flux de travail de recherche vidéo

Fonctionnalité Alpha — non recommandée pour une utilisation en production.

Recherchez des archives vidéo en langage naturel en utilisant les embeddings Cosmos Embed1. Nécessite le profil de recherche — déployez avec la skill vss-deploy-profile (-p search). Ces sources vidéos peuvent être des fichiers ingérés ou des flux RTSP.

Quand l'utiliser

  • « Trouver toutes les instances de chariots élévateurs »
  • « Quand quelqu'un a-t-il pénétré dans la zone restreinte ? »
  • « Montrez-moi les personnes près du quai de chargement »
  • « Rechercher des véhicules entre 8h et midi »
  • Toute recherche en langage naturel dans les archives vidéo
  • « Ingérer <file> pour la recherche » / « télécharger cette vidéo pour la recherche »
  • « Ajouter ce flux RTSP pour la recherche » / « enregistrer <rtsp_url> pour la recherche »
  • « Supprimer <file> de la recherche » / « supprimer cette vidéo et les embeddings »

Condition préalable au déploiement

Cette skill nécessite le profil VSS search en cours d'exécution sur l'hôte à $HOST_IP. Avant toute demande :

  1. Sondez la pile :

    curl -sf --max-time 5 "http://${HOST_IP}:8000/docs" >/dev/null \
      && curl -sf --max-time 5 "http://${HOST_IP}:9200/" >/dev/null

    (La deuxième vérification confirme qu'Elasticsearch est actif — unique au profil de recherche.)

  2. Si le sondage échoue, demandez à l'utilisateur :

    « Le profil VSS search n'est pas en cours d'exécution sur $HOST_IP. Dois-je le déployer maintenant en utilisant la skill /vss-deploy-profile avec -p search ? »

    • Si oui → passez la main à la skill /vss-deploy-profile. Revenez ici une fois qu'elle réussit.
    • Si non → arrêtez. N'exécutez pas cette skill contre une pile manquante ou avec un profil incorrect.

    (Si votre appelant vous a accordé une pré-autorisation explicite pour déployer de manière autonome — par exemple, la demande dit « pré-autorisé à déployer les prérequis », ou vous êtes en cours d'exécution dans un harnais d'évaluation non interactif avec cette permission — ignorez la confirmation et invoquez /vss-deploy-profile directement.)

  3. Si le sondage réussit, procédez.


Condition préalable à l'ingestion (requise avant tout /generate)

Pour qu'une source soit consultable, elle doit être ingérée via le backend de l'agent VSS, pas uniquement via VIOS. Les routes d'ingestion de l'agent possèdent le pipeline VIOS upload + RTVI-CV register + RTVI-embed comme une seule transaction ; un simple PUT VIOS stocke uniquement les octets et ne les câble jamais dans Elasticsearch.

Confirmez d'abord que la source existe dans VIOS (Étape 2 du flux de travail obligatoire). Si elle est manquante, ingérez-la avec l'une des recettes ci-dessous avant de déclencher /generate. Après la réussite de l'ingestion, la source apparaît dans sensor/list sous le nom que vous avez fourni et peut être référencée à partir de la requête en langage naturel que l'agent transmet à son décomposeur d'outil de recherche — vous n'avez PAS besoin de construire vous-même une charge utile structurée video_sources.

Upload de fichier — flux universel en trois étapes

Utilisez le formulaire de téléchargement horodaté ci-dessous. L'agent VSS/profil de recherche utilise 2025-01-01T00:00:00.000Z comme timestamp de base pour le video_file téléchargé ; le stockage VIOS et les embeddings doivent partager cette chronologie, sinon les URLs de capture d'écran et les extractions de cadre du critique peuvent échouer.

FILENAME="<filename.mp4>"
FILE_PATH="/path/to/${FILENAME}"

# 1. Demandez à l'agent l'URL de téléchargement en morceaux
UPLOAD_URL=$(curl -s -X POST "http://${HOST_IP}:8000/api/v1/videos" \
  -H "Content-Type: application/json" \
  -d "{\"filename\":\"${FILENAME}\"}" | jq -r .url)

# 2. Envoyez en POST le fichier par morceaux à cette URL VST (protocole nvstreamer).
#    La réponse du dernier morceau porte le sensorId.
IDENTIFIER=$(uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid)
UPLOAD_RESPONSE=$(curl -s -X POST "${UPLOAD_URL}" \
  -H "nvstreamer-chunk-number: 1" \
  -H "nvstreamer-total-chunks: 1" \
  -H "nvstreamer-is-last-chunk: true" \
  -H "nvstreamer-identifier: ${IDENTIFIER}" \
  -H "nvstreamer-file-name: ${FILENAME}" \
  -F "mediaFile=@${FILE_PATH};filename=${FILENAME}" \
  -F "filename=${FILENAME}" \
  -F 'metadata={"timestamp":"2025-01-01T00:00:00"}')

# 3. Dites à l'agent que le téléchargement est terminé — cela se démultiplexe vers RTVI-CV + RTVI-embed
SENSOR=$(printf '%s' "${UPLOAD_RESPONSE}" | jq -r .sensorId)
[ -z "${SENSOR}" ] || [ "${SENSOR}" = "null" ] \
  && { echo "Upload failed: no sensorId in response: ${UPLOAD_RESPONSE}"; exit 1; }
printf '%s' "${UPLOAD_RESPONSE}" \
  | jq --arg filename "${FILENAME}" '. + {filename: $filename}' \
  | curl -s -X POST "http://${HOST_IP}:8000/api/v1/videos/${SENSOR}/complete" \
      -H "Content-Type: application/json" \
      -d @- | jq .

Attendez la réponse /complete (elle retourne chunks_processed > 0 une fois que les embeddings atterrissent). C'est seulement à ce moment que la vidéo est consultable.

L'ancienne route PUT /api/v1/videos-for-search/{filename} est également câblée pour les appelants hérités (coup unique, piloté par l'agent), mais son entrée OpenAPI est marquée deprecated. Préférez le flux en trois étapes ci-dessus pour les nouveaux travaux.

Flux RTSP — point de terminaison unique

curl -s -X POST "http://${HOST_IP}:8000/api/v1/rtsp-streams/add" \
  -H "Content-Type: application/json" \
  -d '{
    "sensorUrl": "rtsp://<host>:<port>/<path>",
    "name": "<sensor-name>",
    "username": "",
    "password": "",
    "location": "",
    "tags": ""
  }' | jq .

La forme de réponse est {status, message, error} — pas de sensorId (l'agent indexe le flux par le name que vous avez fourni). Sur l'échec de n'importe quelle étape, les étapes antérieures font l'objet d'une annulation. L'étape start_embedding_generation est fire-and-verify : un 2xx confirme que la demande a été acceptée et le pipeline d'embedding s'exécute en arrière-plan, pas que le flux est consultable. Les résultats de recherche commencent à apparaître seulement après que suffisamment de morceaux arrivent dans Elasticsearch — interrogez avec une requête à faible top_k quelques secondes plus tard si vous avez besoin d'un signal de disponibilité.

Supprimer source — nettoyage soutenu par l'agent

Supprimez via le backend de l'agent, pas le VIOS nu, afin que le stockage VIOS et les embeddings de recherche soient nettoyés ensemble.

# Pour les fichiers vidéo : video_id est l'UUID du capteur/vidéo VIOS
curl -s -X DELETE "http://${HOST_IP}:8000/api/v1/videos/<video_id>" | jq .

# Pour les flux RTSP : name est le nom de la source enregistrée
curl -s -X DELETE "http://${HOST_IP}:8000/api/v1/rtsp-streams/delete/<name>" | jq .

Comment fonctionne la recherche

  1. Ingestion — Les fichiers arrivent via le flux universel en trois étapes de l'agent ; les flux RTSP via /api/v1/rtsp-streams/add. Les deux routes remettent la source à RTVI-CV (détection d'attributs) et RTVI-Embed (Cosmos Embed1) qui génère des embeddings vectoriels pour les segments vidéo.
  2. Indexation — Les embeddings sont stockés dans Elasticsearch via le pipeline Kafka.
  3. Requête — Les requêtes en langage naturel sont intégrées et mises en correspondance avec les vecteurs stockés par similarité.
  4. Résultats — Segments vidéo horodatés classés par pertinence, avec liens de lecture de clip.

Cette recherche orchestrée par l'agent VSS peut conduire à 3 comportements :

  • Attributs uniquement : quand le LLM décompose la requête et ne trouve que des attributs d'apparence sans action (par exemple, « personne portant une veste rouge »)
  • Embedding uniquement : quand la requête n'a pas d'attributs extractibles (par exemple, « montrez-moi des chariots élévateurs »)
  • Fusion : quand la requête a à la fois une action et des attributs (par exemple, « personne en veste rouge courant »), elle exécute d'abord la recherche d'embedding, puis reclasse en utilisant la recherche d'attributs

Flux de travail obligatoire

Lors de l'utilisation de cette skill, SUIVEZ TOUJOURS ce flux de travail de haut niveau :

  1. Résolvez les entrées à partir des instructions de l'utilisateur — ARRÊT OBLIGATOIRE si $HOST_IP n'est pas explicitement fourni. Voir § Résolution des entrées ci-dessous. Ne METTEZ PAS par défaut localhost, 127.0.0.1, l'hôte sur lequel l'agent lui-même s'exécute, ou toute autre supposition. Ne lancez PAS une demande POST http://.../generate jusqu'à ce que l'utilisateur ait fourni un point de terminaison. Répondez à l'utilisateur avec une seule question demandant HOST_IP / le point de terminaison de l'agent VSS et attendez.

  2. Résolvez la source — ARRÊT OBLIGATOIRE avant tout appel /generate. Si la requête de l'utilisateur référence une vidéo / un nom de capteur spécifique (par exemple, « la vidéo de l'aéroport », « warehouse_cam_3 », « sample warehouse »), vérifiez qu'il est réellement enregistré dans VIOS avant de déclencher POST .../generate. Listez les sources via la skill vss-manage-video-io-storage.

    Puis :

    • Si la source nommée (ou un nom clairement correspondant à une sous-chaîne) EST dans la liste → procédez à l'étape 3. Transmettez la requête en langage naturel de l'utilisateur verbatim — le décomposeur d'outil de recherche propre de l'agent (services/agent/src/vss_agents/tools/search.py) extrait video_sources de la prose compte tenu des sources disponibles, la skill n'a donc PAS besoin de construire elle-même une charge utile structurée video_sources.
    • Si la source nommée N'est PAS dans la liste → ARRÊTEZ. Ne lancez PAS /generate en tant que sonde. Répondez à l'utilisateur avec les noms de sources enregistrées et demandez s'il en a voulu l'un d'eux, souhaite ingérer la source manquante (pointez-le vers Condition préalable à l'ingestion et exécutez la recette de fichier ou RTSP correspondante via le backend de l'agent, pas le VIOS nu), ou souhaite abandonner la requête. Attendez la clarification.
    • Si la requête ne nomme pas de source spécifique (« trouver des chariots élévateurs dans les vidéos ingérées », « rechercher dans toutes les sources ») → ignorez la vérification de sous-chaîne, mais sensor/list doit quand même retourner non vide (sinon aucune source n'est ingérée → ARRÊT OBLIGATOIRE).
  3. Exécutez la/les recherche(s) via l'approche choisie

  4. Présentez les résultats à la requête de l'utilisateur. Formatez la réponse comme un rapport d'inspection professionnel mais nommez-le Résultats de la recherche vidéo : — Utilisez des en-têtes de section clairs

    • Organisez les conclusions individuellement avec les détails à l'appui, et terminez par un résumé
    • Utilisez des tableaux où les comparaisons aident. Écrivez comme un rapport technique, pas un message de chat.
    • Si les résultats des critères ne sont pas nuls, alors en plus d'une colonne « Résultat du critique » (« confirmé » | « rejeté » | « ignoré »), incluez une colonne « Critères » avec tous les critères de ce résultat de recherche ({criteria_n}: ✓ | ✗)
  5. CRITIQUE : Vérifiez les résultats et expliquez-le à l'utilisateur de manière concise. Si la recherche échoue, ou retourne des résultats inattendus (c.-à-d. des vidéos qui ne semblent pas correspondre à la requête utilisateur, zéro correspondance, zéro vidéos retournées, erreur, etc.), ARRÊTEZ. Ne procédez pas sans lire troubleshooting.md pour itérer avec des boucles de rétroaction jusqu'à ce que les résultats appropriés soient trouvés et présentés comme un rapport d'inspection professionnel.

  6. Vérifications finales :

    • INFORMEZ TOUJOURS l'utilisateur que des vérifications finales et supplémentaires peuvent être exécutées. Présentez cela comme une Étape de vérification
    • UNIQUEMENT SI l'utilisateur accepte, téléchargez les captures d'écran en utilisant la screenshot_url des meilleurs candidats (scores de similarité les plus élevés) des résultats de recherche (résultats JSON) vers /tmp. Lisez-les et vérifiez s'ils correspondent à la requête de l'utilisateur

Résolution des entrées

Déduisez ces entrées uniquement de la conversation ou de la requête de l'utilisateur (aucun autre fichier sauf s'il est fourni). Si certaines ne peuvent pas être déduites, demandez immédiatement à l'utilisateur :

  • $HOST_IP : où le backend de l'agent VSS s'exécute

Pièges

  • ALLEZ TOUJOURS à l'étape de dépannage du flux de travail immédiatement si quelque chose d'inattendu se produit, lisez troubleshooting.md
  • Les requêtes fonctionnent mieux avec des descriptions visuelles concrètes (objets, actions, emplacements). Augmentez les requêtes de l'utilisateur si nécessaire pour améliorer la qualité des questions, en élargissant les détails potentiels
  • La skill suppose que les sources vidéo sont déjà ingérées via le backend de l'agent (voir Condition préalable à l'ingestion). Elle PEUT exécuter les recettes d'ingestion soutenues par l'agent quand l'utilisateur le demande explicitement (« ingérer <file> pour la recherche », « ajouter <rtsp_url> pour la recherche ») ; elle ne recherche PAS le système de fichiers local pour les fichiers que l'utilisateur n'a pas nommés, et elle n'utilise PAS le chemin nu-VIOS PUT (aucun embedding n'est généré). L'étape 2 du flux de travail rend toujours confirmer « cette source existe dans VIOS » une précondition obligatoire avant /generate.
  • Utilisez la skill vss-query-analytics pour croiser les résultats de recherche avec les données d'incident/d'alerte

Recherche via REST API

Utilisez par défaut cette approche REST API, sauf si l'utilisateur en spécifie une autre.

# Considérez par défaut uniquement les sources de fichiers vidéo ingérés
curl -s -X POST http://${HOST_IP}:8000/generate \
  -H "Content-Type: application/json" \
  -d '{"input_message": "find all instances of forklifts"}' | jq .

Autres exemples

Utilisez la forme de requête messages lors du passage d'options de requête structurées telles que search_source_type ; le raccourci input_message n'accepte pas de champs supplémentaires.

# Rechercher par objet
curl -s -X POST http://${HOST_IP}:8000/generate \
  -H "Content-Type: application/json" \
  -d '{"input_message": "find vehicles in the parking lot"}' | jq .

# Rechercher par action
curl -s -X POST http://${HOST_IP}:8000/generate \
  -H "Content-Type: application/json" \
  -d '{"input_message": "show me people running"}' | jq .

# Rechercher par contexte temporel
curl -s -X POST http://${HOST_IP}:8000/generate \
  -H "Content-Type: application/json" \
  -d '{"input_message": "what happened at the entrance between 2pm and 3pm?"}' | jq .

# Considérez uniquement les sources RTSP avec le filtre `search_source_type` c.-à-d. les flux de caméra en direct
curl -s -X POST http://${HOST_IP}:8000/generate \
  -H "Content-Type: application/json" \
  -d '{"messages": [{"role": "user", "content": "find all instances of forklifts"}], "search_source_type": "rtsp"}' | jq .

Boutons de commande avancés

Si la requête utilisateur est ambiguë, l'utilisateur souhaite plus de conseils ou quand un contrôle fin est nécessaire, augmentez le input_message utilisateur en appelant explicitement certaines options en texte brut et en orientant l'agent dans la direction souhaitée. Axes de commande disponibles :

Axes Type Défaut Description
video sources string[] null Filtrer par des caméras ou noms de capteurs spécifiques
top k int 10 Max de résultats
minimum similarity float 0,0 Seuil de similarité min ; augmentez (par exemple 0,3) pour filtrer le bruit
critic usage bool true VLM vérifie chaque résultat et supprime les faux positifs
description string null Filtrer par métadonnées de caméra (par exemple, localisation, catégorie) si les métadonnées sont disponibles

Choisissez et sélectionnez certaines de ces options d'ajustement. Ajustez-les au besoin selon la situation et la requête de l'utilisateur. Pour des exemples de modes de découverte exploitant ceux-ci, voir discovery_modes.md.


Recherche via l'interface utilisateur Agent

Ouvrez http://${HOST_IP}:3000/ et tapez des requêtes en langage naturel :

find all instances of forklifts
show me people near the loading dock
when did a truck arrive at the gate?
find someone wearing a red jacket

Les résultats incluent des clips horodatés avec des scores de similarité.

bump:2

Skills similaires