파트너십

TwelveLabs와 Pixeltable로 크로스 모달 비디오 검색 구축하기

제임스 러

개발자는 Twelve Labs의 Marengo 3.0 임베딩과 Pixeltable의 선언적 데이터 인프라를 활용하여 크로스 모달 비디오 검색 시스템을 구축할 수 있습니다. 이를 통해 자동 임베딩 계산 및 증분 업데이트를 지원하는 단일 통합 시맨틱 인덱스를 기반으로 텍스트, 이미지, 오디오, 비디오 쿼리를 모두 처리할 수 있습니다.

개발자는 Twelve Labs의 Marengo 3.0 임베딩과 Pixeltable의 선언적 데이터 인프라를 활용하여 크로스 모달 비디오 검색 시스템을 구축할 수 있습니다. 이를 통해 자동 임베딩 계산 및 증분 업데이트를 지원하는 단일 통합 시맨틱 인덱스를 기반으로 텍스트, 이미지, 오디오, 비디오 쿼리를 모두 처리할 수 있습니다.

In this article

No headings found on page

뉴스레터 구독하기

뉴스레터 구독하기

영상 이해 분야의 최신 기술 업데이트, 튜토리얼 및 인사이트를 받아보세요.

영상 이해 분야의 최신 기술 업데이트, 튜토리얼 및 인사이트를 받아보세요.

AI로 영상을 검색하고, 분석하고, 탐색하세요.

2026. 2. 4.

5분

링크 복사하기

이 통합을 위해 저와 협업해 준 Pixeltable 팀(Alison Hill, Pierre Brunelle, Marcel Kornacker, Aaron Siegel)에 깊은 감사를 표합니다!


소개

지능형 비디오 애플리케이션을 구축하는 데는 근본적인 어려움이 따릅니다. 비디오에는 시각적 콘텐츠, 오디오, 텍스트 등 여러 모달리티가 포함되어 있어 기존의 검색 시스템으로는 매끄럽게 쿼리하기가 어렵습니다. 개발자는 일반적으로 각 모달리티를 위한 개별 모델, 복잡한 브릿지 로직, 그리고 크로스 모달(cross-modal) 검색을 구현하기 위한 상당한 엔지니어링 공수를 투입해야만 합니다.

TwelveLabs의 멀티모달 임베딩은 텍스트, 이미지, 오디오, 비디오를 하나의 통합된 시맨틱 공간으로 투사하여 이 문제를 해결합니다. 즉, 어떤 모달리티를 사용하든 비디오 라이브러리를 검색할 수 있습니다. 텍스트 설명("연설하는 사람")으로 클립을 찾거나, 기준 이미지와 시각적으로 유사한 비디오를 찾거나, 일치하는 오디오 특성을 가진 콘텐츠를 검색하거나, 유사한 비디오 세그먼트를 식별하는 작업이 모두 동일한 임베딩 모델을 통해 가능해집니다.


이 튜토리얼에서는 TwelveLabs의 Marengo 3.0 모델멀티모달 AI를 위한 Pixeltable의 선언적 데이터 인프라를 결합하여 완전한 크로스 모달 비디오 검색 시스템을 구축해 보겠습니다. Pixeltable은 임베딩 계산, 인덱싱, 증분 업데이트의 복잡한 과정을 자동으로 처리하므로, 개발자는 인프라 관리 대신 기능 구현에만 집중할 수 있습니다. 완료하고 나면 최소한의 코드만으로 진정한 멀티모달 비디오 이해를 보여주는 작동하는 시스템을 갖추게 됩니다.


사전 준비 및 설정

크로스 모달 검색 시스템을 빌드하기 전에 Python 3.8 이상이 설치되어 있는지 확인하세요. TwelveLabs API 키가 필요하며, 이는 playground.twelvelabs.io에 가입하여 발급받을 수 있습니다.

먼저 필요한 패키지를 설치합니다:

pip install -qU

그 다음, TwelveLabs API 키를 안전하게 설정합니다. 환경 변수로 지정하거나 대화형으로 입력할 수 있습니다:

import os
import getpass

if 'TWELVELABS_API_KEY' not in os.environ:
    os.environ['TWELVELABS_API_KEY'] = getpass.getpass('Enter your Twelve Labs API key: ')

Pixeltable을 초기화하고 이 프로젝트를 위한 전용 디렉터리를 생성합니다:

import pixeltable as pxt
from pixeltable.functions.twelvelabs import embed

# Create a fresh directory for our video search system
pxt.drop_dir('video_search', force=True)
pxt.create_dir('video_search')

Pixeltable은 이 디렉터리 내에서 데이터 영속성, 버전 관리, 메타데이터 추적을 자동으로 처리합니다.

중요: Twelve Labs는 최적의 임베딩 품질을 위해 오디오 및 비디오 콘텐츠의 길이가 최소 4초 이상이어야 합니다. 비디오 콘텐츠를 준비할 때 이 제약 조건을 염두에 두시기 바랍니다.


핵심 개념: 멀티모달 임베딩

기존의 비디오 검색은 시각적 콘텐츠용, 오디오용, 텍스트용 모델을 각각 따로 두고 이들을 연결하는 복잡한 로직이 필요했습니다. TwelveLabs의 Marengo 모델은 이와 근본적으로 다른 방식으로 접근합니다. 즉, 모든 모달리티가 공존하는 하나의 통합된 시맨틱 공간을 생성합니다.

이 공유 공간에서는 누군가 말하고 있는 비디오 클립, 그 말의 스크립트, 비디오의 스틸 프레임, 그리고 텍스트 설명이 모두 서로 가까운 지점에 매핑됩니다. 덕분에 진정한 크로스 모달 검색이 가능해집니다. 어떤 모달리티로도 쿼리를 던져 원하는 모달리티의 관련 콘텐츠를 찾아낼 수 있습니다.

여러분들이 직접 빌드해 볼 크로스 모달 검색 기능은 다음과 같습니다:

쿼리 유형

사용 사례

텍스트 → 비디오

"연설하는 사람"에 해당하는 클립 찾기

이미지 → 비디오

참조 사진과 시각적으로 유사한 비디오 위치 찾기

오디오 → 비디오

유사한 오디오 특징을 가진 콘텐츠 발견하기

비디오 → 비디오

유사한 클립 또는 동일한 장면의 다른 테이크 식별하기

이 통합된 임베딩 공간이 존재하기에 TwelveLabs와 Pixeltable의 결합이 그토록 강력한 힘을 발휘합니다. 한 번만 구축하면 모든 모달리티에 걸쳐 원활하게 검색할 수 있으니까요.


비디오 검색 시스템 빌드하기

Pixeltable과 TwelveLabs를 활용해 검색 가능한 비디오 인덱스를 생성하는 과정은 단 몇 단계의 선언적 작업만으로 충분합니다. 먼저 비디오를 저장할 테이블을 정의하는 것부터 시작합니다:

from pixeltable.functions.video import splitter

# Create a table for videos
videos = pxt.create_table('video_search.videos', {'video': pxt.Video})

# Insert a sample video
video_url = 'https://github.com/pixeltable/pixeltable/raw/main/docs/resources/The-Pursuit-of-Happiness.mp4'
videos.insert([{'video': video_url}])

다음으로 비디오를 검색 가능한 청크(chunk) 단위로 세분화하는 뷰(view)를 성합니다. 이 부분에서 Pixeltable의 반복자(iterator) 기능이 진가를 발휘합니다:

splitter 반복자는 각 비디오를 5초짜리 세그먼트로 자동 분할하는 동시에, TwelveLabs가 요구하는 최소 기준인 4초 아래로 떨어지는 세그먼트가 없도록 보장합니다. 이 뷰의 각 행은 하나의 비디오 세그먼트를 나타냅니다.

이제 가장 중요한 단계인 임베딩 인덱스 추가입니다:

# Add embedding index for cross-modal search
video_chunks.add_embedding_index(
    'video_segment',
    embedding=embed.using(model_name='marengo3.0')
)

이 한 줄만으로 강력한 자동화가 실행됩니다. Pixeltable은 모든 비디오 세그먼트에 대해 TwelveLabs 임베딩을 계산하고 이 인덱스를 증분 방식으로 유지 관리합니다. 새 비디오를 추가하면 임베딩이 자동으로 계산되므로 수동으로 조율할 필요가 없습니다.

이 선언적 접근 방식의 장점은 처리하는 방법이 아닌, 무엇을 계산할지(비디오 세그먼트의 임베딩)만 지정하면 된다는 것입니다. 일괄 처리, 오류 복구, 캐싱 등 백그라운드의 복잡한 일들은 Pixeltable이 알아서 처리합니다.


크로스 모달 검색 가이드

비디오 인덱스가 빌드되었다면 이제 어떤 모달리티로도 검색을 시작할 수 있습니다. 핵심은 video_segment 열에서 호출하여 재사용 가능한 유사도 표현식을 만드는 similarity() 메서드입니다.


텍스트 기반 비디오 검색 (Text-to-Video)

먼저 텍스트 쿼리에 대한 유사도 표현식을 정의합니다:

# Define similarity to a text query
sim = video_chunks.video_segment.similarity(string='person giving a speech')

# Get the top 3 matching segments
results = video_chunks.order_by(sim, asc=False).limit(3).select(
    video_chunks.video_segment,
    score=sim
)

results.collect()

여기서 sim은 "각 세그먼트와 이 텍스트 문자열 간의 유사도"를 나타내는 표현식이며, 이를 order_by, select 또는 기타 필터에 활용할 수 있습니다.


이미지 기반 비디오 검색 (Image-to-Video)

이미지 쿼리에도 동일한 패턴을 적용합니다:

# Load a reference image
reference_image = pxt.Image('path/to/reference_image.jpg')

# Define similarity to the image
sim_image = video_chunks.video_segment.similarity(image=reference_image)

# Top 3 visually similar segments
results = video_chunks.order_by(sim_image, asc=False).limit(3).select(
    video_chunks.video_segment,
    score=sim_image
)

results.collect()

이를 통해 시각적 콘텐츠가 참조 이미지와 가장 유사한 비디오 세그먼트를 찾아냅니다.


오디오 기반 비디오 검색 (Audio-to-Video)

오디오 클립을 사용해 검색하는 것도 가능합니다:

# Load a reference audio sample
reference_audio = pxt.Audio('path/to/reference_audio.mp3')

# Define similarity to the audio
sim_audio = video_chunks.video_segment.similarity(audio=reference_audio)

# Top 3 segments with similar audio characteristics
results = video_chunks.order_by(sim_audio, asc=False).limit(3).select(
    video_chunks.video_segment,
    score=sim_audio
)

results.collect()

배경 음악, 말하는 스타일 또는 기타 음향적 특징을 매칭시키고자 할 때 매우 유용합니다.


비디오 기반 비디오 검색 (Video-to-Video)

마지막으로 비디오(또는 세그먼트) 자체를 쿼리로 사용해 유사한 클립을 찾을 수 있습니다:

# Use an existing segment as the query
query_segment = (
    video_chunks
        .select(video_chunks.video_segment)
        .limit(1)
        .collect()[0]['video_segment']
)

# Define similarity to the query segment
sim_video = video_chunks.video_segment.similarity(video=query_segment)

# Top 5 similar segments across the library
results = video_chunks.order_by(sim_video, asc=False).limit(5).select(
    video_chunks.video_segment,
    score=sim_video
)

results.collect()

이 기능은 콘텐츠 추천 시스템이나 중복 콘텐츠 탐지, 혹은 유사한 장면의 다른 촬영본(alternative take)을 찾는 데 활용될 수 있습니다.

네 가지 사례 모두 동일한 패턴을 따릅니다. video_segment 열에 similarity() 표현식을 정의한 후, 이 표현식을 order_byselect에 재사용하여 텍스트, 이미지, 오디오, 비디오 쿼리에 가장 잘 맞는 결과를 가져오는 방식입니다.


비디오를 넘어: 멀티모달 데이터 유형의 확장

TwelveLabs 임베딩은 비디오 영역을 넘어 진정한 의미의 멀티모달 애플리케이션을 완성해 줍니다. 동일한 Marengo 모델을 사용해 텍스트 문서, 독립된 이미지, 오디오 파일까지 임베딩 함으로써 서로 다른 유형의 데이터 간 교차 검색이 가능해집니다.

여러 모달리티를 가진 상품 카탈로그 테이블을 만들어 보겠습니다:

# Create a product catalog with text and images
products = pxt.create_table(
    'video_search.products',
    {
        'title': pxt.String,
        'description': pxt.String,
        'thumbnail': pxt.Image
    }
)

# Add computed column combining title and description
products.add_computed_column(
		text_content=products.title + '. ' + products.description,
		if_exists='replace'
)

# Add embedding indices for both text and images
products.add_embedding_index(
    'text_content',
    embedding=embed.using(model_name='marengo3.0')
)

products.add_embedding_index(
    'thumbnail',
    embedding=embed.using(model_name='marengo3.0')
)

이제 멀티모달 카탈로그 검색을 수행합니다:

# Search products using text
text_results = products.select(
    products.title,
    products.thumbnail,
    products.score
).order_by(
    products.score, asc=False
).where(
    products.text_content.sim('outdoor hiking gear') > 0.6
).limit(5)

# Search products using an image
query_image = pxt.Image('path/to/query.jpg')
image_results = products.select(
    products.title,
    products.description,
    products.score
).order_by(
    products.score, asc=False
).where(
    products.thumbnail.sim(query_image) > 0.7
).limit(5)

심지어 비디오 클립으로 제품 카탈로그를 검색하거나, 오디오 샘플과 관련된 상품을 찾는 것까지 가능합니다. 이렇게 하나로 통합된 방식을 활용하면 단 하나의 임베딩 모델로 텍스트 문서, 이미지, 오디오 파일, 비디오 등 애플리케이션 내의 모든 데이터를 커버할 수 있습니다.

이러한 패턴은 스크린샷으로 문서를 검색하거나, 텍스트로 오디오 클립을 찾거나, 비디오 프레임과 유사한 이미지를 찾는 등 다른 시나리오에도 똑같이 적용됩니다. TwelveLabs의 멀티모달 임베딩은 데이터 유형 간 존재하던 한계를 완벽히 허물어 줍니다.


성능 최적화 및 모범 사례

Pixeltable은 임베딩 계산을 알아서 최적화하지만, 다음의 몇 가지 모범 사례를 따르면 프로덕션 환경에서 더욱 뛰어난 성능을 누릴 수 있습니다.

배치 작업(Batch Operations): 비디오를 하나씩 삽입하기보다 여러 개를 한 번에 넣으세요. Pixeltable은 배치로 실행할 때 임베딩을 더 효율적으로 처리합니다.

# Efficient: batch insert
videos.insert([
    {'video': 'url1.mp4'},
    {'video': 'url2.mp4'},
    {'video': 'url3.mp4'}
])

유사도 임계값 조절: 비즈니스가 요구하는 정밀도(precision)와 재현율(recall)에 맞춰 임계값을 조정하세요. 높은 값(0.7~0.9)을 설정하면 개수는 적지만 확실히 관련 있는 결과가 나오고, 낮은 값(0.4~0.6)은 더 넓은 범위를 짚어 줍니다. 보유한 실제 콘텐츠로 적절한 수준을 찾아 보시기 바랍니다.

증분 업데이트: Pixeltable의 계산된 열(computed column)은 새 데이터가 들어올 때 자동으로 갱신됩니다. 임베딩 인덱스도 수동으로 재처리할 필요 없이 최신 상태로 유지되므로, 언제든 비디오를 추가하자마자 바로 검색 엔진에 반영됩니다.

캐싱: Pixeltable은 임베딩 인덱스를 관리하며, 원본 데이터가 변경되지 않는 한 이미 인덱싱이 끝난 유사도 검색에 대해서는 추가적인 API 호출을 발생시키지 않습니다.

에러 핸들링: Pixeltable은 실패한 임베딩 연산을 자동으로 재시도합니다. (제공업체별 속도 제한 가이드는 설정 디테일을 참고하세요.) 더불어 대량의 배치 작업 중 API 호출 제한(rate limit)을 방지할 수 있도록 TwelveLabs API 쿼터를 모니터링해야 합니다.

이러한 실무 팁을 활용하면 지연 시간(latency)을 낮게 유지하면서도 대규모로 유연하게 작동하는 상용 수준의 비디오 검색 시스템을 구축할 수 있습니다.


추가 리소스

이 통합을 위해 저와 협업해 준 Pixeltable 팀(Alison Hill, Pierre Brunelle, Marcel Kornacker, Aaron Siegel)에 깊은 감사를 표합니다!


소개

지능형 비디오 애플리케이션을 구축하는 데는 근본적인 어려움이 따릅니다. 비디오에는 시각적 콘텐츠, 오디오, 텍스트 등 여러 모달리티가 포함되어 있어 기존의 검색 시스템으로는 매끄럽게 쿼리하기가 어렵습니다. 개발자는 일반적으로 각 모달리티를 위한 개별 모델, 복잡한 브릿지 로직, 그리고 크로스 모달(cross-modal) 검색을 구현하기 위한 상당한 엔지니어링 공수를 투입해야만 합니다.

TwelveLabs의 멀티모달 임베딩은 텍스트, 이미지, 오디오, 비디오를 하나의 통합된 시맨틱 공간으로 투사하여 이 문제를 해결합니다. 즉, 어떤 모달리티를 사용하든 비디오 라이브러리를 검색할 수 있습니다. 텍스트 설명("연설하는 사람")으로 클립을 찾거나, 기준 이미지와 시각적으로 유사한 비디오를 찾거나, 일치하는 오디오 특성을 가진 콘텐츠를 검색하거나, 유사한 비디오 세그먼트를 식별하는 작업이 모두 동일한 임베딩 모델을 통해 가능해집니다.


이 튜토리얼에서는 TwelveLabs의 Marengo 3.0 모델멀티모달 AI를 위한 Pixeltable의 선언적 데이터 인프라를 결합하여 완전한 크로스 모달 비디오 검색 시스템을 구축해 보겠습니다. Pixeltable은 임베딩 계산, 인덱싱, 증분 업데이트의 복잡한 과정을 자동으로 처리하므로, 개발자는 인프라 관리 대신 기능 구현에만 집중할 수 있습니다. 완료하고 나면 최소한의 코드만으로 진정한 멀티모달 비디오 이해를 보여주는 작동하는 시스템을 갖추게 됩니다.


사전 준비 및 설정

크로스 모달 검색 시스템을 빌드하기 전에 Python 3.8 이상이 설치되어 있는지 확인하세요. TwelveLabs API 키가 필요하며, 이는 playground.twelvelabs.io에 가입하여 발급받을 수 있습니다.

먼저 필요한 패키지를 설치합니다:

pip install -qU

그 다음, TwelveLabs API 키를 안전하게 설정합니다. 환경 변수로 지정하거나 대화형으로 입력할 수 있습니다:

import os
import getpass

if 'TWELVELABS_API_KEY' not in os.environ:
    os.environ['TWELVELABS_API_KEY'] = getpass.getpass('Enter your Twelve Labs API key: ')

Pixeltable을 초기화하고 이 프로젝트를 위한 전용 디렉터리를 생성합니다:

import pixeltable as pxt
from pixeltable.functions.twelvelabs import embed

# Create a fresh directory for our video search system
pxt.drop_dir('video_search', force=True)
pxt.create_dir('video_search')

Pixeltable은 이 디렉터리 내에서 데이터 영속성, 버전 관리, 메타데이터 추적을 자동으로 처리합니다.

중요: Twelve Labs는 최적의 임베딩 품질을 위해 오디오 및 비디오 콘텐츠의 길이가 최소 4초 이상이어야 합니다. 비디오 콘텐츠를 준비할 때 이 제약 조건을 염두에 두시기 바랍니다.


핵심 개념: 멀티모달 임베딩

기존의 비디오 검색은 시각적 콘텐츠용, 오디오용, 텍스트용 모델을 각각 따로 두고 이들을 연결하는 복잡한 로직이 필요했습니다. TwelveLabs의 Marengo 모델은 이와 근본적으로 다른 방식으로 접근합니다. 즉, 모든 모달리티가 공존하는 하나의 통합된 시맨틱 공간을 생성합니다.

이 공유 공간에서는 누군가 말하고 있는 비디오 클립, 그 말의 스크립트, 비디오의 스틸 프레임, 그리고 텍스트 설명이 모두 서로 가까운 지점에 매핑됩니다. 덕분에 진정한 크로스 모달 검색이 가능해집니다. 어떤 모달리티로도 쿼리를 던져 원하는 모달리티의 관련 콘텐츠를 찾아낼 수 있습니다.

여러분들이 직접 빌드해 볼 크로스 모달 검색 기능은 다음과 같습니다:

쿼리 유형

사용 사례

텍스트 → 비디오

"연설하는 사람"에 해당하는 클립 찾기

이미지 → 비디오

참조 사진과 시각적으로 유사한 비디오 위치 찾기

오디오 → 비디오

유사한 오디오 특징을 가진 콘텐츠 발견하기

비디오 → 비디오

유사한 클립 또는 동일한 장면의 다른 테이크 식별하기

이 통합된 임베딩 공간이 존재하기에 TwelveLabs와 Pixeltable의 결합이 그토록 강력한 힘을 발휘합니다. 한 번만 구축하면 모든 모달리티에 걸쳐 원활하게 검색할 수 있으니까요.


비디오 검색 시스템 빌드하기

Pixeltable과 TwelveLabs를 활용해 검색 가능한 비디오 인덱스를 생성하는 과정은 단 몇 단계의 선언적 작업만으로 충분합니다. 먼저 비디오를 저장할 테이블을 정의하는 것부터 시작합니다:

from pixeltable.functions.video import splitter

# Create a table for videos
videos = pxt.create_table('video_search.videos', {'video': pxt.Video})

# Insert a sample video
video_url = 'https://github.com/pixeltable/pixeltable/raw/main/docs/resources/The-Pursuit-of-Happiness.mp4'
videos.insert([{'video': video_url}])

다음으로 비디오를 검색 가능한 청크(chunk) 단위로 세분화하는 뷰(view)를 성합니다. 이 부분에서 Pixeltable의 반복자(iterator) 기능이 진가를 발휘합니다:

splitter 반복자는 각 비디오를 5초짜리 세그먼트로 자동 분할하는 동시에, TwelveLabs가 요구하는 최소 기준인 4초 아래로 떨어지는 세그먼트가 없도록 보장합니다. 이 뷰의 각 행은 하나의 비디오 세그먼트를 나타냅니다.

이제 가장 중요한 단계인 임베딩 인덱스 추가입니다:

# Add embedding index for cross-modal search
video_chunks.add_embedding_index(
    'video_segment',
    embedding=embed.using(model_name='marengo3.0')
)

이 한 줄만으로 강력한 자동화가 실행됩니다. Pixeltable은 모든 비디오 세그먼트에 대해 TwelveLabs 임베딩을 계산하고 이 인덱스를 증분 방식으로 유지 관리합니다. 새 비디오를 추가하면 임베딩이 자동으로 계산되므로 수동으로 조율할 필요가 없습니다.

이 선언적 접근 방식의 장점은 처리하는 방법이 아닌, 무엇을 계산할지(비디오 세그먼트의 임베딩)만 지정하면 된다는 것입니다. 일괄 처리, 오류 복구, 캐싱 등 백그라운드의 복잡한 일들은 Pixeltable이 알아서 처리합니다.


크로스 모달 검색 가이드

비디오 인덱스가 빌드되었다면 이제 어떤 모달리티로도 검색을 시작할 수 있습니다. 핵심은 video_segment 열에서 호출하여 재사용 가능한 유사도 표현식을 만드는 similarity() 메서드입니다.


텍스트 기반 비디오 검색 (Text-to-Video)

먼저 텍스트 쿼리에 대한 유사도 표현식을 정의합니다:

# Define similarity to a text query
sim = video_chunks.video_segment.similarity(string='person giving a speech')

# Get the top 3 matching segments
results = video_chunks.order_by(sim, asc=False).limit(3).select(
    video_chunks.video_segment,
    score=sim
)

results.collect()

여기서 sim은 "각 세그먼트와 이 텍스트 문자열 간의 유사도"를 나타내는 표현식이며, 이를 order_by, select 또는 기타 필터에 활용할 수 있습니다.


이미지 기반 비디오 검색 (Image-to-Video)

이미지 쿼리에도 동일한 패턴을 적용합니다:

# Load a reference image
reference_image = pxt.Image('path/to/reference_image.jpg')

# Define similarity to the image
sim_image = video_chunks.video_segment.similarity(image=reference_image)

# Top 3 visually similar segments
results = video_chunks.order_by(sim_image, asc=False).limit(3).select(
    video_chunks.video_segment,
    score=sim_image
)

results.collect()

이를 통해 시각적 콘텐츠가 참조 이미지와 가장 유사한 비디오 세그먼트를 찾아냅니다.


오디오 기반 비디오 검색 (Audio-to-Video)

오디오 클립을 사용해 검색하는 것도 가능합니다:

# Load a reference audio sample
reference_audio = pxt.Audio('path/to/reference_audio.mp3')

# Define similarity to the audio
sim_audio = video_chunks.video_segment.similarity(audio=reference_audio)

# Top 3 segments with similar audio characteristics
results = video_chunks.order_by(sim_audio, asc=False).limit(3).select(
    video_chunks.video_segment,
    score=sim_audio
)

results.collect()

배경 음악, 말하는 스타일 또는 기타 음향적 특징을 매칭시키고자 할 때 매우 유용합니다.


비디오 기반 비디오 검색 (Video-to-Video)

마지막으로 비디오(또는 세그먼트) 자체를 쿼리로 사용해 유사한 클립을 찾을 수 있습니다:

# Use an existing segment as the query
query_segment = (
    video_chunks
        .select(video_chunks.video_segment)
        .limit(1)
        .collect()[0]['video_segment']
)

# Define similarity to the query segment
sim_video = video_chunks.video_segment.similarity(video=query_segment)

# Top 5 similar segments across the library
results = video_chunks.order_by(sim_video, asc=False).limit(5).select(
    video_chunks.video_segment,
    score=sim_video
)

results.collect()

이 기능은 콘텐츠 추천 시스템이나 중복 콘텐츠 탐지, 혹은 유사한 장면의 다른 촬영본(alternative take)을 찾는 데 활용될 수 있습니다.

네 가지 사례 모두 동일한 패턴을 따릅니다. video_segment 열에 similarity() 표현식을 정의한 후, 이 표현식을 order_byselect에 재사용하여 텍스트, 이미지, 오디오, 비디오 쿼리에 가장 잘 맞는 결과를 가져오는 방식입니다.


비디오를 넘어: 멀티모달 데이터 유형의 확장

TwelveLabs 임베딩은 비디오 영역을 넘어 진정한 의미의 멀티모달 애플리케이션을 완성해 줍니다. 동일한 Marengo 모델을 사용해 텍스트 문서, 독립된 이미지, 오디오 파일까지 임베딩 함으로써 서로 다른 유형의 데이터 간 교차 검색이 가능해집니다.

여러 모달리티를 가진 상품 카탈로그 테이블을 만들어 보겠습니다:

# Create a product catalog with text and images
products = pxt.create_table(
    'video_search.products',
    {
        'title': pxt.String,
        'description': pxt.String,
        'thumbnail': pxt.Image
    }
)

# Add computed column combining title and description
products.add_computed_column(
		text_content=products.title + '. ' + products.description,
		if_exists='replace'
)

# Add embedding indices for both text and images
products.add_embedding_index(
    'text_content',
    embedding=embed.using(model_name='marengo3.0')
)

products.add_embedding_index(
    'thumbnail',
    embedding=embed.using(model_name='marengo3.0')
)

이제 멀티모달 카탈로그 검색을 수행합니다:

# Search products using text
text_results = products.select(
    products.title,
    products.thumbnail,
    products.score
).order_by(
    products.score, asc=False
).where(
    products.text_content.sim('outdoor hiking gear') > 0.6
).limit(5)

# Search products using an image
query_image = pxt.Image('path/to/query.jpg')
image_results = products.select(
    products.title,
    products.description,
    products.score
).order_by(
    products.score, asc=False
).where(
    products.thumbnail.sim(query_image) > 0.7
).limit(5)

심지어 비디오 클립으로 제품 카탈로그를 검색하거나, 오디오 샘플과 관련된 상품을 찾는 것까지 가능합니다. 이렇게 하나로 통합된 방식을 활용하면 단 하나의 임베딩 모델로 텍스트 문서, 이미지, 오디오 파일, 비디오 등 애플리케이션 내의 모든 데이터를 커버할 수 있습니다.

이러한 패턴은 스크린샷으로 문서를 검색하거나, 텍스트로 오디오 클립을 찾거나, 비디오 프레임과 유사한 이미지를 찾는 등 다른 시나리오에도 똑같이 적용됩니다. TwelveLabs의 멀티모달 임베딩은 데이터 유형 간 존재하던 한계를 완벽히 허물어 줍니다.


성능 최적화 및 모범 사례

Pixeltable은 임베딩 계산을 알아서 최적화하지만, 다음의 몇 가지 모범 사례를 따르면 프로덕션 환경에서 더욱 뛰어난 성능을 누릴 수 있습니다.

배치 작업(Batch Operations): 비디오를 하나씩 삽입하기보다 여러 개를 한 번에 넣으세요. Pixeltable은 배치로 실행할 때 임베딩을 더 효율적으로 처리합니다.

# Efficient: batch insert
videos.insert([
    {'video': 'url1.mp4'},
    {'video': 'url2.mp4'},
    {'video': 'url3.mp4'}
])

유사도 임계값 조절: 비즈니스가 요구하는 정밀도(precision)와 재현율(recall)에 맞춰 임계값을 조정하세요. 높은 값(0.7~0.9)을 설정하면 개수는 적지만 확실히 관련 있는 결과가 나오고, 낮은 값(0.4~0.6)은 더 넓은 범위를 짚어 줍니다. 보유한 실제 콘텐츠로 적절한 수준을 찾아 보시기 바랍니다.

증분 업데이트: Pixeltable의 계산된 열(computed column)은 새 데이터가 들어올 때 자동으로 갱신됩니다. 임베딩 인덱스도 수동으로 재처리할 필요 없이 최신 상태로 유지되므로, 언제든 비디오를 추가하자마자 바로 검색 엔진에 반영됩니다.

캐싱: Pixeltable은 임베딩 인덱스를 관리하며, 원본 데이터가 변경되지 않는 한 이미 인덱싱이 끝난 유사도 검색에 대해서는 추가적인 API 호출을 발생시키지 않습니다.

에러 핸들링: Pixeltable은 실패한 임베딩 연산을 자동으로 재시도합니다. (제공업체별 속도 제한 가이드는 설정 디테일을 참고하세요.) 더불어 대량의 배치 작업 중 API 호출 제한(rate limit)을 방지할 수 있도록 TwelveLabs API 쿼터를 모니터링해야 합니다.

이러한 실무 팁을 활용하면 지연 시간(latency)을 낮게 유지하면서도 대규모로 유연하게 작동하는 상용 수준의 비디오 검색 시스템을 구축할 수 있습니다.


추가 리소스

이 통합을 위해 저와 협업해 준 Pixeltable 팀(Alison Hill, Pierre Brunelle, Marcel Kornacker, Aaron Siegel)에 깊은 감사를 표합니다!


소개

지능형 비디오 애플리케이션을 구축하는 데는 근본적인 어려움이 따릅니다. 비디오에는 시각적 콘텐츠, 오디오, 텍스트 등 여러 모달리티가 포함되어 있어 기존의 검색 시스템으로는 매끄럽게 쿼리하기가 어렵습니다. 개발자는 일반적으로 각 모달리티를 위한 개별 모델, 복잡한 브릿지 로직, 그리고 크로스 모달(cross-modal) 검색을 구현하기 위한 상당한 엔지니어링 공수를 투입해야만 합니다.

TwelveLabs의 멀티모달 임베딩은 텍스트, 이미지, 오디오, 비디오를 하나의 통합된 시맨틱 공간으로 투사하여 이 문제를 해결합니다. 즉, 어떤 모달리티를 사용하든 비디오 라이브러리를 검색할 수 있습니다. 텍스트 설명("연설하는 사람")으로 클립을 찾거나, 기준 이미지와 시각적으로 유사한 비디오를 찾거나, 일치하는 오디오 특성을 가진 콘텐츠를 검색하거나, 유사한 비디오 세그먼트를 식별하는 작업이 모두 동일한 임베딩 모델을 통해 가능해집니다.


이 튜토리얼에서는 TwelveLabs의 Marengo 3.0 모델멀티모달 AI를 위한 Pixeltable의 선언적 데이터 인프라를 결합하여 완전한 크로스 모달 비디오 검색 시스템을 구축해 보겠습니다. Pixeltable은 임베딩 계산, 인덱싱, 증분 업데이트의 복잡한 과정을 자동으로 처리하므로, 개발자는 인프라 관리 대신 기능 구현에만 집중할 수 있습니다. 완료하고 나면 최소한의 코드만으로 진정한 멀티모달 비디오 이해를 보여주는 작동하는 시스템을 갖추게 됩니다.


사전 준비 및 설정

크로스 모달 검색 시스템을 빌드하기 전에 Python 3.8 이상이 설치되어 있는지 확인하세요. TwelveLabs API 키가 필요하며, 이는 playground.twelvelabs.io에 가입하여 발급받을 수 있습니다.

먼저 필요한 패키지를 설치합니다:

pip install -qU

그 다음, TwelveLabs API 키를 안전하게 설정합니다. 환경 변수로 지정하거나 대화형으로 입력할 수 있습니다:

import os
import getpass

if 'TWELVELABS_API_KEY' not in os.environ:
    os.environ['TWELVELABS_API_KEY'] = getpass.getpass('Enter your Twelve Labs API key: ')

Pixeltable을 초기화하고 이 프로젝트를 위한 전용 디렉터리를 생성합니다:

import pixeltable as pxt
from pixeltable.functions.twelvelabs import embed

# Create a fresh directory for our video search system
pxt.drop_dir('video_search', force=True)
pxt.create_dir('video_search')

Pixeltable은 이 디렉터리 내에서 데이터 영속성, 버전 관리, 메타데이터 추적을 자동으로 처리합니다.

중요: Twelve Labs는 최적의 임베딩 품질을 위해 오디오 및 비디오 콘텐츠의 길이가 최소 4초 이상이어야 합니다. 비디오 콘텐츠를 준비할 때 이 제약 조건을 염두에 두시기 바랍니다.


핵심 개념: 멀티모달 임베딩

기존의 비디오 검색은 시각적 콘텐츠용, 오디오용, 텍스트용 모델을 각각 따로 두고 이들을 연결하는 복잡한 로직이 필요했습니다. TwelveLabs의 Marengo 모델은 이와 근본적으로 다른 방식으로 접근합니다. 즉, 모든 모달리티가 공존하는 하나의 통합된 시맨틱 공간을 생성합니다.

이 공유 공간에서는 누군가 말하고 있는 비디오 클립, 그 말의 스크립트, 비디오의 스틸 프레임, 그리고 텍스트 설명이 모두 서로 가까운 지점에 매핑됩니다. 덕분에 진정한 크로스 모달 검색이 가능해집니다. 어떤 모달리티로도 쿼리를 던져 원하는 모달리티의 관련 콘텐츠를 찾아낼 수 있습니다.

여러분들이 직접 빌드해 볼 크로스 모달 검색 기능은 다음과 같습니다:

쿼리 유형

사용 사례

텍스트 → 비디오

"연설하는 사람"에 해당하는 클립 찾기

이미지 → 비디오

참조 사진과 시각적으로 유사한 비디오 위치 찾기

오디오 → 비디오

유사한 오디오 특징을 가진 콘텐츠 발견하기

비디오 → 비디오

유사한 클립 또는 동일한 장면의 다른 테이크 식별하기

이 통합된 임베딩 공간이 존재하기에 TwelveLabs와 Pixeltable의 결합이 그토록 강력한 힘을 발휘합니다. 한 번만 구축하면 모든 모달리티에 걸쳐 원활하게 검색할 수 있으니까요.


비디오 검색 시스템 빌드하기

Pixeltable과 TwelveLabs를 활용해 검색 가능한 비디오 인덱스를 생성하는 과정은 단 몇 단계의 선언적 작업만으로 충분합니다. 먼저 비디오를 저장할 테이블을 정의하는 것부터 시작합니다:

from pixeltable.functions.video import splitter

# Create a table for videos
videos = pxt.create_table('video_search.videos', {'video': pxt.Video})

# Insert a sample video
video_url = 'https://github.com/pixeltable/pixeltable/raw/main/docs/resources/The-Pursuit-of-Happiness.mp4'
videos.insert([{'video': video_url}])

다음으로 비디오를 검색 가능한 청크(chunk) 단위로 세분화하는 뷰(view)를 성합니다. 이 부분에서 Pixeltable의 반복자(iterator) 기능이 진가를 발휘합니다:

splitter 반복자는 각 비디오를 5초짜리 세그먼트로 자동 분할하는 동시에, TwelveLabs가 요구하는 최소 기준인 4초 아래로 떨어지는 세그먼트가 없도록 보장합니다. 이 뷰의 각 행은 하나의 비디오 세그먼트를 나타냅니다.

이제 가장 중요한 단계인 임베딩 인덱스 추가입니다:

# Add embedding index for cross-modal search
video_chunks.add_embedding_index(
    'video_segment',
    embedding=embed.using(model_name='marengo3.0')
)

이 한 줄만으로 강력한 자동화가 실행됩니다. Pixeltable은 모든 비디오 세그먼트에 대해 TwelveLabs 임베딩을 계산하고 이 인덱스를 증분 방식으로 유지 관리합니다. 새 비디오를 추가하면 임베딩이 자동으로 계산되므로 수동으로 조율할 필요가 없습니다.

이 선언적 접근 방식의 장점은 처리하는 방법이 아닌, 무엇을 계산할지(비디오 세그먼트의 임베딩)만 지정하면 된다는 것입니다. 일괄 처리, 오류 복구, 캐싱 등 백그라운드의 복잡한 일들은 Pixeltable이 알아서 처리합니다.


크로스 모달 검색 가이드

비디오 인덱스가 빌드되었다면 이제 어떤 모달리티로도 검색을 시작할 수 있습니다. 핵심은 video_segment 열에서 호출하여 재사용 가능한 유사도 표현식을 만드는 similarity() 메서드입니다.


텍스트 기반 비디오 검색 (Text-to-Video)

먼저 텍스트 쿼리에 대한 유사도 표현식을 정의합니다:

# Define similarity to a text query
sim = video_chunks.video_segment.similarity(string='person giving a speech')

# Get the top 3 matching segments
results = video_chunks.order_by(sim, asc=False).limit(3).select(
    video_chunks.video_segment,
    score=sim
)

results.collect()

여기서 sim은 "각 세그먼트와 이 텍스트 문자열 간의 유사도"를 나타내는 표현식이며, 이를 order_by, select 또는 기타 필터에 활용할 수 있습니다.


이미지 기반 비디오 검색 (Image-to-Video)

이미지 쿼리에도 동일한 패턴을 적용합니다:

# Load a reference image
reference_image = pxt.Image('path/to/reference_image.jpg')

# Define similarity to the image
sim_image = video_chunks.video_segment.similarity(image=reference_image)

# Top 3 visually similar segments
results = video_chunks.order_by(sim_image, asc=False).limit(3).select(
    video_chunks.video_segment,
    score=sim_image
)

results.collect()

이를 통해 시각적 콘텐츠가 참조 이미지와 가장 유사한 비디오 세그먼트를 찾아냅니다.


오디오 기반 비디오 검색 (Audio-to-Video)

오디오 클립을 사용해 검색하는 것도 가능합니다:

# Load a reference audio sample
reference_audio = pxt.Audio('path/to/reference_audio.mp3')

# Define similarity to the audio
sim_audio = video_chunks.video_segment.similarity(audio=reference_audio)

# Top 3 segments with similar audio characteristics
results = video_chunks.order_by(sim_audio, asc=False).limit(3).select(
    video_chunks.video_segment,
    score=sim_audio
)

results.collect()

배경 음악, 말하는 스타일 또는 기타 음향적 특징을 매칭시키고자 할 때 매우 유용합니다.


비디오 기반 비디오 검색 (Video-to-Video)

마지막으로 비디오(또는 세그먼트) 자체를 쿼리로 사용해 유사한 클립을 찾을 수 있습니다:

# Use an existing segment as the query
query_segment = (
    video_chunks
        .select(video_chunks.video_segment)
        .limit(1)
        .collect()[0]['video_segment']
)

# Define similarity to the query segment
sim_video = video_chunks.video_segment.similarity(video=query_segment)

# Top 5 similar segments across the library
results = video_chunks.order_by(sim_video, asc=False).limit(5).select(
    video_chunks.video_segment,
    score=sim_video
)

results.collect()

이 기능은 콘텐츠 추천 시스템이나 중복 콘텐츠 탐지, 혹은 유사한 장면의 다른 촬영본(alternative take)을 찾는 데 활용될 수 있습니다.

네 가지 사례 모두 동일한 패턴을 따릅니다. video_segment 열에 similarity() 표현식을 정의한 후, 이 표현식을 order_byselect에 재사용하여 텍스트, 이미지, 오디오, 비디오 쿼리에 가장 잘 맞는 결과를 가져오는 방식입니다.


비디오를 넘어: 멀티모달 데이터 유형의 확장

TwelveLabs 임베딩은 비디오 영역을 넘어 진정한 의미의 멀티모달 애플리케이션을 완성해 줍니다. 동일한 Marengo 모델을 사용해 텍스트 문서, 독립된 이미지, 오디오 파일까지 임베딩 함으로써 서로 다른 유형의 데이터 간 교차 검색이 가능해집니다.

여러 모달리티를 가진 상품 카탈로그 테이블을 만들어 보겠습니다:

# Create a product catalog with text and images
products = pxt.create_table(
    'video_search.products',
    {
        'title': pxt.String,
        'description': pxt.String,
        'thumbnail': pxt.Image
    }
)

# Add computed column combining title and description
products.add_computed_column(
		text_content=products.title + '. ' + products.description,
		if_exists='replace'
)

# Add embedding indices for both text and images
products.add_embedding_index(
    'text_content',
    embedding=embed.using(model_name='marengo3.0')
)

products.add_embedding_index(
    'thumbnail',
    embedding=embed.using(model_name='marengo3.0')
)

이제 멀티모달 카탈로그 검색을 수행합니다:

# Search products using text
text_results = products.select(
    products.title,
    products.thumbnail,
    products.score
).order_by(
    products.score, asc=False
).where(
    products.text_content.sim('outdoor hiking gear') > 0.6
).limit(5)

# Search products using an image
query_image = pxt.Image('path/to/query.jpg')
image_results = products.select(
    products.title,
    products.description,
    products.score
).order_by(
    products.score, asc=False
).where(
    products.thumbnail.sim(query_image) > 0.7
).limit(5)

심지어 비디오 클립으로 제품 카탈로그를 검색하거나, 오디오 샘플과 관련된 상품을 찾는 것까지 가능합니다. 이렇게 하나로 통합된 방식을 활용하면 단 하나의 임베딩 모델로 텍스트 문서, 이미지, 오디오 파일, 비디오 등 애플리케이션 내의 모든 데이터를 커버할 수 있습니다.

이러한 패턴은 스크린샷으로 문서를 검색하거나, 텍스트로 오디오 클립을 찾거나, 비디오 프레임과 유사한 이미지를 찾는 등 다른 시나리오에도 똑같이 적용됩니다. TwelveLabs의 멀티모달 임베딩은 데이터 유형 간 존재하던 한계를 완벽히 허물어 줍니다.


성능 최적화 및 모범 사례

Pixeltable은 임베딩 계산을 알아서 최적화하지만, 다음의 몇 가지 모범 사례를 따르면 프로덕션 환경에서 더욱 뛰어난 성능을 누릴 수 있습니다.

배치 작업(Batch Operations): 비디오를 하나씩 삽입하기보다 여러 개를 한 번에 넣으세요. Pixeltable은 배치로 실행할 때 임베딩을 더 효율적으로 처리합니다.

# Efficient: batch insert
videos.insert([
    {'video': 'url1.mp4'},
    {'video': 'url2.mp4'},
    {'video': 'url3.mp4'}
])

유사도 임계값 조절: 비즈니스가 요구하는 정밀도(precision)와 재현율(recall)에 맞춰 임계값을 조정하세요. 높은 값(0.7~0.9)을 설정하면 개수는 적지만 확실히 관련 있는 결과가 나오고, 낮은 값(0.4~0.6)은 더 넓은 범위를 짚어 줍니다. 보유한 실제 콘텐츠로 적절한 수준을 찾아 보시기 바랍니다.

증분 업데이트: Pixeltable의 계산된 열(computed column)은 새 데이터가 들어올 때 자동으로 갱신됩니다. 임베딩 인덱스도 수동으로 재처리할 필요 없이 최신 상태로 유지되므로, 언제든 비디오를 추가하자마자 바로 검색 엔진에 반영됩니다.

캐싱: Pixeltable은 임베딩 인덱스를 관리하며, 원본 데이터가 변경되지 않는 한 이미 인덱싱이 끝난 유사도 검색에 대해서는 추가적인 API 호출을 발생시키지 않습니다.

에러 핸들링: Pixeltable은 실패한 임베딩 연산을 자동으로 재시도합니다. (제공업체별 속도 제한 가이드는 설정 디테일을 참고하세요.) 더불어 대량의 배치 작업 중 API 호출 제한(rate limit)을 방지할 수 있도록 TwelveLabs API 쿼터를 모니터링해야 합니다.

이러한 실무 팁을 활용하면 지연 시간(latency)을 낮게 유지하면서도 대규모로 유연하게 작동하는 상용 수준의 비디오 검색 시스템을 구축할 수 있습니다.


추가 리소스