docs: tighten videodb listener guidance

This commit is contained in:
Affaan Mustafa
2026-03-10 21:22:35 -07:00
parent db2bf16427
commit 70449a1cd7
4 changed files with 46 additions and 14 deletions

View File

@@ -10,7 +10,7 @@ argument-hint: "[task description]"
**Perception + memory + actions for video, live streams, and desktop sessions.** **Perception + memory + actions for video, live streams, and desktop sessions.**
## When to Use ## When to use
### Desktop Perception ### Desktop Perception
- Start/stop a **desktop session** capturing **screen, mic, and system audio** - Start/stop a **desktop session** capturing **screen, mic, and system audio**
@@ -37,7 +37,7 @@ argument-hint: "[task description]"
- Connect **RTSP/live feeds** - Connect **RTSP/live feeds**
- Run **real-time visual and spoken understanding** and emit **events/alerts** for monitoring workflows - Run **real-time visual and spoken understanding** and emit **events/alerts** for monitoring workflows
## How It Works ## How it works
### Common inputs ### Common inputs
- Local **file path**, public **URL**, or **RTSP URL** - Local **file path**, public **URL**, or **RTSP URL**

View File

@@ -383,8 +383,13 @@ For RTStream methods (indexing, transcription, alerts, batch config), see [rtstr
│ active │ ──> Start AI pipelines │ active │ ──> Start AI pipelines
└───────┬──────────────┐ └───────┬──────────────┐
│ │ │ │
└──────────────┐ v
client.stop_capture() │ unrecoverable capture error ┌───────────────┐ WebSocket: capture_session.failed
│ │ failed │ ──> Inspect error payload and retry setup
│ └───────────────┘
│ unrecoverable capture error
│ client.stop_capture()
v v
┌───────────────┐ WebSocket: capture_session.stopping ┌───────────────┐ WebSocket: capture_session.stopping
│ stopping │ ──> Finalize streams │ stopping │ ──> Finalize streams
@@ -399,11 +404,4 @@ For RTStream methods (indexing, transcription, alerts, batch config), see [rtstr
┌───────────────┐ WebSocket: capture_session.exported ┌───────────────┐ WebSocket: capture_session.exported
│ exported │ ──> Access video_id, stream_url, player_url │ exported │ ──> Access video_id, stream_url, player_url
└───────────────┘ └───────────────┘
unrecoverable capture error
v
┌───────────────┐ WebSocket: capture_session.failed
│ failed │ ──> Inspect error payload and retry setup
└───────────────┘
``` ```

View File

@@ -165,7 +165,7 @@ Combine scene extraction with text generation:
from videodb import SceneExtractionType from videodb import SceneExtractionType
# First index scenes # First index scenes
video.index_scenes( scenes = video.index_scenes(
extraction_type=SceneExtractionType.time_based, extraction_type=SceneExtractionType.time_based,
extraction_config={"time": 10}, extraction_config={"time": 10},
prompt="Describe the visual content in this scene.", prompt="Describe the visual content in this scene.",
@@ -173,11 +173,21 @@ video.index_scenes(
# Get transcript for spoken context # Get transcript for spoken context
transcript_text = video.get_transcript_text() transcript_text = video.get_transcript_text()
scene_descriptions = []
for scene in scenes:
if isinstance(scene, dict):
description = scene.get("description") or scene.get("summary")
else:
description = getattr(scene, "description", None) or getattr(scene, "summary", None)
scene_descriptions.append(description or str(scene))
scenes_text = "\n".join(scene_descriptions)
# Analyze with collection LLM # Analyze with collection LLM
result = coll.generate_text( result = coll.generate_text(
prompt=( prompt=(
f"Given this video transcript:\n{transcript_text}\n\n" f"Given this video transcript:\n{transcript_text}\n\n"
f"And these visual scene descriptions:\n{scenes_text}\n\n"
"Based on the spoken and visual content, describe the main topics covered." "Based on the spoken and visual content, describe the main topics covered."
), ),
model_name="pro", model_name="pro",

View File

@@ -39,6 +39,7 @@ from dotenv import load_dotenv
load_dotenv() load_dotenv()
import videodb import videodb
from videodb.exceptions import AuthenticationError
# Retry config # Retry config
MAX_RETRIES = 10 MAX_RETRIES = 10
@@ -82,6 +83,8 @@ def parse_args() -> tuple[bool, Path]:
for arg in args: for arg in args:
if arg == "--clear": if arg == "--clear":
clear = True clear = True
elif arg.startswith("-"):
raise SystemExit(f"Unknown flag: {arg}")
elif not arg.startswith("-"): elif not arg.startswith("-"):
output_dir = arg output_dir = arg
@@ -127,6 +130,17 @@ def cleanup_pid():
LOGGER.debug("Failed to remove PID file %s: %s", PID_FILE, exc) LOGGER.debug("Failed to remove PID file %s: %s", PID_FILE, exc)
def is_fatal_error(exc: Exception) -> bool:
"""Return True when retrying would hide a permanent configuration error."""
if isinstance(exc, (AuthenticationError, PermissionError)):
return True
status = getattr(exc, "status_code", None)
if status in {401, 403}:
return True
message = str(exc).lower()
return "401" in message or "403" in message or "auth" in message
async def listen_with_retry(): async def listen_with_retry():
"""Main listen loop with auto-reconnect and exponential backoff.""" """Main listen loop with auto-reconnect and exponential backoff."""
global _first_connection global _first_connection
@@ -143,7 +157,12 @@ async def listen_with_retry():
except asyncio.CancelledError: except asyncio.CancelledError:
log("Shutdown requested") log("Shutdown requested")
raise raise
except RETRYABLE_ERRORS as e: except Exception as e:
if is_fatal_error(e):
log(f"Fatal configuration error: {e}")
raise
if not isinstance(e, RETRYABLE_ERRORS):
raise
retry_count += 1 retry_count += 1
log(f"Connection error: {e}") log(f"Connection error: {e}")
@@ -182,7 +201,12 @@ async def listen_with_retry():
except asyncio.CancelledError: except asyncio.CancelledError:
log("Shutdown requested") log("Shutdown requested")
raise raise
except RETRYABLE_ERRORS as e: except Exception as e:
if is_fatal_error(e):
log(f"Fatal configuration error: {e}")
raise
if not isinstance(e, RETRYABLE_ERRORS):
raise
retry_count += 1 retry_count += 1
log(f"Connection error: {e}") log(f"Connection error: {e}")