본문으로 건너뛰기

빠른 시작

이 안내를 따라 하면 공개 영상 URL 하나로 검색 가능한 장면 데이터를 만들 수 있습니다. 대시보드의 API Keys 탭에서 발급한 API 키가 필요합니다. 인증을 참고하세요.

아래 예시에서 쓸 수 있도록 한 번 export 해 둡니다.

export VUF_API_KEY="vuf_live_xxxxxxxx.yyyyyyyy"
  1. 영상 제출

    POST /api/v1/videos는 공개적으로 가져올 수 있는 http/https URL과 선택 항목인 title을 받습니다. 즉시 202 Accepted를 반환하며, 색인 생성은 장면 감지, 캡션 생성, 임베딩, 검수 순서로 비동기 처리됩니다.

    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"}'

    응답:

    {
    "video_id": "3f2c9d1e-...",
    "job_id": "a81b7c44-...",
    "created": true
    }

    같은 URL이 이미 색인 중이면 created는 false입니다. 이때는 중복 파이프라인을 만들지 않고 기존 video_id와 job_id를 돌려주며, 상태 코드는 그대로 202입니다.

    POST /api/v1/videos를 참고하세요.

  2. 작업 폴링

    GET /api/v1/jobs/{job_id}는 파이프라인 상태를 반환합니다. status는 pending → running → done 또는 failed 순으로 바뀝니다. 실행 중에는 done_scenes / total_scenes로 진행률을 알 수 있습니다.

    curl https://video.pyler.ai/api/v1/jobs/$JOB_ID \
    -H "Authorization: Bearer $VUF_API_KEY"

    실행 중 응답:

    {
    "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}를 참고하세요.

  3. 장면 조회와 검색

    작업이 done이 되면 GET /api/v1/videos/{video_id}/scenes로 영상의 장면을 페이지 단위로 조회합니다. 각 페이지는 ScenesPage이며 items, offset, limit(1–200, 기본값 50), total로 구성됩니다.

    curl "https://video.pyler.ai/api/v1/videos/$VIDEO_ID/scenes?offset=0&limit=50" \
    -H "Authorization: Bearer $VUF_API_KEY"

    각 항목은 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 -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}'

    응답은 일치한 장면을 영상별로 묶고, 모달리티마다 목록 하나를 둡니다. 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를 참고하세요.

다음 단계​