VideoDB 스킬
비디오, 라이브 스트림 및 데스크톱 세션을 위한 인식 + 메모리 + 작업.
사용 시기
데스크톱 인식
- 데스크톱 세션을 시작/중지하여 화면, 마이크 및 시스템 오디오를 캡처합니다.
- 라이브 컨텍스트를 스트리밍하고 에피소드 세션 메모리를 저장합니다.
- 화면에서 말한 내용과 발생하는 상황에 대해 실시간 알림/트리거를 실행합니다.
- 세션 요약, 검색 가능한 타임라인 및 재생 가능한 증거 링크를 생성합니다.
비디오 수집 + 스트림
- 파일 또는 URL을 수집하고 재생 가능한 웹 스트림 링크를 반환합니다.
- 트랜스코딩/정규화: 코덱, 비트레이트, FPS, 해상도, 종횡비
인덱스 + 검색 (타임스탬프 + 증거)
- 시각적, 음성 및 키워드 인덱스를 구축합니다.
- 타임스탬프 및 재생 가능한 증거와 함께 정확한 순간을 검색하고 반환합니다.
- 검색 결과에서 클립을 자동 생성합니다.
타임라인 편집 + 생성
- 자막: 생성, 번역, 굽기
- 오버레이: 텍스트/이미지/브랜딩, 모션 캡션
- 오디오: 배경 음악, 음성 해설, 더빙
- 타임라인 작업을 통한 프로그래밍 방식 합성 및 내보내기
라이브 스트림(RTSP) + 모니터링
- RTSP/라이브 피드 연결
- 실시간 시각적 및 음성 인식을 실행하고 모니터링 워크플로를 위한 이벤트/알림을 내보냅니다.
작동 방식
일반적인 입력
- 로컬 파일 경로, 공용 URL 또는 RTSP URL
- 데스크톱 캡처 요청: 세션 시작 / 중지 / 요약
- 원하는 작업: 이해를 위한 컨텍스트 가져오기, 트랜스코딩 사양, 인덱스 사양, 검색 쿼리, 클립 범위, 타임라인 편집, 알림 규칙
일반적인 출력
- 스트림 URL
- 타임스탬프 및 증거 링크가 포함된 검색 결과
- 생성된 에셋: 자막, 오디오, 이미지, 클립
- 라이브 스트림을 위한 이벤트/알림 페이로드
- 데스크톱 세션 요약 및 메모리 항목
Python 코드 실행
VideoDB 코드를 실행하기 전에 프로젝트 디렉터리로 변경하고 환경 변수를 로드합니다.
from dotenv import load_dotenv
load_dotenv(".env")
import videodb
conn = videodb.connect()
이렇게 하면 다음 위치에서 VIDEO_DB_API_KEY를 읽습니다.
- 환경(이미 내보낸 경우)
- 현재 디렉터리에 있는 프로젝트의
.env파일
키가 누락된 경우 videodb.connect()에서 자동으로 AuthenticationError를 발생시킵니다.
짧은 인라인 명령으로 충분할 때는 스크립트 파일을 작성하지 마십시오.
인라인 Python(python -c "...")을 작성할 때는 항상 적절한 형식의 코드를 사용하십시오. 세미콜론을 사용하여 명령문을 구분하고 가독성을 유지하십시오. 약 3개 이상의 명령문이 필요한 경우 대신 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
설정
사용자가 "videodb 설정" 또는 이와 유사한 내용을 요청하는 경우:
1. SDK 설치
pip install "videodb[capture]" python-dotenv
Linux에서 videodb[capture]가 실패하면 캡처 확장 없이 설치합니다.
pip install videodb python-dotenv
2. API 키 구성
사용자는 다음 방법 중 하나를 사용하여 VIDEO_DB_API_KEY를 설정해야 합니다.
- 터미널에서 내보내기(Claude 시작 전):
export VIDEO_DB_API_KEY=your-key - 프로젝트
.env파일: 프로젝트의.env파일에VIDEO_DB_API_KEY=your-key저장
console.videodb.io에서 무료 API 키를 받으십시오(무료 업로드 50회, 신용 카드 필요 없음).
API 키를 직접 읽거나, 쓰거나, 처리하지 마십시오. 항상 사용자가 설정하도록 하십시오.
빠른 참조
미디어 업로드
# URL
video = coll.upload(url="https://example.com/video.mp4")
# YouTube
video = coll.upload(url="https://www.youtube.com/watch?v=VIDEO_ID")
# 로컬 파일
video = coll.upload(file_path="/path/to/video.mp4")
자막 + 자막
# force=True는 비디오가 이미 인덱싱된 경우 오류를 건너뜁니다.
video.index_spoken_words(force=True)
text = video.get_transcript_text()
stream_url = video.add_subtitle()
비디오 내 검색
from videodb.exceptions import InvalidRequestError
video.index_spoken_words(force=True)
# search()는 결과가 없으면 InvalidRequestError를 발생시킵니다.
# 항상 try/except로 감싸고 "결과 없음"을 빈 결과로 처리하십시오.
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
장면 검색
import re
from videodb import SearchType, IndexType, SceneExtractionType
from videodb.exceptions import InvalidRequestError
# index_scenes()에는 force 매개변수가 없습니다. 장면 인덱스가 이미 존재하면 오류를 발생시킵니다.
# 오류에서 기존 인덱스 ID를 추출합니다.
try:
scene_index_id = video.index_scenes(
extraction_type=SceneExtractionType.shot_based,
prompt="Describe the visual content in this scene.",
)
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
# score_threshold를 사용하여 관련 없는 노이즈를 필터링합니다(권장: 0.3+).
try:
results = video.search(
query="person writing on a whiteboard",
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
타임라인 편집
중요: 타임라인을 구축하기 전에 항상 타임스탬프의 유효성을 검사하십시오.
start는 >= 0이어야 합니다(음수 값은 자동으로 허용되지만 깨진 출력을 생성합니다).start는end보다 작아야 합니다.end는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="The End", duration=3, style=TextStyle(fontsize=36)))
stream_url = timeline.generate_stream()
비디오 트랜스코딩(해상도/품질 변경)
from videodb import TranscodeMode, VideoConfig, AudioConfig
# 서버 측에서 해상도, 품질 또는 종횡비를 변경합니다.
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),
)
종횡비 재조정(소셜 플랫폼용)
경고: reframe()은 느린 서버 측 작업입니다. 긴 비디오의 경우 몇 분이 걸리고 시간이 초과될 수 있습니다.
최선의 방법:
- 가능할 때마다 항상
start/end를 사용하여 짧은 세그먼트로 제한하십시오. - 전체 길이 비디오의 경우
callback_url을 사용하여 비동기 처리를 수행하십시오. - 먼저
Timeline에서 비디오를 자른 다음, 더 짧은 결과를 리프레임하십시오.
from videodb import ReframeMode
# 항상 짧은 세그먼트를 리프레임하는 것을 선호합니다.
reframed = video.reframe(start=0, end=60, target="vertical", mode=ReframeMode.smart)
# 전체 길이 비디오를 위한 비동기 리프레임(None 반환, 결과는 웹훅을 통해 전달됨).
video.reframe(target="vertical", callback_url="https://example.com/webhook")
# 프리셋: "vertical"(9:16), "square"(1:1), "landscape"(16:9)
reframed = video.reframe(start=0, end=60, target="square")
# 사용자 정의 크기
reframed = video.reframe(start=0, end=60, target={"width": 1280, "height": 720})
생성형 미디어
image = coll.generate_image(
prompt="산 위의 일몰",
aspect_ratio="16:9",
)
오류 처리
from videodb.exceptions import AuthenticationError, InvalidRequestError
try:
conn = videodb.connect()
except AuthenticationError:
print("VIDEO_DB_API_KEY를 확인하십시오.")
try:
video = coll.upload(url="https://example.com/video.mp4")
except InvalidRequestError as e:
print(f"업로드 실패: {e}")
일반적인 문제점
| 시나리오 | 오류 메시지 | 해결책 |
|---|---|---|
| 이미 인덱싱된 비디오 인덱싱 | Spoken word index for video already exists | force=True와 함께 video.index_spoken_words(force=True) 사용하여 이미 인덱싱된 경우 건너뜁니다. |
| 장면 인덱스가 이미 존재함 | Scene index with id XXXX already exists | re.search(r"id\s+([a-f0-9]+)", str(e))로 오류에서 기존 scene_index_id 추출 |
| 검색 결과 없음 | InvalidRequestError: No results found | 예외를 포착하고 빈 결과로 처리(shots = []) |
| 리프레임 시간 초과 | 긴 비디오에서 무기한 차단됨 | start/end로 세그먼트를 제한하거나 callback_url을 전달하여 비동기 처리 |
| 타임라인의 음수 타임스탬프 | 자동으로 깨진 스트림 생성 | VideoAsset 생성 전에 항상 start >= 0 확인 |
generate_video() / create_collection() 실패 | Operation not allowed 또는 maximum limit | 요금제에 따른 기능임을 사용자에게 알리고 요금제 제한에 대해 안내 |
예제
표준 프롬프트
- "데스크톱 캡처를 시작하고 비밀번호 필드가 나타나면 알림을 보내줘."
- "내 세션을 기록하고 종료 시 실행 가능한 요약을 생성해줘."
- "이 파일을 수집하고 재생 가능한 스트림 링크를 반환해줘."
- "이 폴더를 인덱싱하고 사람이 있는 모든 장면을 찾아 타임스탬프를 반환해줘."
- "자막을 생성하고 굽고 가벼운 배경 음악을 추가해줘."
- "이 RTSP URL을 연결하고 사람이 구역에 들어오면 알림을 보내줘."
화면 녹화(데스크톱 캡처)
녹화 세션 중 WebSocket 이벤트를 캡처하려면 ws_listener.py를 사용하십시오. 데스크톱 캡처는 macOS만 지원합니다.
빠른 시작
- 상태 디렉터리 선택:
STATE_DIR="${VIDEODB_EVENTS_DIR:-$HOME/.local/state/videodb}" - 리스너 시작:
VIDEODB_EVENTS_DIR="$STATE_DIR" python scripts/ws_listener.py --clear "$STATE_DIR" & - WebSocket ID 가져오기:
cat "$STATE_DIR/videodb_ws_id" - 캡처 코드 실행(전체 워크플로는 reference/capture.md 참조)
- 이벤트 작성 위치:
$STATE_DIR/videodb_events.jsonl
새로운 캡처 실행을 시작할 때마다 --clear를 사용하여 오래된 기록 및 시각적 이벤트가 새 세션으로 유입되는 것을 방지하십시오.
이벤트 쿼리
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
]
추가 문서
참조 문서는 이 SKILL.md 파일과 동일한 디렉터리의 reference/ 디렉터리에 있습니다. 필요한 경우 Glob 도구를 사용하여 찾으십시오.
- reference/api-reference.md - 전체 VideoDB Python SDK API 참조
- reference/search.md - 비디오 검색 심층 가이드(음성 및 장면 기반)
- reference/editor.md - 타임라인 편집, 에셋 및 구성
- reference/streaming.md - HLS 스트리밍 및 즉시 재생
- reference/generative.md - AI 기반 미디어 생성(이미지, 비디오, 오디오)
- reference/rtstream.md - 라이브 스트림 수집 워크플로(RTSP/RTMP)
- reference/rtstream-reference.md - RTStream SDK 메서드 및 AI 파이프라인
- reference/capture.md - 데스크톱 캡처 워크플로
- reference/capture-reference.md - 캡처 SDK 및 WebSocket 이벤트
- reference/use-cases.md - 일반적인 비디오 처리 패턴 및 예제
VideoDB가 작업을 지원하는 경우 ffmpeg, moviepy 또는 로컬 인코딩 도구를 사용하지 마십시오. 다음은 모두 VideoDB에서 서버 측에서 처리합니다. 트리밍, 클립 결합, 오디오/음악 오버레이, 자막 추가, 텍스트/이미지 오버레이, 트랜스코딩, 해상도 변경, 종횡비 변환, 플랫폼 요구 사항에 맞는 크기 조정, 전사 및 미디어 생성. 로컬 도구는 reference/editor.md의 제한 사항(전환, 속도 변경, 자르기/확대, 색상 보정, 볼륨 혼합)에 설명된 작업에만 사용하십시오.
무엇을 사용해야 할까?
| 문제 | VideoDB 솔루션 |
|---|---|
| 플랫폼이 비디오 종횡비 또는 해상도를 거부함 | video.reframe() 또는 VideoConfig와 함께 conn.transcode() |
| Twitter/Instagram/TikTok용 비디오 크기 조정 필요 | video.reframe(target="vertical") 또는 target="square" |
| 해상도 변경 필요(예: 1080p → 720p) | VideoConfig(resolution=720)와 함께 conn.transcode() |
| 비디오에 오디오/음악 오버레이 필요 | Timeline의 AudioAsset |
| 자막 추가 필요 | video.add_subtitle() 또는 CaptionAsset |
| 클립 결합/자르기 필요 | Timeline의 VideoAsset |
| 음성 해설, 음악 또는 SFX 생성 필요 | coll.generate_voice(), generate_music(), generate_sound_effect() |
출처
이 스킬의 참조 자료는 skills/videodb/reference/ 아래에 로컬로 제공됩니다.
런타임에 외부 저장소 링크를 따르는 대신 위의 로컬 복사본을 사용하십시오.