
튜토리얼
TwelveLabs와 Perplexity Sonar로 구축하는 비디오 딥 리서치(Deep Research)

흐리시케시 야다브 (Hrishikesh Yadav)
이 튜토리얼에서는 Twelve Labs의 Pegasus 1.2 모델을 사용해 비디오 콘텐츠를 분석하고, Perplexity Sonar를 통해 분석 결과로부터 인용 출처가 포함된 연구 인사이트를 생성하는 Video Deep Research 애플리케이션 구축 과정을 소개합니다. 프론트엔드는 Next.js로, 백엔드는 Flask로 구성되어 있으며, 이미 인덱싱된 비디오와 직접 업로드하는 방식 모두를 지원합니다.
이 튜토리얼에서는 Twelve Labs의 Pegasus 1.2 모델을 사용해 비디오 콘텐츠를 분석하고, Perplexity Sonar를 통해 분석 결과로부터 인용 출처가 포함된 연구 인사이트를 생성하는 Video Deep Research 애플리케이션 구축 과정을 소개합니다. 프론트엔드는 Next.js로, 백엔드는 Flask로 구성되어 있으며, 이미 인덱싱된 비디오와 직접 업로드하는 방식 모두를 지원합니다.

목차
No headings found on page
뉴스레터 구독하기
뉴스레터 구독하기
영상 이해 분야의 최신 기술 업데이트, 튜토리얼 및 인사이트를 받아보세요.
영상 이해 분야의 최신 기술 업데이트, 튜토리얼 및 인사이트를 받아보세요.
AI로 영상을 검색하고, 분석하고, 탐색하세요.
2025. 10. 7.
13분
링크 복사하기
소개
웹에서 텍스트를 검색하듯 비디오를 간편하게 검색하고, 신뢰할 수 있는 인용 출처가 포함된 통찰력을 얻을 수 있다면 어떨까요? 🎥🔍
오늘날 이는 여전히 웹에서 누락된 퍼즐 조각과 같습니다. 기존 검색 엔진은 비디오를 결과를 도출하기 위한 입력값으로 고려하지 않습니다. 이 때문에 연구자, 크리에이터, 전문가들은 체계적인 통찰력을 추출하거나 이를 검증할 신뢰할 수 있는 방법 없이, 수작업으로 몇 시간 분량의 영상을 일일이 확인해야 하는 번거로움을 겪고 있습니다.
비디오 딥 리서치(Video Deep Research)는 비디오를 탐색하는 패러다임을 혁신합니다. 의미론적 비디오 이해를 위한 TwelveLabs Analyze pegasus-1.2와 인용 기반의 지식 검색을 지원하는 Sonar by Perplexity를 결합하여, 비디오를 검색 가능하고 신뢰할 수 있는 연구 자원으로 전환해 줍니다.
그럼 비디오 딥 리서치 애플리케이션이 어떻게 작동하는지 알아보고, TwelveLabs Python SDK와 Perplexity Sonar를 활용하여 어떻게 고도화된 비디오 이해 및 딥 리서치 솔루션을 직접 구축할 수 있는지 살펴보겠습니다.
애플리케이션의 데모는 여기에서 확인하실 수 있습니다: Video Deep Research Application
사전 준비 단계
TwelveLabs Playground에 가입하여 API 키를 생성하세요.
Sonar에 가입하고 모델에 접근하기 위한 API 키를 생성합니다.
이 애플리케이션의 리포지토리는 Github Repository에서 확인하실 수 있습니다.
Python, Flask 및 Next.js에 대한 기본적인 이해가 필요합니다.
데모 애플리케이션
본 데모 애플리케이션은 비디오 이해와 지식 검색의 결합이 어떻게 리서치 방식의 새로운 지평을 열 수 있는지 보여줍니다.
사용자는 TwelveLabs API 키를 연결하여 비디오를 간편하게 업로드하거나 이미 인덱싱된 비디오 중에서 선택할 수 있습니다. 이후 애플리케이션이 콘텐츠를 분석하여 구조화된 정보(통찰력)를 추출하고, 이를 검증 가능한 논거 및 출처와 연결함으로써 비디오와 신뢰할 수 있는 연구 데이터를 매끄럽게 이어줍니다.
지금부터 직접 비디오 딥 리서치 기반 애플리케이션을 구축하고 확장해 볼 수 있도록 코드와 데모의 상세 가이드를 제공합니다 —

애플리케이션 작동 방식
이 애플리케이션은 두 가지 고유한 상호작용 모드를 지원합니다 -
TwelveLabs API 키 사용: 개인 TwelveLabs API 키를 연결하여 이미 인덱싱된 비디오에 접근하고 분석할 수 있습니다. 연결이 완료되면 기존 Index ID와 해당하는 비디오를 선택하면 됩니다.
비디오 업로드: 비디오를 업로드할 때, 애플리케이션이 원활한 설정을 위해 기본 TwelveLabs API 키를 자동으로 사용하도록 설계되었습니다. 업로드가 완료되면 인덱싱 프로세스가 즉시 시작됩니다. 인덱싱이 완료되면 가장 최근에 업로드된 비디오가 최신 사용 가능한 콘텐츠로 표시됩니다. 이 단계 이후부터는 쿼리 및 인용 출처 도출 워크플로우가 아래 명시된 단계에 따라 두 모드 모두 동일하게 진행됩니다.
애플리케이션의 전체 워크플로우는 TwelveLabs 클라이언트를 설정하는 것으로 시작합니다. 이를 위해 시스템 환경 변수에서 제공하는 키를 활용하거나, 사용자가 클라이언트 사이드에서 자체 API 키를 등록하여 이미 인덱싱된 비디오에 접근할 수 있도록 설정해야 합니다. 클라이언트가 구성되면 아래에 정리된 일련의 프로세스에 따라 분석이 수행됩니다 –
인덱스 불러오기 (Fetch Indexes) – 연동된 TwelveLabs 계정에 연결된 인덱스 목록을 보여줍니다.
비디오 선택 (Select Video) – 분석하고자 하는 인덱스에서 대상 비디오를 선택합니다.
비디오 분석 (Analyze Video) – 제공된 질의(Query)에 따라 선택한 비디오의 내용과 맥락을 정밀 분석합니다.
딥 리서치 (Deep Research) – 비디오 분석 결과와 구조화된 프롬프트, 그리고 사용자의 질의를 결합하여 Sonar 연구 모델로 전달해, 깊이 있는 추론과 검증된 인용 정보를 바탕으로 풍부한 결과물을 창출합니다.
이와 같이 정밀하게 짜인 워크플로우 덕분에 비디오 인덱싱부터 고급 리서치에 이르기까지 일련의 과정이 흐르듯 매끄럽게 진행되며 사용자에게 맥락을 정확히 꿰뚫는 분석 결과를 제공합니다.
두 가지 접근 방식 모두 아래 아키텍처 다이어그램에서 가시적으로 보여주고 있습니다.

연구 응답이 생성된 후 사용자는 동일한 컨텍스트 내에서 추가 문서나 더 깊이 있는 내용을 요하는 후속 질의를 할 수 있습니다. 이러한 연속된 질의들은 다시 Sonar 리서치 루프로 유입되어 컨텍스트의 연속성을 유지하면서 기존 지식 베이스를 점점 더 넓혀갑니다. 이 반복적인 구조 덕분에 새로운 질의가 있을 때마다 이전 분석 결과를 토대로 더욱 고도화되고 깊이 있는 리서치 결과물이 쌓여가게 됩니다.
사전 준비 단계
TwelveLabs Playground에서 API 키를 발급받아 환경 변수로 등록합니다.
TwelveLabs Playground를 통해
pegasus-1.2엔진을 선택하여 인덱스를 생성하고, 이 애플리케이션에 적용할 구체적인index_id를 확인해 둡니다.Github에서 프로젝트 코드를 클론합니다.
Sonar by Perplexity에서 API 키를 발급 받습니다.
TwelveLabs 및 Sonar 인증 정보를 모두 포함하는
.env파일을 작성합니다. 예시 템플릿은 여기에서 참고하실 수 있습니다.
위의 단계를 모두 준비하셨다면 이제 본격적인 개발로 나아갈 준비가 되었습니다!
비디오 딥 리서치 앱 구현 상세 가이드
이번 튜토리얼에서는 비디오 콘텐츠를 기반으로 웹에서 신뢰할 수 있는 정보와 구체적인 인용 자료를 완벽히 매칭하는 애플리케이션의 구축 방법을 다룹니다. 프론트엔드는 Next.js를, 백엔드는 Flask API(CORS 구성 적용)를 바탕으로 하고 있습니다. 특히 비디오 딥 리서치 기능을 지탱하는 백엔드 유틸리티 핵심 로직 구현과 함께, 분석 환경 전체를 구성하는 부분에 초점을 맞춰 이야기하겠습니다.
구체적인 설정 방식과 프로젝트 파일 전반의 세부 구성은 GitHub 리포지토리의 README.md 파일을 살펴보세요.
1 - 비디오 딥 리서치 구현 워크플로우
이 설계 과정에서 가장 중요한 단계는 바로 TwelveLabs API 키를 안전하게 초기화하고 다루는 일입니다. 애플리케이션은 기본 설정을 위해 환경 변수에서 키를 읽어오거나 사용자가 포털 화면을 통해 입력한 자체 API 키를 동적으로 적용할 수 있습니다.
backend/service/twelvelabs_service.py (14-36 Line)
class TwelveLabsService: def __init__(self, api_key=None): # API 키가 주어지지 않은 경우 환경 변수 조회를 시도합니다. if api_key is None: api_key = os.environ.get('TWELVELABS_API_KEY', '') self.api_key = api_key # 인스턴스에 API 키 저장 self.client = TwelveLabs(api_key=api_key) # TwelveLabs 클라이언트 초기화
1.1 인덱스 리스트(Indexes) 가져오기
사용자가 브라우저 콘솔 창을 통해 입력하거나 내부 환경 변수로부터 TwelveLabs API 키를 성공적으로 로드하면 계정에 할당된 모든 인덱스 데이터를 수집합니다. 정돈된 정보는 비디오 선택을 위해 프론트엔드 컴포넌트에 직관적으로 전달됩니다.
backend/service/twelvelabs_service.py (14-36 Line)
def get_indexes(self): try: print("인덱스를 가져오는 중...") # API 키 사용 가능 여부 확인 if not self.api_key: print("사용 가능한 API 키가 없습니다.") return [] # TwelveLabs 클라이언트를 사용해 인덱스 목록 획득 indexes = self.client.indexes.list() result = [] for index in indexes: # 인덱스 상세 구조 구성 result.append({ "id": index.id, "name": index.index_name }) print(f"ID: {index.id}") print(f" Name: {index.index_name}") return result except Exception as e: print(f"인덱스를 가져오는 중 오류 발생: {e}") return []
1.2 선택된 Index ID에 해당하는 비디오 목록 가져오기
사용자가 탐색할 인덱스를 하나 선택하면 애플리케이션은 해당 index_id를 기준으로 매핑된 최적화 비디오 항목들을 모조리 수집해 프론트엔드로 전달합니다.
backend/service/twelvelabs_service.py (38-70 Line)
def get_videos(self, index_id, page=1): try: # API 키 사용 가능 여부 확인 if not self.api_key: print("사용 가능한 API 키가 없습니다.") return [] # TwelveLabs 클라이언트를 사용해 비디오 조회 videos_response = self.client.indexes.videos.list(index_id=index_id, page=page) result = [] for video in videos_response.items: system_metadata = video.system_metadata hls_data = video.hls thumbnail_urls = hls_data.get('thumbnail_urls', []) if hls_data else [] thumbnail_url = thumbnail_urls[0] if thumbnail_urls else None video_url = hls_data.get('video_url') if hls_data else None # 비디오 상세 인스턴스 사전 매핑 result.append({ "id": video.id, "name": system_metadata.filename if system_metadata and system_metadata.filename else f'Video {video.id}', "duration": system_metadata.duration if system_metadata else 0, "thumbnail_url": thumbnail_url, "video_url": video_url, "width": system_metadata.width if system_metadata else 0, "height": system_metadata.height if system_metadata else 0, "fps": system_metadata.fps if system_metadata else 0, "size": system_metadata.size if system_metadata else 0 }) return result except Exception as e: print(f"인덱스 {index_id}의 비디오를 가져오는 중 오류 발생: {e}") return []
1.3 비디오 콘텐츠 내부 정보 분석
사용자가 최종 비디오 타겟을 정하고 질문을 던지면 분석 모듈로 video_id와 질의를 전송합니다. 질의문은 정밀 설계된 기반 프롬프트 뒤에 연결되며, 이를 통해 맥락이 풍부하고 유의미한 비디오 분석 데이터를 확보합니다. 비디오 분석을 유도하기 위해 설정한 핵심 프롬프트의 내용은 여기서 직접 둘러보실 수 있습니다.
backend/service/twelvelabs_service.py (72-81 Line)
def analyze_video(self, video_id, prompt): try: # TwelveLabs 클라이언트를 통한 비디오 정보 생성 analysis_response = self.client.analyze( video_id=video_id, prompt=prompt ) return analysis_response.data except Exception as e: print(f"비디오 {video_id} 분석 중 오류 발생: {e}") raise e
1.4 분석된 비디오 정보 기반의 딥 리서치 전개
비디오 분석 데이터 수집이 일단락되면 Sonar 추론 모델을 활성화하여 딥 리서치 영역으로 나아갑니다. 하나의 페이로드 안에 사용자의 원래 질의, 리서치 정밀 가이드 템플릿, 그리고 방금 생성된 비디오 전반의 세부 컨텍스트를 하나로 묶어 송신합니다. Sonar는 이를 완전히 분해하고 가공해 정돈된 정보와 최적화된 자료 출처를 보여줍니다. 딥 리서치 처리를 구축한 뼈대 프롬프트 양식은 여기서 열어보실 수 있습니다.
backend/service/sonar_service.py (13-52 Line)
def deep_research(self, query, timeout=180): try: # API 키 사용 가능 여부 확인 if not self.api_key: raise ValueError("API 키가 필요합니다.") payload = { "model": "sonar", "messages": [ {"role": "user", "content": query} ] } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } # 타임아웃 설정을 포함해 API 엔드포인트로 POST 요청 전송 response = requests.post( self.base_url, json=payload, headers=headers, timeout=timeout ) # 요청 결과 승인 확인 if response.status_code == 200: return response.json() else: print(f"오류: {response.status_code} - {response.text}") return {"error": f"API 요청 실패 (상태 코드: {response.status_code})"} except requests.exceptions.Timeout: print("요청 시간 초과") return {"error": "요청 시간 초과 - Sonar 리서치가 너무 오래 걸립니다."} except requests.exceptions.RequestException as e: print(f"요청 중 오류 발생: {e}") return {"error": f"네트워크 오류: {str(e)}"} except Exception as e: print(f"deep_research 실행 중 오류 발생: {e}") return {"error": str(e)}
Perplexity 모델은 sonar 외에도 sonar-reasoning, sonar-deep-research 같은 폭넓은 옵션을 열어두고 있습니다. 특히 sonar-deep-research 모델은 깊이 있는 연구 프로세스와 수집 과정 속도의 균형을 이상적으로 맞춘 medium 값을 디폴트로 하여 reasoning_effort(low, medium, high) 설정을 추가 조율할 수 있습니다. 난이도를 high로 세팅하면 훨씬 가치 있고 밀도 높은 주석들과 레퍼런스들이 창출되지만, 처리 대기 연산과 토큰 비용이 함께 오르기 때문에 프로젝트 목표 속성과 지연 예산 범위를 조화롭게 타협해 기용 모델 버전을 설계하시는 편이 이상적입니다.
단순히 모델명을 sonar-deep-research로 수정하는 것만으로 훨씬 입체적인 추론과 광범위한 리서치 출처 모음집을 경험할 수 있어, 기본 sonar 옵션 설정 대비 고차원적 정보 구조를 형성하기 좋습니다. 생성된 정밀 답변 예제를 직접 아래의 화면을 조율해 관찰하세요 —

1.5 리서치 기능 동작 종합 흐름 제어
연계 흐름의 기점은 API 통신 자격 및 대상 비디오 컨텍스트가 완전한 상태인지 확인하는 파트입니다. 해당 선제 검수가 완벽히 확인되면 백엔드는 타겟 비디오의 필수 구조 요소를 즉시 수집합니다. 이를 통해 선택한 비디오의 맥락을 명확히 정의한 뒤 다음 단계로 넘어갑니다. 백엔드가 도출하는 진행 정보들을 실시간 스트리밍 형태로 전면 UI에 전달하도록 yield 제어기를 탑재하여, 프론트엔드 유저는 결과 완성을 무기한 기다리지 않고 진척 정보를 체감할 수 있습니다.
정보를 품은 제어기 파이프는 TwelveLabs 서비스가 안착시킨 analyze_video 객체로 전진합니다. 획득한 비주얼 타겟의 요소를 미리 만든 템플릿과 정돈된 질문 양식 구조에 결합하여, 마크다운 형태를 유지하면서 사용자 맞춤형 출력의 통일성을 지켜냅니다. 이렇게 조율된 최적화 패키지를 Sonar API로 밀어 넣어 가장 세련된 검증 데이터를 수집하고 정돈해 출력창에 전달합니다.
backend/routes/api_routes.py (31-162 Line)
def generate_workflow(twelvelabs_api_key, index_id, video_id, analysis_prompt, research_query, research_prompt_template): # 입력 값 유효성 체크 if not twelvelabs_api_key: yield json.dumps({'type': 'error', 'message': 'TwelveLabs API 키가 필요합니다.'}) + '\n' return if not index_id or not video_id: yield json.dumps({'type': 'error', 'message': 'Index ID와 Video ID가 필요합니다.'}) + '\n' return if not research_query: yield json.dumps({'type': 'error', 'message': '리서치 질의가 필요합니다.'}) + '\n' return try: twelvelabs_service = TwelveLabsService(api_key=twelvelabs_api_key) # 1단계: 비디오 상세 정보 가져오기 yield safe_json_dumps({ 'type': 'progress', 'step': 'video_details', 'message': '비디오 상세 정보를 가져오는 중...', 'progress': 0 }) + '\n' video_details = twelvelabs_service.get_video_details(index_id, video_id) if not video_details: yield safe_json_dumps({'type': 'error', 'message': '비디오 상세 정보를 검색할 수 없습니다.'}) + '\n' return yield safe_json_dumps({ 'type': 'data', 'step': 'video_details', 'data': { 'id': video_details.get('_id', ''), 'filename': video_details.get('system_metadata', {}).get('filename', ''), 'duration': video_details.get('system_metadata', {}).get('duration', 0) }, 'progress': 33 }) + '\n' # 2단계: 비디오 분석 yield safe_json_dumps({ 'type': 'progress', 'step': 'analysis', 'message': '비디오 콘텐츠 분석 중...', 'progress': 33 }) + '\n' analysis_result = twelvelabs_service.analyze_video(video_id, analysis_prompt) yield safe_json_dumps({ 'type': 'data', 'step': 'analysis', 'data': analysis_result, 'progress': 66 }) + '\n' # 3단계: 컨텍스트 기반 리서치 yield safe_json_dumps({ 'type': 'progress', 'step': 'research', 'message': '심층 리서치 진행 중...', 'progress': 66 }) + '\n' enhanced_query = research_prompt_template.format( analysis_result=analysis_result, research_query=research_query ) sonar_service = SonarService() research_result = sonar_service.deep_research(enhanced_query, timeout=180) if 'error' in research_result: yield safe_json_dumps({'type': 'error', 'message': f'리서치 실패: {research_result["error"]}'}) + '\n' return # 리서치 결과 콘텐츠 추출 research_content = "" if research_result and research_result.get('choices'): research_content = research_result['choices'][0].get('message', {}).get('content', '') # 결과 데이터가 클 경우 청크 단위로 나누어 전송 max_chunk_size = 10000 if len(research_content) > max_chunk_size: for i in range(0, len(research_content), max_chunk_size): chunk = research_content[i:i + max_chunk_size] is_final = (i + max_chunk_size) >= len(research_content) yield safe_json_dumps({ 'type': 'research_chunk', 'content': chunk, 'is_final': is_final, 'progress': 80 + (i / len(research_content)) * 20 }) + '\n' # 청크 분할 전송 완료 플래그 적용 yield safe_json_dumps({ 'type': 'complete', 'data': { 'research': { 'choices': [{ 'message': { 'content': '[CHUNKED_CONTENT]' } }], 'citations': research_result.get('citations', [])[:10], 'usage': research_result.get('usage', {}) }, 'sources': research_result.get('search_results', [])[:10] }, 'progress': 100 }) + '\n' else: # 단일 전송 전개 수렴 완료 처리 yield safe_json_dumps({ 'type': 'complete', 'data': { 'research': { 'choices': [{ 'message': { 'content': research_content } }], 'citations': research_result.get('citations', [])[:10], 'usage': research_result.get('usage', {}) }, 'sources': research_result.get('search_results', [])[:10] }, 'progress': 100 }) + '\n' except Exception as e: yield safe_json_dumps({'type': 'error', 'message': str(e)}) + '\n'
방대한 양의 리서치 결과물을 안정적으로 처리하기 위해, 백엔드 엔진은 응답 청크 분할 전송 방식을 차용하고 있습니다. Sonar 모델은 간혹 치밀한 추론 논리와 엄청난 수의 각주 정보를 일시에 대량으로 퍼내는 경향이 있어서, 이를 단 하나의 거대한 JSON 패키지로 모아 직렬화하면 크기 제한 임계치를 초과해 먹통이 될 리스크가 존재합니다. 따라서 안정적인 단위로 데이터를 조각내어 순차적으로 전송(Streaming)해야 확장성을 확보하고 네트워크 병목 현상을 방지하면서 프론트엔드의 화면 반응성을 가볍게 유지할 수 있습니다.
2 - 핵심 비디오 업로드 인덱싱 가이드
미리 정의해 둔 인덱스 비디오 리스트 대신, 사용자가 동영상 미디어를 즉시 직접 인출해 업로드해야 하는 환경도 빈번히 마주합니다. 이에 대응하기 위해 upload_video_file 메서드가 유효성을 검증하며, API 키 및 로컬 업로드 파일 경로가 완전한 상태에서 TwelveLabs 백엔드로 다이렉트 전송하는 신규 Task 생성 요청 단계를 밟습니다. 해당 미디어 전송 통신 처리가 안정되면 고유 번호인 task_id를 인출하여 모니터링 주기를 활성화합니다.
그 뒤 백엔드는 일정한 주기마다 완료 보고 혹은 에러 여부를 추적하는 폴링(Polling) 프로세스 루프를 돌기 시작합니다. 대기 시간이 마감 임계점을 넘지 않고 인덱싱 작업이 완결되면 결과 개체에서 video_id를 인출하는데, 이는 해당 신규 비디오 미디어가 즉시 해석 가능한 단계의 자원이 되었다는 마커입니다. 업로드된 파일이 정상적으로 작동하여 최신 동영상 풀에 합류하게 되며, 처리 실패 같은 이상 정황 시에는 적합한 정보 파라미터를 돌려주어 확실한 예외 대응 수단을 확보합니다.
backend/service/twelvelabs_service.py (145-207 Line)
def upload_video_file(self, index_id: str, file_path: str, timeout_seconds: int = 900): import sys try: if not self.api_key: return {"error": "TwelveLabs API 키가 없습니다."} if not index_id: return {"error": "index_id가 없습니다."} if not os.path.exists(file_path): return {"error": f"파일을 찾을 수 없습니다: {file_path}"} print(f"파일 업로드 시작: {file_path}", file=sys.stderr) tasks_url = "https://api.twelvelabs.io/v1.3/tasks" headers = { "x-api-key": self.api_key } # 업로드 태스크 생성 with open(file_path, "rb") as f: files = { "video_file": (os.path.basename(file_path), f) } data = { "index_id": index_id } resp = requests.post(tasks_url, headers=headers, files=files, data=data) if resp.status_code not in (200, 201): return {"error": f"업로드 태스크 생성 실패: {resp.status_code} {resp.text}"} resp_json = resp.json() if resp.text else {} task_id = resp_json.get("id") or resp_json.get("task_id") or resp_json.get("_id") if not task_id: return {"error": f"반환된 태스크 id가 없습니다: {resp_json}"} # 작업이 완결될 때까지 폴링(Polling) 수행 import time start_time = time.time() print(f"태스크 {task_id} 완료 여부 확인 중...", file=sys.stderr) while time.time() - start_time < timeout_seconds: r = requests.get(f"{tasks_url}/{task_id}", headers=headers) if r.status_code != 200: time.sleep(2) continue task = r.json() if r.text else {} status = task.get("status") print(f"태스크 {task_id} 상태: {status}", file=sys.stderr) if status in ("ready", "completed"): video_id = task.get("video_id") or (task.get("data") or {}).get("video_id") print(f"인덱싱이 성공적으로 완료되었습니다! Video ID: {video_id}", file=sys.stderr) return {"status": status, "video_id": video_id, "task": task} if status in ("failed", "error"): print(f"인덱싱 실패, 상태: {status}", file=sys.stderr) return {"error": f"인덱싱 실패와 관련된 상태값 {status}", "task": task} time.sleep(2) print(f"{timeout_seconds}초 초과로 업로드 타임아웃 발생", file=sys.stderr) return {"error": "업로드 시간 초과"}
동영상 자료의 업로드 및 인덱스 처리가 안전하게 끝나 video_id가 성공적으로 반환되면, 이후 분석과 지식 탐색 워크플로우 파이프라인은 앞서 검토했던 방식 그대로 일정하게 밟아나갑니다. 이 덕분에 이미 저장되어 있던 기성 비디오를 이용하든 새로운 사용자의 맞춤형 미디어를 다루든 백엔드의 수렴성이 일관되게 보존됩니다. 비디오 업로드 인출 과정 및 인덱싱 처리, 심층 리서치 작동 전 과정을 관찰하려면 하단의 동영상을 클릭하세요 —

이 설계 구조는 프론트엔드 환경에서 TwelveLabs API 토큰 제어를 동적으로 바인딩하는 것을 도우므로, 연구용 계정 소유의 API 자격으로 직접 접근하여 서버를 통해 개인 비디오 소스 목록을 인출하려는 파트너들에게도 원활한 유연함을 보장합니다.

이 튜토리얼을 응용할 수 있는 혁신적인 방안들
비디오에 대한 의미론적 이해와 외부의 검증된 리서치 지식이 통합됨에 따라, 한층 강력하고 다채로운 분석 서비스를 만들 수 있는 무한한 가능성이 열렸습니다. 다음은 TwelveLabs Analyze와 Perplexity Sonar 엔진들을 핵심 모형으로 기용해 직접 구축해 볼 만한 가치 있는 아이디어들입니다 —
🔍 정밀 비디오 팩트 제크(Fact-Checking) 서비스: 비디오 데이터가 지니는 단서 논점들을 검출한 뒤, 가장 공신력 높은 외부 출처들의 정보망과 교차 매칭하여 주장을 지능적으로 검증하고 참 거짓을 밝혀줍니다.
📑 지능형 비디오 서머리 및 요약: 수 시간 길이의 영상에서 담론 구조를 완전히 발라내고 구조화된 리포트를 실시간 창출하여 효율적인 연구 및 논문 정리 작업 속도를 획기적으로 낮춥니다.
📚 차세대 상호작용 학습 채널(Learning Workflows): 미디어 요점과 관련된 심층 지식망을 결합해, 연구원, 학생, 지식 콘텐츠 창작자에게 지능적인 대화 중심 인터랙티브 교육 어플라이언스를 구축해 줍니다.
마치며
본 튜토리얼은 비디오 세부 상황을 종합적으로 이해하는 프로세스가 연구 생산성에 얼마나 지대한 공헌을 할 수 있는지를 단적으로 알려 줍니다. 비주얼 컨텍스트 분석의 강자인 TwelveLabs Analyze의 비디오 추출력과 공신력 있는 근거 자료를 수집·가공하는 Sonar by Perplexity를 이상적으로 조립하여, 정적이고 수동적이었던 비디오 리소스를 탐색 가능하고 신뢰할 수 있는 학술 리서치 데이터로 승화시켰습니다. 이제 연구자, 크리에이터 및 다양한 파트너들이 한 차원 높은 깊은 탐색을 바탕으로 소통할 수 있게 되었습니다.
추가 리소스
비디오 분석의 핵심 심장인 멀티모달 프레임워크 학습의 자세한 구조를 탐구하세요 — Pegasus-1.2. TwelveLabs에 대한 풍부한 이해 도모 및 구현 꿀팁을 습득하고 싶으시다면 다음 사이트들을 편하게 경유하세요.
더 많은 활용 사례 발견하기: Sonar by Perplexity에 방문하여 강력한 검색 기능에 대해 알아보고, 본 가이드의 기본 얼개 구조를 살짝 튜닝해 세상에 없던 창조적인 사용 사례를 구현하세요.
고객 커뮤니티 네트워킹: 본 설계안이나 분석 아이디어와 관련된 피드백을 TwelveLabs Discord에서 동료 엔지니어들과 활기차게 소통할 수 있습니다.
다양한 튜토리얼 살펴보기: TwelveLabs만의 압도적인 하이 테크 서비스 활용 지식을 가득 품은 세분화된 가이드 아카이브를 전면 개방합니다.
저희는 여러분이 이러한 리소스를 적극적으로 활용하여 지식을 확장하고, TwelveLabs의 비디오 이해 기술을 통해 혁신적인 서비스를 직접 만들어 갈 수 있도록 든든한 파트너로서 지원할 것입니다.
소개
웹에서 텍스트를 검색하듯 비디오를 간편하게 검색하고, 신뢰할 수 있는 인용 출처가 포함된 통찰력을 얻을 수 있다면 어떨까요? 🎥🔍
오늘날 이는 여전히 웹에서 누락된 퍼즐 조각과 같습니다. 기존 검색 엔진은 비디오를 결과를 도출하기 위한 입력값으로 고려하지 않습니다. 이 때문에 연구자, 크리에이터, 전문가들은 체계적인 통찰력을 추출하거나 이를 검증할 신뢰할 수 있는 방법 없이, 수작업으로 몇 시간 분량의 영상을 일일이 확인해야 하는 번거로움을 겪고 있습니다.
비디오 딥 리서치(Video Deep Research)는 비디오를 탐색하는 패러다임을 혁신합니다. 의미론적 비디오 이해를 위한 TwelveLabs Analyze pegasus-1.2와 인용 기반의 지식 검색을 지원하는 Sonar by Perplexity를 결합하여, 비디오를 검색 가능하고 신뢰할 수 있는 연구 자원으로 전환해 줍니다.
그럼 비디오 딥 리서치 애플리케이션이 어떻게 작동하는지 알아보고, TwelveLabs Python SDK와 Perplexity Sonar를 활용하여 어떻게 고도화된 비디오 이해 및 딥 리서치 솔루션을 직접 구축할 수 있는지 살펴보겠습니다.
애플리케이션의 데모는 여기에서 확인하실 수 있습니다: Video Deep Research Application
사전 준비 단계
TwelveLabs Playground에 가입하여 API 키를 생성하세요.
Sonar에 가입하고 모델에 접근하기 위한 API 키를 생성합니다.
이 애플리케이션의 리포지토리는 Github Repository에서 확인하실 수 있습니다.
Python, Flask 및 Next.js에 대한 기본적인 이해가 필요합니다.
데모 애플리케이션
본 데모 애플리케이션은 비디오 이해와 지식 검색의 결합이 어떻게 리서치 방식의 새로운 지평을 열 수 있는지 보여줍니다.
사용자는 TwelveLabs API 키를 연결하여 비디오를 간편하게 업로드하거나 이미 인덱싱된 비디오 중에서 선택할 수 있습니다. 이후 애플리케이션이 콘텐츠를 분석하여 구조화된 정보(통찰력)를 추출하고, 이를 검증 가능한 논거 및 출처와 연결함으로써 비디오와 신뢰할 수 있는 연구 데이터를 매끄럽게 이어줍니다.
지금부터 직접 비디오 딥 리서치 기반 애플리케이션을 구축하고 확장해 볼 수 있도록 코드와 데모의 상세 가이드를 제공합니다 —

애플리케이션 작동 방식
이 애플리케이션은 두 가지 고유한 상호작용 모드를 지원합니다 -
TwelveLabs API 키 사용: 개인 TwelveLabs API 키를 연결하여 이미 인덱싱된 비디오에 접근하고 분석할 수 있습니다. 연결이 완료되면 기존 Index ID와 해당하는 비디오를 선택하면 됩니다.
비디오 업로드: 비디오를 업로드할 때, 애플리케이션이 원활한 설정을 위해 기본 TwelveLabs API 키를 자동으로 사용하도록 설계되었습니다. 업로드가 완료되면 인덱싱 프로세스가 즉시 시작됩니다. 인덱싱이 완료되면 가장 최근에 업로드된 비디오가 최신 사용 가능한 콘텐츠로 표시됩니다. 이 단계 이후부터는 쿼리 및 인용 출처 도출 워크플로우가 아래 명시된 단계에 따라 두 모드 모두 동일하게 진행됩니다.
애플리케이션의 전체 워크플로우는 TwelveLabs 클라이언트를 설정하는 것으로 시작합니다. 이를 위해 시스템 환경 변수에서 제공하는 키를 활용하거나, 사용자가 클라이언트 사이드에서 자체 API 키를 등록하여 이미 인덱싱된 비디오에 접근할 수 있도록 설정해야 합니다. 클라이언트가 구성되면 아래에 정리된 일련의 프로세스에 따라 분석이 수행됩니다 –
인덱스 불러오기 (Fetch Indexes) – 연동된 TwelveLabs 계정에 연결된 인덱스 목록을 보여줍니다.
비디오 선택 (Select Video) – 분석하고자 하는 인덱스에서 대상 비디오를 선택합니다.
비디오 분석 (Analyze Video) – 제공된 질의(Query)에 따라 선택한 비디오의 내용과 맥락을 정밀 분석합니다.
딥 리서치 (Deep Research) – 비디오 분석 결과와 구조화된 프롬프트, 그리고 사용자의 질의를 결합하여 Sonar 연구 모델로 전달해, 깊이 있는 추론과 검증된 인용 정보를 바탕으로 풍부한 결과물을 창출합니다.
이와 같이 정밀하게 짜인 워크플로우 덕분에 비디오 인덱싱부터 고급 리서치에 이르기까지 일련의 과정이 흐르듯 매끄럽게 진행되며 사용자에게 맥락을 정확히 꿰뚫는 분석 결과를 제공합니다.
두 가지 접근 방식 모두 아래 아키텍처 다이어그램에서 가시적으로 보여주고 있습니다.

연구 응답이 생성된 후 사용자는 동일한 컨텍스트 내에서 추가 문서나 더 깊이 있는 내용을 요하는 후속 질의를 할 수 있습니다. 이러한 연속된 질의들은 다시 Sonar 리서치 루프로 유입되어 컨텍스트의 연속성을 유지하면서 기존 지식 베이스를 점점 더 넓혀갑니다. 이 반복적인 구조 덕분에 새로운 질의가 있을 때마다 이전 분석 결과를 토대로 더욱 고도화되고 깊이 있는 리서치 결과물이 쌓여가게 됩니다.
사전 준비 단계
TwelveLabs Playground에서 API 키를 발급받아 환경 변수로 등록합니다.
TwelveLabs Playground를 통해
pegasus-1.2엔진을 선택하여 인덱스를 생성하고, 이 애플리케이션에 적용할 구체적인index_id를 확인해 둡니다.Github에서 프로젝트 코드를 클론합니다.
Sonar by Perplexity에서 API 키를 발급 받습니다.
TwelveLabs 및 Sonar 인증 정보를 모두 포함하는
.env파일을 작성합니다. 예시 템플릿은 여기에서 참고하실 수 있습니다.
위의 단계를 모두 준비하셨다면 이제 본격적인 개발로 나아갈 준비가 되었습니다!
비디오 딥 리서치 앱 구현 상세 가이드
이번 튜토리얼에서는 비디오 콘텐츠를 기반으로 웹에서 신뢰할 수 있는 정보와 구체적인 인용 자료를 완벽히 매칭하는 애플리케이션의 구축 방법을 다룹니다. 프론트엔드는 Next.js를, 백엔드는 Flask API(CORS 구성 적용)를 바탕으로 하고 있습니다. 특히 비디오 딥 리서치 기능을 지탱하는 백엔드 유틸리티 핵심 로직 구현과 함께, 분석 환경 전체를 구성하는 부분에 초점을 맞춰 이야기하겠습니다.
구체적인 설정 방식과 프로젝트 파일 전반의 세부 구성은 GitHub 리포지토리의 README.md 파일을 살펴보세요.
1 - 비디오 딥 리서치 구현 워크플로우
이 설계 과정에서 가장 중요한 단계는 바로 TwelveLabs API 키를 안전하게 초기화하고 다루는 일입니다. 애플리케이션은 기본 설정을 위해 환경 변수에서 키를 읽어오거나 사용자가 포털 화면을 통해 입력한 자체 API 키를 동적으로 적용할 수 있습니다.
backend/service/twelvelabs_service.py (14-36 Line)
class TwelveLabsService: def __init__(self, api_key=None): # API 키가 주어지지 않은 경우 환경 변수 조회를 시도합니다. if api_key is None: api_key = os.environ.get('TWELVELABS_API_KEY', '') self.api_key = api_key # 인스턴스에 API 키 저장 self.client = TwelveLabs(api_key=api_key) # TwelveLabs 클라이언트 초기화
1.1 인덱스 리스트(Indexes) 가져오기
사용자가 브라우저 콘솔 창을 통해 입력하거나 내부 환경 변수로부터 TwelveLabs API 키를 성공적으로 로드하면 계정에 할당된 모든 인덱스 데이터를 수집합니다. 정돈된 정보는 비디오 선택을 위해 프론트엔드 컴포넌트에 직관적으로 전달됩니다.
backend/service/twelvelabs_service.py (14-36 Line)
def get_indexes(self): try: print("인덱스를 가져오는 중...") # API 키 사용 가능 여부 확인 if not self.api_key: print("사용 가능한 API 키가 없습니다.") return [] # TwelveLabs 클라이언트를 사용해 인덱스 목록 획득 indexes = self.client.indexes.list() result = [] for index in indexes: # 인덱스 상세 구조 구성 result.append({ "id": index.id, "name": index.index_name }) print(f"ID: {index.id}") print(f" Name: {index.index_name}") return result except Exception as e: print(f"인덱스를 가져오는 중 오류 발생: {e}") return []
1.2 선택된 Index ID에 해당하는 비디오 목록 가져오기
사용자가 탐색할 인덱스를 하나 선택하면 애플리케이션은 해당 index_id를 기준으로 매핑된 최적화 비디오 항목들을 모조리 수집해 프론트엔드로 전달합니다.
backend/service/twelvelabs_service.py (38-70 Line)
def get_videos(self, index_id, page=1): try: # API 키 사용 가능 여부 확인 if not self.api_key: print("사용 가능한 API 키가 없습니다.") return [] # TwelveLabs 클라이언트를 사용해 비디오 조회 videos_response = self.client.indexes.videos.list(index_id=index_id, page=page) result = [] for video in videos_response.items: system_metadata = video.system_metadata hls_data = video.hls thumbnail_urls = hls_data.get('thumbnail_urls', []) if hls_data else [] thumbnail_url = thumbnail_urls[0] if thumbnail_urls else None video_url = hls_data.get('video_url') if hls_data else None # 비디오 상세 인스턴스 사전 매핑 result.append({ "id": video.id, "name": system_metadata.filename if system_metadata and system_metadata.filename else f'Video {video.id}', "duration": system_metadata.duration if system_metadata else 0, "thumbnail_url": thumbnail_url, "video_url": video_url, "width": system_metadata.width if system_metadata else 0, "height": system_metadata.height if system_metadata else 0, "fps": system_metadata.fps if system_metadata else 0, "size": system_metadata.size if system_metadata else 0 }) return result except Exception as e: print(f"인덱스 {index_id}의 비디오를 가져오는 중 오류 발생: {e}") return []
1.3 비디오 콘텐츠 내부 정보 분석
사용자가 최종 비디오 타겟을 정하고 질문을 던지면 분석 모듈로 video_id와 질의를 전송합니다. 질의문은 정밀 설계된 기반 프롬프트 뒤에 연결되며, 이를 통해 맥락이 풍부하고 유의미한 비디오 분석 데이터를 확보합니다. 비디오 분석을 유도하기 위해 설정한 핵심 프롬프트의 내용은 여기서 직접 둘러보실 수 있습니다.
backend/service/twelvelabs_service.py (72-81 Line)
def analyze_video(self, video_id, prompt): try: # TwelveLabs 클라이언트를 통한 비디오 정보 생성 analysis_response = self.client.analyze( video_id=video_id, prompt=prompt ) return analysis_response.data except Exception as e: print(f"비디오 {video_id} 분석 중 오류 발생: {e}") raise e
1.4 분석된 비디오 정보 기반의 딥 리서치 전개
비디오 분석 데이터 수집이 일단락되면 Sonar 추론 모델을 활성화하여 딥 리서치 영역으로 나아갑니다. 하나의 페이로드 안에 사용자의 원래 질의, 리서치 정밀 가이드 템플릿, 그리고 방금 생성된 비디오 전반의 세부 컨텍스트를 하나로 묶어 송신합니다. Sonar는 이를 완전히 분해하고 가공해 정돈된 정보와 최적화된 자료 출처를 보여줍니다. 딥 리서치 처리를 구축한 뼈대 프롬프트 양식은 여기서 열어보실 수 있습니다.
backend/service/sonar_service.py (13-52 Line)
def deep_research(self, query, timeout=180): try: # API 키 사용 가능 여부 확인 if not self.api_key: raise ValueError("API 키가 필요합니다.") payload = { "model": "sonar", "messages": [ {"role": "user", "content": query} ] } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } # 타임아웃 설정을 포함해 API 엔드포인트로 POST 요청 전송 response = requests.post( self.base_url, json=payload, headers=headers, timeout=timeout ) # 요청 결과 승인 확인 if response.status_code == 200: return response.json() else: print(f"오류: {response.status_code} - {response.text}") return {"error": f"API 요청 실패 (상태 코드: {response.status_code})"} except requests.exceptions.Timeout: print("요청 시간 초과") return {"error": "요청 시간 초과 - Sonar 리서치가 너무 오래 걸립니다."} except requests.exceptions.RequestException as e: print(f"요청 중 오류 발생: {e}") return {"error": f"네트워크 오류: {str(e)}"} except Exception as e: print(f"deep_research 실행 중 오류 발생: {e}") return {"error": str(e)}
Perplexity 모델은 sonar 외에도 sonar-reasoning, sonar-deep-research 같은 폭넓은 옵션을 열어두고 있습니다. 특히 sonar-deep-research 모델은 깊이 있는 연구 프로세스와 수집 과정 속도의 균형을 이상적으로 맞춘 medium 값을 디폴트로 하여 reasoning_effort(low, medium, high) 설정을 추가 조율할 수 있습니다. 난이도를 high로 세팅하면 훨씬 가치 있고 밀도 높은 주석들과 레퍼런스들이 창출되지만, 처리 대기 연산과 토큰 비용이 함께 오르기 때문에 프로젝트 목표 속성과 지연 예산 범위를 조화롭게 타협해 기용 모델 버전을 설계하시는 편이 이상적입니다.
단순히 모델명을 sonar-deep-research로 수정하는 것만으로 훨씬 입체적인 추론과 광범위한 리서치 출처 모음집을 경험할 수 있어, 기본 sonar 옵션 설정 대비 고차원적 정보 구조를 형성하기 좋습니다. 생성된 정밀 답변 예제를 직접 아래의 화면을 조율해 관찰하세요 —

1.5 리서치 기능 동작 종합 흐름 제어
연계 흐름의 기점은 API 통신 자격 및 대상 비디오 컨텍스트가 완전한 상태인지 확인하는 파트입니다. 해당 선제 검수가 완벽히 확인되면 백엔드는 타겟 비디오의 필수 구조 요소를 즉시 수집합니다. 이를 통해 선택한 비디오의 맥락을 명확히 정의한 뒤 다음 단계로 넘어갑니다. 백엔드가 도출하는 진행 정보들을 실시간 스트리밍 형태로 전면 UI에 전달하도록 yield 제어기를 탑재하여, 프론트엔드 유저는 결과 완성을 무기한 기다리지 않고 진척 정보를 체감할 수 있습니다.
정보를 품은 제어기 파이프는 TwelveLabs 서비스가 안착시킨 analyze_video 객체로 전진합니다. 획득한 비주얼 타겟의 요소를 미리 만든 템플릿과 정돈된 질문 양식 구조에 결합하여, 마크다운 형태를 유지하면서 사용자 맞춤형 출력의 통일성을 지켜냅니다. 이렇게 조율된 최적화 패키지를 Sonar API로 밀어 넣어 가장 세련된 검증 데이터를 수집하고 정돈해 출력창에 전달합니다.
backend/routes/api_routes.py (31-162 Line)
def generate_workflow(twelvelabs_api_key, index_id, video_id, analysis_prompt, research_query, research_prompt_template): # 입력 값 유효성 체크 if not twelvelabs_api_key: yield json.dumps({'type': 'error', 'message': 'TwelveLabs API 키가 필요합니다.'}) + '\n' return if not index_id or not video_id: yield json.dumps({'type': 'error', 'message': 'Index ID와 Video ID가 필요합니다.'}) + '\n' return if not research_query: yield json.dumps({'type': 'error', 'message': '리서치 질의가 필요합니다.'}) + '\n' return try: twelvelabs_service = TwelveLabsService(api_key=twelvelabs_api_key) # 1단계: 비디오 상세 정보 가져오기 yield safe_json_dumps({ 'type': 'progress', 'step': 'video_details', 'message': '비디오 상세 정보를 가져오는 중...', 'progress': 0 }) + '\n' video_details = twelvelabs_service.get_video_details(index_id, video_id) if not video_details: yield safe_json_dumps({'type': 'error', 'message': '비디오 상세 정보를 검색할 수 없습니다.'}) + '\n' return yield safe_json_dumps({ 'type': 'data', 'step': 'video_details', 'data': { 'id': video_details.get('_id', ''), 'filename': video_details.get('system_metadata', {}).get('filename', ''), 'duration': video_details.get('system_metadata', {}).get('duration', 0) }, 'progress': 33 }) + '\n' # 2단계: 비디오 분석 yield safe_json_dumps({ 'type': 'progress', 'step': 'analysis', 'message': '비디오 콘텐츠 분석 중...', 'progress': 33 }) + '\n' analysis_result = twelvelabs_service.analyze_video(video_id, analysis_prompt) yield safe_json_dumps({ 'type': 'data', 'step': 'analysis', 'data': analysis_result, 'progress': 66 }) + '\n' # 3단계: 컨텍스트 기반 리서치 yield safe_json_dumps({ 'type': 'progress', 'step': 'research', 'message': '심층 리서치 진행 중...', 'progress': 66 }) + '\n' enhanced_query = research_prompt_template.format( analysis_result=analysis_result, research_query=research_query ) sonar_service = SonarService() research_result = sonar_service.deep_research(enhanced_query, timeout=180) if 'error' in research_result: yield safe_json_dumps({'type': 'error', 'message': f'리서치 실패: {research_result["error"]}'}) + '\n' return # 리서치 결과 콘텐츠 추출 research_content = "" if research_result and research_result.get('choices'): research_content = research_result['choices'][0].get('message', {}).get('content', '') # 결과 데이터가 클 경우 청크 단위로 나누어 전송 max_chunk_size = 10000 if len(research_content) > max_chunk_size: for i in range(0, len(research_content), max_chunk_size): chunk = research_content[i:i + max_chunk_size] is_final = (i + max_chunk_size) >= len(research_content) yield safe_json_dumps({ 'type': 'research_chunk', 'content': chunk, 'is_final': is_final, 'progress': 80 + (i / len(research_content)) * 20 }) + '\n' # 청크 분할 전송 완료 플래그 적용 yield safe_json_dumps({ 'type': 'complete', 'data': { 'research': { 'choices': [{ 'message': { 'content': '[CHUNKED_CONTENT]' } }], 'citations': research_result.get('citations', [])[:10], 'usage': research_result.get('usage', {}) }, 'sources': research_result.get('search_results', [])[:10] }, 'progress': 100 }) + '\n' else: # 단일 전송 전개 수렴 완료 처리 yield safe_json_dumps({ 'type': 'complete', 'data': { 'research': { 'choices': [{ 'message': { 'content': research_content } }], 'citations': research_result.get('citations', [])[:10], 'usage': research_result.get('usage', {}) }, 'sources': research_result.get('search_results', [])[:10] }, 'progress': 100 }) + '\n' except Exception as e: yield safe_json_dumps({'type': 'error', 'message': str(e)}) + '\n'
방대한 양의 리서치 결과물을 안정적으로 처리하기 위해, 백엔드 엔진은 응답 청크 분할 전송 방식을 차용하고 있습니다. Sonar 모델은 간혹 치밀한 추론 논리와 엄청난 수의 각주 정보를 일시에 대량으로 퍼내는 경향이 있어서, 이를 단 하나의 거대한 JSON 패키지로 모아 직렬화하면 크기 제한 임계치를 초과해 먹통이 될 리스크가 존재합니다. 따라서 안정적인 단위로 데이터를 조각내어 순차적으로 전송(Streaming)해야 확장성을 확보하고 네트워크 병목 현상을 방지하면서 프론트엔드의 화면 반응성을 가볍게 유지할 수 있습니다.
2 - 핵심 비디오 업로드 인덱싱 가이드
미리 정의해 둔 인덱스 비디오 리스트 대신, 사용자가 동영상 미디어를 즉시 직접 인출해 업로드해야 하는 환경도 빈번히 마주합니다. 이에 대응하기 위해 upload_video_file 메서드가 유효성을 검증하며, API 키 및 로컬 업로드 파일 경로가 완전한 상태에서 TwelveLabs 백엔드로 다이렉트 전송하는 신규 Task 생성 요청 단계를 밟습니다. 해당 미디어 전송 통신 처리가 안정되면 고유 번호인 task_id를 인출하여 모니터링 주기를 활성화합니다.
그 뒤 백엔드는 일정한 주기마다 완료 보고 혹은 에러 여부를 추적하는 폴링(Polling) 프로세스 루프를 돌기 시작합니다. 대기 시간이 마감 임계점을 넘지 않고 인덱싱 작업이 완결되면 결과 개체에서 video_id를 인출하는데, 이는 해당 신규 비디오 미디어가 즉시 해석 가능한 단계의 자원이 되었다는 마커입니다. 업로드된 파일이 정상적으로 작동하여 최신 동영상 풀에 합류하게 되며, 처리 실패 같은 이상 정황 시에는 적합한 정보 파라미터를 돌려주어 확실한 예외 대응 수단을 확보합니다.
backend/service/twelvelabs_service.py (145-207 Line)
def upload_video_file(self, index_id: str, file_path: str, timeout_seconds: int = 900): import sys try: if not self.api_key: return {"error": "TwelveLabs API 키가 없습니다."} if not index_id: return {"error": "index_id가 없습니다."} if not os.path.exists(file_path): return {"error": f"파일을 찾을 수 없습니다: {file_path}"} print(f"파일 업로드 시작: {file_path}", file=sys.stderr) tasks_url = "https://api.twelvelabs.io/v1.3/tasks" headers = { "x-api-key": self.api_key } # 업로드 태스크 생성 with open(file_path, "rb") as f: files = { "video_file": (os.path.basename(file_path), f) } data = { "index_id": index_id } resp = requests.post(tasks_url, headers=headers, files=files, data=data) if resp.status_code not in (200, 201): return {"error": f"업로드 태스크 생성 실패: {resp.status_code} {resp.text}"} resp_json = resp.json() if resp.text else {} task_id = resp_json.get("id") or resp_json.get("task_id") or resp_json.get("_id") if not task_id: return {"error": f"반환된 태스크 id가 없습니다: {resp_json}"} # 작업이 완결될 때까지 폴링(Polling) 수행 import time start_time = time.time() print(f"태스크 {task_id} 완료 여부 확인 중...", file=sys.stderr) while time.time() - start_time < timeout_seconds: r = requests.get(f"{tasks_url}/{task_id}", headers=headers) if r.status_code != 200: time.sleep(2) continue task = r.json() if r.text else {} status = task.get("status") print(f"태스크 {task_id} 상태: {status}", file=sys.stderr) if status in ("ready", "completed"): video_id = task.get("video_id") or (task.get("data") or {}).get("video_id") print(f"인덱싱이 성공적으로 완료되었습니다! Video ID: {video_id}", file=sys.stderr) return {"status": status, "video_id": video_id, "task": task} if status in ("failed", "error"): print(f"인덱싱 실패, 상태: {status}", file=sys.stderr) return {"error": f"인덱싱 실패와 관련된 상태값 {status}", "task": task} time.sleep(2) print(f"{timeout_seconds}초 초과로 업로드 타임아웃 발생", file=sys.stderr) return {"error": "업로드 시간 초과"}
동영상 자료의 업로드 및 인덱스 처리가 안전하게 끝나 video_id가 성공적으로 반환되면, 이후 분석과 지식 탐색 워크플로우 파이프라인은 앞서 검토했던 방식 그대로 일정하게 밟아나갑니다. 이 덕분에 이미 저장되어 있던 기성 비디오를 이용하든 새로운 사용자의 맞춤형 미디어를 다루든 백엔드의 수렴성이 일관되게 보존됩니다. 비디오 업로드 인출 과정 및 인덱싱 처리, 심층 리서치 작동 전 과정을 관찰하려면 하단의 동영상을 클릭하세요 —

이 설계 구조는 프론트엔드 환경에서 TwelveLabs API 토큰 제어를 동적으로 바인딩하는 것을 도우므로, 연구용 계정 소유의 API 자격으로 직접 접근하여 서버를 통해 개인 비디오 소스 목록을 인출하려는 파트너들에게도 원활한 유연함을 보장합니다.

이 튜토리얼을 응용할 수 있는 혁신적인 방안들
비디오에 대한 의미론적 이해와 외부의 검증된 리서치 지식이 통합됨에 따라, 한층 강력하고 다채로운 분석 서비스를 만들 수 있는 무한한 가능성이 열렸습니다. 다음은 TwelveLabs Analyze와 Perplexity Sonar 엔진들을 핵심 모형으로 기용해 직접 구축해 볼 만한 가치 있는 아이디어들입니다 —
🔍 정밀 비디오 팩트 제크(Fact-Checking) 서비스: 비디오 데이터가 지니는 단서 논점들을 검출한 뒤, 가장 공신력 높은 외부 출처들의 정보망과 교차 매칭하여 주장을 지능적으로 검증하고 참 거짓을 밝혀줍니다.
📑 지능형 비디오 서머리 및 요약: 수 시간 길이의 영상에서 담론 구조를 완전히 발라내고 구조화된 리포트를 실시간 창출하여 효율적인 연구 및 논문 정리 작업 속도를 획기적으로 낮춥니다.
📚 차세대 상호작용 학습 채널(Learning Workflows): 미디어 요점과 관련된 심층 지식망을 결합해, 연구원, 학생, 지식 콘텐츠 창작자에게 지능적인 대화 중심 인터랙티브 교육 어플라이언스를 구축해 줍니다.
마치며
본 튜토리얼은 비디오 세부 상황을 종합적으로 이해하는 프로세스가 연구 생산성에 얼마나 지대한 공헌을 할 수 있는지를 단적으로 알려 줍니다. 비주얼 컨텍스트 분석의 강자인 TwelveLabs Analyze의 비디오 추출력과 공신력 있는 근거 자료를 수집·가공하는 Sonar by Perplexity를 이상적으로 조립하여, 정적이고 수동적이었던 비디오 리소스를 탐색 가능하고 신뢰할 수 있는 학술 리서치 데이터로 승화시켰습니다. 이제 연구자, 크리에이터 및 다양한 파트너들이 한 차원 높은 깊은 탐색을 바탕으로 소통할 수 있게 되었습니다.
추가 리소스
비디오 분석의 핵심 심장인 멀티모달 프레임워크 학습의 자세한 구조를 탐구하세요 — Pegasus-1.2. TwelveLabs에 대한 풍부한 이해 도모 및 구현 꿀팁을 습득하고 싶으시다면 다음 사이트들을 편하게 경유하세요.
더 많은 활용 사례 발견하기: Sonar by Perplexity에 방문하여 강력한 검색 기능에 대해 알아보고, 본 가이드의 기본 얼개 구조를 살짝 튜닝해 세상에 없던 창조적인 사용 사례를 구현하세요.
고객 커뮤니티 네트워킹: 본 설계안이나 분석 아이디어와 관련된 피드백을 TwelveLabs Discord에서 동료 엔지니어들과 활기차게 소통할 수 있습니다.
다양한 튜토리얼 살펴보기: TwelveLabs만의 압도적인 하이 테크 서비스 활용 지식을 가득 품은 세분화된 가이드 아카이브를 전면 개방합니다.
저희는 여러분이 이러한 리소스를 적극적으로 활용하여 지식을 확장하고, TwelveLabs의 비디오 이해 기술을 통해 혁신적인 서비스를 직접 만들어 갈 수 있도록 든든한 파트너로서 지원할 것입니다.
소개
웹에서 텍스트를 검색하듯 비디오를 간편하게 검색하고, 신뢰할 수 있는 인용 출처가 포함된 통찰력을 얻을 수 있다면 어떨까요? 🎥🔍
오늘날 이는 여전히 웹에서 누락된 퍼즐 조각과 같습니다. 기존 검색 엔진은 비디오를 결과를 도출하기 위한 입력값으로 고려하지 않습니다. 이 때문에 연구자, 크리에이터, 전문가들은 체계적인 통찰력을 추출하거나 이를 검증할 신뢰할 수 있는 방법 없이, 수작업으로 몇 시간 분량의 영상을 일일이 확인해야 하는 번거로움을 겪고 있습니다.
비디오 딥 리서치(Video Deep Research)는 비디오를 탐색하는 패러다임을 혁신합니다. 의미론적 비디오 이해를 위한 TwelveLabs Analyze pegasus-1.2와 인용 기반의 지식 검색을 지원하는 Sonar by Perplexity를 결합하여, 비디오를 검색 가능하고 신뢰할 수 있는 연구 자원으로 전환해 줍니다.
그럼 비디오 딥 리서치 애플리케이션이 어떻게 작동하는지 알아보고, TwelveLabs Python SDK와 Perplexity Sonar를 활용하여 어떻게 고도화된 비디오 이해 및 딥 리서치 솔루션을 직접 구축할 수 있는지 살펴보겠습니다.
애플리케이션의 데모는 여기에서 확인하실 수 있습니다: Video Deep Research Application
사전 준비 단계
TwelveLabs Playground에 가입하여 API 키를 생성하세요.
Sonar에 가입하고 모델에 접근하기 위한 API 키를 생성합니다.
이 애플리케이션의 리포지토리는 Github Repository에서 확인하실 수 있습니다.
Python, Flask 및 Next.js에 대한 기본적인 이해가 필요합니다.
데모 애플리케이션
본 데모 애플리케이션은 비디오 이해와 지식 검색의 결합이 어떻게 리서치 방식의 새로운 지평을 열 수 있는지 보여줍니다.
사용자는 TwelveLabs API 키를 연결하여 비디오를 간편하게 업로드하거나 이미 인덱싱된 비디오 중에서 선택할 수 있습니다. 이후 애플리케이션이 콘텐츠를 분석하여 구조화된 정보(통찰력)를 추출하고, 이를 검증 가능한 논거 및 출처와 연결함으로써 비디오와 신뢰할 수 있는 연구 데이터를 매끄럽게 이어줍니다.
지금부터 직접 비디오 딥 리서치 기반 애플리케이션을 구축하고 확장해 볼 수 있도록 코드와 데모의 상세 가이드를 제공합니다 —

애플리케이션 작동 방식
이 애플리케이션은 두 가지 고유한 상호작용 모드를 지원합니다 -
TwelveLabs API 키 사용: 개인 TwelveLabs API 키를 연결하여 이미 인덱싱된 비디오에 접근하고 분석할 수 있습니다. 연결이 완료되면 기존 Index ID와 해당하는 비디오를 선택하면 됩니다.
비디오 업로드: 비디오를 업로드할 때, 애플리케이션이 원활한 설정을 위해 기본 TwelveLabs API 키를 자동으로 사용하도록 설계되었습니다. 업로드가 완료되면 인덱싱 프로세스가 즉시 시작됩니다. 인덱싱이 완료되면 가장 최근에 업로드된 비디오가 최신 사용 가능한 콘텐츠로 표시됩니다. 이 단계 이후부터는 쿼리 및 인용 출처 도출 워크플로우가 아래 명시된 단계에 따라 두 모드 모두 동일하게 진행됩니다.
애플리케이션의 전체 워크플로우는 TwelveLabs 클라이언트를 설정하는 것으로 시작합니다. 이를 위해 시스템 환경 변수에서 제공하는 키를 활용하거나, 사용자가 클라이언트 사이드에서 자체 API 키를 등록하여 이미 인덱싱된 비디오에 접근할 수 있도록 설정해야 합니다. 클라이언트가 구성되면 아래에 정리된 일련의 프로세스에 따라 분석이 수행됩니다 –
인덱스 불러오기 (Fetch Indexes) – 연동된 TwelveLabs 계정에 연결된 인덱스 목록을 보여줍니다.
비디오 선택 (Select Video) – 분석하고자 하는 인덱스에서 대상 비디오를 선택합니다.
비디오 분석 (Analyze Video) – 제공된 질의(Query)에 따라 선택한 비디오의 내용과 맥락을 정밀 분석합니다.
딥 리서치 (Deep Research) – 비디오 분석 결과와 구조화된 프롬프트, 그리고 사용자의 질의를 결합하여 Sonar 연구 모델로 전달해, 깊이 있는 추론과 검증된 인용 정보를 바탕으로 풍부한 결과물을 창출합니다.
이와 같이 정밀하게 짜인 워크플로우 덕분에 비디오 인덱싱부터 고급 리서치에 이르기까지 일련의 과정이 흐르듯 매끄럽게 진행되며 사용자에게 맥락을 정확히 꿰뚫는 분석 결과를 제공합니다.
두 가지 접근 방식 모두 아래 아키텍처 다이어그램에서 가시적으로 보여주고 있습니다.

연구 응답이 생성된 후 사용자는 동일한 컨텍스트 내에서 추가 문서나 더 깊이 있는 내용을 요하는 후속 질의를 할 수 있습니다. 이러한 연속된 질의들은 다시 Sonar 리서치 루프로 유입되어 컨텍스트의 연속성을 유지하면서 기존 지식 베이스를 점점 더 넓혀갑니다. 이 반복적인 구조 덕분에 새로운 질의가 있을 때마다 이전 분석 결과를 토대로 더욱 고도화되고 깊이 있는 리서치 결과물이 쌓여가게 됩니다.
사전 준비 단계
TwelveLabs Playground에서 API 키를 발급받아 환경 변수로 등록합니다.
TwelveLabs Playground를 통해
pegasus-1.2엔진을 선택하여 인덱스를 생성하고, 이 애플리케이션에 적용할 구체적인index_id를 확인해 둡니다.Github에서 프로젝트 코드를 클론합니다.
Sonar by Perplexity에서 API 키를 발급 받습니다.
TwelveLabs 및 Sonar 인증 정보를 모두 포함하는
.env파일을 작성합니다. 예시 템플릿은 여기에서 참고하실 수 있습니다.
위의 단계를 모두 준비하셨다면 이제 본격적인 개발로 나아갈 준비가 되었습니다!
비디오 딥 리서치 앱 구현 상세 가이드
이번 튜토리얼에서는 비디오 콘텐츠를 기반으로 웹에서 신뢰할 수 있는 정보와 구체적인 인용 자료를 완벽히 매칭하는 애플리케이션의 구축 방법을 다룹니다. 프론트엔드는 Next.js를, 백엔드는 Flask API(CORS 구성 적용)를 바탕으로 하고 있습니다. 특히 비디오 딥 리서치 기능을 지탱하는 백엔드 유틸리티 핵심 로직 구현과 함께, 분석 환경 전체를 구성하는 부분에 초점을 맞춰 이야기하겠습니다.
구체적인 설정 방식과 프로젝트 파일 전반의 세부 구성은 GitHub 리포지토리의 README.md 파일을 살펴보세요.
1 - 비디오 딥 리서치 구현 워크플로우
이 설계 과정에서 가장 중요한 단계는 바로 TwelveLabs API 키를 안전하게 초기화하고 다루는 일입니다. 애플리케이션은 기본 설정을 위해 환경 변수에서 키를 읽어오거나 사용자가 포털 화면을 통해 입력한 자체 API 키를 동적으로 적용할 수 있습니다.
backend/service/twelvelabs_service.py (14-36 Line)
class TwelveLabsService: def __init__(self, api_key=None): # API 키가 주어지지 않은 경우 환경 변수 조회를 시도합니다. if api_key is None: api_key = os.environ.get('TWELVELABS_API_KEY', '') self.api_key = api_key # 인스턴스에 API 키 저장 self.client = TwelveLabs(api_key=api_key) # TwelveLabs 클라이언트 초기화
1.1 인덱스 리스트(Indexes) 가져오기
사용자가 브라우저 콘솔 창을 통해 입력하거나 내부 환경 변수로부터 TwelveLabs API 키를 성공적으로 로드하면 계정에 할당된 모든 인덱스 데이터를 수집합니다. 정돈된 정보는 비디오 선택을 위해 프론트엔드 컴포넌트에 직관적으로 전달됩니다.
backend/service/twelvelabs_service.py (14-36 Line)
def get_indexes(self): try: print("인덱스를 가져오는 중...") # API 키 사용 가능 여부 확인 if not self.api_key: print("사용 가능한 API 키가 없습니다.") return [] # TwelveLabs 클라이언트를 사용해 인덱스 목록 획득 indexes = self.client.indexes.list() result = [] for index in indexes: # 인덱스 상세 구조 구성 result.append({ "id": index.id, "name": index.index_name }) print(f"ID: {index.id}") print(f" Name: {index.index_name}") return result except Exception as e: print(f"인덱스를 가져오는 중 오류 발생: {e}") return []
1.2 선택된 Index ID에 해당하는 비디오 목록 가져오기
사용자가 탐색할 인덱스를 하나 선택하면 애플리케이션은 해당 index_id를 기준으로 매핑된 최적화 비디오 항목들을 모조리 수집해 프론트엔드로 전달합니다.
backend/service/twelvelabs_service.py (38-70 Line)
def get_videos(self, index_id, page=1): try: # API 키 사용 가능 여부 확인 if not self.api_key: print("사용 가능한 API 키가 없습니다.") return [] # TwelveLabs 클라이언트를 사용해 비디오 조회 videos_response = self.client.indexes.videos.list(index_id=index_id, page=page) result = [] for video in videos_response.items: system_metadata = video.system_metadata hls_data = video.hls thumbnail_urls = hls_data.get('thumbnail_urls', []) if hls_data else [] thumbnail_url = thumbnail_urls[0] if thumbnail_urls else None video_url = hls_data.get('video_url') if hls_data else None # 비디오 상세 인스턴스 사전 매핑 result.append({ "id": video.id, "name": system_metadata.filename if system_metadata and system_metadata.filename else f'Video {video.id}', "duration": system_metadata.duration if system_metadata else 0, "thumbnail_url": thumbnail_url, "video_url": video_url, "width": system_metadata.width if system_metadata else 0, "height": system_metadata.height if system_metadata else 0, "fps": system_metadata.fps if system_metadata else 0, "size": system_metadata.size if system_metadata else 0 }) return result except Exception as e: print(f"인덱스 {index_id}의 비디오를 가져오는 중 오류 발생: {e}") return []
1.3 비디오 콘텐츠 내부 정보 분석
사용자가 최종 비디오 타겟을 정하고 질문을 던지면 분석 모듈로 video_id와 질의를 전송합니다. 질의문은 정밀 설계된 기반 프롬프트 뒤에 연결되며, 이를 통해 맥락이 풍부하고 유의미한 비디오 분석 데이터를 확보합니다. 비디오 분석을 유도하기 위해 설정한 핵심 프롬프트의 내용은 여기서 직접 둘러보실 수 있습니다.
backend/service/twelvelabs_service.py (72-81 Line)
def analyze_video(self, video_id, prompt): try: # TwelveLabs 클라이언트를 통한 비디오 정보 생성 analysis_response = self.client.analyze( video_id=video_id, prompt=prompt ) return analysis_response.data except Exception as e: print(f"비디오 {video_id} 분석 중 오류 발생: {e}") raise e
1.4 분석된 비디오 정보 기반의 딥 리서치 전개
비디오 분석 데이터 수집이 일단락되면 Sonar 추론 모델을 활성화하여 딥 리서치 영역으로 나아갑니다. 하나의 페이로드 안에 사용자의 원래 질의, 리서치 정밀 가이드 템플릿, 그리고 방금 생성된 비디오 전반의 세부 컨텍스트를 하나로 묶어 송신합니다. Sonar는 이를 완전히 분해하고 가공해 정돈된 정보와 최적화된 자료 출처를 보여줍니다. 딥 리서치 처리를 구축한 뼈대 프롬프트 양식은 여기서 열어보실 수 있습니다.
backend/service/sonar_service.py (13-52 Line)
def deep_research(self, query, timeout=180): try: # API 키 사용 가능 여부 확인 if not self.api_key: raise ValueError("API 키가 필요합니다.") payload = { "model": "sonar", "messages": [ {"role": "user", "content": query} ] } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } # 타임아웃 설정을 포함해 API 엔드포인트로 POST 요청 전송 response = requests.post( self.base_url, json=payload, headers=headers, timeout=timeout ) # 요청 결과 승인 확인 if response.status_code == 200: return response.json() else: print(f"오류: {response.status_code} - {response.text}") return {"error": f"API 요청 실패 (상태 코드: {response.status_code})"} except requests.exceptions.Timeout: print("요청 시간 초과") return {"error": "요청 시간 초과 - Sonar 리서치가 너무 오래 걸립니다."} except requests.exceptions.RequestException as e: print(f"요청 중 오류 발생: {e}") return {"error": f"네트워크 오류: {str(e)}"} except Exception as e: print(f"deep_research 실행 중 오류 발생: {e}") return {"error": str(e)}
Perplexity 모델은 sonar 외에도 sonar-reasoning, sonar-deep-research 같은 폭넓은 옵션을 열어두고 있습니다. 특히 sonar-deep-research 모델은 깊이 있는 연구 프로세스와 수집 과정 속도의 균형을 이상적으로 맞춘 medium 값을 디폴트로 하여 reasoning_effort(low, medium, high) 설정을 추가 조율할 수 있습니다. 난이도를 high로 세팅하면 훨씬 가치 있고 밀도 높은 주석들과 레퍼런스들이 창출되지만, 처리 대기 연산과 토큰 비용이 함께 오르기 때문에 프로젝트 목표 속성과 지연 예산 범위를 조화롭게 타협해 기용 모델 버전을 설계하시는 편이 이상적입니다.
단순히 모델명을 sonar-deep-research로 수정하는 것만으로 훨씬 입체적인 추론과 광범위한 리서치 출처 모음집을 경험할 수 있어, 기본 sonar 옵션 설정 대비 고차원적 정보 구조를 형성하기 좋습니다. 생성된 정밀 답변 예제를 직접 아래의 화면을 조율해 관찰하세요 —

1.5 리서치 기능 동작 종합 흐름 제어
연계 흐름의 기점은 API 통신 자격 및 대상 비디오 컨텍스트가 완전한 상태인지 확인하는 파트입니다. 해당 선제 검수가 완벽히 확인되면 백엔드는 타겟 비디오의 필수 구조 요소를 즉시 수집합니다. 이를 통해 선택한 비디오의 맥락을 명확히 정의한 뒤 다음 단계로 넘어갑니다. 백엔드가 도출하는 진행 정보들을 실시간 스트리밍 형태로 전면 UI에 전달하도록 yield 제어기를 탑재하여, 프론트엔드 유저는 결과 완성을 무기한 기다리지 않고 진척 정보를 체감할 수 있습니다.
정보를 품은 제어기 파이프는 TwelveLabs 서비스가 안착시킨 analyze_video 객체로 전진합니다. 획득한 비주얼 타겟의 요소를 미리 만든 템플릿과 정돈된 질문 양식 구조에 결합하여, 마크다운 형태를 유지하면서 사용자 맞춤형 출력의 통일성을 지켜냅니다. 이렇게 조율된 최적화 패키지를 Sonar API로 밀어 넣어 가장 세련된 검증 데이터를 수집하고 정돈해 출력창에 전달합니다.
backend/routes/api_routes.py (31-162 Line)
def generate_workflow(twelvelabs_api_key, index_id, video_id, analysis_prompt, research_query, research_prompt_template): # 입력 값 유효성 체크 if not twelvelabs_api_key: yield json.dumps({'type': 'error', 'message': 'TwelveLabs API 키가 필요합니다.'}) + '\n' return if not index_id or not video_id: yield json.dumps({'type': 'error', 'message': 'Index ID와 Video ID가 필요합니다.'}) + '\n' return if not research_query: yield json.dumps({'type': 'error', 'message': '리서치 질의가 필요합니다.'}) + '\n' return try: twelvelabs_service = TwelveLabsService(api_key=twelvelabs_api_key) # 1단계: 비디오 상세 정보 가져오기 yield safe_json_dumps({ 'type': 'progress', 'step': 'video_details', 'message': '비디오 상세 정보를 가져오는 중...', 'progress': 0 }) + '\n' video_details = twelvelabs_service.get_video_details(index_id, video_id) if not video_details: yield safe_json_dumps({'type': 'error', 'message': '비디오 상세 정보를 검색할 수 없습니다.'}) + '\n' return yield safe_json_dumps({ 'type': 'data', 'step': 'video_details', 'data': { 'id': video_details.get('_id', ''), 'filename': video_details.get('system_metadata', {}).get('filename', ''), 'duration': video_details.get('system_metadata', {}).get('duration', 0) }, 'progress': 33 }) + '\n' # 2단계: 비디오 분석 yield safe_json_dumps({ 'type': 'progress', 'step': 'analysis', 'message': '비디오 콘텐츠 분석 중...', 'progress': 33 }) + '\n' analysis_result = twelvelabs_service.analyze_video(video_id, analysis_prompt) yield safe_json_dumps({ 'type': 'data', 'step': 'analysis', 'data': analysis_result, 'progress': 66 }) + '\n' # 3단계: 컨텍스트 기반 리서치 yield safe_json_dumps({ 'type': 'progress', 'step': 'research', 'message': '심층 리서치 진행 중...', 'progress': 66 }) + '\n' enhanced_query = research_prompt_template.format( analysis_result=analysis_result, research_query=research_query ) sonar_service = SonarService() research_result = sonar_service.deep_research(enhanced_query, timeout=180) if 'error' in research_result: yield safe_json_dumps({'type': 'error', 'message': f'리서치 실패: {research_result["error"]}'}) + '\n' return # 리서치 결과 콘텐츠 추출 research_content = "" if research_result and research_result.get('choices'): research_content = research_result['choices'][0].get('message', {}).get('content', '') # 결과 데이터가 클 경우 청크 단위로 나누어 전송 max_chunk_size = 10000 if len(research_content) > max_chunk_size: for i in range(0, len(research_content), max_chunk_size): chunk = research_content[i:i + max_chunk_size] is_final = (i + max_chunk_size) >= len(research_content) yield safe_json_dumps({ 'type': 'research_chunk', 'content': chunk, 'is_final': is_final, 'progress': 80 + (i / len(research_content)) * 20 }) + '\n' # 청크 분할 전송 완료 플래그 적용 yield safe_json_dumps({ 'type': 'complete', 'data': { 'research': { 'choices': [{ 'message': { 'content': '[CHUNKED_CONTENT]' } }], 'citations': research_result.get('citations', [])[:10], 'usage': research_result.get('usage', {}) }, 'sources': research_result.get('search_results', [])[:10] }, 'progress': 100 }) + '\n' else: # 단일 전송 전개 수렴 완료 처리 yield safe_json_dumps({ 'type': 'complete', 'data': { 'research': { 'choices': [{ 'message': { 'content': research_content } }], 'citations': research_result.get('citations', [])[:10], 'usage': research_result.get('usage', {}) }, 'sources': research_result.get('search_results', [])[:10] }, 'progress': 100 }) + '\n' except Exception as e: yield safe_json_dumps({'type': 'error', 'message': str(e)}) + '\n'
방대한 양의 리서치 결과물을 안정적으로 처리하기 위해, 백엔드 엔진은 응답 청크 분할 전송 방식을 차용하고 있습니다. Sonar 모델은 간혹 치밀한 추론 논리와 엄청난 수의 각주 정보를 일시에 대량으로 퍼내는 경향이 있어서, 이를 단 하나의 거대한 JSON 패키지로 모아 직렬화하면 크기 제한 임계치를 초과해 먹통이 될 리스크가 존재합니다. 따라서 안정적인 단위로 데이터를 조각내어 순차적으로 전송(Streaming)해야 확장성을 확보하고 네트워크 병목 현상을 방지하면서 프론트엔드의 화면 반응성을 가볍게 유지할 수 있습니다.
2 - 핵심 비디오 업로드 인덱싱 가이드
미리 정의해 둔 인덱스 비디오 리스트 대신, 사용자가 동영상 미디어를 즉시 직접 인출해 업로드해야 하는 환경도 빈번히 마주합니다. 이에 대응하기 위해 upload_video_file 메서드가 유효성을 검증하며, API 키 및 로컬 업로드 파일 경로가 완전한 상태에서 TwelveLabs 백엔드로 다이렉트 전송하는 신규 Task 생성 요청 단계를 밟습니다. 해당 미디어 전송 통신 처리가 안정되면 고유 번호인 task_id를 인출하여 모니터링 주기를 활성화합니다.
그 뒤 백엔드는 일정한 주기마다 완료 보고 혹은 에러 여부를 추적하는 폴링(Polling) 프로세스 루프를 돌기 시작합니다. 대기 시간이 마감 임계점을 넘지 않고 인덱싱 작업이 완결되면 결과 개체에서 video_id를 인출하는데, 이는 해당 신규 비디오 미디어가 즉시 해석 가능한 단계의 자원이 되었다는 마커입니다. 업로드된 파일이 정상적으로 작동하여 최신 동영상 풀에 합류하게 되며, 처리 실패 같은 이상 정황 시에는 적합한 정보 파라미터를 돌려주어 확실한 예외 대응 수단을 확보합니다.
backend/service/twelvelabs_service.py (145-207 Line)
def upload_video_file(self, index_id: str, file_path: str, timeout_seconds: int = 900): import sys try: if not self.api_key: return {"error": "TwelveLabs API 키가 없습니다."} if not index_id: return {"error": "index_id가 없습니다."} if not os.path.exists(file_path): return {"error": f"파일을 찾을 수 없습니다: {file_path}"} print(f"파일 업로드 시작: {file_path}", file=sys.stderr) tasks_url = "https://api.twelvelabs.io/v1.3/tasks" headers = { "x-api-key": self.api_key } # 업로드 태스크 생성 with open(file_path, "rb") as f: files = { "video_file": (os.path.basename(file_path), f) } data = { "index_id": index_id } resp = requests.post(tasks_url, headers=headers, files=files, data=data) if resp.status_code not in (200, 201): return {"error": f"업로드 태스크 생성 실패: {resp.status_code} {resp.text}"} resp_json = resp.json() if resp.text else {} task_id = resp_json.get("id") or resp_json.get("task_id") or resp_json.get("_id") if not task_id: return {"error": f"반환된 태스크 id가 없습니다: {resp_json}"} # 작업이 완결될 때까지 폴링(Polling) 수행 import time start_time = time.time() print(f"태스크 {task_id} 완료 여부 확인 중...", file=sys.stderr) while time.time() - start_time < timeout_seconds: r = requests.get(f"{tasks_url}/{task_id}", headers=headers) if r.status_code != 200: time.sleep(2) continue task = r.json() if r.text else {} status = task.get("status") print(f"태스크 {task_id} 상태: {status}", file=sys.stderr) if status in ("ready", "completed"): video_id = task.get("video_id") or (task.get("data") or {}).get("video_id") print(f"인덱싱이 성공적으로 완료되었습니다! Video ID: {video_id}", file=sys.stderr) return {"status": status, "video_id": video_id, "task": task} if status in ("failed", "error"): print(f"인덱싱 실패, 상태: {status}", file=sys.stderr) return {"error": f"인덱싱 실패와 관련된 상태값 {status}", "task": task} time.sleep(2) print(f"{timeout_seconds}초 초과로 업로드 타임아웃 발생", file=sys.stderr) return {"error": "업로드 시간 초과"}
동영상 자료의 업로드 및 인덱스 처리가 안전하게 끝나 video_id가 성공적으로 반환되면, 이후 분석과 지식 탐색 워크플로우 파이프라인은 앞서 검토했던 방식 그대로 일정하게 밟아나갑니다. 이 덕분에 이미 저장되어 있던 기성 비디오를 이용하든 새로운 사용자의 맞춤형 미디어를 다루든 백엔드의 수렴성이 일관되게 보존됩니다. 비디오 업로드 인출 과정 및 인덱싱 처리, 심층 리서치 작동 전 과정을 관찰하려면 하단의 동영상을 클릭하세요 —

이 설계 구조는 프론트엔드 환경에서 TwelveLabs API 토큰 제어를 동적으로 바인딩하는 것을 도우므로, 연구용 계정 소유의 API 자격으로 직접 접근하여 서버를 통해 개인 비디오 소스 목록을 인출하려는 파트너들에게도 원활한 유연함을 보장합니다.

이 튜토리얼을 응용할 수 있는 혁신적인 방안들
비디오에 대한 의미론적 이해와 외부의 검증된 리서치 지식이 통합됨에 따라, 한층 강력하고 다채로운 분석 서비스를 만들 수 있는 무한한 가능성이 열렸습니다. 다음은 TwelveLabs Analyze와 Perplexity Sonar 엔진들을 핵심 모형으로 기용해 직접 구축해 볼 만한 가치 있는 아이디어들입니다 —
🔍 정밀 비디오 팩트 제크(Fact-Checking) 서비스: 비디오 데이터가 지니는 단서 논점들을 검출한 뒤, 가장 공신력 높은 외부 출처들의 정보망과 교차 매칭하여 주장을 지능적으로 검증하고 참 거짓을 밝혀줍니다.
📑 지능형 비디오 서머리 및 요약: 수 시간 길이의 영상에서 담론 구조를 완전히 발라내고 구조화된 리포트를 실시간 창출하여 효율적인 연구 및 논문 정리 작업 속도를 획기적으로 낮춥니다.
📚 차세대 상호작용 학습 채널(Learning Workflows): 미디어 요점과 관련된 심층 지식망을 결합해, 연구원, 학생, 지식 콘텐츠 창작자에게 지능적인 대화 중심 인터랙티브 교육 어플라이언스를 구축해 줍니다.
마치며
본 튜토리얼은 비디오 세부 상황을 종합적으로 이해하는 프로세스가 연구 생산성에 얼마나 지대한 공헌을 할 수 있는지를 단적으로 알려 줍니다. 비주얼 컨텍스트 분석의 강자인 TwelveLabs Analyze의 비디오 추출력과 공신력 있는 근거 자료를 수집·가공하는 Sonar by Perplexity를 이상적으로 조립하여, 정적이고 수동적이었던 비디오 리소스를 탐색 가능하고 신뢰할 수 있는 학술 리서치 데이터로 승화시켰습니다. 이제 연구자, 크리에이터 및 다양한 파트너들이 한 차원 높은 깊은 탐색을 바탕으로 소통할 수 있게 되었습니다.
추가 리소스
비디오 분석의 핵심 심장인 멀티모달 프레임워크 학습의 자세한 구조를 탐구하세요 — Pegasus-1.2. TwelveLabs에 대한 풍부한 이해 도모 및 구현 꿀팁을 습득하고 싶으시다면 다음 사이트들을 편하게 경유하세요.
더 많은 활용 사례 발견하기: Sonar by Perplexity에 방문하여 강력한 검색 기능에 대해 알아보고, 본 가이드의 기본 얼개 구조를 살짝 튜닝해 세상에 없던 창조적인 사용 사례를 구현하세요.
고객 커뮤니티 네트워킹: 본 설계안이나 분석 아이디어와 관련된 피드백을 TwelveLabs Discord에서 동료 엔지니어들과 활기차게 소통할 수 있습니다.
다양한 튜토리얼 살펴보기: TwelveLabs만의 압도적인 하이 테크 서비스 활용 지식을 가득 품은 세분화된 가이드 아카이브를 전면 개방합니다.
저희는 여러분이 이러한 리소스를 적극적으로 활용하여 지식을 확장하고, TwelveLabs의 비디오 이해 기술을 통해 혁신적인 서비스를 직접 만들어 갈 수 있도록 든든한 파트너로서 지원할 것입니다.




