From 944049fcd51bc344a901e144f0a5dda02daf180a Mon Sep 17 00:00:00 2001 From: sedanah-m Date: Wed, 2 Sep 2026 09:59:57 -0700 Subject: [PATCH 1/9] feat: quickstart video-analysis sample feature --- .../src/features/video-anaylsis/index.tsx | 237 ++++++++++++++++++ .../src/features/video-anaylsis/service.ts | 87 +++++++ 2 files changed, 324 insertions(+) create mode 100644 ai/ai-samples/src/features/video-anaylsis/index.tsx create mode 100644 ai/ai-samples/src/features/video-anaylsis/service.ts diff --git a/ai/ai-samples/src/features/video-anaylsis/index.tsx b/ai/ai-samples/src/features/video-anaylsis/index.tsx new file mode 100644 index 000000000..360d04c67 --- /dev/null +++ b/ai/ai-samples/src/features/video-anaylsis/index.tsx @@ -0,0 +1,237 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { analyzeVideo, streamVideoAnalysis } from './service'; + +const SAMPLE_PROMPTS = [ + 'Describe what is happening in this video in detail.' +]; + +export default function VideoAnalysisView() { + const [prompt, setPrompt] = useState(SAMPLE_PROMPTS[0]); + const [selectedFile, setSelectedFile] = useState(null); + const [previewUrl, setPreviewUrl] = useState(null); + const [useStreaming, setUseStreaming] = useState(true); + const [response, setResponse] = useState(''); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const fileInputRef = useRef(null); + + useEffect(() => { + if (!selectedFile) { + setPreviewUrl(null); + return; + } + + const objectUrl = URL.createObjectURL(selectedFile); + setPreviewUrl(objectUrl); + + return () => { + URL.revokeObjectURL(objectUrl); + }; + }, [selectedFile]); + + const handleFileChange = (e: React.ChangeEvent) => { + const file = e.target.files?.[0] || null; + setSelectedFile(file); + setError(null); + }; + + const handleAnalyze = async () => { + const cleanedPrompt = prompt.trim(); + if (!selectedFile || !cleanedPrompt) return; + + setLoading(true); + setError(null); + setResponse(''); + + try { + if (useStreaming) { + await streamVideoAnalysis(cleanedPrompt, selectedFile, (chunk) => { + setResponse((prev) => prev + chunk); + }); + } else { + const resultText = await analyzeVideo(cleanedPrompt, selectedFile); + setResponse(resultText); + } + } catch (err: unknown) { + const message = + err instanceof Error + ? err.message + : 'An unexpected error occurred during video analysis.'; + setError(message); + } finally { + setLoading(false); + } + }; + + const handleClear = () => { + setSelectedFile(null); + setResponse(''); + setError(null); + if (fileInputRef.current) { + fileInputRef.current.value = ''; + } + }; + + return ( +
+
+

Video Analysis & Understanding

+ {(selectedFile || response) && ( + + )} +
+ +

+ Upload a video file alongside a prompt to analyze video frames, extract timestamps, describe actions, or transcribe content using Gemini. +

+ + {/* Video Upload Section */} +
+ + + + Supported formats: MP4, WebM, MOV, etc. (Inline payloads recommended under 20MB). + +
+ + {/* Video Preview */} + {previewUrl && ( +
+
+ )} + + {/* Prompt Suggestions */} +
+ +
+ {SAMPLE_PROMPTS.map((sample, idx) => ( + + ))} +
+
+ + {/* Prompt Input */} +
+ +