diff --git a/examples/youtube_analyzer_multimodal.ipynb b/examples/youtube_analyzer_multimodal.ipynb
new file mode 100644
index 000000000..d859d3cc9
--- /dev/null
+++ b/examples/youtube_analyzer_multimodal.ipynb
@@ -0,0 +1,420 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/opt/anaconda3/envs/kospi/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
+ " from .autonotebook import tqdm as notebook_tqdm\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Import required libraries for JSON parsing, data modeling and LLM integration\n",
+ "from langchain_core.output_parsers import JsonOutputParser\n",
+ "from pydantic import BaseModel, Field\n",
+ "from langchain_google_genai import ChatGoogleGenerativeAI\n",
+ "from typing import List\n",
+ "\n",
+ "\n",
+ "# Define VideoAnalysis class to structure video metadata\n",
+ "class VideoAnalysis(BaseModel):\n",
+ " ad_type: str = Field(description=\"Type of advertisement (e.g., Brand ad, Product ad, etc.)\")\n",
+ " main_category: str = Field(description=\"Main category of the video\")\n",
+ " sub_categories: List[str] = Field(description=\"List of video sub-categories\")\n",
+ " main_theme_message: str = Field(description=\"Main theme and message of the video\")\n",
+ " tone_and_manner: str = Field(description=\"Tone and manner of the video\")\n",
+ " target_audience: List[str] = Field(description=\"Target customer segments\")\n",
+ " key_keywords: List[str] = Field(description=\"List of key keywords\")\n",
+ " suitable_industries: List[str] = Field(description=\"List of suitable industries\")\n",
+ " expected_viewer_interest: str = Field(description=\"Expected viewer interest level (High/Medium/Low)\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from langchain_google_genai import ChatGoogleGenerativeAI\n",
+ "\n",
+ "gemini_llm = ChatGoogleGenerativeAI(\n",
+ " model=\"gemini-1.5-pro\",\n",
+ " temperature=0\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import google.generativeai as genai\n",
+ "import time\n",
+ "import os\n",
+ "import json\n",
+ "import yt_dlp\n",
+ "from dotenv import load_dotenv\n",
+ "load_dotenv()\n",
+ "\n",
+ "class GeminiVideoAnalyzer:\n",
+ " def __init__(self):\n",
+ " \n",
+ " self.GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')\n",
+ " genai.configure(api_key=self.GOOGLE_API_KEY)\n",
+ " self.model = genai.GenerativeModel(model_name=\"gemini-1.5-pro\")\n",
+ " \n",
+ " def download_video(self, url: str) -> str:\n",
+ " \"\"\"Download YouTube video\"\"\"\n",
+ " video_dir = \"download_video\"\n",
+ " os.makedirs(video_dir, exist_ok=True)\n",
+ " \n",
+ " try:\n",
+ " ydl_opts = {\n",
+ " 'format': 'bestvideo[height<=720][ext=mp4]+bestaudio[ext=m4a]/best[height<=720][ext=mp4]/best',\n",
+ " 'outtmpl': os.path.join(video_dir, '%(title)s.%(ext)s'),\n",
+ " 'quiet': True,\n",
+ " 'no_warnings': True,\n",
+ " 'extract_flat': False,\n",
+ " 'merge_output_format': 'mp4'\n",
+ " }\n",
+ " \n",
+ " with yt_dlp.YoutubeDL(ydl_opts) as ydl:\n",
+ " info = ydl.extract_info(url, download=True)\n",
+ " video_path = ydl.prepare_filename(info)\n",
+ " \n",
+ " if not os.path.exists(video_path):\n",
+ " raise FileNotFoundError(f\"Downloaded video not found: {video_path}\")\n",
+ " \n",
+ " print(f\"Video download completed: {video_path}\")\n",
+ " return video_path\n",
+ " \n",
+ " except Exception as e:\n",
+ " print(f\"Error occurred during video download: {str(e)}\")\n",
+ " raise\n",
+ "\n",
+ " def analyze_video(self, video_path: str) -> dict:\n",
+ " \"\"\"Analyze video using Gemini\"\"\"\n",
+ " try:\n",
+ " video_file = genai.upload_file(video_path, mime_type='video/mp4')\n",
+ " print(f\"Starting file upload: {video_path}\")\n",
+ "\n",
+ " if video_file.state.name == \"PROCESSING\":\n",
+ " print('Processing upload...', end='', flush=True)\n",
+ " time.sleep(5)\n",
+ " video_file = genai.get_file(video_file.name)\n",
+ "\n",
+ " if video_file.state.name == \"FAILED\":\n",
+ " raise ValueError(f\"File processing failed: {video_file.state}\")\n",
+ " elif video_file.state.name == \"ACTIVE\":\n",
+ " print(f\"\\nFile processing complete! Status: {video_file.state.name}\")\n",
+ "\n",
+ " prompt = \"\"\"\n",
+ " Please analyze the main content of this video. Include the following items:\n",
+ " \n",
+ " 1. Ad type (Product ad, Brand ad, etc.)\n",
+ " 2. Main category\n",
+ " 3. Sub categories\n",
+ " 4. Main theme/message\n",
+ " 5. Tone and manner\n",
+ " 6. Target audience\n",
+ " 7. Key keywords\n",
+ " 8. Suitable industries\n",
+ " 9. Expected viewer interest (High/Medium/Low)\n",
+ " \n",
+ " Please respond in JSON format.\n",
+ " \"\"\"\n",
+ "\n",
+ " print(\"Requesting Gemini analysis...\")\n",
+ " response = self.model.generate_content(\n",
+ " [video_file, prompt],\n",
+ " request_options={\"timeout\": 600}\n",
+ " )\n",
+ " \n",
+ " return response.text\n",
+ "\n",
+ " except Exception as e:\n",
+ " print(f\"Error occurred during video analysis: {str(e)}\")\n",
+ " raise\n",
+ " finally:\n",
+ " # Clean up temporary files\n",
+ " if os.path.exists(video_path):\n",
+ " try:\n",
+ " os.remove(video_path)\n",
+ " except Exception as e:\n",
+ " print(f\"Failed to delete temporary file: {str(e)}\")\n",
+ "\n",
+ " def analyze_youtube_video(self, url: str) -> dict:\n",
+ " \"\"\"Run complete analysis process from YouTube URL\"\"\"\n",
+ " try:\n",
+ " video_path = self.download_video(url)\n",
+ " result = self.analyze_video(video_path)\n",
+ " return result\n",
+ " except Exception as e:\n",
+ " print(f\"Analysis failed: {str(e)}\")\n",
+ " raise"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Video download completed: download_video/Google Gemini | 엉뚱발랄 채령과 Gemini가 새로 개발(?)한 젠가 떡볶이🤣 | 제미나이 키친 - 채령 15s ver..mp4\n",
+ "Starting file upload: download_video/Google Gemini | 엉뚱발랄 채령과 Gemini가 새로 개발(?)한 젠가 떡볶이🤣 | 제미나이 키친 - 채령 15s ver..mp4\n",
+ "Processing upload...\n",
+ "File processing complete! Status: ACTIVE\n",
+ "Requesting Gemini analysis...\n",
+ "\"Sure, here’s the video analysis in JSON format.\\n\\n```json\\n{\\n \\\"ad_type\\\": \\\"Product Ad\\\",\\n \\\"main_category\\\": \\\"Technology\\\",\\n \\\"sub_categories\\\": [\\\"Software\\\", \\\"Artificial Intelligence\\\", \\\"Mobile Apps\\\"],\\n \\\"main_theme_message\\\": \\\"Introducing Google Gemini, a helpful AI assistant that can answer questions, provide information, and even offer creative inspiration for cooking.\\\",\\n \\\"tone_and_manner\\\": \\\"Friendly, Playful, Informative\\\",\\n \\\"target_audience\\\": [\\\"Tech-savvy individuals\\\", \\\"Early adopters\\\", \\\"People interested in AI\\\", \\\"Users seeking convenient information access\\\", \\\"Content creators\\\"],\\n \\\"key_keywords\\\": [\\\"Google Gemini\\\", \\\"AI assistant\\\", \\\"Artificial intelligence\\\", \\\"Mobile app\\\", \\\"Information retrieval\\\", \\\"Creative assistance\\\", \\\"Cooking inspiration\\\", \\\"Tteokbokki\\\"],\\n \\\"suitable_industries\\\": [\\\"Technology\\\", \\\"Food and beverage\\\", \\\"Content creation\\\", \\\"Education\\\", \\\"Customer service\\\"],\\n \\\"expected_viewer_interest\\\": \\\"Medium\\\"\\n}\\n\\n```\"\n"
+ ]
+ }
+ ],
+ "source": [
+ "url = \"https://www.youtube.com/watch?v=XMgt2e7l6hk\"\n",
+ "# 분석기 초기화 및 실행\n",
+ "try:\n",
+ " analyzer = GeminiVideoAnalyzer()\n",
+ " result = analyzer.analyze_youtube_video(url)\n",
+ " print(json.dumps(result, indent=2, ensure_ascii=False))\n",
+ "except Exception as e:\n",
+ " print(f\"error in run: {str(e)}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from langchain_core.output_parsers import JsonOutputParser\n",
+ "from langchain_core.prompts import PromptTemplate\n",
+ "\n",
+ "def create_video_analysis_chain():\n",
+ " \"\"\"Function to create LangChain chain for video analysis\"\"\"\n",
+ " parser = JsonOutputParser(pydantic_object=VideoAnalysis)\n",
+ " \n",
+ " prompt = PromptTemplate(\n",
+ " template=\"\"\"Please analyze the given video and provide detailed information.\n",
+ "\n",
+ " {format_instructions}\n",
+ "\n",
+ " Video description: {input}\n",
+ " \"\"\",\n",
+ " input_variables=[\"input\"],\n",
+ " partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
+ " )\n",
+ " \n",
+ " chain = prompt | gemini_llm | parser\n",
+ " return chain\n",
+ "\n",
+ "def analyze_video(video_description: str, context: str = \"\"):\n",
+ " \"\"\"\n",
+ " Function that analyzes video and returns structured results\n",
+ " \n",
+ " Args:\n",
+ " video_description (str): Description of video to analyze\n",
+ " context (str): Additional context information (optional)\n",
+ " \n",
+ " Returns:\n",
+ " VideoAnalysis: Analysis results\n",
+ " \"\"\"\n",
+ " chain = create_video_analysis_chain()\n",
+ " result = chain.invoke({\n",
+ " \"input\": video_description,\n",
+ " })\n",
+ " return result"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'ad_type': 'Product Ad', 'main_category': 'Technology', 'sub_categories': ['Software', 'Artificial Intelligence', 'Mobile Apps'], 'main_theme_message': 'Introducing Google Gemini, a helpful AI assistant that can answer questions, provide information, and even offer creative inspiration for cooking.', 'tone_and_manner': 'Friendly, Playful, Informative', 'target_audience': ['Tech-savvy individuals', 'Early adopters', 'People interested in AI', 'Users seeking convenient information access', 'Content creators'], 'key_keywords': ['Google Gemini', 'AI assistant', 'Artificial intelligence', 'Mobile app', 'Information retrieval', 'Creative assistance', 'Cooking inspiration', 'Tteokbokki'], 'suitable_industries': ['Technology', 'Food and beverage', 'Content creation', 'Education', 'Customer service'], 'expected_viewer_interest': 'Medium'}\n"
+ ]
+ }
+ ],
+ "source": [
+ "final_result = analyze_video(result)\n",
+ "print(final_result)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "벡터 스토어 초기화 시작...\n",
+ "CSV 파일 로드 완료: 6 개의 광고 데이터\n",
+ "Document 객체 생성 완료: 6 개\n",
+ "벡터 스토어 생성 완료\n",
+ "벡터 스토어 저장 완료: ad_vectorstore\n",
+ "\n",
+ "Similar Ad Search Results:\n",
+ "Filename: [ KT | Microsoft 파트너십편 ] KT가 만듭니다. 글로벌 K-AI.mp4\n",
+ "Category: IT/기술\n",
+ "Ad Type: 브랜드 광고\n",
+ "Target Audience: ['기업 관계자', 'IT 업계']\n",
+ "\n",
+ "Ad Content:\n",
+ "광고 유형: 브랜드 광고\n",
+ " 주요 카테고리: IT/기술\n",
+ " 서브 카테고리: 인공지능(AI), 통신, 소프트웨어\n",
+ " 주요 테마: KT-Microsoft AI 파트너십\n",
+ " 톤앤매너: 밝고 긍정적, 미래지향적\n",
+ " 타겟 고객: 기업 관계자, IT 업계\n",
+ " 키워드: 인공지능, AI, KT, Microsoft\n",
+ " 적합 산업군: IT/기술, 통신, 소프트웨어, 교육\n"
+ ]
+ }
+ ],
+ "source": [
+ "from app.vector import AdVectorDB\n",
+ "from app.vector_search import AdVectorSearch\n",
+ "# Initialize and save vector DB\n",
+ "csv_path = \"/Users/kdb/Desktop/youtube_add/final_ad_analysis.csv\"\n",
+ "vector_db = AdVectorDB(csv_path)\n",
+ "vector_db.initialize_vector_store(\"ad_vectorstore\")\n",
+ "\n",
+ "# Execute vector search\n",
+ "from app.vector_search import AdVectorSearch\n",
+ "vector_search = AdVectorSearch(\"ad_vectorstore\")\n",
+ "similar_video = vector_search.search_similar_ads(result)\n",
+ "\n",
+ "# Print results\n",
+ "print(\"\\nSimilar Ad Search Results:\")\n",
+ "print(f\"Filename: {similar_video['metadata']['filename']}\")\n",
+ "print(f\"Category: {similar_video['metadata']['main_category']}\")\n",
+ "print(f\"Ad Type: {similar_video['metadata']['content_type']}\")\n",
+ "print(f\"Target Audience: {similar_video['metadata']['target_audience']}\")\n",
+ "print(\"\\nAd Content:\")\n",
+ "print(similar_video['content'])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'/Users/kdb/Desktop/youtube_add/KT_ad/[ KT | Microsoft 파트너십편 ] KT가 만듭니다. 글로벌 K-AI.mp4'"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "similar_video['metadata']['video_path']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Playing file: /Users/kdb/Desktop/youtube_add/KT_ad/[ 팬메이드K-AI 아이디어 챌린지 ] No.01 ‘배려심 넘치는 조명’편 | KT.mp4\n"
+ ]
+ }
+ ],
+ "source": [
+ "from IPython.display import Video, display\n",
+ "import os\n",
+ "from pathlib import Path\n",
+ "import urllib.parse\n",
+ "\n",
+ "def play_video(similar_video):\n",
+ " \"\"\"Play video\"\"\"\n",
+ " try:\n",
+ " base_dir = Path(\"/Users/kdb/Desktop/youtube_add/KT_ad\")\n",
+ " filename = \"[ 팬메이드K-AI 아이디어 챌린지 ] No.01 ‘배려심 넘치는 조명’편 | KT.mp4\"\n",
+ " \n",
+ " # Find actual file in current directory\n",
+ " for file in base_dir.iterdir():\n",
+ " if file.name == filename:\n",
+ " video_path = file\n",
+ " break\n",
+ " \n",
+ " if 'video_path' in locals():\n",
+ " # Display video (with size adjustment)\n",
+ " display(Video(str(video_path), embed=True, width=800, height=450))\n",
+ " print(f\"Playing file: {video_path}\")\n",
+ " else:\n",
+ " print(\"File not found.\")\n",
+ " print(\"\\nDirectory contents:\")\n",
+ " for file in base_dir.iterdir():\n",
+ " print(file.name)\n",
+ " \n",
+ " except Exception as e:\n",
+ " print(f\"Error occurred while playing video: {e}\")\n",
+ " if 'video_path' in locals():\n",
+ " print(f\"Attempted path: {video_path}\")\n",
+ "\n",
+ "# Play video\n",
+ "play_video(similar_video)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "kospi",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}