빠른 시작
이 안내를 따라 하면 공개 영상 URL 하나로 검색 가능한 장면 데이터를 만들 수 있습니다. 대시보드의 API Keys 탭에서 발급한 API 키가 필요합니다. 인증을 참고하세요.
아래 예시에서 쓸 수 있도록 한 번 export 해 둡니다.
export VUF_API_KEY="vuf_live_xxxxxxxx.yyyyyyyy"
- 영상 제출
POST /api/v1/videos는 공개적으로 가져올 수 있는http/httpsURL과 선택 항목인title을 받습니다. 즉시202 Accepted를 반환하며, 색인 생성은 장면 감지, 캡션 생성, 임베딩, 검수 순서로 비동기 처리됩니다.- cURL
- Python
curl -X POST https://video.pyler.ai/api/v1/videos \-H "Authorization: Bearer $VUF_API_KEY" \-H "Content-Type: application/json" \-d '{"url": "https://example.com/clip.mp4", "title": "demo clip"}'import osimport requestsBASE = "https://video.pyler.ai/api/v1"HEADERS = {"Authorization": f"Bearer {os.environ['VUF_API_KEY']}"}r = requests.post(f"{BASE}/videos",headers=HEADERS,json={"url": "https://example.com/clip.mp4", "title": "demo clip"},)r.raise_for_status()submitted = r.json()video_id, job_id = submitted["video_id"], submitted["job_id"]응답:
{"video_id": "3f2c9d1e-...","job_id": "a81b7c44-...","created": true}같은 URL이 이미 색인 중이면
created는false입니다. 이때는 중복 파이프라인을 만들지 않고 기존video_id와job_id를 돌려주며, 상태 코드는 그대로202입니다.POST /api/v1/videos를 참고하세요. - 작업 폴링
GET /api/v1/jobs/{job_id}는 파이프라인 상태를 반환합니다.status는pending→running→done또는failed순으로 바뀝니다. 실행 중에는done_scenes/total_scenes로 진행률을 알 수 있습니다.- cURL
- Python
curl https://video.pyler.ai/api/v1/jobs/$JOB_ID \-H "Authorization: Bearer $VUF_API_KEY"import timewhile True:job = requests.get(f"{BASE}/jobs/{job_id}", headers=HEADERS).json()print(job["status"], job.get("done_scenes", 0), "/", job.get("total_scenes", 0))if job["status"] == "done":breakif job["status"] == "failed":raise RuntimeError(f"indexing failed: {job.get('reason_code')} {job.get('error')}")time.sleep(5)실행 중 응답:
{"id": "a81b7c44-...","video_id": "3f2c9d1e-...","status": "running","total_scenes": 42,"done_scenes": 18,"error": null,"reason_code": null,"reason": null,"started_at": "2026-06-04T10:23:01Z","completed_at": null}failed이면 안정적인 원인 값인reason_code로 분기하세요.error에는 원문 메시지가 담깁니다.GET /api/v1/jobs/{job_id}를 참고하세요. - 장면 조회와 검색
작업이
done이 되면GET /api/v1/videos/{video_id}/scenes로 영상의 장면을 페이지 단위로 조회합니다. 각 페이지는ScenesPage이며items,offset,limit(1–200, 기본값 50),total로 구성됩니다.- cURL
- Python
curl "https://video.pyler.ai/api/v1/videos/$VIDEO_ID/scenes?offset=0&limit=50" \-H "Authorization: Bearer $VUF_API_KEY"page = requests.get(f"{BASE}/videos/{video_id}/scenes",headers=HEADERS,params={"offset": 0, "limit": 50},).json()for scene in page["items"]:print(scene["scene_index"], scene["start_ms"], scene["end_ms"], scene.get("caption"))각 항목은
SceneLite입니다.{"items": [{"id": "c0a4e2f7-...","video_id": "3f2c9d1e-...","scene_index": 0,"start_ms": 0,"end_ms": 4120,"caption": "A child in a red jacket runs across a snowy yard.","transcript": null,"text_on_screen": [],"valence": 4,"arousal": 3,"music_mood": "playful","audio_events": ["laughter"],"garm_categories": [],"brands": [],"product_categories_visible": [],"people": [],"locations": ["backyard"],"action": ["running"],"human_activity": ["playing"],"weather": "snow","keyframe_url": "https://...","clip_url": "https://..."}],"offset": 0,"limit": 50,"total": 42}경고알 수 없는
video_id는404가 아니라 빈 페이지(total: 0)를 반환합니다. "없는 영상"과 "장면이 없는 영상"을 구분해야 한다면GET /api/v1/videos/{video_id}를 사용하세요.이제 전체 영상을 검색합니다.
POST /api/v1/search는 자연어query,modality(caption,transcript,omni,both,all),k(1–100, 기본값 20)를 받습니다.video_id를 추가하면 영상 하나의 장면으로 검색 범위를 좁힙니다.- cURL
- Python
curl -X POST https://video.pyler.ai/api/v1/search \-H "Authorization: Bearer $VUF_API_KEY" \-H "Content-Type: application/json" \-d '{"query": "child playing in snow", "modality": "both", "k": 10}'results = requests.post(f"{BASE}/search",headers=HEADERS,json={"query": "child playing in snow", "modality": "both", "k": 10},).json()for match in results["caption"]:print(match["score"], match["video"]["id"], match["video"]["title"])for hit in match["scenes"]:s = hit["scene"]print(" ", hit["score"], s["start_ms"], s["end_ms"], s.get("caption"))응답은 일치한 장면을 영상별로 묶고, 모달리티마다 목록 하나를 둡니다.
modality: "both"이면caption과omni목록이 채워지고transcript는 비어 있습니다.{"caption": [{"score": 0.81,"video": {"id": "3f2c9d1e-...","title": "demo clip","duration_ms": 183000},"scenes": [{"score": 0.79,"scene": {"id": "c0a4e2f7-...","video_id": "3f2c9d1e-...","scene_index": 0,"start_ms": 0,"end_ms": 4120,"caption": "A child in a red jacket runs across a snowy yard.","keyframe_url": "https://...","clip_url": "https://..."}}]}],"transcript": [],"omni": []}GET /api/v1/videos/{video_id}/scenes와POST /api/v1/search를 참고하세요.