튜토리얼

브랜드 통합 어시스턴트 및 광고 구간 탐색기

김미란

이 튜토리얼에서는 Twelve Labs의 Analyze 및 Embed API와 Pinecone을 활용하여 광고 메타데이터 태그를 자동으로 생성하고, 멀티모달 유사성 검색을 통해 문맥에 맞는 비디오 콘텐츠를 찾으며, AI가 생성한 챕터 분할 지점에 중간 광고 삽입을 시뮬레이션하는 '브랜드 통합 어시스턴트 및 광고 위치 찾기(Ad Break Finder) 앱'의 구축 과정을 단계별로 안내합니다.

이 튜토리얼에서는 Twelve Labs의 Analyze 및 Embed API와 Pinecone을 활용하여 광고 메타데이터 태그를 자동으로 생성하고, 멀티모달 유사성 검색을 통해 문맥에 맞는 비디오 콘텐츠를 찾으며, AI가 생성한 챕터 분할 지점에 중간 광고 삽입을 시뮬레이션하는 '브랜드 통합 어시스턴트 및 광고 위치 찾기(Ad Break Finder) 앱'의 구축 과정을 단계별로 안내합니다.

목차

No headings found on page

뉴스레터 구독하기

뉴스레터 구독하기

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

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

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

2025. 7. 14.

12분

링크 복사하기

소개

시청자들은 종종 자신이 보고 있는 콘텐츠와 어울리지 않는 무관한 광고로 인해 피로감을 느낍니다. 이러한 불일치는 불만을 유발하고, 광고가 침입적이거나 타이밍이 맞지 않는다는 인상을 주게 됩니다.

브랜드 통합 어시스턴트 및 광고 시간 탐색기(Brand Integration Assistant & Ad Break Finder) 앱맥락적으로 연관성 높은 광고 추천을 제공하여 이를 해결합니다. 이를 통해 완벽한 참여의 순간에 적합한 오디언스에게 정확한 메시지가 도달하도록 보장합니다.

이 튜토리얼에서는 앱의 주요 기능을 작동해 보며 다음과 같은 방법을 배우게 됩니다:

  • 자동 태그 생성: 업로드된 각 광고를 분석하여 주제 카테고리, 감정, 브랜드, 타겟 인구 통계(성별 및 연령), 위치 등 풍부한 메타데이터를 생성합니다. 이를 통해 스마트한 필터링, 검색, 그리고 콘텐츠 매칭이 가능해집니다.

  • 맥락적으로 정렬된 콘텐츠 검색: AI 기반 유사성 검색을 활용해 비디오 및 텍스트 임베딩을 기반으로 광고와 의미론적으로 정렬된 콘텐츠 비디오를 찾아냅니다.

  • 광고 시간 추천 및 시뮬레이션: 콘텐츠를 자동으로 챕터 단위로 분할하고 미드롤 광고 삽입을 시뮬레이션하여 매끄럽고 몰입감 넘치는 광고 경험을 선사합니다.


사전 준비 단계

  • Twelve Labs Playground에 가입하고 API 키를 생성한 후, 광고와 콘텐츠 비디오를 위한 전용 인덱스를 각각 하나씩 총 두 개 생성합니다. 

  • Pinecone 계정을 설정하고 비디오 임베딩을 저장할 인덱스를 생성합니다.

    • Dimensions1024로, MetricCosine으로 설정해야 합니다.

  • 제공된 GitHub 리포지토리에서 애플리케이션의 소스 코드를 확인하세요.

  • 더 원활한 빌드 및 개발 경험을 위해 JavaScript, TypeScript 및 Next.js에 익숙하면 큰 도움이 됩니다.


데모

직접 체험해 보려면 데모 애플리케이션을 확인하거나, 아래의 간단한 데모 비디오를 통해 실제 작동 방식을 간편하게 살펴보세요: https://www.loom.com/share/233cc8cb66ae44218e3cff69afb772d7

전체 데모가 포함된 웨비나 녹화본은 아래에서 시청하실 수 있습니다:


앱 작동 방식  

앱을 실행하면 두 가지 기본 메뉴인 Ads Library(광고 라이브러리)Contextual Alignment Analysis(맥락적 정렬 분석)를 확인할 수 있습니다.

Ads Library (광고 라이브러리) - 브랜드 마케터에게 자동으로 생성된 태그가 풍부하게 포함된 광고 비디오들의 체계적인 뷰를 제공합니다. 사용자는 Twelve Labs Search API를 사용해 주제 카테고리, 감정, 브랜드, 성별, 연령, 위치별로 광고를 필터링하거나 단일 키워드 및 시퀀스 키워드로 검색할 수 있습니다. 이 튜토리얼에서는 광고 라이브러리의 자동 태그 생성 기능에 집중해 다룹니다.

Contextual Alignment Analysis (맥락적 정렬 분석) - 이 섹션에서는 사용자가 각 광고에 대해 가장 맥락적으로 연관성 높은 콘텐츠 비디오를 찾을 수 있도록 지원합니다. 태그 및 비디오 임베딩을 위한 Twelve Labs EMBED 및 GET 비디오 API와 유사성 기반 필터링을 지원하는 Pinecone의 기술력을 바탕으로, 고도로 정렬된 콘텐츠를 표면 위로 도출합니다.

그 다음 사용자는 콘텐츠 비디오를 선택하고, 광고 시간 삽입을 위한 자동 챕터를 생성한 뒤, 챕터가 전환되는 시점에서 광고 재생을 시뮬레이션할 수 있습니다.

이어지는 튜토리얼을 통해 콘텐츠 매칭과 광고 시뮬레이션 기능 모두를 자세히 살펴보겠습니다.


앱의 세 가지 핵심 기능과 작동 원리


핵심 기능 1. 자동 태그 생성 (‘Ads Library’ 메뉴)

광고 라이브러리(Ads Library)에서 사용자는 인덱싱된 비디오 컬렉션을 탐색하고 자동으로 생성된 태그를 확인할 수 있습니다. 이 태그들은 Twelve Labs의 Analyze API를 통해 추출되며, 비디오를 소주제, 감정, 브랜드, 인구 통계학적 특성 등으로 정확하게 분류해 줍니다.


1단계 - 각 비디오의 태그 생성

비디오를 불러왔을 때 메타데이터가 불완전하거나 누락된 것으로 판단되면, 시스템은 Twelve Labs의 Analyze API를 활용해 태그를 가져오는 generateMetadata를 호출합니다.

⭐️ Twelve Labs의 Analyze API에 대한 자세한 내용은 여기에서 확인하세요.

🔁 사용 대상 및 위치

이 호출은 page.tsx의 processVideoMetadataSingle 내부에서 다음과 같이 구현되어 있습니다:

ads-library/page.ts (279-290행)

     if (!video.user_metadata ||
         Object.keys(video.user_metadata).length === 0 ||
          !video.user_metadata.topic_category &&
          !video.user_metadata.emotions && 
          !video.user_metadata.brands &&
          !video.user_metadata.locations)) {


       setVideosInProcessing(prev => [...prev, videoId]);


       const hashtagText = await generateMetadata(videoId);


       if (hashtagText) {
         const metadata = parseHashtags(hashtagText);

generateMetadata 함수는 Twelve Labs 엔진에 AI 생성 태그를 요청하기 위해 서버 사이드 API 호출을 실행하는 커스텀 훅입니다.

이는 api/analyze/route.ts 내부의 백엔드 핸들러를 실행하며, Twelve Labs Analyze API에 맞게 구조적이고 구체적인 프롬프트를 구성합니다. 임포팅된 이 프롬프트는 반환되는 데이터가 명확하게 카테고리화되고 일관된 형식으로 정렬되도록 보장하여, 간편하게 태그로 변환하고 필터 메뉴(Filter Menu)에 렌더링할 수 있도록 돕습니다. 백엔드 라우트의 핵심 로직은 다음과 같습니다:

api/analyze/route.ts (1 - 85행)

import { NextResponse } from 'next/server';


const API_KEY = process.env.TWELVELABS_API_KEY;
const TWELVELABS_API_BASE_URL = process.env.TWELVELABS_API_BASE_URL;


export const maxDuration = 60;


export async function GET(req: Request) {
   const { searchParams } = new URL(req.url);
   const videoId = searchParams.get("videoId");
   const prompt =
   `You are a marketing assistant specialized in generating hashtags for video content.


Based on the input video metadata, generate a list of hashtags labeled by category.


**Output Format:**
Each line must be in the format:
[Category]: [Hashtag]
(e.g., sector: #beauty)




**Allowed Values:**


Gender: Male, Female
Age: 18-25, 25-34, 35-44, 45-54, 55+
Topic: Beauty, Fashion, Tech, Travel, CPG, Food & Bev, Retail, Other
Emotions: sorrow, happiness, laughter, anger, empathy, fear, love, trust, sadness, belonging, guilt, compassion, pride


**Instructions:**


1. Use only the values provided in Allowed Values.
2. Do not invent new values except for Brands and Location. Only use values from the Allowed Values.
3. Output must contain at least one hashtag for each of the following categories:
 - Gender
 - Age
 - Topic
 - Emotions
 - Location
 - Brands


4. Do not output any explanations or category names—only return the final hashtag list.


**Output Example:**


Gender: female
Age: 25-34
Topic: beauty
Emotions: happiness
Location: Los Angeles
Brands: Fenty Beauty


---
`


  


   const url = `${TWELVELABS_API_BASE_URL}/analyze`;
   const options = {
       method: "POST",
       headers: {
           "Content-Type": "application/json",
           "x-api-key": API_KEY,
       },
       body: JSON.stringify({
           prompt: prompt,
           video_id: videoId,
           stream: false
       })
   };


   try {
     const response = await fetch(url, options);

2단계 - 생성된 태그를 저장하기 위해 각 비디오에 PUT 실행

/api/analyze 라우트를 사용해 태그가 생성되고 나면, 다음 단계는 이를 인덱싱된 라이브러리 내부의 해당 비디오 객체에 다시 저장하는 것입니다. 이는 Twelve Labs 인덱스 내 비디오의 메타데이터를 업데이트하는 PUT API 호출을 통해 진행됩니다.

⭐️ Twelve Labs의 Update Video Information API에 대한 자세한 정보는 여기를 참고해 주세요.

이 작업은 api/videos/metadata/route.ts에 위치한 백엔드 라우트를 동작시키는 updateVideoMetadata 훅에 의해 핸들링됩니다.

❗️커스텀 메타데이터를 저장할 때는 각 비디오를 업데이트할 때 키 명칭으로 user_metadata를 사용하고 있는지 필히 확인하십시오.

api/videos/metadata/route.ts (1-68행)

import { NextRequest, NextResponse } from 'next/server';



export async function PUT(request: NextRequest) {
 try {
   // Parse request body
   const body: MetadataUpdateRequest = await request.json();
   const { videoId, indexId, metadata } = body;
  


   // Prepare API request
   const url = `${TWELVELABS_API_BASE_URL}/indexes/${indexId}/videos/${videoId}`;


   const requestBody = {
     user_metadata: {
       source: metadata.source || '',
       sector: metadata.sector || '',
       emotions: metadata.emotions || '',
       brands: metadata.brands || '',
       locations: metadata.locations || '',
       demographics: metadata.demographics || ''
     }
   };


   const options = {
     method: 'PUT',
     headers: {
       'Content-Type': 'application/json',
       'x-api-key': API_KEY,
     },
     body: JSON.stringify(requestBody)
   };


   // Call Twelve Labs API
   const response = await fetch(url, options);


🔁 사용 대상 및 위치

이 호출은 page.tsxprocessVideoMetadataSingle 내부에 있으며, 다음과 같은 형태로 명시되어 있습니다:

ads-library/page.tsx (289-292행)

 if (hashtagText) {
         const metadata = parseHashtags(hashtagText);


         await updateVideoMetadata(videoId, adsIndexId, metadata);

📌 user_metadata 안에는 무엇이 포함되나요?

저장된 user_metadata 객체는 아래와 같은 키 필드로 정렬됩니다:

{
  "gender": "female",
  "age": "25-34",
  "topic": "beauty",
  "emotions": "happiness",
  "location": "Los Angeles",
  "brands": "Fenty Beauty"

이처럼 일관된 형식은 대시보드 내 카테고리별 필터 UX 제공, 비디오 검색 및 시각적 그룹화를 가능케 합니다. 이 커스텀 메타데이터들은 이제 Twelve Labs에서 검색해 오는 비디오 자체에 완벽히 내장되므로, 단순히 GET 요청을 통해 해당 비디오를 로드하여 필요에 맞게 렌더링하고 사용하면 됩니다.

⭐️ Twelve Labs의 Retrieve Video Information API에 대한 자세한 정보는 여기를 눌러 확인하세요.


핵심 기능 2. 유사 비디오 검색 (‘Contextual Alignment Analysis’ 메뉴)

Contextual Alignment Analysis(맥락적 정렬 분석) 기능은 비디오 및 텍스트 임베딩을 정교하게 비교하여 사용자가 선택한 광고와 최고의 타겟 연관성을 갖는 콘텐츠 비디오를 선별해 냅니다. 이 임베딩 기술은:

  • Twelve Labs에 의해 개발 및 생성됩니다.

  • 유사성 검색을 위해 Pinecone을 거쳐 영구 보관되며 쿼리 처리됩니다.

이 기술이 설계 의도대로 완벽히 작동하기 위해 다음 조치들이 먼저 확보되어야 합니다:

  • 모든 콘텐츠 비디오에 대한 백터 임베딩이 미리 존재해야 합니다.

  • 선택한 해당 광고 비디오에 대한 백터 임베딩 역시 사전에 존재해야 합니다.

  • 모든 임베딩은 최종적으로 동일한 단일 Pinecone 인덱스 내에 안전하게 정제 및 저장되어야 합니다.

❗️Twelve Labs 솔루션을 활용해 특정 비디오를 정상 인덱싱하면 임베딩 벡터가 자동 생성되며, Retrieve Video Information API 호출을 활용해 이를 즉시 불러올 수 있게 됩니다.


1단계 - 콘텐츠 비디오 임베딩 업로드 및 가동 프로세스

실시간 유사성 벡터 매칭을 실행하기 전, 분석 풀 내 모든 콘텐츠 비디오들의 임베딩이 Pinecone 인덱스 내에 안전하게 축적 완료되어 있어야 합니다. 이 선행 처리는 클라이언트 사이드 함수인 processContentVideoEmbeddings()를 통해 흐름이 이어집니다.

💡 내부 구동 플로우

🔧 핵심 시스템 함수 리스트

checkVectorExists 비디오 전용 임베딩 성분(벡터)이 이미 Pinecone 스토리지 내에 캐싱되어 있는지 교차 확인합니다. 내부적으로 프로젝트 백엔드 라우터 쪽 통신을 처리합니다.

api/vectors/exists (15-27행)

   // Fetch vectors using metadata filter instead of direct ID
   const queryResponse = await index.query({
     vector: new Array(1024).fill(0),
     filter: {
       tl_video_id: videoId
     },
     topK: 1,
     includeMetadata: true
   });


   return NextResponse.json({
     exists: queryResponse.matches.length > 0
   });

벡터 임베딩 값을 사전에 찾지 못했을 경우, getAndStoreEmbeddings가 작동을 시작합니다:

  1. Twelve Labs에서 대상 임베딩 벡터를 고속 로드합니다 (/api/videos/[videoId]?embed=true)

  2. 이를 /api/vectors/store 라우트를 경유해 Pinecone에 완전히 반영(업서트)합니다.

api/videos/[videoId] (77-95행)

// Base URL
 let url = `${TWELVELABS_API_BASE_URL}/indexes/${indexId}/videos/${videoId}`;


 // Always include embedding query parameters if requested
 if (requestEmbeddings) {
   // Include only supported embedding options
   url += `?embedding_option=visual-text&embedding_option=audio`;
 }


 const options = {
   method: "GET",
   headers: {
     "x-api-key": `${API_KEY}`,
     "Accept": "application/json"
   },
 };


 try {
   const response = await fetch(url, options);

api/vectors/store (126-173행)

// Create vectors from embedding segments
   const vectors = embedding.video_embedding.segments.map((segment: Segment, index: number) => {
     // Create a meaningful and unique vector ID
     const vectorId = `${vectorIdBase}_segment${index + 1}`;


     const vector = {
       id: vectorId,
       values: segment.float,
       metadata: {
         video_file: actualFileName,
         video_title: videoTitle,
         video_segment: index + 1,
         start_time: segment.start_offset_sec,
         end_time: segment.end_offset_sec,
         scope: segment.embedding_scope,
         tl_video_id: videoId,
         tl_index_id: indexId,
         category
       }
     };


     return vector;
   });


   try {
     const index = getPineconeIndex();


     // Upload vectors in batches
     const batchSize = 100;
     const totalBatches = Math.ceil(vectors.length / batchSize);


     console.log(`🚀 FILENAME DEBUG - Starting vector upload with ${totalBatches} batches...`);


     for (let i = 0; i < vectors.length; i += batchSize) {
       const batch = vectors.slice(i, i + batchSize);
       const batchNumber = Math.floor(i / batchSize) + 1;


       try {
         // Test Pinecone connection before upserting
         try {
           await index.describeIndexStats();
         } catch (statsError) {
           console.error(`❌ Pinecone connection test failed:`, statsError);
           throw new Error(`Failed to connect to Pinecone: ${statsError instanceof Error ? statsError.message : 'Unknown error'}`);
         }


         // Perform the actual upsert
         await index.upsert(batch);


2단계 - 선택한 특정 광고 비디오에 대한 임베딩 체크 및 생성

마케터가 단일 광고를 마우스로 지정하면 애플리케이션 프론트엔드는 해당 벡터가 준비된 상태인지 자동 식별을 수행합니다. 이 제어는 타겟 비디오 정보를 리스닝 중이던 useEffect() 훅을 통해 동작하게 됩니다:

contextual-analysis/page.tsx (296-318행)

// Automatically check ONLY the ad video embedding when a video is selected
 useEffect(() => {
   if (selectedVideoId && !isLoadingEmbeddings) {
     const cachedStatus = queryClient.getQueryData(['embeddingStatus', selectedVideoId]) as
       { checked: boolean, ready: boolean } | undefined;


     if (!cachedStatus?.checked) {
       setIsLoadingEmbeddings(true);


       ensureEmbeddings().then(success => {
         queryClient.setQueryData(['embeddingStatus', selectedVideoId], {
           checked: true,
           ready: success
         });


         setEmbeddingsReady(success);
         setIsLoadingEmbeddings(false);
       });
     } else {
       setEmbeddingsReady(cachedStatus.ready);
     }
   }
 }, [selectedVideoId, isLoadingEmbeddings, queryClient]);

🔧 핵심 시스템 함수 리스트

ensureEmbeddings는 다음 내부 연산을 위해 checkAndEnsureEmbeddings() 를 즉시 사용합니다:

  • 특정 대상 광고의 가용 전용 비디오 임베딩 여부를 checkVectorExists 호출로 안전하게 검증합니다

  • 발견하지 못했을 경우 getAndStoreEmbeddings 방식을 호출해 타겟 인덱스에 새롭게 기입합니다

  • 필요 시, 동일 로직 스레드에서 모든 내부 콘텐츠 비디오들을 백그라운드로 동시 로드하여 처리하게 할 수 있습니다

❗️checkVectorExists() 및 getAndStoreEmbeddings()의 상세한 구현 형태 및 동작 과정은 앞서 1단계에서 한 차례 안내하였으므로 중복 기술하지 않고 생략합니다.


3단계 - Pinecone 내 유사성 벡터 매칭 및 Twelve Labs 서칭 프로세스 

마침내 모든 비디오 소스(광고 비디오 및 일반 비디오)의 다차원 벡터가 무사히 업로드 완료된 후 사용자가 "Run Contextual Analysis" 버튼을 실행하면, 백그라운드 엔진은 실시간 시너지 효과를 위해 아래의 두 병렬 서칭 모델을 상호 유기적으로 가동시킵니다:

  • 텍스트 기반 비디오 맥락 분석 (Text-to-Video Search): 추출 완료된 마케팅 **텍스트 메타 태그** 정보 (예시: 소속 브랜드 분야 및 내재된 인물 표정 감정 상태) 등을 타겟 질의어로 치환 및 가공 연산하여 의미론적으로 완벽히 융합되는 매칭 영상들을 Pinecone 컬렉션 중에서 우선순위로 선별해 냅니다.

  •  이미지 프레임 기반 비디오 교차 매칭 (Video-to-Video Search): 영상의 흐름에 포함된 **미세 구간 프레임 임베딩 벡터 데이터**를 활용해 대상 광고와 비주얼적 및 분위기 측면에서 놀라운 비주얼 맥락 매칭을 이루는 세부 일반 영상 클립들을 찾아내 줍니다.

  • 이 두 단계를 거쳐 수집된 후보 결과들은 **정교한 가중치 합산 연산 모델**을 거치며 정렬 품질이 더욱 고도화됩니다. 양방향 정렬 조건에 다각도로 걸러진 최상위 후보들은 매칭 리스트 순위 구조에서 매우 확실한 상위 우선 지위를 부여받게 됩니다.

텍스트 기반 비디오 맥락 분석 (Text-to-Video Search)

contextual-analysis/page.tsx (351-384행)

const handleContextualAnalysis = async () => {
  
     try {
       textResults = await textToVideoEmbeddingSearch(selectedVideoId, adsIndexId, contentIndexId);
      
     try {
       videoResults = await videoToVideoEmbeddingSearch(selectedVideoId, adsIndexId, contentIndexId);

textToVideoEmbeddingSearch는 지목된 타겟 광고 정보 및 타이틀로부터 광고 분야 특성 세부 카테고리와 구체적인 감정 상태(Emotions) 태그를 정확히 정제하고 확보합니다.

  • 정밀 선별 단계에 필요한 키워드를 api/embeddingSearch/textToVideo에 인포트 처리합니다.

  • Twelve Labs 엔진은 가공 처리된 고차원 텍스트 전용 특성 임베딩 벡터를 신속 조립 후 매칭 후보인 Pinecone 비디오 데이터베이스 내에서 일품 맥락 매칭 비디오 콘텐츠들을 대거 선별하여 전송합니다.

api/embeddingSearch/textToVideo (20-45행)

const { data: embedData } = await axios.post(url, formData, {
    // extract embedding vector from text_embedding object
   const textEmbedding = embedData.text_embedding.segments[0].float;

   // Get index and search
   const searchResults = await index.query({
     vector: textEmbedding,
     filter: {
       // video_type: 'ad',
       tl_index_id: indexId,
       scope: 'clip'
     },
     topK: 10,
     includeMetadata: true,
   });

이미지 프레임 기반 비디오 교차 매칭 (Video-to-Video Search)

videoToVideoEmbeddingSearch는 사전에 지정된 해당 타켓형 키 디바이스 광고의 유효 미세 구간(세그먼트 벡터값)을 직접 역추적하여 선별합니다.

  • 수집 완료된 고해상 세그먼트 백터 단위 정보를 Pinecone 콘텐츠 비딩 인덱싱 스레드와 직접 교차 매칭하며 분석합니다.

  • 추출 성사된 각 요소들은 정렬 타당성이 매우 높은 양방향 비디오 임베딩 값들을 대표하는 증거가 되어 줍니다.

api/embeddingSearch/videoToVideo (22-50행)

// First, get the original video's clip embedding
   const originalClipQuery = await index.query({
     filter: {
       tl_video_id: videoId,
       scope: 'clip'
     },
     topK: 100,
     includeMetadata: true,
     includeValues: true,
     vector: new Array(1024).fill(0)
   });


   // If we found matching clips, search for similar ads for each match
   const similarResults = [];
   if (originalClipQuery.matches.length > 0) {
     for (const originalClip of originalClipQuery.matches) {
       const vectorValues = originalClip.values || new Array(1024).fill(0);
       const queryResult = await index.query({
         vector: vectorValues,
         filter: {
           tl_index_id: indexId,
           scope: 'clip'
         },
         topK: 5,
         includeMetadata: true,
       });
       similarResults.push(queryResult);
     }
   }

결과 데이터셋 크로싱 결합

스레드별 추출물들은 일차적으로 타겟 비디오 ID를 매개변수 삼아 한 곳에 바인딩됩니다. 우수한 신뢰성을 보이며 두 영역에 공통 출현한 콘텐츠는 최종 분석 단계에서 스코어를 2배 보정 처리(부스팅)해 가산합니다.

contextual-analysis/page.tsx (412-428행)

 if (combinedResultsMap.has(videoId)) {
           // This is a match found in both searches - update it
           const existingResult = combinedResultsMap.get(videoId);


           // Apply a significant boost for results found in both searches (50% boost)
           const boostMultiplier = 2;


           // Combine the scores: use the max of both scores and apply the boost
           const maxScore = Math.max(existingResult.textScore, result.score);
           const boostedScore = maxScore * boostMultiplier;


           combinedResultsMap.set(videoId, {
             ...existingResult,
             videoScore: result.score,
             finalScore: boostedScore,  // Boosted score for appearing in both searches
             source: "BOTH"
           });

핵심 기능 3. 챕터 나누기 및 똑똑한 광고 시간 자동 정렬 시뮬레이션 (‘Contextual Alignment Analysis’ 메뉴)

이 핵심 영역은 단순히 비디오를 일차원적으로 연동 및 매칭하는 것을 넘어 일반 가용 영상을 지능적인 단위 **챕터군**으로 자동 구획화한 후, 챕터 세그먼트 끝단에 자연스럽게 선택 광고를 안착시킵니다. 즉 실제 미디어 플랫폼에서 운용하는 실시간 중간 광고 서비스 경험을 그대로 시물레이션 구현하여 비디오 비즈니스의 부가적 가치 창출을 풍부히 대변해 줍니다.


1단계 - 지능형 자동 비디오 챕터 생성 작업

운영자가 비디오 상세 뷰어 프레임인 VideoModal을 화면에 로드하는 즉시, 핵심 코드는 Twelve Labs 플랫폼이 가진 최적의 성능을 끌어오기 위해 내부적으로 generateChapters API를 작동시켜 콘텐츠 파트를 분절합니다.

videoModal.tsx (42-47행)

 // Fetch chapters data
 const { data: chaptersData, isLoading: isChaptersLoading } = useQuery({
   queryKey: ["chapters", videoId],
   queryFn: () => generateChapters(videoId),
   enabled: isOpen && !!videoId,
 });

반환된 각 챕터 데이터 안에는 아래의 유용한 세부 메트릭이 수반됩니다:

  • end: 해당 분절의 마침 정보 필드값 (광고 큐 시점이자 삽입 트리거 포인트역할을 담당합니다)

  • chapter_title: 가독성에 맞춰 깔끔하게 자동 명명된 챕터 헤더 타이틀입니다

  • chapter_summary: 해당 특정 씬이 미장센 흐름상 또는 스토리 맥락상 마케팅 광고를 걸어 넣기에 왜 이상적인 구간인지에 대한 AI 기반의 세련된 논리적 해설(한 문장 정리)을 제시해 줍니다

이처럼 자동 구성된 지능형 챕터 정보들은 웹 런타임 뷰 내부의 **챕터 시간 타임라인 바**에 작은 점 형태의 end 인디케이터로 부드럽게 시각화됩니다. 이 타임라인 상의 미세 점을 원클릭 지목 및 제어하면, **마치 해당 영상 중간이 자연스럽게 막간 전개를 맺듯이 바로 이어서 광고를 연출**하는 식의 흐름을 시뮬레이션할 수 있습니다.

사용자 인터랙션(UX) 흐름에 따른 구체적 변화 양상:

  • 챕터가 종료되는 최접점에 예쁜 매핑 인디케이터 도트(Dot) 포인트가 배열 정렬됩니다.

  • 화면 상 도트 포인트를 사용자가 누르면 설정된 큐포인트에서 지체없이 "Show Ad" 오버레이 마스크가 자연스럽게 작동합니다.

  • 재생되는 지정 광고는 스킵 기능을 충실히 수용 가능하여 현실 유동 상황과 일치하는 미드롤 스트리밍을 제공합니다.

서버 사이드 내부 아키텍처: Twelve Labs 기능을 통한 요약 정보 챕터 생성

정제되고 깔끔한 챕터 도메인 구성 처리를 성사시키기 위해, 이 과정은 Twelve Labs 플랫폼이 자랑하는 고유의 요약(Summarize) 전용 엔드포인트 기능을 활용하며 동시에 다음과 같이 최적화된 프롬프트 구문을 빌려 사용합니다.

api/generateChapters (19-30행)

 const url = `${TWELVELABS_API_BASE_URL}/summarize`;
     const options = {
         method: "POST",
         headers: {
             "Content-Type": "application/json",
             "x-api-key": `${API_KEY}`,
           },
           body: JSON.stringify({type: "chapter", video_id: videoId, prompt: "Chapterize this video into 3 chapters. For every chapter, describe why it is a strategically appropriate point for placing an advertisement. Do not mention what type of advertisement would be suitable, as the ad content has already been determined. "})
       };


     try {
       const response = await fetch(url, options);

클라이언트 사이드 전처리 함수: generateChapters

이 함수는 React Query와 결합되어 실시간 챕터 데이터 조회를 유기적으로 성사시키고 연소 지원합니다:

apiHooks.tsx (981-984행)

export const generateChapters = async (videoId: string): Promise<ChaptersData> => {
 try {
   const response = await fetch(`/api/generateChapters?videoId=${videoId}`);


2단계 - 사용자가 특정 챕터 선택 시 중간 광고 실행 및 자연스러운 흐름 처리

마케터가 화면의 특정 챕터 마크업을 트리거하는 순간 백그라운드에서는 다음과 같은 단계적 흐름이 실행됩니다:

  1. 플레이어 타임 바가 활성화되며, 즉시 해당 선택 챕터의 공식 완결 시점이 도래하기 정확히 3초 전으로 플레이 재생바 헤드를 미끄러지듯 이동(Seek)시킵니다.

  2. 이후 재생 흐름이 실제 임계 완결 시점에 도달하자마자, 본 영상은 정지하고 곧바로 정해진 **광고 연속 재생 사이클**로 넘어가게 됩니다.

  3. 매칭 전용 광고 출현 분량이 마무리된 후에는, 원래 재생 중이던 메인 영상 파트로 매끄럽게 되돌아와 광고 전환이 연출되었던 직후 시간 축부터 재생을 자연스럽게 이어갑니다.

인디케이터 점 포인트 원터치 클릭 연산 제어

가시적이고 명시적인 중간 미드롤 광고 시뮬레이션을 원활히 작동시키기 위해, 타임라인을 나타내는 미세 도트 선택 이벤트 수신 시점에서의 플레이 시점 조정 단계는 다음과 같이 명확히 처리 구체화되어 있습니다.

VideoModal.tsx (102-126행)

 // Chapter click handler
 const handleChapterClick = (index: number) => {
   if (playbackSequence === 'ad') {
     return;
   }


   if (!adVideoDetail?.hls?.video_url) {
     console.warn("No ad selected. Please select an ad in the contextual analysis page.");
     return;
   }


   if (!chaptersData) return;


   const chapter = chaptersData.chapters[index];
   setSelectedChapter(index);
   setHasPlayedAd(false);
   setPlaybackSequence('video');
   setShowChapterInfo(true);


   if (playerRef.current) {
     // Start 3 seconds before the chapter end time
     const startTime = Math.max(0, chapter.end - 3);
     playerRef.current.seekTo(startTime, 'seconds');
   }
 };

재생 시점 모니터링 – 도트 도달 순간 광고 전환 실행

영상 콘텐츠의 스트리밍이 일정 속도로 흐르는 동안, 코드는 매 순간 재생 헤더 도달 포인트를 역계산하며 타겟 챕터 연산 종료 좌표에 이르렀다고 인정되는 최상의 전환 타이밍 조건을 충족하는 즉시 광고 재생 레이어로 화면을 넘겨 줍니다.

VideoModal.tsx (82-100행)

 // Track video progress
 const handleProgress = (state: { playedSeconds: number }) => {
   if (selectedChapter === null || !chaptersData || !adVideoDetail) {
     return;
   }


   const chapter = chaptersData.chapters[selectedChapter];
   const timeDiff = state.playedSeconds - chapter.end;
   const isLastChapter = selectedChapter === chaptersData.chapters.length - 1;


   if (
     playbackSequence === 'video' &&
     !hasPlayedAd &&
     ((isLastChapter && Math.abs(timeDiff) < 0.5) || (!isLastChapter && timeDiff >= 0))
   ) {
     setPlaybackSequence('ad');
     setHasPlayedAd(true);
   }
 };

지정 광고 종료 후 자연스러운 원래 본편 복귀 처리

영상이 끝난 바로 수 밀리초 이후, 시스템 흐름은 광고 타임라인에 머물러 있던 미디어 영역을 다시 원래의 라이브 챕터 잔여 구간으로 자동 원복시킵니다.

VideoModal.tsx (128-136행)

 // Ad ended handler
 const handleAdEnded = () => {
   if (selectedChapter === null || !chaptersData) return;
   const chapter = chaptersData.chapters[selectedChapter];
   setPlaybackSequence('video');
   setReturnToTime(chapter.end);
   setIsPlaying(true);
 };

이 기술은 일반 영상을 유연하게 단락 지으며 자연스럽게 가치 있는 지성적 중간 맞춤 전단 광고를 적재적소에 올릴 수 있는 지름길이 되어 줍니다. 콘텐츠 소스의 전개가 끊어지지 않는 완벽한 정서적 휴지기를 교묘히 활용함으로써 극강의 **지능형 맥락 부합 타깃 광고** 연출을 실현하고 비즈니스 부가 성과를 실증합니다.


맺음말

이 튜토리얼을 통해 고성능 맥락적 동영상 분석(Contextual Analysis)의 전진기지가 되어 줄 멋진 여정을 완수하였습니다. Twelve Labs 고유의 풍성한 멀티모달 프레임워크 임베딩 데이터 생성 및 적재, Pinecone 백터 파티셔닝 기술을 통한 고도의 유사 정보 병렬 선별, 그리고 결과물을 요리하듯 다듬어 챕터 구획 단위 끝자락에 안착시키는 시뮬레이션 모델까지 전 과정을 깊이 있게 탐색해 보았습니다. Twelve Labs가 제시하는 다차원 입체 멀티모달 임베딩 방식과 Pinecone의 속도감 있는 벡터 연산 필터 구조를 세심히 응용하면, 혁신적 수준의 미묘한 맥락 타기팅 경험을 실현할 수 있습니다. 이 단단히 구축된 연동 아키텍처 토대는, 빅데이터 수준의 실시간 초정밀 타기팅 연산, 자동화 A/B 마케팅 스플릿 전개, 더 나아가 초대형 고도화 비디오 비즈니스 서비스 라인업으로도 웅장하게 확장될 수 있습니다.

소개

시청자들은 종종 자신이 보고 있는 콘텐츠와 어울리지 않는 무관한 광고로 인해 피로감을 느낍니다. 이러한 불일치는 불만을 유발하고, 광고가 침입적이거나 타이밍이 맞지 않는다는 인상을 주게 됩니다.

브랜드 통합 어시스턴트 및 광고 시간 탐색기(Brand Integration Assistant & Ad Break Finder) 앱맥락적으로 연관성 높은 광고 추천을 제공하여 이를 해결합니다. 이를 통해 완벽한 참여의 순간에 적합한 오디언스에게 정확한 메시지가 도달하도록 보장합니다.

이 튜토리얼에서는 앱의 주요 기능을 작동해 보며 다음과 같은 방법을 배우게 됩니다:

  • 자동 태그 생성: 업로드된 각 광고를 분석하여 주제 카테고리, 감정, 브랜드, 타겟 인구 통계(성별 및 연령), 위치 등 풍부한 메타데이터를 생성합니다. 이를 통해 스마트한 필터링, 검색, 그리고 콘텐츠 매칭이 가능해집니다.

  • 맥락적으로 정렬된 콘텐츠 검색: AI 기반 유사성 검색을 활용해 비디오 및 텍스트 임베딩을 기반으로 광고와 의미론적으로 정렬된 콘텐츠 비디오를 찾아냅니다.

  • 광고 시간 추천 및 시뮬레이션: 콘텐츠를 자동으로 챕터 단위로 분할하고 미드롤 광고 삽입을 시뮬레이션하여 매끄럽고 몰입감 넘치는 광고 경험을 선사합니다.


사전 준비 단계

  • Twelve Labs Playground에 가입하고 API 키를 생성한 후, 광고와 콘텐츠 비디오를 위한 전용 인덱스를 각각 하나씩 총 두 개 생성합니다. 

  • Pinecone 계정을 설정하고 비디오 임베딩을 저장할 인덱스를 생성합니다.

    • Dimensions1024로, MetricCosine으로 설정해야 합니다.

  • 제공된 GitHub 리포지토리에서 애플리케이션의 소스 코드를 확인하세요.

  • 더 원활한 빌드 및 개발 경험을 위해 JavaScript, TypeScript 및 Next.js에 익숙하면 큰 도움이 됩니다.


데모

직접 체험해 보려면 데모 애플리케이션을 확인하거나, 아래의 간단한 데모 비디오를 통해 실제 작동 방식을 간편하게 살펴보세요: https://www.loom.com/share/233cc8cb66ae44218e3cff69afb772d7

전체 데모가 포함된 웨비나 녹화본은 아래에서 시청하실 수 있습니다:


앱 작동 방식  

앱을 실행하면 두 가지 기본 메뉴인 Ads Library(광고 라이브러리)Contextual Alignment Analysis(맥락적 정렬 분석)를 확인할 수 있습니다.

Ads Library (광고 라이브러리) - 브랜드 마케터에게 자동으로 생성된 태그가 풍부하게 포함된 광고 비디오들의 체계적인 뷰를 제공합니다. 사용자는 Twelve Labs Search API를 사용해 주제 카테고리, 감정, 브랜드, 성별, 연령, 위치별로 광고를 필터링하거나 단일 키워드 및 시퀀스 키워드로 검색할 수 있습니다. 이 튜토리얼에서는 광고 라이브러리의 자동 태그 생성 기능에 집중해 다룹니다.

Contextual Alignment Analysis (맥락적 정렬 분석) - 이 섹션에서는 사용자가 각 광고에 대해 가장 맥락적으로 연관성 높은 콘텐츠 비디오를 찾을 수 있도록 지원합니다. 태그 및 비디오 임베딩을 위한 Twelve Labs EMBED 및 GET 비디오 API와 유사성 기반 필터링을 지원하는 Pinecone의 기술력을 바탕으로, 고도로 정렬된 콘텐츠를 표면 위로 도출합니다.

그 다음 사용자는 콘텐츠 비디오를 선택하고, 광고 시간 삽입을 위한 자동 챕터를 생성한 뒤, 챕터가 전환되는 시점에서 광고 재생을 시뮬레이션할 수 있습니다.

이어지는 튜토리얼을 통해 콘텐츠 매칭과 광고 시뮬레이션 기능 모두를 자세히 살펴보겠습니다.


앱의 세 가지 핵심 기능과 작동 원리


핵심 기능 1. 자동 태그 생성 (‘Ads Library’ 메뉴)

광고 라이브러리(Ads Library)에서 사용자는 인덱싱된 비디오 컬렉션을 탐색하고 자동으로 생성된 태그를 확인할 수 있습니다. 이 태그들은 Twelve Labs의 Analyze API를 통해 추출되며, 비디오를 소주제, 감정, 브랜드, 인구 통계학적 특성 등으로 정확하게 분류해 줍니다.


1단계 - 각 비디오의 태그 생성

비디오를 불러왔을 때 메타데이터가 불완전하거나 누락된 것으로 판단되면, 시스템은 Twelve Labs의 Analyze API를 활용해 태그를 가져오는 generateMetadata를 호출합니다.

⭐️ Twelve Labs의 Analyze API에 대한 자세한 내용은 여기에서 확인하세요.

🔁 사용 대상 및 위치

이 호출은 page.tsx의 processVideoMetadataSingle 내부에서 다음과 같이 구현되어 있습니다:

ads-library/page.ts (279-290행)

     if (!video.user_metadata ||
         Object.keys(video.user_metadata).length === 0 ||
          !video.user_metadata.topic_category &&
          !video.user_metadata.emotions && 
          !video.user_metadata.brands &&
          !video.user_metadata.locations)) {


       setVideosInProcessing(prev => [...prev, videoId]);


       const hashtagText = await generateMetadata(videoId);


       if (hashtagText) {
         const metadata = parseHashtags(hashtagText);

generateMetadata 함수는 Twelve Labs 엔진에 AI 생성 태그를 요청하기 위해 서버 사이드 API 호출을 실행하는 커스텀 훅입니다.

이는 api/analyze/route.ts 내부의 백엔드 핸들러를 실행하며, Twelve Labs Analyze API에 맞게 구조적이고 구체적인 프롬프트를 구성합니다. 임포팅된 이 프롬프트는 반환되는 데이터가 명확하게 카테고리화되고 일관된 형식으로 정렬되도록 보장하여, 간편하게 태그로 변환하고 필터 메뉴(Filter Menu)에 렌더링할 수 있도록 돕습니다. 백엔드 라우트의 핵심 로직은 다음과 같습니다:

api/analyze/route.ts (1 - 85행)

import { NextResponse } from 'next/server';


const API_KEY = process.env.TWELVELABS_API_KEY;
const TWELVELABS_API_BASE_URL = process.env.TWELVELABS_API_BASE_URL;


export const maxDuration = 60;


export async function GET(req: Request) {
   const { searchParams } = new URL(req.url);
   const videoId = searchParams.get("videoId");
   const prompt =
   `You are a marketing assistant specialized in generating hashtags for video content.


Based on the input video metadata, generate a list of hashtags labeled by category.


**Output Format:**
Each line must be in the format:
[Category]: [Hashtag]
(e.g., sector: #beauty)




**Allowed Values:**


Gender: Male, Female
Age: 18-25, 25-34, 35-44, 45-54, 55+
Topic: Beauty, Fashion, Tech, Travel, CPG, Food & Bev, Retail, Other
Emotions: sorrow, happiness, laughter, anger, empathy, fear, love, trust, sadness, belonging, guilt, compassion, pride


**Instructions:**


1. Use only the values provided in Allowed Values.
2. Do not invent new values except for Brands and Location. Only use values from the Allowed Values.
3. Output must contain at least one hashtag for each of the following categories:
 - Gender
 - Age
 - Topic
 - Emotions
 - Location
 - Brands


4. Do not output any explanations or category names—only return the final hashtag list.


**Output Example:**


Gender: female
Age: 25-34
Topic: beauty
Emotions: happiness
Location: Los Angeles
Brands: Fenty Beauty


---
`


  


   const url = `${TWELVELABS_API_BASE_URL}/analyze`;
   const options = {
       method: "POST",
       headers: {
           "Content-Type": "application/json",
           "x-api-key": API_KEY,
       },
       body: JSON.stringify({
           prompt: prompt,
           video_id: videoId,
           stream: false
       })
   };


   try {
     const response = await fetch(url, options);

2단계 - 생성된 태그를 저장하기 위해 각 비디오에 PUT 실행

/api/analyze 라우트를 사용해 태그가 생성되고 나면, 다음 단계는 이를 인덱싱된 라이브러리 내부의 해당 비디오 객체에 다시 저장하는 것입니다. 이는 Twelve Labs 인덱스 내 비디오의 메타데이터를 업데이트하는 PUT API 호출을 통해 진행됩니다.

⭐️ Twelve Labs의 Update Video Information API에 대한 자세한 정보는 여기를 참고해 주세요.

이 작업은 api/videos/metadata/route.ts에 위치한 백엔드 라우트를 동작시키는 updateVideoMetadata 훅에 의해 핸들링됩니다.

❗️커스텀 메타데이터를 저장할 때는 각 비디오를 업데이트할 때 키 명칭으로 user_metadata를 사용하고 있는지 필히 확인하십시오.

api/videos/metadata/route.ts (1-68행)

import { NextRequest, NextResponse } from 'next/server';



export async function PUT(request: NextRequest) {
 try {
   // Parse request body
   const body: MetadataUpdateRequest = await request.json();
   const { videoId, indexId, metadata } = body;
  


   // Prepare API request
   const url = `${TWELVELABS_API_BASE_URL}/indexes/${indexId}/videos/${videoId}`;


   const requestBody = {
     user_metadata: {
       source: metadata.source || '',
       sector: metadata.sector || '',
       emotions: metadata.emotions || '',
       brands: metadata.brands || '',
       locations: metadata.locations || '',
       demographics: metadata.demographics || ''
     }
   };


   const options = {
     method: 'PUT',
     headers: {
       'Content-Type': 'application/json',
       'x-api-key': API_KEY,
     },
     body: JSON.stringify(requestBody)
   };


   // Call Twelve Labs API
   const response = await fetch(url, options);


🔁 사용 대상 및 위치

이 호출은 page.tsxprocessVideoMetadataSingle 내부에 있으며, 다음과 같은 형태로 명시되어 있습니다:

ads-library/page.tsx (289-292행)

 if (hashtagText) {
         const metadata = parseHashtags(hashtagText);


         await updateVideoMetadata(videoId, adsIndexId, metadata);

📌 user_metadata 안에는 무엇이 포함되나요?

저장된 user_metadata 객체는 아래와 같은 키 필드로 정렬됩니다:

{
  "gender": "female",
  "age": "25-34",
  "topic": "beauty",
  "emotions": "happiness",
  "location": "Los Angeles",
  "brands": "Fenty Beauty"

이처럼 일관된 형식은 대시보드 내 카테고리별 필터 UX 제공, 비디오 검색 및 시각적 그룹화를 가능케 합니다. 이 커스텀 메타데이터들은 이제 Twelve Labs에서 검색해 오는 비디오 자체에 완벽히 내장되므로, 단순히 GET 요청을 통해 해당 비디오를 로드하여 필요에 맞게 렌더링하고 사용하면 됩니다.

⭐️ Twelve Labs의 Retrieve Video Information API에 대한 자세한 정보는 여기를 눌러 확인하세요.


핵심 기능 2. 유사 비디오 검색 (‘Contextual Alignment Analysis’ 메뉴)

Contextual Alignment Analysis(맥락적 정렬 분석) 기능은 비디오 및 텍스트 임베딩을 정교하게 비교하여 사용자가 선택한 광고와 최고의 타겟 연관성을 갖는 콘텐츠 비디오를 선별해 냅니다. 이 임베딩 기술은:

  • Twelve Labs에 의해 개발 및 생성됩니다.

  • 유사성 검색을 위해 Pinecone을 거쳐 영구 보관되며 쿼리 처리됩니다.

이 기술이 설계 의도대로 완벽히 작동하기 위해 다음 조치들이 먼저 확보되어야 합니다:

  • 모든 콘텐츠 비디오에 대한 백터 임베딩이 미리 존재해야 합니다.

  • 선택한 해당 광고 비디오에 대한 백터 임베딩 역시 사전에 존재해야 합니다.

  • 모든 임베딩은 최종적으로 동일한 단일 Pinecone 인덱스 내에 안전하게 정제 및 저장되어야 합니다.

❗️Twelve Labs 솔루션을 활용해 특정 비디오를 정상 인덱싱하면 임베딩 벡터가 자동 생성되며, Retrieve Video Information API 호출을 활용해 이를 즉시 불러올 수 있게 됩니다.


1단계 - 콘텐츠 비디오 임베딩 업로드 및 가동 프로세스

실시간 유사성 벡터 매칭을 실행하기 전, 분석 풀 내 모든 콘텐츠 비디오들의 임베딩이 Pinecone 인덱스 내에 안전하게 축적 완료되어 있어야 합니다. 이 선행 처리는 클라이언트 사이드 함수인 processContentVideoEmbeddings()를 통해 흐름이 이어집니다.

💡 내부 구동 플로우

🔧 핵심 시스템 함수 리스트

checkVectorExists 비디오 전용 임베딩 성분(벡터)이 이미 Pinecone 스토리지 내에 캐싱되어 있는지 교차 확인합니다. 내부적으로 프로젝트 백엔드 라우터 쪽 통신을 처리합니다.

api/vectors/exists (15-27행)

   // Fetch vectors using metadata filter instead of direct ID
   const queryResponse = await index.query({
     vector: new Array(1024).fill(0),
     filter: {
       tl_video_id: videoId
     },
     topK: 1,
     includeMetadata: true
   });


   return NextResponse.json({
     exists: queryResponse.matches.length > 0
   });

벡터 임베딩 값을 사전에 찾지 못했을 경우, getAndStoreEmbeddings가 작동을 시작합니다:

  1. Twelve Labs에서 대상 임베딩 벡터를 고속 로드합니다 (/api/videos/[videoId]?embed=true)

  2. 이를 /api/vectors/store 라우트를 경유해 Pinecone에 완전히 반영(업서트)합니다.

api/videos/[videoId] (77-95행)

// Base URL
 let url = `${TWELVELABS_API_BASE_URL}/indexes/${indexId}/videos/${videoId}`;


 // Always include embedding query parameters if requested
 if (requestEmbeddings) {
   // Include only supported embedding options
   url += `?embedding_option=visual-text&embedding_option=audio`;
 }


 const options = {
   method: "GET",
   headers: {
     "x-api-key": `${API_KEY}`,
     "Accept": "application/json"
   },
 };


 try {
   const response = await fetch(url, options);

api/vectors/store (126-173행)

// Create vectors from embedding segments
   const vectors = embedding.video_embedding.segments.map((segment: Segment, index: number) => {
     // Create a meaningful and unique vector ID
     const vectorId = `${vectorIdBase}_segment${index + 1}`;


     const vector = {
       id: vectorId,
       values: segment.float,
       metadata: {
         video_file: actualFileName,
         video_title: videoTitle,
         video_segment: index + 1,
         start_time: segment.start_offset_sec,
         end_time: segment.end_offset_sec,
         scope: segment.embedding_scope,
         tl_video_id: videoId,
         tl_index_id: indexId,
         category
       }
     };


     return vector;
   });


   try {
     const index = getPineconeIndex();


     // Upload vectors in batches
     const batchSize = 100;
     const totalBatches = Math.ceil(vectors.length / batchSize);


     console.log(`🚀 FILENAME DEBUG - Starting vector upload with ${totalBatches} batches...`);


     for (let i = 0; i < vectors.length; i += batchSize) {
       const batch = vectors.slice(i, i + batchSize);
       const batchNumber = Math.floor(i / batchSize) + 1;


       try {
         // Test Pinecone connection before upserting
         try {
           await index.describeIndexStats();
         } catch (statsError) {
           console.error(`❌ Pinecone connection test failed:`, statsError);
           throw new Error(`Failed to connect to Pinecone: ${statsError instanceof Error ? statsError.message : 'Unknown error'}`);
         }


         // Perform the actual upsert
         await index.upsert(batch);


2단계 - 선택한 특정 광고 비디오에 대한 임베딩 체크 및 생성

마케터가 단일 광고를 마우스로 지정하면 애플리케이션 프론트엔드는 해당 벡터가 준비된 상태인지 자동 식별을 수행합니다. 이 제어는 타겟 비디오 정보를 리스닝 중이던 useEffect() 훅을 통해 동작하게 됩니다:

contextual-analysis/page.tsx (296-318행)

// Automatically check ONLY the ad video embedding when a video is selected
 useEffect(() => {
   if (selectedVideoId && !isLoadingEmbeddings) {
     const cachedStatus = queryClient.getQueryData(['embeddingStatus', selectedVideoId]) as
       { checked: boolean, ready: boolean } | undefined;


     if (!cachedStatus?.checked) {
       setIsLoadingEmbeddings(true);


       ensureEmbeddings().then(success => {
         queryClient.setQueryData(['embeddingStatus', selectedVideoId], {
           checked: true,
           ready: success
         });


         setEmbeddingsReady(success);
         setIsLoadingEmbeddings(false);
       });
     } else {
       setEmbeddingsReady(cachedStatus.ready);
     }
   }
 }, [selectedVideoId, isLoadingEmbeddings, queryClient]);

🔧 핵심 시스템 함수 리스트

ensureEmbeddings는 다음 내부 연산을 위해 checkAndEnsureEmbeddings() 를 즉시 사용합니다:

  • 특정 대상 광고의 가용 전용 비디오 임베딩 여부를 checkVectorExists 호출로 안전하게 검증합니다

  • 발견하지 못했을 경우 getAndStoreEmbeddings 방식을 호출해 타겟 인덱스에 새롭게 기입합니다

  • 필요 시, 동일 로직 스레드에서 모든 내부 콘텐츠 비디오들을 백그라운드로 동시 로드하여 처리하게 할 수 있습니다

❗️checkVectorExists() 및 getAndStoreEmbeddings()의 상세한 구현 형태 및 동작 과정은 앞서 1단계에서 한 차례 안내하였으므로 중복 기술하지 않고 생략합니다.


3단계 - Pinecone 내 유사성 벡터 매칭 및 Twelve Labs 서칭 프로세스 

마침내 모든 비디오 소스(광고 비디오 및 일반 비디오)의 다차원 벡터가 무사히 업로드 완료된 후 사용자가 "Run Contextual Analysis" 버튼을 실행하면, 백그라운드 엔진은 실시간 시너지 효과를 위해 아래의 두 병렬 서칭 모델을 상호 유기적으로 가동시킵니다:

  • 텍스트 기반 비디오 맥락 분석 (Text-to-Video Search): 추출 완료된 마케팅 **텍스트 메타 태그** 정보 (예시: 소속 브랜드 분야 및 내재된 인물 표정 감정 상태) 등을 타겟 질의어로 치환 및 가공 연산하여 의미론적으로 완벽히 융합되는 매칭 영상들을 Pinecone 컬렉션 중에서 우선순위로 선별해 냅니다.

  •  이미지 프레임 기반 비디오 교차 매칭 (Video-to-Video Search): 영상의 흐름에 포함된 **미세 구간 프레임 임베딩 벡터 데이터**를 활용해 대상 광고와 비주얼적 및 분위기 측면에서 놀라운 비주얼 맥락 매칭을 이루는 세부 일반 영상 클립들을 찾아내 줍니다.

  • 이 두 단계를 거쳐 수집된 후보 결과들은 **정교한 가중치 합산 연산 모델**을 거치며 정렬 품질이 더욱 고도화됩니다. 양방향 정렬 조건에 다각도로 걸러진 최상위 후보들은 매칭 리스트 순위 구조에서 매우 확실한 상위 우선 지위를 부여받게 됩니다.

텍스트 기반 비디오 맥락 분석 (Text-to-Video Search)

contextual-analysis/page.tsx (351-384행)

const handleContextualAnalysis = async () => {
  
     try {
       textResults = await textToVideoEmbeddingSearch(selectedVideoId, adsIndexId, contentIndexId);
      
     try {
       videoResults = await videoToVideoEmbeddingSearch(selectedVideoId, adsIndexId, contentIndexId);

textToVideoEmbeddingSearch는 지목된 타겟 광고 정보 및 타이틀로부터 광고 분야 특성 세부 카테고리와 구체적인 감정 상태(Emotions) 태그를 정확히 정제하고 확보합니다.

  • 정밀 선별 단계에 필요한 키워드를 api/embeddingSearch/textToVideo에 인포트 처리합니다.

  • Twelve Labs 엔진은 가공 처리된 고차원 텍스트 전용 특성 임베딩 벡터를 신속 조립 후 매칭 후보인 Pinecone 비디오 데이터베이스 내에서 일품 맥락 매칭 비디오 콘텐츠들을 대거 선별하여 전송합니다.

api/embeddingSearch/textToVideo (20-45행)

const { data: embedData } = await axios.post(url, formData, {
    // extract embedding vector from text_embedding object
   const textEmbedding = embedData.text_embedding.segments[0].float;

   // Get index and search
   const searchResults = await index.query({
     vector: textEmbedding,
     filter: {
       // video_type: 'ad',
       tl_index_id: indexId,
       scope: 'clip'
     },
     topK: 10,
     includeMetadata: true,
   });

이미지 프레임 기반 비디오 교차 매칭 (Video-to-Video Search)

videoToVideoEmbeddingSearch는 사전에 지정된 해당 타켓형 키 디바이스 광고의 유효 미세 구간(세그먼트 벡터값)을 직접 역추적하여 선별합니다.

  • 수집 완료된 고해상 세그먼트 백터 단위 정보를 Pinecone 콘텐츠 비딩 인덱싱 스레드와 직접 교차 매칭하며 분석합니다.

  • 추출 성사된 각 요소들은 정렬 타당성이 매우 높은 양방향 비디오 임베딩 값들을 대표하는 증거가 되어 줍니다.

api/embeddingSearch/videoToVideo (22-50행)

// First, get the original video's clip embedding
   const originalClipQuery = await index.query({
     filter: {
       tl_video_id: videoId,
       scope: 'clip'
     },
     topK: 100,
     includeMetadata: true,
     includeValues: true,
     vector: new Array(1024).fill(0)
   });


   // If we found matching clips, search for similar ads for each match
   const similarResults = [];
   if (originalClipQuery.matches.length > 0) {
     for (const originalClip of originalClipQuery.matches) {
       const vectorValues = originalClip.values || new Array(1024).fill(0);
       const queryResult = await index.query({
         vector: vectorValues,
         filter: {
           tl_index_id: indexId,
           scope: 'clip'
         },
         topK: 5,
         includeMetadata: true,
       });
       similarResults.push(queryResult);
     }
   }

결과 데이터셋 크로싱 결합

스레드별 추출물들은 일차적으로 타겟 비디오 ID를 매개변수 삼아 한 곳에 바인딩됩니다. 우수한 신뢰성을 보이며 두 영역에 공통 출현한 콘텐츠는 최종 분석 단계에서 스코어를 2배 보정 처리(부스팅)해 가산합니다.

contextual-analysis/page.tsx (412-428행)

 if (combinedResultsMap.has(videoId)) {
           // This is a match found in both searches - update it
           const existingResult = combinedResultsMap.get(videoId);


           // Apply a significant boost for results found in both searches (50% boost)
           const boostMultiplier = 2;


           // Combine the scores: use the max of both scores and apply the boost
           const maxScore = Math.max(existingResult.textScore, result.score);
           const boostedScore = maxScore * boostMultiplier;


           combinedResultsMap.set(videoId, {
             ...existingResult,
             videoScore: result.score,
             finalScore: boostedScore,  // Boosted score for appearing in both searches
             source: "BOTH"
           });

핵심 기능 3. 챕터 나누기 및 똑똑한 광고 시간 자동 정렬 시뮬레이션 (‘Contextual Alignment Analysis’ 메뉴)

이 핵심 영역은 단순히 비디오를 일차원적으로 연동 및 매칭하는 것을 넘어 일반 가용 영상을 지능적인 단위 **챕터군**으로 자동 구획화한 후, 챕터 세그먼트 끝단에 자연스럽게 선택 광고를 안착시킵니다. 즉 실제 미디어 플랫폼에서 운용하는 실시간 중간 광고 서비스 경험을 그대로 시물레이션 구현하여 비디오 비즈니스의 부가적 가치 창출을 풍부히 대변해 줍니다.


1단계 - 지능형 자동 비디오 챕터 생성 작업

운영자가 비디오 상세 뷰어 프레임인 VideoModal을 화면에 로드하는 즉시, 핵심 코드는 Twelve Labs 플랫폼이 가진 최적의 성능을 끌어오기 위해 내부적으로 generateChapters API를 작동시켜 콘텐츠 파트를 분절합니다.

videoModal.tsx (42-47행)

 // Fetch chapters data
 const { data: chaptersData, isLoading: isChaptersLoading } = useQuery({
   queryKey: ["chapters", videoId],
   queryFn: () => generateChapters(videoId),
   enabled: isOpen && !!videoId,
 });

반환된 각 챕터 데이터 안에는 아래의 유용한 세부 메트릭이 수반됩니다:

  • end: 해당 분절의 마침 정보 필드값 (광고 큐 시점이자 삽입 트리거 포인트역할을 담당합니다)

  • chapter_title: 가독성에 맞춰 깔끔하게 자동 명명된 챕터 헤더 타이틀입니다

  • chapter_summary: 해당 특정 씬이 미장센 흐름상 또는 스토리 맥락상 마케팅 광고를 걸어 넣기에 왜 이상적인 구간인지에 대한 AI 기반의 세련된 논리적 해설(한 문장 정리)을 제시해 줍니다

이처럼 자동 구성된 지능형 챕터 정보들은 웹 런타임 뷰 내부의 **챕터 시간 타임라인 바**에 작은 점 형태의 end 인디케이터로 부드럽게 시각화됩니다. 이 타임라인 상의 미세 점을 원클릭 지목 및 제어하면, **마치 해당 영상 중간이 자연스럽게 막간 전개를 맺듯이 바로 이어서 광고를 연출**하는 식의 흐름을 시뮬레이션할 수 있습니다.

사용자 인터랙션(UX) 흐름에 따른 구체적 변화 양상:

  • 챕터가 종료되는 최접점에 예쁜 매핑 인디케이터 도트(Dot) 포인트가 배열 정렬됩니다.

  • 화면 상 도트 포인트를 사용자가 누르면 설정된 큐포인트에서 지체없이 "Show Ad" 오버레이 마스크가 자연스럽게 작동합니다.

  • 재생되는 지정 광고는 스킵 기능을 충실히 수용 가능하여 현실 유동 상황과 일치하는 미드롤 스트리밍을 제공합니다.

서버 사이드 내부 아키텍처: Twelve Labs 기능을 통한 요약 정보 챕터 생성

정제되고 깔끔한 챕터 도메인 구성 처리를 성사시키기 위해, 이 과정은 Twelve Labs 플랫폼이 자랑하는 고유의 요약(Summarize) 전용 엔드포인트 기능을 활용하며 동시에 다음과 같이 최적화된 프롬프트 구문을 빌려 사용합니다.

api/generateChapters (19-30행)

 const url = `${TWELVELABS_API_BASE_URL}/summarize`;
     const options = {
         method: "POST",
         headers: {
             "Content-Type": "application/json",
             "x-api-key": `${API_KEY}`,
           },
           body: JSON.stringify({type: "chapter", video_id: videoId, prompt: "Chapterize this video into 3 chapters. For every chapter, describe why it is a strategically appropriate point for placing an advertisement. Do not mention what type of advertisement would be suitable, as the ad content has already been determined. "})
       };


     try {
       const response = await fetch(url, options);

클라이언트 사이드 전처리 함수: generateChapters

이 함수는 React Query와 결합되어 실시간 챕터 데이터 조회를 유기적으로 성사시키고 연소 지원합니다:

apiHooks.tsx (981-984행)

export const generateChapters = async (videoId: string): Promise<ChaptersData> => {
 try {
   const response = await fetch(`/api/generateChapters?videoId=${videoId}`);


2단계 - 사용자가 특정 챕터 선택 시 중간 광고 실행 및 자연스러운 흐름 처리

마케터가 화면의 특정 챕터 마크업을 트리거하는 순간 백그라운드에서는 다음과 같은 단계적 흐름이 실행됩니다:

  1. 플레이어 타임 바가 활성화되며, 즉시 해당 선택 챕터의 공식 완결 시점이 도래하기 정확히 3초 전으로 플레이 재생바 헤드를 미끄러지듯 이동(Seek)시킵니다.

  2. 이후 재생 흐름이 실제 임계 완결 시점에 도달하자마자, 본 영상은 정지하고 곧바로 정해진 **광고 연속 재생 사이클**로 넘어가게 됩니다.

  3. 매칭 전용 광고 출현 분량이 마무리된 후에는, 원래 재생 중이던 메인 영상 파트로 매끄럽게 되돌아와 광고 전환이 연출되었던 직후 시간 축부터 재생을 자연스럽게 이어갑니다.

인디케이터 점 포인트 원터치 클릭 연산 제어

가시적이고 명시적인 중간 미드롤 광고 시뮬레이션을 원활히 작동시키기 위해, 타임라인을 나타내는 미세 도트 선택 이벤트 수신 시점에서의 플레이 시점 조정 단계는 다음과 같이 명확히 처리 구체화되어 있습니다.

VideoModal.tsx (102-126행)

 // Chapter click handler
 const handleChapterClick = (index: number) => {
   if (playbackSequence === 'ad') {
     return;
   }


   if (!adVideoDetail?.hls?.video_url) {
     console.warn("No ad selected. Please select an ad in the contextual analysis page.");
     return;
   }


   if (!chaptersData) return;


   const chapter = chaptersData.chapters[index];
   setSelectedChapter(index);
   setHasPlayedAd(false);
   setPlaybackSequence('video');
   setShowChapterInfo(true);


   if (playerRef.current) {
     // Start 3 seconds before the chapter end time
     const startTime = Math.max(0, chapter.end - 3);
     playerRef.current.seekTo(startTime, 'seconds');
   }
 };

재생 시점 모니터링 – 도트 도달 순간 광고 전환 실행

영상 콘텐츠의 스트리밍이 일정 속도로 흐르는 동안, 코드는 매 순간 재생 헤더 도달 포인트를 역계산하며 타겟 챕터 연산 종료 좌표에 이르렀다고 인정되는 최상의 전환 타이밍 조건을 충족하는 즉시 광고 재생 레이어로 화면을 넘겨 줍니다.

VideoModal.tsx (82-100행)

 // Track video progress
 const handleProgress = (state: { playedSeconds: number }) => {
   if (selectedChapter === null || !chaptersData || !adVideoDetail) {
     return;
   }


   const chapter = chaptersData.chapters[selectedChapter];
   const timeDiff = state.playedSeconds - chapter.end;
   const isLastChapter = selectedChapter === chaptersData.chapters.length - 1;


   if (
     playbackSequence === 'video' &&
     !hasPlayedAd &&
     ((isLastChapter && Math.abs(timeDiff) < 0.5) || (!isLastChapter && timeDiff >= 0))
   ) {
     setPlaybackSequence('ad');
     setHasPlayedAd(true);
   }
 };

지정 광고 종료 후 자연스러운 원래 본편 복귀 처리

영상이 끝난 바로 수 밀리초 이후, 시스템 흐름은 광고 타임라인에 머물러 있던 미디어 영역을 다시 원래의 라이브 챕터 잔여 구간으로 자동 원복시킵니다.

VideoModal.tsx (128-136행)

 // Ad ended handler
 const handleAdEnded = () => {
   if (selectedChapter === null || !chaptersData) return;
   const chapter = chaptersData.chapters[selectedChapter];
   setPlaybackSequence('video');
   setReturnToTime(chapter.end);
   setIsPlaying(true);
 };

이 기술은 일반 영상을 유연하게 단락 지으며 자연스럽게 가치 있는 지성적 중간 맞춤 전단 광고를 적재적소에 올릴 수 있는 지름길이 되어 줍니다. 콘텐츠 소스의 전개가 끊어지지 않는 완벽한 정서적 휴지기를 교묘히 활용함으로써 극강의 **지능형 맥락 부합 타깃 광고** 연출을 실현하고 비즈니스 부가 성과를 실증합니다.


맺음말

이 튜토리얼을 통해 고성능 맥락적 동영상 분석(Contextual Analysis)의 전진기지가 되어 줄 멋진 여정을 완수하였습니다. Twelve Labs 고유의 풍성한 멀티모달 프레임워크 임베딩 데이터 생성 및 적재, Pinecone 백터 파티셔닝 기술을 통한 고도의 유사 정보 병렬 선별, 그리고 결과물을 요리하듯 다듬어 챕터 구획 단위 끝자락에 안착시키는 시뮬레이션 모델까지 전 과정을 깊이 있게 탐색해 보았습니다. Twelve Labs가 제시하는 다차원 입체 멀티모달 임베딩 방식과 Pinecone의 속도감 있는 벡터 연산 필터 구조를 세심히 응용하면, 혁신적 수준의 미묘한 맥락 타기팅 경험을 실현할 수 있습니다. 이 단단히 구축된 연동 아키텍처 토대는, 빅데이터 수준의 실시간 초정밀 타기팅 연산, 자동화 A/B 마케팅 스플릿 전개, 더 나아가 초대형 고도화 비디오 비즈니스 서비스 라인업으로도 웅장하게 확장될 수 있습니다.

소개

시청자들은 종종 자신이 보고 있는 콘텐츠와 어울리지 않는 무관한 광고로 인해 피로감을 느낍니다. 이러한 불일치는 불만을 유발하고, 광고가 침입적이거나 타이밍이 맞지 않는다는 인상을 주게 됩니다.

브랜드 통합 어시스턴트 및 광고 시간 탐색기(Brand Integration Assistant & Ad Break Finder) 앱맥락적으로 연관성 높은 광고 추천을 제공하여 이를 해결합니다. 이를 통해 완벽한 참여의 순간에 적합한 오디언스에게 정확한 메시지가 도달하도록 보장합니다.

이 튜토리얼에서는 앱의 주요 기능을 작동해 보며 다음과 같은 방법을 배우게 됩니다:

  • 자동 태그 생성: 업로드된 각 광고를 분석하여 주제 카테고리, 감정, 브랜드, 타겟 인구 통계(성별 및 연령), 위치 등 풍부한 메타데이터를 생성합니다. 이를 통해 스마트한 필터링, 검색, 그리고 콘텐츠 매칭이 가능해집니다.

  • 맥락적으로 정렬된 콘텐츠 검색: AI 기반 유사성 검색을 활용해 비디오 및 텍스트 임베딩을 기반으로 광고와 의미론적으로 정렬된 콘텐츠 비디오를 찾아냅니다.

  • 광고 시간 추천 및 시뮬레이션: 콘텐츠를 자동으로 챕터 단위로 분할하고 미드롤 광고 삽입을 시뮬레이션하여 매끄럽고 몰입감 넘치는 광고 경험을 선사합니다.


사전 준비 단계

  • Twelve Labs Playground에 가입하고 API 키를 생성한 후, 광고와 콘텐츠 비디오를 위한 전용 인덱스를 각각 하나씩 총 두 개 생성합니다. 

  • Pinecone 계정을 설정하고 비디오 임베딩을 저장할 인덱스를 생성합니다.

    • Dimensions1024로, MetricCosine으로 설정해야 합니다.

  • 제공된 GitHub 리포지토리에서 애플리케이션의 소스 코드를 확인하세요.

  • 더 원활한 빌드 및 개발 경험을 위해 JavaScript, TypeScript 및 Next.js에 익숙하면 큰 도움이 됩니다.


데모

직접 체험해 보려면 데모 애플리케이션을 확인하거나, 아래의 간단한 데모 비디오를 통해 실제 작동 방식을 간편하게 살펴보세요: https://www.loom.com/share/233cc8cb66ae44218e3cff69afb772d7

전체 데모가 포함된 웨비나 녹화본은 아래에서 시청하실 수 있습니다:


앱 작동 방식  

앱을 실행하면 두 가지 기본 메뉴인 Ads Library(광고 라이브러리)Contextual Alignment Analysis(맥락적 정렬 분석)를 확인할 수 있습니다.

Ads Library (광고 라이브러리) - 브랜드 마케터에게 자동으로 생성된 태그가 풍부하게 포함된 광고 비디오들의 체계적인 뷰를 제공합니다. 사용자는 Twelve Labs Search API를 사용해 주제 카테고리, 감정, 브랜드, 성별, 연령, 위치별로 광고를 필터링하거나 단일 키워드 및 시퀀스 키워드로 검색할 수 있습니다. 이 튜토리얼에서는 광고 라이브러리의 자동 태그 생성 기능에 집중해 다룹니다.

Contextual Alignment Analysis (맥락적 정렬 분석) - 이 섹션에서는 사용자가 각 광고에 대해 가장 맥락적으로 연관성 높은 콘텐츠 비디오를 찾을 수 있도록 지원합니다. 태그 및 비디오 임베딩을 위한 Twelve Labs EMBED 및 GET 비디오 API와 유사성 기반 필터링을 지원하는 Pinecone의 기술력을 바탕으로, 고도로 정렬된 콘텐츠를 표면 위로 도출합니다.

그 다음 사용자는 콘텐츠 비디오를 선택하고, 광고 시간 삽입을 위한 자동 챕터를 생성한 뒤, 챕터가 전환되는 시점에서 광고 재생을 시뮬레이션할 수 있습니다.

이어지는 튜토리얼을 통해 콘텐츠 매칭과 광고 시뮬레이션 기능 모두를 자세히 살펴보겠습니다.


앱의 세 가지 핵심 기능과 작동 원리


핵심 기능 1. 자동 태그 생성 (‘Ads Library’ 메뉴)

광고 라이브러리(Ads Library)에서 사용자는 인덱싱된 비디오 컬렉션을 탐색하고 자동으로 생성된 태그를 확인할 수 있습니다. 이 태그들은 Twelve Labs의 Analyze API를 통해 추출되며, 비디오를 소주제, 감정, 브랜드, 인구 통계학적 특성 등으로 정확하게 분류해 줍니다.


1단계 - 각 비디오의 태그 생성

비디오를 불러왔을 때 메타데이터가 불완전하거나 누락된 것으로 판단되면, 시스템은 Twelve Labs의 Analyze API를 활용해 태그를 가져오는 generateMetadata를 호출합니다.

⭐️ Twelve Labs의 Analyze API에 대한 자세한 내용은 여기에서 확인하세요.

🔁 사용 대상 및 위치

이 호출은 page.tsx의 processVideoMetadataSingle 내부에서 다음과 같이 구현되어 있습니다:

ads-library/page.ts (279-290행)

     if (!video.user_metadata ||
         Object.keys(video.user_metadata).length === 0 ||
          !video.user_metadata.topic_category &&
          !video.user_metadata.emotions && 
          !video.user_metadata.brands &&
          !video.user_metadata.locations)) {


       setVideosInProcessing(prev => [...prev, videoId]);


       const hashtagText = await generateMetadata(videoId);


       if (hashtagText) {
         const metadata = parseHashtags(hashtagText);

generateMetadata 함수는 Twelve Labs 엔진에 AI 생성 태그를 요청하기 위해 서버 사이드 API 호출을 실행하는 커스텀 훅입니다.

이는 api/analyze/route.ts 내부의 백엔드 핸들러를 실행하며, Twelve Labs Analyze API에 맞게 구조적이고 구체적인 프롬프트를 구성합니다. 임포팅된 이 프롬프트는 반환되는 데이터가 명확하게 카테고리화되고 일관된 형식으로 정렬되도록 보장하여, 간편하게 태그로 변환하고 필터 메뉴(Filter Menu)에 렌더링할 수 있도록 돕습니다. 백엔드 라우트의 핵심 로직은 다음과 같습니다:

api/analyze/route.ts (1 - 85행)

import { NextResponse } from 'next/server';


const API_KEY = process.env.TWELVELABS_API_KEY;
const TWELVELABS_API_BASE_URL = process.env.TWELVELABS_API_BASE_URL;


export const maxDuration = 60;


export async function GET(req: Request) {
   const { searchParams } = new URL(req.url);
   const videoId = searchParams.get("videoId");
   const prompt =
   `You are a marketing assistant specialized in generating hashtags for video content.


Based on the input video metadata, generate a list of hashtags labeled by category.


**Output Format:**
Each line must be in the format:
[Category]: [Hashtag]
(e.g., sector: #beauty)




**Allowed Values:**


Gender: Male, Female
Age: 18-25, 25-34, 35-44, 45-54, 55+
Topic: Beauty, Fashion, Tech, Travel, CPG, Food & Bev, Retail, Other
Emotions: sorrow, happiness, laughter, anger, empathy, fear, love, trust, sadness, belonging, guilt, compassion, pride


**Instructions:**


1. Use only the values provided in Allowed Values.
2. Do not invent new values except for Brands and Location. Only use values from the Allowed Values.
3. Output must contain at least one hashtag for each of the following categories:
 - Gender
 - Age
 - Topic
 - Emotions
 - Location
 - Brands


4. Do not output any explanations or category names—only return the final hashtag list.


**Output Example:**


Gender: female
Age: 25-34
Topic: beauty
Emotions: happiness
Location: Los Angeles
Brands: Fenty Beauty


---
`


  


   const url = `${TWELVELABS_API_BASE_URL}/analyze`;
   const options = {
       method: "POST",
       headers: {
           "Content-Type": "application/json",
           "x-api-key": API_KEY,
       },
       body: JSON.stringify({
           prompt: prompt,
           video_id: videoId,
           stream: false
       })
   };


   try {
     const response = await fetch(url, options);

2단계 - 생성된 태그를 저장하기 위해 각 비디오에 PUT 실행

/api/analyze 라우트를 사용해 태그가 생성되고 나면, 다음 단계는 이를 인덱싱된 라이브러리 내부의 해당 비디오 객체에 다시 저장하는 것입니다. 이는 Twelve Labs 인덱스 내 비디오의 메타데이터를 업데이트하는 PUT API 호출을 통해 진행됩니다.

⭐️ Twelve Labs의 Update Video Information API에 대한 자세한 정보는 여기를 참고해 주세요.

이 작업은 api/videos/metadata/route.ts에 위치한 백엔드 라우트를 동작시키는 updateVideoMetadata 훅에 의해 핸들링됩니다.

❗️커스텀 메타데이터를 저장할 때는 각 비디오를 업데이트할 때 키 명칭으로 user_metadata를 사용하고 있는지 필히 확인하십시오.

api/videos/metadata/route.ts (1-68행)

import { NextRequest, NextResponse } from 'next/server';



export async function PUT(request: NextRequest) {
 try {
   // Parse request body
   const body: MetadataUpdateRequest = await request.json();
   const { videoId, indexId, metadata } = body;
  


   // Prepare API request
   const url = `${TWELVELABS_API_BASE_URL}/indexes/${indexId}/videos/${videoId}`;


   const requestBody = {
     user_metadata: {
       source: metadata.source || '',
       sector: metadata.sector || '',
       emotions: metadata.emotions || '',
       brands: metadata.brands || '',
       locations: metadata.locations || '',
       demographics: metadata.demographics || ''
     }
   };


   const options = {
     method: 'PUT',
     headers: {
       'Content-Type': 'application/json',
       'x-api-key': API_KEY,
     },
     body: JSON.stringify(requestBody)
   };


   // Call Twelve Labs API
   const response = await fetch(url, options);


🔁 사용 대상 및 위치

이 호출은 page.tsxprocessVideoMetadataSingle 내부에 있으며, 다음과 같은 형태로 명시되어 있습니다:

ads-library/page.tsx (289-292행)

 if (hashtagText) {
         const metadata = parseHashtags(hashtagText);


         await updateVideoMetadata(videoId, adsIndexId, metadata);

📌 user_metadata 안에는 무엇이 포함되나요?

저장된 user_metadata 객체는 아래와 같은 키 필드로 정렬됩니다:

{
  "gender": "female",
  "age": "25-34",
  "topic": "beauty",
  "emotions": "happiness",
  "location": "Los Angeles",
  "brands": "Fenty Beauty"

이처럼 일관된 형식은 대시보드 내 카테고리별 필터 UX 제공, 비디오 검색 및 시각적 그룹화를 가능케 합니다. 이 커스텀 메타데이터들은 이제 Twelve Labs에서 검색해 오는 비디오 자체에 완벽히 내장되므로, 단순히 GET 요청을 통해 해당 비디오를 로드하여 필요에 맞게 렌더링하고 사용하면 됩니다.

⭐️ Twelve Labs의 Retrieve Video Information API에 대한 자세한 정보는 여기를 눌러 확인하세요.


핵심 기능 2. 유사 비디오 검색 (‘Contextual Alignment Analysis’ 메뉴)

Contextual Alignment Analysis(맥락적 정렬 분석) 기능은 비디오 및 텍스트 임베딩을 정교하게 비교하여 사용자가 선택한 광고와 최고의 타겟 연관성을 갖는 콘텐츠 비디오를 선별해 냅니다. 이 임베딩 기술은:

  • Twelve Labs에 의해 개발 및 생성됩니다.

  • 유사성 검색을 위해 Pinecone을 거쳐 영구 보관되며 쿼리 처리됩니다.

이 기술이 설계 의도대로 완벽히 작동하기 위해 다음 조치들이 먼저 확보되어야 합니다:

  • 모든 콘텐츠 비디오에 대한 백터 임베딩이 미리 존재해야 합니다.

  • 선택한 해당 광고 비디오에 대한 백터 임베딩 역시 사전에 존재해야 합니다.

  • 모든 임베딩은 최종적으로 동일한 단일 Pinecone 인덱스 내에 안전하게 정제 및 저장되어야 합니다.

❗️Twelve Labs 솔루션을 활용해 특정 비디오를 정상 인덱싱하면 임베딩 벡터가 자동 생성되며, Retrieve Video Information API 호출을 활용해 이를 즉시 불러올 수 있게 됩니다.


1단계 - 콘텐츠 비디오 임베딩 업로드 및 가동 프로세스

실시간 유사성 벡터 매칭을 실행하기 전, 분석 풀 내 모든 콘텐츠 비디오들의 임베딩이 Pinecone 인덱스 내에 안전하게 축적 완료되어 있어야 합니다. 이 선행 처리는 클라이언트 사이드 함수인 processContentVideoEmbeddings()를 통해 흐름이 이어집니다.

💡 내부 구동 플로우

🔧 핵심 시스템 함수 리스트

checkVectorExists 비디오 전용 임베딩 성분(벡터)이 이미 Pinecone 스토리지 내에 캐싱되어 있는지 교차 확인합니다. 내부적으로 프로젝트 백엔드 라우터 쪽 통신을 처리합니다.

api/vectors/exists (15-27행)

   // Fetch vectors using metadata filter instead of direct ID
   const queryResponse = await index.query({
     vector: new Array(1024).fill(0),
     filter: {
       tl_video_id: videoId
     },
     topK: 1,
     includeMetadata: true
   });


   return NextResponse.json({
     exists: queryResponse.matches.length > 0
   });

벡터 임베딩 값을 사전에 찾지 못했을 경우, getAndStoreEmbeddings가 작동을 시작합니다:

  1. Twelve Labs에서 대상 임베딩 벡터를 고속 로드합니다 (/api/videos/[videoId]?embed=true)

  2. 이를 /api/vectors/store 라우트를 경유해 Pinecone에 완전히 반영(업서트)합니다.

api/videos/[videoId] (77-95행)

// Base URL
 let url = `${TWELVELABS_API_BASE_URL}/indexes/${indexId}/videos/${videoId}`;


 // Always include embedding query parameters if requested
 if (requestEmbeddings) {
   // Include only supported embedding options
   url += `?embedding_option=visual-text&embedding_option=audio`;
 }


 const options = {
   method: "GET",
   headers: {
     "x-api-key": `${API_KEY}`,
     "Accept": "application/json"
   },
 };


 try {
   const response = await fetch(url, options);

api/vectors/store (126-173행)

// Create vectors from embedding segments
   const vectors = embedding.video_embedding.segments.map((segment: Segment, index: number) => {
     // Create a meaningful and unique vector ID
     const vectorId = `${vectorIdBase}_segment${index + 1}`;


     const vector = {
       id: vectorId,
       values: segment.float,
       metadata: {
         video_file: actualFileName,
         video_title: videoTitle,
         video_segment: index + 1,
         start_time: segment.start_offset_sec,
         end_time: segment.end_offset_sec,
         scope: segment.embedding_scope,
         tl_video_id: videoId,
         tl_index_id: indexId,
         category
       }
     };


     return vector;
   });


   try {
     const index = getPineconeIndex();


     // Upload vectors in batches
     const batchSize = 100;
     const totalBatches = Math.ceil(vectors.length / batchSize);


     console.log(`🚀 FILENAME DEBUG - Starting vector upload with ${totalBatches} batches...`);


     for (let i = 0; i < vectors.length; i += batchSize) {
       const batch = vectors.slice(i, i + batchSize);
       const batchNumber = Math.floor(i / batchSize) + 1;


       try {
         // Test Pinecone connection before upserting
         try {
           await index.describeIndexStats();
         } catch (statsError) {
           console.error(`❌ Pinecone connection test failed:`, statsError);
           throw new Error(`Failed to connect to Pinecone: ${statsError instanceof Error ? statsError.message : 'Unknown error'}`);
         }


         // Perform the actual upsert
         await index.upsert(batch);


2단계 - 선택한 특정 광고 비디오에 대한 임베딩 체크 및 생성

마케터가 단일 광고를 마우스로 지정하면 애플리케이션 프론트엔드는 해당 벡터가 준비된 상태인지 자동 식별을 수행합니다. 이 제어는 타겟 비디오 정보를 리스닝 중이던 useEffect() 훅을 통해 동작하게 됩니다:

contextual-analysis/page.tsx (296-318행)

// Automatically check ONLY the ad video embedding when a video is selected
 useEffect(() => {
   if (selectedVideoId && !isLoadingEmbeddings) {
     const cachedStatus = queryClient.getQueryData(['embeddingStatus', selectedVideoId]) as
       { checked: boolean, ready: boolean } | undefined;


     if (!cachedStatus?.checked) {
       setIsLoadingEmbeddings(true);


       ensureEmbeddings().then(success => {
         queryClient.setQueryData(['embeddingStatus', selectedVideoId], {
           checked: true,
           ready: success
         });


         setEmbeddingsReady(success);
         setIsLoadingEmbeddings(false);
       });
     } else {
       setEmbeddingsReady(cachedStatus.ready);
     }
   }
 }, [selectedVideoId, isLoadingEmbeddings, queryClient]);

🔧 핵심 시스템 함수 리스트

ensureEmbeddings는 다음 내부 연산을 위해 checkAndEnsureEmbeddings() 를 즉시 사용합니다:

  • 특정 대상 광고의 가용 전용 비디오 임베딩 여부를 checkVectorExists 호출로 안전하게 검증합니다

  • 발견하지 못했을 경우 getAndStoreEmbeddings 방식을 호출해 타겟 인덱스에 새롭게 기입합니다

  • 필요 시, 동일 로직 스레드에서 모든 내부 콘텐츠 비디오들을 백그라운드로 동시 로드하여 처리하게 할 수 있습니다

❗️checkVectorExists() 및 getAndStoreEmbeddings()의 상세한 구현 형태 및 동작 과정은 앞서 1단계에서 한 차례 안내하였으므로 중복 기술하지 않고 생략합니다.


3단계 - Pinecone 내 유사성 벡터 매칭 및 Twelve Labs 서칭 프로세스 

마침내 모든 비디오 소스(광고 비디오 및 일반 비디오)의 다차원 벡터가 무사히 업로드 완료된 후 사용자가 "Run Contextual Analysis" 버튼을 실행하면, 백그라운드 엔진은 실시간 시너지 효과를 위해 아래의 두 병렬 서칭 모델을 상호 유기적으로 가동시킵니다:

  • 텍스트 기반 비디오 맥락 분석 (Text-to-Video Search): 추출 완료된 마케팅 **텍스트 메타 태그** 정보 (예시: 소속 브랜드 분야 및 내재된 인물 표정 감정 상태) 등을 타겟 질의어로 치환 및 가공 연산하여 의미론적으로 완벽히 융합되는 매칭 영상들을 Pinecone 컬렉션 중에서 우선순위로 선별해 냅니다.

  •  이미지 프레임 기반 비디오 교차 매칭 (Video-to-Video Search): 영상의 흐름에 포함된 **미세 구간 프레임 임베딩 벡터 데이터**를 활용해 대상 광고와 비주얼적 및 분위기 측면에서 놀라운 비주얼 맥락 매칭을 이루는 세부 일반 영상 클립들을 찾아내 줍니다.

  • 이 두 단계를 거쳐 수집된 후보 결과들은 **정교한 가중치 합산 연산 모델**을 거치며 정렬 품질이 더욱 고도화됩니다. 양방향 정렬 조건에 다각도로 걸러진 최상위 후보들은 매칭 리스트 순위 구조에서 매우 확실한 상위 우선 지위를 부여받게 됩니다.

텍스트 기반 비디오 맥락 분석 (Text-to-Video Search)

contextual-analysis/page.tsx (351-384행)

const handleContextualAnalysis = async () => {
  
     try {
       textResults = await textToVideoEmbeddingSearch(selectedVideoId, adsIndexId, contentIndexId);
      
     try {
       videoResults = await videoToVideoEmbeddingSearch(selectedVideoId, adsIndexId, contentIndexId);

textToVideoEmbeddingSearch는 지목된 타겟 광고 정보 및 타이틀로부터 광고 분야 특성 세부 카테고리와 구체적인 감정 상태(Emotions) 태그를 정확히 정제하고 확보합니다.

  • 정밀 선별 단계에 필요한 키워드를 api/embeddingSearch/textToVideo에 인포트 처리합니다.

  • Twelve Labs 엔진은 가공 처리된 고차원 텍스트 전용 특성 임베딩 벡터를 신속 조립 후 매칭 후보인 Pinecone 비디오 데이터베이스 내에서 일품 맥락 매칭 비디오 콘텐츠들을 대거 선별하여 전송합니다.

api/embeddingSearch/textToVideo (20-45행)

const { data: embedData } = await axios.post(url, formData, {
    // extract embedding vector from text_embedding object
   const textEmbedding = embedData.text_embedding.segments[0].float;

   // Get index and search
   const searchResults = await index.query({
     vector: textEmbedding,
     filter: {
       // video_type: 'ad',
       tl_index_id: indexId,
       scope: 'clip'
     },
     topK: 10,
     includeMetadata: true,
   });

이미지 프레임 기반 비디오 교차 매칭 (Video-to-Video Search)

videoToVideoEmbeddingSearch는 사전에 지정된 해당 타켓형 키 디바이스 광고의 유효 미세 구간(세그먼트 벡터값)을 직접 역추적하여 선별합니다.

  • 수집 완료된 고해상 세그먼트 백터 단위 정보를 Pinecone 콘텐츠 비딩 인덱싱 스레드와 직접 교차 매칭하며 분석합니다.

  • 추출 성사된 각 요소들은 정렬 타당성이 매우 높은 양방향 비디오 임베딩 값들을 대표하는 증거가 되어 줍니다.

api/embeddingSearch/videoToVideo (22-50행)

// First, get the original video's clip embedding
   const originalClipQuery = await index.query({
     filter: {
       tl_video_id: videoId,
       scope: 'clip'
     },
     topK: 100,
     includeMetadata: true,
     includeValues: true,
     vector: new Array(1024).fill(0)
   });


   // If we found matching clips, search for similar ads for each match
   const similarResults = [];
   if (originalClipQuery.matches.length > 0) {
     for (const originalClip of originalClipQuery.matches) {
       const vectorValues = originalClip.values || new Array(1024).fill(0);
       const queryResult = await index.query({
         vector: vectorValues,
         filter: {
           tl_index_id: indexId,
           scope: 'clip'
         },
         topK: 5,
         includeMetadata: true,
       });
       similarResults.push(queryResult);
     }
   }

결과 데이터셋 크로싱 결합

스레드별 추출물들은 일차적으로 타겟 비디오 ID를 매개변수 삼아 한 곳에 바인딩됩니다. 우수한 신뢰성을 보이며 두 영역에 공통 출현한 콘텐츠는 최종 분석 단계에서 스코어를 2배 보정 처리(부스팅)해 가산합니다.

contextual-analysis/page.tsx (412-428행)

 if (combinedResultsMap.has(videoId)) {
           // This is a match found in both searches - update it
           const existingResult = combinedResultsMap.get(videoId);


           // Apply a significant boost for results found in both searches (50% boost)
           const boostMultiplier = 2;


           // Combine the scores: use the max of both scores and apply the boost
           const maxScore = Math.max(existingResult.textScore, result.score);
           const boostedScore = maxScore * boostMultiplier;


           combinedResultsMap.set(videoId, {
             ...existingResult,
             videoScore: result.score,
             finalScore: boostedScore,  // Boosted score for appearing in both searches
             source: "BOTH"
           });

핵심 기능 3. 챕터 나누기 및 똑똑한 광고 시간 자동 정렬 시뮬레이션 (‘Contextual Alignment Analysis’ 메뉴)

이 핵심 영역은 단순히 비디오를 일차원적으로 연동 및 매칭하는 것을 넘어 일반 가용 영상을 지능적인 단위 **챕터군**으로 자동 구획화한 후, 챕터 세그먼트 끝단에 자연스럽게 선택 광고를 안착시킵니다. 즉 실제 미디어 플랫폼에서 운용하는 실시간 중간 광고 서비스 경험을 그대로 시물레이션 구현하여 비디오 비즈니스의 부가적 가치 창출을 풍부히 대변해 줍니다.


1단계 - 지능형 자동 비디오 챕터 생성 작업

운영자가 비디오 상세 뷰어 프레임인 VideoModal을 화면에 로드하는 즉시, 핵심 코드는 Twelve Labs 플랫폼이 가진 최적의 성능을 끌어오기 위해 내부적으로 generateChapters API를 작동시켜 콘텐츠 파트를 분절합니다.

videoModal.tsx (42-47행)

 // Fetch chapters data
 const { data: chaptersData, isLoading: isChaptersLoading } = useQuery({
   queryKey: ["chapters", videoId],
   queryFn: () => generateChapters(videoId),
   enabled: isOpen && !!videoId,
 });

반환된 각 챕터 데이터 안에는 아래의 유용한 세부 메트릭이 수반됩니다:

  • end: 해당 분절의 마침 정보 필드값 (광고 큐 시점이자 삽입 트리거 포인트역할을 담당합니다)

  • chapter_title: 가독성에 맞춰 깔끔하게 자동 명명된 챕터 헤더 타이틀입니다

  • chapter_summary: 해당 특정 씬이 미장센 흐름상 또는 스토리 맥락상 마케팅 광고를 걸어 넣기에 왜 이상적인 구간인지에 대한 AI 기반의 세련된 논리적 해설(한 문장 정리)을 제시해 줍니다

이처럼 자동 구성된 지능형 챕터 정보들은 웹 런타임 뷰 내부의 **챕터 시간 타임라인 바**에 작은 점 형태의 end 인디케이터로 부드럽게 시각화됩니다. 이 타임라인 상의 미세 점을 원클릭 지목 및 제어하면, **마치 해당 영상 중간이 자연스럽게 막간 전개를 맺듯이 바로 이어서 광고를 연출**하는 식의 흐름을 시뮬레이션할 수 있습니다.

사용자 인터랙션(UX) 흐름에 따른 구체적 변화 양상:

  • 챕터가 종료되는 최접점에 예쁜 매핑 인디케이터 도트(Dot) 포인트가 배열 정렬됩니다.

  • 화면 상 도트 포인트를 사용자가 누르면 설정된 큐포인트에서 지체없이 "Show Ad" 오버레이 마스크가 자연스럽게 작동합니다.

  • 재생되는 지정 광고는 스킵 기능을 충실히 수용 가능하여 현실 유동 상황과 일치하는 미드롤 스트리밍을 제공합니다.

서버 사이드 내부 아키텍처: Twelve Labs 기능을 통한 요약 정보 챕터 생성

정제되고 깔끔한 챕터 도메인 구성 처리를 성사시키기 위해, 이 과정은 Twelve Labs 플랫폼이 자랑하는 고유의 요약(Summarize) 전용 엔드포인트 기능을 활용하며 동시에 다음과 같이 최적화된 프롬프트 구문을 빌려 사용합니다.

api/generateChapters (19-30행)

 const url = `${TWELVELABS_API_BASE_URL}/summarize`;
     const options = {
         method: "POST",
         headers: {
             "Content-Type": "application/json",
             "x-api-key": `${API_KEY}`,
           },
           body: JSON.stringify({type: "chapter", video_id: videoId, prompt: "Chapterize this video into 3 chapters. For every chapter, describe why it is a strategically appropriate point for placing an advertisement. Do not mention what type of advertisement would be suitable, as the ad content has already been determined. "})
       };


     try {
       const response = await fetch(url, options);

클라이언트 사이드 전처리 함수: generateChapters

이 함수는 React Query와 결합되어 실시간 챕터 데이터 조회를 유기적으로 성사시키고 연소 지원합니다:

apiHooks.tsx (981-984행)

export const generateChapters = async (videoId: string): Promise<ChaptersData> => {
 try {
   const response = await fetch(`/api/generateChapters?videoId=${videoId}`);


2단계 - 사용자가 특정 챕터 선택 시 중간 광고 실행 및 자연스러운 흐름 처리

마케터가 화면의 특정 챕터 마크업을 트리거하는 순간 백그라운드에서는 다음과 같은 단계적 흐름이 실행됩니다:

  1. 플레이어 타임 바가 활성화되며, 즉시 해당 선택 챕터의 공식 완결 시점이 도래하기 정확히 3초 전으로 플레이 재생바 헤드를 미끄러지듯 이동(Seek)시킵니다.

  2. 이후 재생 흐름이 실제 임계 완결 시점에 도달하자마자, 본 영상은 정지하고 곧바로 정해진 **광고 연속 재생 사이클**로 넘어가게 됩니다.

  3. 매칭 전용 광고 출현 분량이 마무리된 후에는, 원래 재생 중이던 메인 영상 파트로 매끄럽게 되돌아와 광고 전환이 연출되었던 직후 시간 축부터 재생을 자연스럽게 이어갑니다.

인디케이터 점 포인트 원터치 클릭 연산 제어

가시적이고 명시적인 중간 미드롤 광고 시뮬레이션을 원활히 작동시키기 위해, 타임라인을 나타내는 미세 도트 선택 이벤트 수신 시점에서의 플레이 시점 조정 단계는 다음과 같이 명확히 처리 구체화되어 있습니다.

VideoModal.tsx (102-126행)

 // Chapter click handler
 const handleChapterClick = (index: number) => {
   if (playbackSequence === 'ad') {
     return;
   }


   if (!adVideoDetail?.hls?.video_url) {
     console.warn("No ad selected. Please select an ad in the contextual analysis page.");
     return;
   }


   if (!chaptersData) return;


   const chapter = chaptersData.chapters[index];
   setSelectedChapter(index);
   setHasPlayedAd(false);
   setPlaybackSequence('video');
   setShowChapterInfo(true);


   if (playerRef.current) {
     // Start 3 seconds before the chapter end time
     const startTime = Math.max(0, chapter.end - 3);
     playerRef.current.seekTo(startTime, 'seconds');
   }
 };

재생 시점 모니터링 – 도트 도달 순간 광고 전환 실행

영상 콘텐츠의 스트리밍이 일정 속도로 흐르는 동안, 코드는 매 순간 재생 헤더 도달 포인트를 역계산하며 타겟 챕터 연산 종료 좌표에 이르렀다고 인정되는 최상의 전환 타이밍 조건을 충족하는 즉시 광고 재생 레이어로 화면을 넘겨 줍니다.

VideoModal.tsx (82-100행)

 // Track video progress
 const handleProgress = (state: { playedSeconds: number }) => {
   if (selectedChapter === null || !chaptersData || !adVideoDetail) {
     return;
   }


   const chapter = chaptersData.chapters[selectedChapter];
   const timeDiff = state.playedSeconds - chapter.end;
   const isLastChapter = selectedChapter === chaptersData.chapters.length - 1;


   if (
     playbackSequence === 'video' &&
     !hasPlayedAd &&
     ((isLastChapter && Math.abs(timeDiff) < 0.5) || (!isLastChapter && timeDiff >= 0))
   ) {
     setPlaybackSequence('ad');
     setHasPlayedAd(true);
   }
 };

지정 광고 종료 후 자연스러운 원래 본편 복귀 처리

영상이 끝난 바로 수 밀리초 이후, 시스템 흐름은 광고 타임라인에 머물러 있던 미디어 영역을 다시 원래의 라이브 챕터 잔여 구간으로 자동 원복시킵니다.

VideoModal.tsx (128-136행)

 // Ad ended handler
 const handleAdEnded = () => {
   if (selectedChapter === null || !chaptersData) return;
   const chapter = chaptersData.chapters[selectedChapter];
   setPlaybackSequence('video');
   setReturnToTime(chapter.end);
   setIsPlaying(true);
 };

이 기술은 일반 영상을 유연하게 단락 지으며 자연스럽게 가치 있는 지성적 중간 맞춤 전단 광고를 적재적소에 올릴 수 있는 지름길이 되어 줍니다. 콘텐츠 소스의 전개가 끊어지지 않는 완벽한 정서적 휴지기를 교묘히 활용함으로써 극강의 **지능형 맥락 부합 타깃 광고** 연출을 실현하고 비즈니스 부가 성과를 실증합니다.


맺음말

이 튜토리얼을 통해 고성능 맥락적 동영상 분석(Contextual Analysis)의 전진기지가 되어 줄 멋진 여정을 완수하였습니다. Twelve Labs 고유의 풍성한 멀티모달 프레임워크 임베딩 데이터 생성 및 적재, Pinecone 백터 파티셔닝 기술을 통한 고도의 유사 정보 병렬 선별, 그리고 결과물을 요리하듯 다듬어 챕터 구획 단위 끝자락에 안착시키는 시뮬레이션 모델까지 전 과정을 깊이 있게 탐색해 보았습니다. Twelve Labs가 제시하는 다차원 입체 멀티모달 임베딩 방식과 Pinecone의 속도감 있는 벡터 연산 필터 구조를 세심히 응용하면, 혁신적 수준의 미묘한 맥락 타기팅 경험을 실현할 수 있습니다. 이 단단히 구축된 연동 아키텍처 토대는, 빅데이터 수준의 실시간 초정밀 타기팅 연산, 자동화 A/B 마케팅 스플릿 전개, 더 나아가 초대형 고도화 비디오 비즈니스 서비스 라인업으로도 웅장하게 확장될 수 있습니다.