vss-deploy-dense-captioning

Par nvidia · skills

Utilisez cette skill lors du déploiement du dense captioning RT-VLM autonome ou lors de l'appel à son API REST (uploads, captions, streams, chat-completions, Kafka). Non applicable pour le déploiement du profil VSS ou l'ingestion video-search.

npx skills add https://github.com/nvidia/skills --skill vss-deploy-dense-captioning

Objectif

Déployer le microservice de dense captioning RT-VLM de manière autonome et exercer tous les endpoints exposés (upload de fichier, generate_captions, ajout/suppression de stream, chat-completions, topics Kafka).

Prérequis

Pour le déploiement autonome de RT-VLM :

  • Docker, Docker Compose, NVIDIA Container Toolkit, et un GPU visible.
  • Identifiants de registre NGC dans $NGC_CLI_API_KEY pour docker login nvcr.io, les pull d'images, et les téléchargements locaux de modèles/artefacts NGC.
  • curl, jq, et un répertoire de travail inscriptible pour la copie compose autonome.

Pour les appels API contre un service existant :

  • Service RT-VLM en cours d'exécution accessible via $BASE_URL.
  • Bearer token dans $RTVI_VLM_API_KEY ou $NGC_CLI_API_KEY, selon la configuration du service.

Pour le déploiement complet du profil VSS :

  • Utilisez ../vss-deploy-profile/SKILL.md ; cette skill ne déploie pas les profils VSS complets.

Instructions

Suivez les tableaux de routage et les workflows é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. Le matériel de référence détaillé se trouve dans references/ et les scripts d'aide se trouvent dans scripts/ — appelez-les via run_script quand la skill pointe vers un script par nom.

Exemples

Les exemples complets 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 workflow ci-dessous. Exécutez une évaluation Tier-3 avec nv-base validate <this-skill-dir> --agent-eval pour les rejouer.

Limitations

  • Nécessite soit un service RT-VLM autonome déployé via cette skill, soit un service RT-VLM existant accessible depuis l'appelant.
  • Les modèles hébergés par 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 connexion refusée. Cause : microservice cible non 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 pulls NGC. Cause : NGC_CLI_API_KEY manquant/expiré. Solution : docker login nvcr.io et réexportez la clé avant de réessayer.
  • Erreur : conteneur OOM ou échec du chargement du modèle. Cause : mémoire GPU insuffisante pour le profil sélectionné. Solution : passez à une variante plus petite ou libérez les GPUs via docker compose down.

Déployer et utiliser RT-VLM Dense Captioning (VSS 3.2)

RT-VLM est le microservice vision-langage en temps réel d'NVIDIA : décodez la vidéo (fichier ou RTSP), segmentez-la en chunks, exécutez un VLM (cosmos-reason1, cosmos-reason2, ou n'importe quel modèle compatible OpenAI), diffusez les captions denses en retour via SSE/HTTP, et publiez les captions, alertes d'incident et erreurs sur Kafka. Utilisez cette skill pour déployer le service RT-VLM autonome quand un profil VSS complet n'est pas déjà en cours d'exécution, puis appelez son API /v1/... pour la génération de captions, l'upload de fichiers, la gestion des streams en direct, les vérifications de santé, les chat completions compatibles NIM, ou les métriques Prometheus. Référence API : https://docs.nvidia.com/vss/latest/real-time-vlm-api.html.

Routage de déploiement

Si l'utilisateur demande le déploiement d'un profil VSS complet, utilisez ../vss-deploy-profile/SKILL.md. Cette skill gère le routage de profil, generated.env, resolved.yml, le dimensionnement multi-service, et le déploiement/arrêt de la pile complète.

Si l'utilisateur demande le dense captioning RT-VLM autonome, ou aucun profil VSS n'est déjà en cours d'exécution, utilisez le flux RT-VLM autonome dans references/deploy-rt-vlm-service.md avant d'appeler l'API. Cela suit le même modèle axé sur compose que vss-deploy-profile : recueillez le contexte, exécutez les prévérifications, travaillez à partir d'une copie locale, exécutez un essai à sec avec docker compose config, examinez, déployez, puis attendez la santé.

Flux de déploiement autonome

Suivez toujours cette séquence. Ne sautez jamais l'essai à sec.

# 1. Copiez deploy/docker/services/rtvi/rtvi-vlm/rtvi-vlm-docker-compose.yml
#    dans n'importe quel répertoire de travail autonome inscriptible.
# 2. Dérivez RTVI_VLM_IMAGE_TAG de cette copie compose.
# 3. Supprimez le bloc depends_on orphelin autonome de la copie.
# 4. Créez un .env ignoré par git avec les valeurs RT-VLM requises.
# 5. Préparez les chemins de liaison d'hôte tels que $VSS_DATA_DIR/data_log/vst/clip_storage.
# 6. docker compose --env-file .env -f rtvi-vlm-docker-compose.yml config --quiet
# 7. docker pull le tag d'image RT-VLM exact.
# 8. docker compose ... up -d rtvi-vlm, attendez qu'il soit prêt, puis test de fumée.

Exécutez les prévérifications avant tout pull ou up ; arrêtez et corrigez les défaillances ici avant de déboguer RT-VLM lui-même :

nvidia-smi --query-gpu=index,name --format=csv,noheader
nvidia-container-cli info
docker compose version
docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi

Pour les déploiements autonomes mono-fichier, n'exécutez pas le deploy/docker/services/rtvi/rtvi-vlm/rtvi-vlm-docker-compose.yml brut directement : il contient des références depends_on aux services VLM/NIM frères qui ne sont définis que dans le projet compose complet VSS/met-blueprints. La référence autonome montre comment copier le fichier compose, dériver le tag d'image actuel, supprimer le bloc depends_on, et valider le résultat avant up.

Si docker pull échoue avec une erreur unpack du snapshotter containerd sur Docker 28+, appliquez le correctif containerd-snapshotter=false de /etc/docker/daemon.json dans la référence autonome avant de réessayer.

Valeurs .env autonomes minimales :

Variable env d'hôte Requis quand Objectif
NGC_CLI_API_KEY Chemin de déploiement autonome Pull d'images de registre NGC et téléchargements locaux de modèles/artefacts NGC
RTVI_VLM_API_KEY ou NGC_CLI_API_KEY Appels API authentifiés Authentification Bearer RT-VLM après que le service soit en cours d'exécution
RTVI_VLM_PORT Toujours Port API d'hôte mappé au conteneur 8000
HOST_IP Toujours Hôte bootstrap Kafka (${HOST_IP}:9092)
VSS_DATA_DIR Toujours Montage de liaison clip-storage requis
RTVI_VLM_MODEL_TO_USE Toujours pour autonome Sélecteur backend ; utilisez cosmos-reason2 pour le modèle local par défaut ou openai-compat pour un endpoint distant/frère
RTVI_VLM_MODEL_PATH Modèle auto-hébergé local Chemin Cosmos Reason 2 adossé à la source : ngc:nim/nvidia/cosmos-reason2-8b:0303-fp8-dynamic-kv8
RTVI_VLM_ENDPOINT RTVI_VLM_MODEL_TO_USE=openai-compat Endpoint VLM distant/frère compatible OpenAI
VLM_NAME RTVI_VLM_MODEL_TO_USE=openai-compat Nom du modèle/déploiement exposé par cet endpoint

Configuration

export BASE_URL="http://localhost:${RTVI_VLM_PORT:-8018}"  # port RT-VLM côté hôte
export API_KEY="${NGC_CLI_API_KEY:-${RTVI_VLM_API_KEY:-}}" # bearer token utilisé par les commandes curl côté hôte
: "${API_KEY:?Set NGC_CLI_API_KEY or RTVI_VLM_API_KEY before calling authenticated endpoints}"

Chaque requête ci-dessous utilise Authorization: Bearer $API_KEY. Les endpoints de santé (/v1/health/*, /v1/ready, /v1/live, /v1/startup) fonctionnent généralement sans authentification.

Test de fumée avant utilisation :

curl -fsS "$BASE_URL/v1/health/ready"
MODEL_ID="$(curl -fsS "$BASE_URL/v1/models" -H "Authorization: Bearer $API_KEY" | jq -r '.data[0].id // .id')"
curl -fsS "$BASE_URL/openapi.json" | jq -r '.paths | keys[]' | sort

Démarrage rapide — captions denses à partir d'une vidéo locale

# 1. Uploadez la vidéo, capturez son id de fichier
FILE_ID=$(curl -fsS -X POST "$BASE_URL/v1/files" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@/path/to/warehouse.mp4" \
  -F "purpose=vision" \
  -F "media_type=video" | jq -r '.id')

# 2. Générez les captions + alertes (flux SSE de réponses chunked)
curl -N -X POST "$BASE_URL/v1/generate_captions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"id\": \"$FILE_ID\",
    \"prompt\": \"Write a concise dense caption for each 10-second segment of this warehouse video.\",
    \"model\": \"$MODEL_ID\",
    \"chunk_duration\": 10,
    \"stream\": true
  }"

Endpoints

Captions

Générez les captions VLM et les alertes pour les vidéos et les streams en direct.

POST /v1/generate_captions — Générez les captions VLM (et alertes) pour la vidéo/stream

Requis : | Champ | Type | Description | |-------|------|-------------| | id | string | array | UUID d'un fichier précédemment uploadé, ou id d'un stream en direct actif. Accepte une liste d'ids pour batch | | prompt | string | Prompt utilisateur au VLM (ex. instruction de dense-caption) | | model | string | Id de modèle exact retourné par GET /v1/models, par exemple nim_nvidia_cosmos-reason2-8b_0303-fp8-dynamic-kv8 ; les alias de sélecteur backend comme cosmos-reason2 ne sont pas des ids de modèle de requête |

Champs optionnels clés : | Champ | Type | Défaut | Description | |-------|------|--------|-------------| | system_prompt | string | — | Prompt système ; utilisez les balises <think></think><answer></answer> pour activer le reasoning sur Cosmos Reason | | enable_reasoning | boolean | false | Activez le reasoning pour les modèles Cosmos Reason | | enable_audio | boolean | false | Transcrivez l'audio (via Riva) et pliez-le dans les captions | | chunk_duration | integer | — | Segmentez la vidéo en chunks de N secondes (0 = sans chunking) | | chunk_overlap_duration | integer | 0 | Chevauchement entre chunks consécutifs | | num_frames_per_second_or_fixed_frames_chunk | number | — | FPS (si use_fps_for_chunking=true) ou frames fixes par chunk | | use_fps_for_chunking | boolean | false | Interprétez ci-dessus comme FPS vs. décompte de frames fixe | | vlm_input_width / vlm_input_height | int | — | Redimensionnez les frames avant l'inférence (0 = natif) | | media_info | object | — | {"type":"offset","start_offset":0,"end_offset":10} pour traiter une tranche d'un fichier (pas les streams en direct) | | stream | boolean | false | SSE : émettez les deltas de captions par chunk comme événements data: (recommandé pour les longues vidéos) | | max_tokens / temperature / top_p / top_k / seed / ignore_eos | | | Contrôles d'échantillonnage standards | | response_format | object | — | Objet de format de réponse de requête | | mm_processor_kwargs | object | — | Kwargs supplémentaires pour le processeur multimodal (ex. size, shortest/longest edge) |

curl -N -X POST "$BASE_URL/v1/generate_captions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "prompt": "Dense-caption this warehouse video, one sentence per 10s chunk.",
    "model": "nim_nvidia_cosmos-reason2-8b_0303-fp8-dynamic-kv8",
    "chunk_duration": 10,
    "stream": true
  }'

Forme de réponse : les réponses live 26.05 utilisent chunk_responses avec start_time/end_time ; les flux SSE se terminent par data: [DONE]. Voir references/api-surface-26.05.md.

DELETE /v1/generate_captions/{stream_id} — Arrêtez la génération de captions pour un stream en direct, si exposé

Certains déploiements exposent ce companion endpoint stop. Vérifiez l'OpenAPI live (curl -fsS "$BASE_URL/openapi.json" | jq '.paths | keys[]') avant de l'utiliser. Appairez toujours le nettoyage du stream en direct avec DELETE /v1/streams/delete/{stream_id} pour dés-enregistrer la source RTSP.

curl -X DELETE "$BASE_URL/v1/generate_captions/$STREAM_ID" -H "Authorization: Bearer $API_KEY"

Fichiers

Uploadez et gérez les fichiers média consommés par /v1/generate_captions.

POST /v1/files — Uploadez un fichier média (multipart)

curl -X POST "$BASE_URL/v1/files" -H "Authorization: Bearer $API_KEY" \
  -F "file=@./video.mp4" -F "purpose=vision" -F "media_type=video"

Réponse : { "id", "object": "file", "bytes", "created_at", "filename", "purpose" }. Les métadonnées optionnelles comme sensor_name peuvent être acceptées par les builds plus récentes ; vérifiez l'OpenAPI live avant de l'envoyer.

GET /v1/files?purpose=vision — Listez les fichiers uploadés

GET /v1/files/{file_id} — Métadonnées du fichier

GET /v1/files/{file_id}/content — Téléchargez le contenu du fichier original

DELETE /v1/files/{file_id} — Supprimez le fichier (libère le stockage d'assets)

Stream en direct

Cycle de vie du stream RTSP.

POST /v1/streams/add — Enregistrez un ou plusieurs streams RTSP

Requis par stream : liveStreamUrl (doit commencer par rtsp://), description. Optionnel : username, password, sensor_name, et métadonnées de placement (place_name, place_type, place_lat, place_lon, place_alt, place_coordinate_x, place_coordinate_y).

Vérifiez les sources RTSP publiques ou externes avant de les enregistrer. Un code de sortie de sonde seul n'est pas suffisant ; gst-discoverer-1.0 peut quitter 0 tout en signalant un type de média inconnu. Traitez le stream comme utilisable uniquement quand la sortie de la sonde identifie au moins une entrée de stream/caps vidéo. Si une sonde est peu concluante, vérifiez de manière croisée avec un autre outil tel que ffprobe avant de retourner ou d'enregistrer :

ffprobe -v error -select_streams v:0 \
  -show_entries stream=codec_type -of csv=p=0 "$RTSP_URL" | grep -qx video
STREAM_ID=$(curl -fsS -X POST "$BASE_URL/v1/streams/add" \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -d '{"streams":[{"liveStreamUrl":"rtsp://cam:8554/live","description":"warehouse cam 1"}]}' \
  | jq -r '.results[0].id')

GET /v1/streams/get-stream-info — Listez les streams actifs

DELETE /v1/streams/delete/{stream_id} — Supprimez un seul stream

DELETE /v1/streams/delete-batch — Supprimez plusieurs ({"stream_ids":[...]})

Endpoints de stream au style CV

Les déploiements 26.05 exposent aussi les chemins de contrôle de stream au style CV : POST /v1/stream/add, GET /v1/stream/get-stream-info, et POST /v1/stream/remove. Utilisez-les quand un workflow ou une note de version utilise explicitement l'enveloppe clé/valeur ; sinon préférez les endpoints de stream RT-VLM au pluriel ci-dessus. Voir references/api-surface-26.05.md pour les exemples et la caveat de compatibilité stream_count:0.

Compatible NIM

Endpoints compatibles OpenAI pour l'interopérabilité avec les clients OpenAI/NVIDIA-API.

POST /v1/chat/completions — Chat compatible OpenAI (texte + multimodal)

Requis : messages, model. Les requêtes texte uniquement fonctionnent et omettent id, video_url, et image_url. Pour la vidéo uploadée, video_url direct, image_url direct, streaming, et exemples de chat adossés à RTSP, voir references/api-surface-26.05.md.

curl -X POST "$BASE_URL/v1/chat/completions" -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"model\":\"$MODEL_ID\",\"messages\":[{\"role\":\"user\",\"content\":\"Summarize this scene.\"}]}"

POST /v1/completions — Completions héritées compatible OpenAI

Cet endpoint existe pour la compatibilité, mais sur les builds live 26.05 actuels les requêtes legacy completion texte uniquement retournent HTTP 400 par conception. Utilisez /v1/chat/completions pour les requêtes texte uniquement et multimodales.

GET /v1/version{ "version": "3.2.0-..." }

GET /v1/manifest — Manifeste NIM

GET /v1/health/live · GET /v1/health/ready — Sondes au style NIM

Ne supposez pas que /v1/license existe. L'OpenAPI live 26.05 actuel ne l'expose pas et l'endpoint retourne 404 ; appelez-le uniquement après vérification de GET /openapi.json.

Modèles · Métadonnées · Métriques · Vérification de santé

GET /v1/models — Listez les VLMs chargés : { "data": [{ "id", "object": "model", "owned_by" }] }

GET /v1/metadata — Métadonnées du service (build, release, image tag)

GET /v1/assets/stats — Comptages du stockage d'assets, TTL, et âge du plus ancien asset

GET /v1/metrics — Métriques Prometheus (texte brut)

GET /v1/ready · GET /v1/live · GET /v1/startup — Sondes au style Kubernetes


Workflows courants

Les quatre scénarios standards de dense-captioning.

1. Dense captions à partir d'un fichier vidéo stocké

# Upload → capturez l'id de fichier → générez les captions (flux SSE)
FILE_ID=$(curl -fsS -X POST "$BASE_URL/v1/files" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@warehouse.mp4" -F "purpose=vision" -F "media_type=video" | jq -r '.id')

curl -N -X POST "$BASE_URL/v1/generate_captions" \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -d "{
    \"id\": \"$FILE_ID\",
    \"prompt\": \"Describe warehouse events in 1 sentence per 10s chunk.\",
    \"model\": \"$MODEL_ID\",
    \"chunk_duration\": 10,
    \"stream\": true
  }"

# Une fois terminé, libérez le stockage :
curl -X DELETE "$BASE_URL/v1/files/$FILE_ID" -H "Authorization: Bearer $API_KEY"

2. Dense captions à partir d'un stream RTSP en direct

# Enregistrez le stream
STREAM_ID=$(curl -fsS -X POST "$BASE_URL/v1/streams/add" \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -d '{"streams":[{"liveStreamUrl":"rtsp://10.0.0.5:8554/warehouse","description":"warehouse cam"}]}' \
  | jq -r '.results[0].id')

# Démarrez la génération continue de captions
curl -N -X POST "$BASE_URL/v1/generate_captions" \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -d "{
    \"id\": \"$STREAM_ID\",
    \"prompt\": \"Describe each event; start each sentence with a timestamp.\",
    \"model\": \"$MODEL_ID\",
    \"chunk_duration\": 10,
    \"num_frames_per_second_or_fixed_frames_chunk\": 2,
    \"use_fps_for_chunking\": true,
    \"stream\": true
  }" &

# Arrêtez quand terminé. Si l'OpenAPI live expose
# DELETE /v1/generate_captions/{stream_id}, appelez-le avant dés-enregistrement.
curl -X DELETE "$BASE_URL/v1/streams/delete/$STREAM_ID"  -H "Authorization: Bearer $API_KEY"

3. Dense captions avec alertes à partir d'un stream RTSP

# Prérequis : Kafka est activé et les topics correspondent à la source de déploiement.
# Le .env vérifié et les profils d'alertes VSS utilisent :
#   RTVI_VLM_KAFKA_ENABLED=true
#   RTVI_VLM_KAFKA_TOPIC=mdx-vlm
#   RTVI_VLM_KAFKA_INCIDENT_TOPIC=mdx-vlm-incidents
#   RTVI_VLM_ERROR_MESSAGE_TOPIC=vision-llm-errors
#   HOST_IP=<kafka-host>
# Une compose copiée sans ces overrides env revient aux topics vision-llm-*.
# Confirmez le conteneur live avant de consommer :
#   docker exec vss-rtvi-vlm printenv KAFKA_TOPIC KAFKA_INCIDENT_TOPIC ERROR_MESSAGE_TOPIC

STREAM_ID=$(curl -fsS -X POST "$BASE_URL/v1/streams/add" \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -d '{"streams":[{"liveStreamUrl":"rtsp://10.0.0.5:8554/warehouse","description":"warehouse cam"}]}' \
  | jq -r '.results[0].id')

curl -N -X POST "$BASE_URL/v1/generate_captions" \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -d "{
    \"id\": \"$STREAM_ID\",
    \"prompt\": \"You are a warehouse monitoring system. Describe the scene in one sentence, then on a new line output exactly:\\nAnomaly Detected: Yes/No\\nReason: <one sentence>\\nFlag an anomaly if any worker is missing a hard hat or high-vis vest.\",
    \"system_prompt\": \"Answer the user's question correctly in yes or no.\",
    \"model\": \"$MODEL_ID\",
    \"chunk_duration\": 60,
    \"chunk_overlap_duration\": 10,
    \"stream\": true
  }"

Consommez les alertes depuis Kafka. Les valeurs Kafka sont des payloads protobuf NvSchema, utilisez donc print.value=false pour une passe de validation propre qui montre timestamp, clé, et en-têtes sans dump des octets de payload binaires. La source des alertes/profils VSS utilise mdx-vlm-incidents ; une compose copiée nue peut revenir à vision-llm-events-incidents si aucun override RTVI_VLM_KAFKA_INCIDENT_TOPIC n'est chargé. Préférez l'environnement du conteneur live aux noms de topic codés en dur.

INCIDENT_TOPIC="${INCIDENT_TOPIC:-$(docker exec vss-rtvi-vlm printenv KAFKA_INCIDENT_TOPIC 2>/dev/null || true)}"
INCIDENT_TOPIC="${INCIDENT_TOPIC:-mdx-vlm-incidents}"

docker exec mdx-kafka kafka-console-consumer \
  --bootstrap-server 127.0.0.1:9092 \
  --topic "$INCIDENT_TOPIC" \
  --from-beginning \
  --timeout-ms 5000 \
  --max-messages 10 \
  --property print.timestamp=true \
  --property print.key=true \
  --property print.headers=true \
  --property print.value=false

Si Kafka ne tourne pas dans le conteneur VSS mdx-kafka, utilisez le CLI Kafka depuis l'hôte ou le conteneur qui exécute le broker :

INCIDENT_TOPIC="${INCIDENT_TOPIC:-mdx-vlm-incidents}"

kafka-console-consumer \
  --bootstrap-server "$HOST_IP:9092" \
  --topic "$INCIDENT_TOPIC" \
  --from-beginning \
  --timeout-ms 5000 \
  --max-messages 10 \
  --property print.timestamp=true \
  --property print.key=true \
  --property print.headers=true \
  --property print.value=false

Pour la validation autonome, n'oubliez pas que la compose RT-VLM mappe Kafka via KAFKA_BOOTSTRAP_SERVERS=${HOST_IP}:9092 ; définir KAFKA_BOOTSTRAP_SERVERS directement dans .env est ignoré sauf si la compose est changée. Le broker doit annoncer un listener accessible depuis le conteneur vss-rtvi-vlm. localhost à l'intérieur du broker et des conteneurs de service n'est pas l'hôte, et un alias de broker tel que kafka:9092 fonctionne uniquement quand les deux conteneurs partagent ce réseau Docker. Pour la validation RT-VLM uniquement, préférez le broker autonome dans references/kafka-workflows.md à la compose infra du repo complet ; le dernier s'attend à l'env/config complet du profil SDRC. Si Kafka est déjà en cours d'exécution, demandez à l'utilisateur s'il faut le réutiliser ou lancer un broker dédié avant d'arrêter ou remplacer quoi que ce soit. Exécutez les vérifications CLI à l'intérieur du conteneur du broker réel, mais configurez toujours le listener annoncé pour que RT-VLM puisse se connecter depuis son réseau de conteneur.

Champs clés du protobuf Incident (ext.proto :: Incident) : sensorId, timestamp, end, objectIds, frameIds, place, analyticsModule, category, isAnomaly (true pour les alertes), llm (VisionLLM imbriqué), map info incluant triggerPhrase, verdict, requestId, chunkIdx, streamId, alertCategory (si le déploiement supporte le champ de requête alert_category — post-3.1).

4. Workflows Kafka (alertes + bus de messages)

Le dense captioning avec alertes sur un stream RTSP et le modèle de réponse HTTP-vs-Kafka sont documentés dans references/kafka-workflows.md.

Référence d'erreur

Code Signification Cause commune
400 Requête incorrecte Champ requis manquant (id, prompt, model) ; media_type non supporté ; nom de model inconnu
401 Non autorisé Authorization: Bearer $API_KEY manquant/invalide — ou format de clé incorrect (attendre nvapi-...)
404 Non trouvé file_id supprimé / stream_id non enregistré / chemin d'endpoint incorrect (remarque : {stream_id} est requis sur DELETE /v1/streams/delete/{stream_id})
413 Charge utile trop volumineux Fichier uploadé dépasse MAX_FILE_SIZE du serveur ; augmentez ou pré-chunquez la vidéo
422 Entité non traitable Violation de schéma Pydantic — ex. use_fps_for_chunking=true sans num_frames_per_second_or_fixed_frames_chunk ; ids de stream fournis à un champ fichier uniquement comme media_info
429 Dépassement de limite Trop de streams concurrents — augmentez VLM_BATCH_SIZE ou distribuez sur instances
500 Erreur serveur Exception d'inférence VLM (OOM, modèle indisponible) — vérifiez docker logs vss-rtvi-vlm
503 Service occupé Startup non terminé (modèle toujours en téléchargement) ou dépendance NIM en amont non saine

Pièges

  • Utilisez l'OpenAPI live comme source de vérité. Pour VSS 3.2, l'endpoint de génération de captions est /v1/generate_captions. Certaines références plus anciennes et images utilisaient /v1/generate_captions_alerts ; ne supposez pas que ce chemin existe sauf si GET /openapi.json l'affiche.
  • Le support d'entrée basé sur URL dépend de la version du service déployé. Si le schéma live n'expose pas url/media_type/creation_time, uploadez via POST /v1/files d'abord et passez l'id retourné.
  • Déclencheur d'alerte = les tokens "yes" ou "true" dans la réponse VLM (insensible à la casse). Il n'y a pas de flag d'alerte par requête. Concevez les prompts avec une ligne Anomaly Detected: Yes/No explicite et définissez system_prompt pour contraindre le modèle aux réponses Oui/Non (par les docs VSS). Chaque chunk est publié sur KAFKA_TOPIC ; les chunks correspondants vont aussi à KAFKA_INCIDENT_TOPIC avec isAnomaly=true, info["triggerPhrase"] défini aux tokens correspondants, et info["verdict"]="confirmed".
  • Le support d'alert_category dépend de la version du service déployé. Si le schéma OpenAPI live n'expose pas, les incidents Kafka défaillent à incident.category = "vlm-alert".
  • Les topics Kafka sont config côté serveur, pas par requête. Les variables env KAFKA_* (via rewrites compose RTVI_VLM_KAFKA_*) sont fixées au démarrage du conteneur — les clients ne peuvent pas overrider les topics sur base par-requête. Kafka publish est additif à la réponse HTTP, jamais un remplacement.
  • Les noms de topic diffèrent par source de déploiement. Le .env RT-VLM vérifié et les sources alertes/profils VSS utilisent mdx-vlm et mdx-vlm-incidents ; une compose copiée nue sans overrides RTVI_VLM_KAFKA_* revient à vision-llm-messages et vision-llm-events-incidents. Faites toujours confiance à l'environnement du conteneur live vss-rtvi-vlm avant de consommer.
  • Kafka autonome doit annoncer ${HOST_IP}:9092. La compose RT-VLM utilise KAFKA_BOOTSTRAP_SERVERS=${HOST_IP}:9092 ; un broker qui annonce localhost:9094 ou kafka:9092 peut passer les tests producteur/consommateur à l'intérieur du conteneur broker tandis que la publication RT-VLM échoue.
  • Démarrez Kafka avant RT-VLM quand Kafka est activé. Pour la validation autonome déterministe, rendez le broker accessible à ${HOST_IP}:9092 d'abord. Si vous démarrez Kafka plus tard ou changez son listener annoncé, redémarrez/recréez rtvi-vlm avant de vous attendre à ce que les offsets Kafka bougent.
  • stream=true retourne Server-Sent Events, pas du JSON chunked. Utilisez curl -N (pas de buffering). Chaque événement est data: {...}\n\n avec des champs par chunk tels que content, start_time, et end_time, terminé par data: [DONE]. Sans stream=true le serveur buffer jusqu'à ce que la vidéo entière soit traitée — bien pour les clips courts (<1 min), évitez pour les streams en direct.
  • Faites confiance à l'OpenAPI live pour les endpoints NIM-compatibles optionnels. /v1/license n'est pas exposé par les builds 26.05 actuels et retourne 404, même si les docs génériques NIM plus anciennes peuvent le mentionner.
  • Préférez /v1/chat/completions à /v1/completions. Les completions héritées texte uniquement retournent HTTP 400 par conception sur les builds 26.05 actuels ; les chat completions texte uniquement fonctionnent.
  • chunk_duration=0 désactive le chunking — la vidéo entière est envoyée au VLM d'un seul coup. Significatif uniquement pour les clips courts ; les longues vidéos vont OOM ou dépasser max_model_len.
  • Le budget de frames par défaut plafonne à VLLM_MM_PROCESSOR_VIDEO_NUM_FRAMES (256). Demander un FPS qui implique >256 frames par chunk est silencieusement plafonné ; diminuez le FPS ou raccourcissez chunk_duration pour rester dans le budget.
  • enable_reasoning requiert un modèle Cosmos Reason. Le passer avec Qwen3-VL ou d'autres modèles non-reasoning est un no-op.
  • /v1/metrics est non authentifié sur les builds autonomes 26.05 actuels. Un Bearer token est inoffensif si un déploiement a une auth plus stricte, mais ne retournez pas de validation quand /v1/metrics retourne HTTP 200 sans auth.
  • L'upload de fichier est multipart, pas JSON. Utilisez -F file=@path -F purpose=vision -F media_type=video ; un corps -d retourne 422.
  • Le nettoyage du cycle de vie du stream en direct doit dés-enregistrer le stream : DELETE /v1/streams/delete/{stream_id} supprime la source RTSP. Si le schéma live expose aussi DELETE /v1/generate_captions/{stream_id}, appelez-le d'abord pour arrêter explicitement l'inférence.

Skills similaires