Compétence VideoDB
Perception + mémoire + actions pour la vidéo, les flux en direct et les sessions de bureau.
Quand l'utiliser
Perception de bureau
- Démarrer/arrêter une session de bureau capturant l'écran, le micro et l'audio système
- Diffuser un contexte en direct et stocker une mémoire de session épisodique
- Exécuter des alertes/déclencheurs en temps réel sur ce qui est dit et ce qui se passe à l'écran
- Produire des résumés de session, une timeline consultable et des liens de preuve jouables
Ingestion vidéo + flux
- Ingérer un fichier ou une URL et retourner un lien de flux web jouable
- Transcoder/normaliser : codec, débit, fps, résolution, rapport hauteur/largeur
Indexation + recherche (horodatages + preuves)
- Construire des index visuels, vocaux et par mots-clés
- Rechercher et retourner des moments exacts avec horodatages et preuves jouables
- Créer automatiquement des clips à partir des résultats de recherche
Édition de timeline + génération
- Sous-titres : générer, traduire, incruster
- Superpositions : texte/image/marque, légendes animées
- Audio : musique de fond, voix off, doublage
- Composition programmatique et exportations via opérations de timeline
Flux en direct (RTSP) + surveillance
- Connecter des flux RTSP/en direct
- Exécuter une compréhension visuelle et vocale en temps réel et émettre des événements/alertes pour les flux de surveillance
Comment ça fonctionne
Entrées courantes
- Chemin de fichier local, URL publique ou URL RTSP
- Demande de capture de bureau : démarrer / arrêter / résumer la session
- Opérations souhaitées : obtenir le contexte pour la compréhension, spécification de transcodage, spécification d'indexation, requête de recherche, plages de clips, modifications de timeline, règles d'alerte
Sorties courantes
- URL du flux
- Résultats de recherche avec horodatages et liens de preuve
- Actifs générés : sous-titres, audio, images, clips
- Charges utiles d'événements/alertes pour les flux en direct
- Résumés de session de bureau et entrées mémoire
Exécution de code Python
Avant d'exécuter tout code VideoDB, placez-vous dans le répertoire du projet et chargez les variables d'environnement :
from dotenv import load_dotenv
load_dotenv(".env")
import videodb
conn = videodb.connect()
Ceci lit VIDEO_DB_API_KEY depuis :
- L'environnement (si déjà exportée)
- Le fichier
.envdu projet dans le répertoire courant
Si la clé est manquante, videodb.connect() lève automatiquement AuthenticationError.
N'écrivez PAS de fichier script quand une courte commande en ligne suffit.
Quand vous écrivez du Python en ligne (python -c "..."), utilisez toujours du code correctement formaté — utilisez des points-virgules pour séparer les instructions et gardez-le lisible. Pour tout ce qui dépasse ~3 instructions, utilisez plutôt un heredoc :
python << 'EOF'
from dotenv import load_dotenv
load_dotenv(".env")
import videodb
conn = videodb.connect()
coll = conn.get_collection()
print(f"Videos: {len(coll.get_videos())}")
EOF
Configuration
Quand l'utilisateur demande "configurer videodb" ou similaire :
1. Installer le SDK
pip install "videodb[capture]" python-dotenv
Si videodb[capture] échoue sur Linux, installez sans l'option capture :
pip install videodb python-dotenv
2. Configurer la clé API
L'utilisateur doit définir VIDEO_DB_API_KEY en utilisant l'une ou l'autre des méthodes :
- Exporter dans le terminal (avant de lancer Gemini) :
export VIDEO_DB_API_KEY=votre-clé - Fichier
.envdu projet : EnregistrerVIDEO_DB_API_KEY=votre-clédans le fichier.envdu projet
Obtenez une clé API gratuite sur console.videodb.io (50 téléchargements gratuits, pas de carte de crédit).
Ne lisez, n'écrivez ni ne gérez la clé API vous-même. Laissez toujours l'utilisateur la définir.
Référence rapide
Télécharger un média
# URL
video = coll.upload(url="https://example.com/video.mp4")
# YouTube
video = coll.upload(url="https://www.youtube.com/watch?v=VIDEO_ID")
# Fichier local
video = coll.upload(file_path="/path/to/video.mp4")
Transcription + sous-titre
# force=True évite l'erreur si la vidéo est déjà indexée
video.index_spoken_words(force=True)
text = video.get_transcript_text()
stream_url = video.add_subtitle()
Rechercher dans les vidéos
from videodb.exceptions import InvalidRequestError
video.index_spoken_words(force=True)
# search() lève InvalidRequestError quand aucun résultat n'est trouvé.
# Toujours l'envelopper dans try/except et traiter "Aucun résultat trouvé" comme vide.
try:
results = video.search("product demo")
shots = results.get_shots()
stream_url = results.compile()
except InvalidRequestError as e:
if "No results found" in str(e):
shots = []
else:
raise
Recherche par scène
import re
from videodb import SearchType, IndexType, SceneExtractionType
from videodb.exceptions import InvalidRequestError
# index_scenes() n'a pas de paramètre force — il lève une erreur si un index
# de scène existe déjà. Extrayez l'ID d'index existant à partir de l'erreur.
try:
scene_index_id = video.index_scenes(
extraction_type=SceneExtractionType.shot_based,
prompt="Décrivez le contenu visuel de cette scène.",
)
except Exception as e:
match = re.search(r"id\s+([a-f0-9]+)", str(e))
if match:
scene_index_id = match.group(1)
else:
raise
# Utilisez score_threshold pour filtrer le bruit à faible pertinence (recommandé : 0,3+)
try:
results = video.search(
query="personne écrivant sur un tableau blanc",
search_type=SearchType.semantic,
index_type=IndexType.scene,
scene_index_id=scene_index_id,
score_threshold=0.3,
)
shots = results.get_shots()
stream_url = results.compile()
except InvalidRequestError as e:
if "No results found" in str(e):
shots = []
else:
raise
Édition de timeline
Important : Validez toujours les horodatages avant de construire une timeline :
startdoit être >= 0 (les valeurs négatives sont acceptées silencieusement mais produisent une sortie cassée)startdoit être <endenddoit être <=video.length
from videodb.timeline import Timeline
from videodb.asset import VideoAsset, TextAsset, TextStyle
timeline = Timeline(conn)
timeline.add_inline(VideoAsset(asset_id=video.id, start=10, end=30))
timeline.add_overlay(0, TextAsset(text="La Fin", duration=3, style=TextStyle(fontsize=36)))
stream_url = timeline.generate_stream()
Transcodage vidéo (changement de résolution/qualité)
from videodb import TranscodeMode, VideoConfig, AudioConfig
# Changement de résolution, qualité ou rapport hauteur/largeur côté serveur
job_id = conn.transcode(
source="https://example.com/video.mp4",
callback_url="https://example.com/webhook",
mode=TranscodeMode.economy,
video_config=VideoConfig(resolution=720, quality=23, aspect_ratio="16:9"),
audio_config=AudioConfig(mute=False),
)
Recadrage du rapport hauteur/largeur (pour les réseaux sociaux)
Attention : reframe() est une opération serveur lente. Pour les vidéos longues, cela peut prendre
plusieurs minutes et peut expirer. Meilleures pratiques :
- Limitez toujours à un court segment avec
start/endquand c'est possible - Pour les vidéos en longueur totale, utilisez
callback_urlpour un traitement asynchrone - Rognez d'abord la vidéo sur une
Timeline, puis recadrez le résultat plus court
from videodb import ReframeMode
# Privilégiez toujours le recadrage d'un court segment :
reframed = video.reframe(start=0, end=60, target="vertical", mode=ReframeMode.smart)
# Recadrage asynchrone pour les vidéos en longueur totale (retourne None, résultat via webhook) :
video.reframe(target="vertical", callback_url="https://example.com/webhook")
# Préréglages : "vertical" (9:16), "square" (1:1), "landscape" (16:9)
reframed = video.reframe(start=0, end=60, target="square")
# Dimensions personnalisées
reframed = video.reframe(start=0, end=60, target={"width": 1280, "height": 720})
Média génératif
image = coll.generate_image(
prompt="un coucher de soleil sur des montagnes",
aspect_ratio="16:9",
)
Gestion des erreurs
from videodb.exceptions import AuthenticationError, InvalidRequestError
try:
conn = videodb.connect()
except AuthenticationError:
print("Vérifiez votre VIDEO_DB_API_KEY")
try:
video = coll.upload(url="https://example.com/video.mp4")
except InvalidRequestError as e:
print(f"Le téléchargement a échoué : {e}")
Pièges courants
| Scénario | Message d'erreur | Solution |
|---|---|---|
| Indexer une vidéo déjà indexée | Index de mots parlés pour la vidéo existe déjà | Utilisez video.index_spoken_words(force=True) pour ignorer si déjà indexée |
| Index de scène existe déjà | Index de scène avec l'id XXXX existe déjà | Extrayez le scene_index_id existant de l'erreur avec re.search(r"id\s+([a-f0-9]+)", str(e)) |
| La recherche ne trouve aucune correspondance | InvalidRequestError: Aucun résultat trouvé | Attrapez l'exception et traitez comme résultats vides (shots = []) |
| Recadrage expire | Bloque indéfiniment sur les vidéos longues | Utilisez start/end pour limiter le segment, ou passez callback_url pour asynchrone |
| Horodatages négatifs sur la Timeline | Produit silencieusement un flux cassé | Validez toujours start >= 0 avant de créer VideoAsset |
generate_video() / create_collection() échoue | Opération non autorisée ou limite maximale | Fonctionnalités limitées par forfait — informez l'utilisateur des limites du forfait |
Exemples
Invites canoniques
- "Démarre la capture de bureau et alerte quand un champ de mot de passe apparaît."
- "Enregistre ma session et produit un résumé exploitable quand elle se termine."
- "Ingère ce fichier et retourne un lien de flux jouable."
- "Indexe ce dossier et trouve chaque scène avec des personnes, retourne les horodatages."
- "Génère des sous-titres, incruste-les et ajoute une musique de fond légère."
- "Connecte cette URL RTSP et alerte quand une personne entre dans la zone."
Enregistrement d'écran (capture de bureau)
Utilisez ws_listener.py pour capturer les événements WebSocket pendant les sessions d'enregistrement. La capture de bureau prend en charge macOS uniquement.
Démarrage rapide
- Choisissez le répertoire d'état :
STATE_DIR="${VIDEODB_EVENTS_DIR:-$HOME/.local/state/videodb}" - Démarrez l'écouteur :
VIDEODB_EVENTS_DIR="$STATE_DIR" python scripts/ws_listener.py --clear "$STATE_DIR" & - Obtenez l'ID WebSocket :
cat "$STATE_DIR/videodb_ws_id" - Exécutez le code de capture (voir reference/capture.md pour le workflow complet)
- Événements écrits dans :
$STATE_DIR/videodb_events.jsonl
Utilisez --clear chaque fois que vous démarrez une nouvelle session de capture pour que les événements de transcription et visuels obsolètes ne s'infiltrent pas dans la nouvelle session.
Interroger les événements
import json
import os
import time
from pathlib import Path
events_dir = Path(os.environ.get("VIDEODB_EVENTS_DIR", Path.home() / ".local" / "state" / "videodb"))
events_file = events_dir / "videodb_events.jsonl"
events = []
if events_file.exists():
with events_file.open(encoding="utf-8") as handle:
for line in handle:
try:
events.append(json.loads(line))
except json.JSONDecodeError:
continue
transcripts = [e["data"]["text"] for e in events if e.get("channel") == "transcript"]
cutoff = time.time() - 300
recent_visual = [
e for e in events
if e.get("channel") == "visual_index" and e["unix_ts"] > cutoff
]
Documentation supplémentaire
La documentation de référence se trouve dans le répertoire reference/ adjacent à ce fichier SKILL.md. Utilisez l'outil Glob pour le localiser si nécessaire.
- reference/api-reference.md - Référence complète de l'API Python SDK VideoDB
- reference/search.md - Guide approfondi de la recherche vidéo (mots parlés et basée sur les scènes)
- reference/editor.md - Édition de timeline, actifs et composition
- reference/streaming.md - Streaming HLS et lecture instantanée
- reference/generative.md - Génération de médias par IA (images, vidéo, audio)
- reference/rtstream.md - Workflow d'ingestion de flux en direct (RTSP/RTMP)
- reference/rtstream-reference.md - Méthodes SDK RTStream et pipelines IA
- reference/capture.md - Workflow de capture de bureau
- reference/capture-reference.md - SDK de capture et événements WebSocket
- reference/use-cases.md - Modèles et exemples courants de traitement vidéo
N'utilisez pas ffmpeg, moviepy, ou d'outils d'encodage locaux quand VideoDB prend en charge l'opération. Tout ce qui suit est géré côté serveur par VideoDB : rognage, combinaison de clips, superposition audio ou musicale, ajout de sous-titres, superpositions texte/image, transcodage, changements de résolution, conversion de rapport hauteur/largeur, redimensionnement pour les exigences de plateforme, transcription et génération de médias. Ne recourez aux outils locaux que pour les opérations listées sous Limitations dans reference/editor.md (transitions, changements de vitesse, recadrage/zoom, étalonnage des couleurs, mixage de volume).
Quand utiliser quoi
| Problème | Solution VideoDB |
|---|---|
| La plateforme rejette le rapport hauteur/largeur ou la résolution de la vidéo | video.reframe() ou conn.transcode() avec VideoConfig |
| Besoin de redimensionner la vidéo pour Twitter/Instagram/TikTok | video.reframe(target="vertical") ou target="square" |
| Besoin de changer la résolution (ex. 1080p → 720p) | conn.transcode() avec VideoConfig(resolution=720) |
| Besoin de superposer de l'audio/de la musique sur une vidéo | AudioAsset sur une Timeline |
| Besoin d'ajouter des sous-titres | video.add_subtitle() ou CaptionAsset |
| Besoin de combiner/rogner des clips | VideoAsset sur une Timeline |
| Besoin de générer voix off, musique ou effets sonores | coll.generate_voice(), generate_music(), generate_sound_effect() |
Provenance
Les documents de référence pour cette compétence sont stockés localement sous skills/videodb/reference/.
Utilisez les copies locales ci-dessus plutôt que de suivre des liens vers des dépôts externes à l'exécution.