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_KEYpourdocker 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_KEYou$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
/docsou/health; redéployez viavss-deploy-profileou la skillvss-deploy-*correspondante. - Erreur : HTTP 401/403 depuis les pulls NGC. Cause :
NGC_CLI_API_KEYmanquant/expiré. Solution :docker login nvcr.ioet 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 siGET /openapi.jsonl'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 viaPOST /v1/filesd'abord et passez l'idretourné. - 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 ligneAnomaly Detected: Yes/Noexplicite et définissezsystem_promptpour contraindre le modèle aux réponses Oui/Non (par les docs VSS). Chaque chunk est publié surKAFKA_TOPIC; les chunks correspondants vont aussi àKAFKA_INCIDENT_TOPICavecisAnomaly=true,info["triggerPhrase"]défini aux tokens correspondants, etinfo["verdict"]="confirmed". - Le support d'
alert_categorydé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 composeRTVI_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-vlmetmdx-vlm-incidents; une compose copiée nue sans overridesRTVI_VLM_KAFKA_*revient àvision-llm-messagesetvision-llm-events-incidents. Faites toujours confiance à l'environnement du conteneur livevss-rtvi-vlmavant de consommer. - Kafka autonome doit annoncer
${HOST_IP}:9092. La compose RT-VLM utiliseKAFKA_BOOTSTRAP_SERVERS=${HOST_IP}:9092; un broker qui annoncelocalhost:9094oukafka:9092peut 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}:9092d'abord. Si vous démarrez Kafka plus tard ou changez son listener annoncé, redémarrez/recréezrtvi-vlmavant de vous attendre à ce que les offsets Kafka bougent. stream=trueretourne Server-Sent Events, pas du JSON chunked. Utilisezcurl -N(pas de buffering). Chaque événement estdata: {...}\n\navec des champs par chunk tels quecontent,start_time, etend_time, terminé pardata: [DONE]. Sansstream=truele 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/licensen'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=0dé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épassermax_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 raccourcissezchunk_durationpour rester dans le budget. enable_reasoningrequiert un modèle Cosmos Reason. Le passer avec Qwen3-VL ou d'autres modèles non-reasoning est un no-op./v1/metricsest 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/metricsretourne 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-dretourne 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 aussiDELETE /v1/generate_captions/{stream_id}, appelez-le d'abord pour arrêter explicitement l'inférence.