ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • t2v, i2v, flf2v, omni_reference — Seedance 2.0 fast 약어가 가리키는 것과 조합 매트릭스
    IT 2026. 5. 22. 21:00
    t2v, i2v, flf2v, omni_reference — Seedance 2.0 fast 약어가 가리키는 것과 조합 매트릭스

    📡 이 글은 BytePlus Seedance 2.0 fast 모델을 API로 직접 호출해서 영상을 만드는 사용자를 위한 글입니다. content array의 role을 직접 짜는 시나리오는 API 사용자에게만 해당됩니다. ModelArk 콘솔은 "Image-to-Video", "Reference-to-Video" 같은 UI 라벨로 task_type를 노출하므로 약어를 풀이할 일이 없습니다.

    약어가 너무 많다

    BytePlus Seedance API의 docs를 처음 펼치면 익숙하지 않은 약어들이 떠다닙니다. t2v, i2v, flf2v, omni_reference. 그리고 docs 어디엔가 흩어져 있는 generate_audio: true 같은 옵션. 어떤 건 직관적이고, 어떤 건 풀어 봐도 의미가 잘 안 잡힙니다. 더 큰 문제는 이 task_type들이 서로 자유롭게 섞이지 않는다는 점입니다. 어떤 task_type는 어떤 모델 버전에서만 동작하고, 어떤 조합은 입력 자체를 받지 않습니다.

    저는 이걸 docs로만 읽고 한 번에 정리하지 못해서, 결국 몇 번의 호출이 거절되고 나서야 매트릭스를 손으로 그려 보고 이해했습니다. 다행히 거절 호출은 토큰을 안 먹으니 비용 0이었지만, 한 호출당 polling 90초가 모두 시간 비용으로 빠져나갔습니다. 이 글은 그때 만든 약어 풀이와 매트릭스를 정리한 것입니다.

    약어 풀이 — 공식 task_type 이름으로

    BytePlus Seedance 2.0 시리즈가 docs에서 공식적으로 노출하는 task_type은 4개입니다. 우리가 부르는 약어와 공식 이름의 매핑을 먼저 정리합니다.

    약어 (관행) 공식 task_type 의미
    t2v text_to_video 이미지 입력 없이 prompt 텍스트만으로 영상 생성
    i2v image_to_video 사진 1장을 시작 프레임(first_frame)으로 두고 모델이 그 뒤 motion 생성
    flf2v first_last_frames 첫 프레임 + 끝 프레임 2장 → 그 사이를 보간하는 영상 생성
    omni (구버전에선 r2v) omni_reference 사용자가 업로드한 이미지·비디오·오디오 N개를 reference로 받아, 그 정체성·외형을 유지하면서 prompt 기반 영상 생성. 1.x 시절 reference-to-video(r2v)의 확장판으로, image뿐 아니라 video/audio reference까지 받습니다.

    이 글에서는 짧은 약어와 공식 이름을 혼용합니다. 둘 다 익혀 두는 게 docs와 커뮤니티 글을 동시에 읽기 편합니다.

    오디오는 task_type이 아니라 옵션입니다

    오디오 동시 생성은 별도 task_type이 아니라, 위 4개 task_type 위에 얹는 두 가지 요청 파라미터의 조합입니다.

    • generate_audio: true — request body의 불리언 옵션. "오디오도 함께 합성하라"는 스위치.
    • reference_audio role의 content 요소 — 참조 음성/배경음 mp3·wav 한 개를 입력.

    image_to_videoomni_reference task_type을 그대로 부르되, 위 두 가지를 같이 보내면 입 모양까지 phoneme에 맞춰 lip-sync된 영상이 떨어집니다. task_type은 바뀌지 않습니다.

    generate_audio: false + reference_audio는 "원본 오디오 패스스루"가 아닙니다

    자연스러운 오해 한 가지를 짚어두면 — generate_audio: false로 끄고 reference_audio만 같이 보내면 "오디오를 모델이 생성하지 않고 내가 올린 원본 오디오를 그대로 출력에 입혀줄 것"이라고 기대하기 쉽습니다. 실제는 다릅니다.

    • generate_audio: false → 출력 비디오가 무음(silent) 으로 나옵니다. 모델이 audio head를 그냥 비활성화합니다. 원본 오디오를 출력에 자동으로 입혀주는 동작은 없습니다.
    • reference_audio → 모델이 영상을 만들 때 참조하는 conditioning 입력입니다. 거기서 rhythm, beat, mood, lip phoneme, sound 타이밍 같은 신호를 뽑아 비디오 생성에 반영합니다. 즉 reference_audio는 출력 오디오가 아니라 입력입니다.

    이 둘을 합치면 이런 결과가 나옵니다.

    조합 출력 비디오 출력 오디오 트랙 활용
    generate_audio: true + reference_audio 없음 비디오 모델이 새로 합성한 SFX·BGM·음성 일반 native audio 생성
    generate_audio: true + reference_audio 있음 비디오 (lip-sync 움직임이 reference의 phoneme에 맞춰짐) 모델이 reference를 따라 재합성한 오디오 lip-sync 영상 한 번에
    generate_audio: false + reference_audio 없음 비디오 무음 자체 보이스오버를 따로 입힐 작업
    generate_audio: false + reference_audio 있음 비디오 (입 모양은 여전히 reference에 맞게 움직임) 무음 무음 비디오를 받은 뒤 ffmpeg로 원본 mp3를 직접 mux. 모델이 재합성한 음질 손실을 피하고 싶을 때

    마지막 행이 실용적으로 가장 유용합니다. 인물 발화 영상을 만들 때 입 모양은 reference 음성에 맞추되 출력 오디오 트랙은 모델이 재합성한 음질 손실 버전이 아니라 원본 mp3 그대로를 쓰고 싶다면, generate_audio: false + reference_audio로 무음 비디오를 받은 뒤 ffmpeg -c:a copy로 원본을 입힙니다. 결과적으로 "원본 오디오를 쓴다"는 효과는 달성되지만, 그건 모델이 아니라 우리가 mux한 결과입니다.

    "role"이 뭔가요

    위 표와 본문에 자꾸 등장하는 role은 BytePlus API의 정식 용어입니다. 요청의 content 배열에 들어가는 각 요소에 붙는 라벨 필드로, 모델은 이 라벨을 보고 그 입력의 용도를 판단합니다. 챗 API의 role: "user" / role: "assistant"와 같은 구조지만, 영상 생성에서는 이미지·오디오의 역할을 라벨링합니다.

    role 값 의미
    first_frame 영상의 시작 프레임. 모델이 이 이미지에서 출발해 motion을 만듦
    last_frame 영상의 끝 프레임. first와 함께 주면 그 사이를 보간
    reference_image 정체성 참조. 인물·소품의 외형을 새 영상 안에서도 유지하라는 hint
    reference_video 모션/스타일 참조. 짧은 비디오 클립을 reference로 줘서 그 분위기/움직임을 따라가게 함
    reference_audio 오디오 참조. generate_audio: true와 함께 lip-sync·BGM 입력

    "role 조합"이란 한 호출의 content 배열에 어떤 role의 입력을 몇 개씩 넣었는가를 말합니다. Seedance API에는 명시적인 task_type 파라미터가 없습니다. 모델은 이 role 조합을 보고 자동으로 task_type을 추론합니다. 그래서 role을 잘못 붙이면 "모르는 task_type"이 되어 거절됩니다.

    "task_type이 결정된다"는 게 모델이 바뀐다는 뜻인가요

    아닙니다. 모델은 한 개입니다. 우리가 호출하는 모델은 seedance-2.0-fast(또는 seedance-1.5-pro 등) 하나의 멀티모달 모델이고, 이 모델 안에서 무슨 종류의 생성 작업을 할지를 가리키는 라벨이 task_type입니다. role 조합이 text_to_video로 추론되면 같은 모델이 텍스트만으로 영상을 만들고, omni_reference로 추론되면 같은 모델이 reference 이미지를 따라 영상을 만듭니다. 서버 내부에서 어떤 분기 헤드가 활성화되는가의 차이일 뿐, 모델 자체는 바뀌지 않습니다.

    다시 말해 모델 선택 = model 파라미터에서 결정, task_type 결정 = content role 조합에서 자동 추론. 이 둘은 직교입니다.

    task_type 호환 매트릭스

    이걸 한 표로 가지고 있으면 production cycle에서 시도착오가 사라집니다. 아래는 2026년 5월에 검증한 매트릭스입니다.

    표의 칼럼은 모델 버전 순으로 나열했습니다 — seedance-1.0-pro-fast(가장 오래된) → seedance-1.5-proseedance-2.0-fast(가장 최신). 같은 버전 내에서 pro / fast는 품질·비용 티어지만, 버전 번호가 우선입니다. 즉 2.0-fast가 1.5-pro보다 한 세대 위의 모델입니다.

    4개의 공식 task_type × 모델 버전

    task_type (약어) role 조합 1.0-pro-fast 1.5-pro 2.0-fast
    text_to_video (t2v) (이미지 없음)
    image_to_video (i2v) first_frame × 1
    first_last_frames (flf2v) first_frame + last_frame
    omni_reference (구 r2v / omni) reference_image × N (+ video/audio reference)

    generate_audio: true 옵션 — 어느 task_type 위에 얹을 수 있는가

    오디오 동시 생성은 별도 task_type이 아닙니다. 위 4개 task_type 위에 옵션으로 얹을 수 있고, 모델 버전마다 가능 범위가 다릅니다.

    범례: ✅(검증) = 직접 호출해 성공을 확인. ✅(docs) = BytePlus·플랫폼 공식 문서에 지원 명시, 직접 검증은 안 한 항목. ❓ = docs도 사용자도 확인 안 됨. ❌ = 호출 거절을 직접 확인했거나 모델 capability상 불가능한 것.

    베이스 task_type + generate_audio: true 1.0-pro-fast 1.5-pro 2.0-fast
    text_to_video ✅ (docs) — 2.0 fast text-to-video 엔드포인트 docs는 generate_audio 기본값이 true라고 명시
    image_to_video ✅ (검증)
    first_last_frames ✅ (docs) — 2.0 docs는 native audio가 모델 전반 기능이라고 기술. 직접 검증은 안 함
    omni_reference (1.5에선 r2v 이름) ✅ (검증, 당시 r2v + audio로 호출) ✅ (검증)

    특히 2.0-fast는 native audio가 task_type별 옵션이 아니라 모델 전체에 깔린 기능이라는 게 docs의 일관된 서술입니다. 그래서 text_to_video 위에든 omni_reference 위에든 generate_audio: true(또는 default true)로 호출하면 비디오와 동기화된 오디오가 같이 떨어진다고 적혀 있습니다. 제가 직접 호출해 본 건 image_to_video + audioomni_reference + audio 두 가지뿐이라, text_to_video + audio / first_last_frames + audio는 docs 기준 ✅로 두되 "검증" 표시를 떼서 두 칸의 신뢰 수준을 구분했습니다.

    흥미로운 점은 이전 버전인 1.5-pro도 reference + audio 조합(당시 이름은 r2v + audio)을 이미 지원했다는 것입니다. 다만 1.5는 reference_video / reference_audio가 reference role의 일부로 들어가던 r2v였고, 2.0에서 이게 image+video+audio reference를 모두 받는 omni_reference로 확장됐습니다. 같은 능력이 이름만 바뀌어 살아남은 셈입니다. 1.0-pro-fast는 reference 자체를 받지 않으므로 audio도 불가능합니다. 1.5에서 t2v + audio / i2v + audio / flf2v + audio가 되는지는 docs도 사용자도 확인되지 않아 ❓로 남겨둡니다. 모델 버전과 task_type 지원이 깔끔한 누적 관계는 아니어서 매트릭스를 들고 다닐 가치가 있습니다.

    task_type 자동 추론을 시각화하기

    모드 자동 추론 다이어그램

    다이어그램이 강조하는 건 두 가지입니다 — task_type 파라미터는 따로 없다는 것, 그리고 role 조합이 task_type을 결정한다는 것. role 하나를 잘못 붙이면 의도와 전혀 다른 task_type이 켜지고 거절됩니다.

    매트릭스를 코드에 데이터로 박아두기

    코드에서 task_type 분기를 if/else로 짜기 시작하면 모델이 추가될 때마다 분기가 늘어납니다. 대신 매트릭스 자체를 데이터로 두는 패턴이 진화에 강합니다. 오디오는 task_type이 아니라 옵션이므로, 별도 dict으로 둡니다.

    # 공식 task_type 4개 × 모델 버전 매트릭스
    SUPPORTED_TASKS: dict[tuple[str, str], bool] = {
        ("seedance-1.0-pro-fast", "text_to_video"):     True,
        ("seedance-1.0-pro-fast", "image_to_video"):    True,
        ("seedance-1.5-pro",      "text_to_video"):     True,
        ("seedance-1.5-pro",      "image_to_video"):    True,
        ("seedance-1.5-pro",      "first_last_frames"): True,
        ("seedance-1.5-pro",      "omni_reference"):    True,  # 1.5에서는 r2v 이름
        ("seedance-2.0-fast",     "text_to_video"):     True,
        ("seedance-2.0-fast",     "image_to_video"):    True,
        ("seedance-2.0-fast",     "first_last_frames"): True,
        ("seedance-2.0-fast",     "omni_reference"):    True,
        # 나머지는 default False
    }
    
    # generate_audio: true를 얹을 수 있는 (모델, task_type) 조합
    SUPPORTS_AUDIO_FLAG: set[tuple[str, str]] = {
        ("seedance-1.5-pro",  "omni_reference"),
        ("seedance-2.0-fast", "image_to_video"),
        ("seedance-2.0-fast", "omni_reference"),
    }
    
    def infer_task_type(content_items: list[dict]) -> str:
        """role 조합으로 공식 task_type 추론. 오디오 flag는 별개."""
        roles = [it.get("role") for it in content_items if it["type"] == "image_url"]
        has_first = "first_frame"     in roles
        has_last  = "last_frame"      in roles
        has_ref   = "reference_image" in roles
    
        if has_ref:                return "omni_reference"
        if has_first and has_last: return "first_last_frames"
        if has_first:              return "image_to_video"
        return "text_to_video"
    
    def must_support(model: str, task_type: str, generate_audio: bool) -> None:
        if not SUPPORTED_TASKS.get((model, task_type), False):
            raise UnsupportedModeError(f"{model} does not support {task_type}")
        if generate_audio and (model, task_type) not in SUPPORTS_AUDIO_FLAG:
            raise UnsupportedModeError(
                f"{model} + {task_type}는 generate_audio:true를 받지 못합니다"
            )
    

    SUPPORTED_TASKS는 task_type × 모델 매트릭스, SUPPORTS_AUDIO_FLAG는 옵션 매트릭스. infer_task_type은 모델 서버가 내부에서 하는 role→task_type 추론을 클라이언트 측에서 미리 시뮬레이션합니다. 새 클립을 보내기 전에 must_support(model, infer_task_type(...), generate_audio)를 한 번 호출하면 API에 보내기도 전에 클라이언트가 거절합니다. paid 호출이 polling 90초 들여 돌려준 거절 메시지를, 우리는 로컬에서 1ms만에 받습니다.

    결과 — 매트릭스를 들고 있을 때 달라지는 것

    이 매트릭스를 들고 작업하기 시작한 뒤로는 몇 가지가 명확해졌습니다.

    • 새 클립을 정의할 때 "어떤 task_type인지" 결정이 자연스럽게 첫 단계가 됩니다. task_type을 결정하면 사용할 모델 변종도 같이 좁혀집니다.
    • 새 모델이 출시되면 매트릭스에 한 줄만 추가하면 됩니다. 분기 코드 수정이 필요 없습니다.
    • task_type 자동 추론이 좋아도 명시적 task_type 로그는 필수입니다. 디버깅할 때 "내가 보낸 role 조합 → 모델이 추론한 task_type"를 한 줄에 보고 싶기 때문입니다.

    같은 영상 1편을 두고도 클립마다 다른 task_type을 골라 쓰게 됩니다. wide shot 한 컷은 text_to_video(t2v)로 가볍게, 인물 발화 컷은 omni_reference + generate_audio: true로 진하게. 모드는 사치가 아니라 production 도구상자입니다. 한 번 약어와 공식 이름을 정리하고 매트릭스를 들고 다니면, 그 도구상자가 갑자기 잘 보입니다.


    이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.

Designed by Tistory.