Gemini API 동영상 이해하기
Gemini API 동영상 이해하기 (Video Understanding, Interactions API)
Gemini 모델은 동영상을 처리할 수 있어요. 과거에는 도메인 특화 모델이 필요했을 많은 최첨단 개발자 사용 사례를 가능하게 합니다. 동영상을 설명·분할·정보 추출하고, 동영상 내용에 관한 질문에 답하고, 동영상 안의 특정 타임스탬프를 참조하는 능력을 포함해요.
출처: 문서
본문
동영상 생성에 대해 배우려면 Gemini Omni Flash 가이드를 참고하세요.
Gemini에 동영상을 입력으로 제공하는 방법은 다음과 같아요.
| 입력 방법 | 최대 크기 | 권장 사용 사례 |
|---|---|---|
| File API | 20GB (유료) / 2GB (무료) | 대용량 파일(100MB+), 긴 동영상(10분+), 재사용 파일. |
| Cloud Storage 등록 | 2GB (파일당, 저장 한도 없음) | 대용량 파일(100MB+), 긴 동영상(10분+), 영구·재사용 파일. |
| 인라인 데이터 | < 100MB | 작은 파일(<100MB), 짧은 길이(<1분), 일회성 입력. |
| YouTube URL | 해당 없음 | 공개 YouTube 동영상. |
참고: File API가 대부분의 사용 사례, 특히 100MB보다 큰 파일이나 여러 요청에 걸쳐 파일을 재사용하려 할 때 권장됩니다.
다른 파일 입력 방법은 File input methods 가이드를 참고하세요.
동영상 파일 업로드
아래 코드는 샘플 동영상을 업로드해 Files API로 처리될 때까지 기다린 뒤, 업로드된 파일 참조를 사용해 동영상을 요약해요.
from google import genai
import time
client = genai.Client()
myfile = client.files.upload(file="path/to/sample.mp4")
while not myfile.state or myfile.state.name != "ACTIVE":
print("Processing video...")
time.sleep(5)
myfile = client.files.get(name=myfile.name)
interaction = client.interactions.create(
model="gemini-3.8-flash",
input=[
{"type": "video", "uri": myfile.uri, "mime_type": myfile.mime_type},
{"type": "text", "text": "Summarize this video. Then create a quiz with an answer key based on the information in this video."}
]
)
print(interaction.output_text)
import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({});
async function main() {
const myfile = await ai.files.upload({
file: "path/to/sample.mp4",
config: { mimeType: "video/mp4" },
});
let getFile = await ai.files.get({ name: myfile.name });
while (getFile.state === 'PROCESSING') {
getFile = await ai.files.get({ name: myfile.name });
console.log(`current file status: ${getFile.state}`);
console.log('File is still processing, retrying in 5 seconds');
await new Promise((resolve) => {
setTimeout(resolve, 5000);
});
}
if (getFile.state === 'FAILED') {
throw new Error('File processing failed.');
}
const interaction = await ai.interactions.create({
model: "gemini-3.8-flash",
input: [
{ type: "video", uri: myfile.uri, mime_type: myfile.mimeType },
{ type: "text", text: "Summarize this video. Then create a quiz with an answer key based on the information in this video." }
],
});
console.log(interaction.output_text);
}
await main();
import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.Content;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.interactions.TextContent;
import com.google.genai.gaos.models.interactions.VideoContent;
import com.google.genai.gaos.models.interactions.VideoContentMimeType;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import com.google.genai.types.File;
import com.google.genai.types.FileState;
import com.google.genai.types.UploadFileConfig;
import java.util.Arrays;
import java.util.List;
Client client = new Client();
File myfile =
client.files.upload(
"path/to/sample.mp4", UploadFileConfig.builder().mimeType("video/mp4").build());
while (!myfile.state().isPresent()
|| myfile.state().get().knownEnum() != FileState.Known.ACTIVE) {
System.out.println("Processing video...");
Thread.sleep(5000);
myfile = client.files.get(myfile.name().get(), null);
}
Content videoContent =
VideoContent.builder()
.uri(myfile.uri().get())
.mimeType(VideoContentMimeType.of(myfile.mimeType().get()))
.build();
Content textContent =
TextContent.builder()
.text(
"Summarize this video. Then create a quiz with an answer key based on the information in this video.")
.build();
List<Content> contents = Arrays.asList(videoContent, textContent);
CreateModelInteraction params =
CreateModelInteraction.builder()
.model(Model.of("gemini-3.8-flash"))
.input(InteractionsInput.ofContent(contents))
.build();
Interaction interaction =
client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();
System.out.println(interaction.outputText().orElse(""));
package main
import (
"context"
"fmt"
"log"
"time"
"google.golang.org/genai"
"google.golang.org/genai/interactions/models/interactions"
"google.golang.org/genai/interactions/models/operations"
)
func main() {
ctx := context.Background()
client, err := genai.NewClient(ctx, nil)
if err != nil {
log.Fatal(err)
}
myfile, err := client.Files.UploadFromPath(ctx, "path/to/sample.mp4", &genai.UploadFileConfig{
MIMEType: "video/mp4",
})
if err != nil {
log.Fatal(err)
}
for myfile.State != genai.FileStateActive {
fmt.Println("Processing video...")
time.Sleep(5 * time.Second)
myfile, err = client.Files.Get(ctx, myfile.Name, nil)
if err != nil {
log.Fatal(err)
}
}
contents := []interactions.Content{
interactions.NewContent(interactions.VideoContent{
URI: genai.Ptr(myfile.URI),
MimeType: interactions.VideoContentMimeType(myfile.MIMEType).ToPointer(),
}),
interactions.NewContent(interactions.TextContent{
Text: "Summarize this video. Then create a quiz with an answer key based on the information in this video.",
}),
}
res, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
Body: operations.NewCreateInteractionRequestBody(interactions.CreateModelInteraction{
Model: interactions.Model("gemini-3.8-flash"),
Input: interactions.NewInteractionsInput(contents),
}),
})
if err != nil {
log.Fatal(err)
}
if res.Interaction.OutputText != nil {
fmt.Println(*res.Interaction.OutputText)
}
}
VIDEO_PATH="path/to/sample.mp4"
MIME_TYPE=$(file -b --mime-type "${VIDEO_PATH}")
NUM_BYTES=$(wc -c < "${VIDEO_PATH}")
DISPLAY_NAME=VIDEO
tmp_header_file=upload-header.tmp
echo "Starting file upload..."
curl "https://generativelanguage.googleapis.com/upload/v1beta/files" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-D ${tmp_header_file} \
-H "X-Goog-Upload-Protocol: resumable" \
-H "X-Goog-Upload-Command: start" \
-H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \
-H "X-Goog-Upload-Header-Content-Type: ${MIME_TYPE}" \
-H "Content-Type: application/json" \
-d "{'file': {'display_name': '${DISPLAY_NAME}'}}" 2> /dev/null
upload_url=$(grep -i "x-goog-upload-url: " "${tmp_header_file}" | cut -d" " -f2 | tr -d "\r")
rm "${tmp_header_file}"
echo "Uploading video data..."
curl "${upload_url}" \
-H "Content-Length: ${NUM_BYTES}" \
-H "X-Goog-Upload-Offset: 0" \
-H "X-Goog-Upload-Command: upload, finalize" \
--data-binary "@${VIDEO_PATH}" 2> /dev/null > file_info.json
file_uri=$(jq -r ".file.uri" file_info.json)
file_name=$(jq -r ".file.name" file_info.json)
echo file_uri=$file_uri
echo "File uploaded successfully. File URI: ${file_uri}"
# Polling loop
echo "Waiting for file to be processed..."
while true; do
curl -s "https://generativelanguage.googleapis.com/v1beta/${file_name}" \
-H "x-goog-api-key: $GEMINI_API_KEY" > file_status.json
state=$(jq -r ".state" file_status.json)
echo "Current state: $state"
if [ "$state" == "ACTIVE" ]; then
break
elif [ "$state" == "FAILED" ]; then
echo "File processing failed."
exit 1
fi
sleep 5
done
echo "Generating content from video..."
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "gemini-3.8-flash",
"input": [
{"type": "video", "uri": "'${file_uri}'", "mime_type": "'${MIME_TYPE}'"},
{"type": "text", "text": "Summarize this video. Then create a quiz with an answer key based on the information in this video."}
]
}' 2> /dev/null > response.json
jq ".steps[].content[0].text" response.json
토큰 효율과 성능을 최적화하려면 에이전틱 동영상 처리를 고려해 보세요.
전체 요청 크기(파일, 텍스트 프롬프트, 시스템 지시 포함)가 20MB보다 크거나, 동영상 길이가 상당하거나, 같은 동영상을 여러 프롬프트에서 사용하려 한다면 항상 Files API를 사용하세요. File API는 동영상 파일 형식을 직접 받아들여요.
미디어 파일 다루는 방법은 Files API에서 더 배울 수 있어요.
동영상 데이터 인라인 전달
File API로 동영상 파일을 업로드하는 대신, 더 작은 동영상을 요청에 직접 전달할 수 있어요. 전체 요청 크기가 20MB 미만인 더 짧은 동영상에 적합해요.
인라인 동영상 데이터 예시:
from google import genai
import base64
video_file_name = "/path/to/your/video.mp4"
video_bytes = open(video_file_name, 'rb').read()
client = genai.Client()
interaction = client.interactions.create(
model='gemini-3.8-flash',
input=[
{"type": "text", "text": "Please summarize the video in 3 sentences."},
{
"type": "video",
"data": base64.b64encode(video_bytes).decode('utf-8'),
"mime_type": "video/mp4"
}
]
)
print(interaction.output_text)
import { GoogleGenAI } from "@google/genai";
import * as fs from "node:fs";
const ai = new GoogleGenAI({});
const base64VideoFile = fs.readFileSync("path/to/small-sample.mp4", {
encoding: "base64",
});
const interaction = await ai.interactions.create({
model: "gemini-3.8-flash",
input: [
{ type: "text", text: "Please summarize the video in 3 sentences." },
{
type: "video",
data: base64VideoFile,
mime_type: "video/mp4",
}
],
});
console.log(interaction.output_text);
import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.Content;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.interactions.TextContent;
import com.google.genai.gaos.models.interactions.VideoContent;
import com.google.genai.gaos.models.interactions.VideoContentMimeType;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
String videoFileName = "/path/to/your/video.mp4";
byte[] videoBytes = Files.readAllBytes(Paths.get(videoFileName));
String base64Video = Base64.getEncoder().encodeToString(videoBytes);
Client client = new Client();
Content textContent =
TextContent.builder().text("Please summarize the video in 3 sentences.").build();
Content videoContent =
VideoContent.builder()
.data(base64Video)
.mimeType(VideoContentMimeType.VIDEO_MP4)
.build();
List<Content> contents = Arrays.asList(textContent, videoContent);
CreateModelInteraction params =
CreateModelInteraction.builder()
.model(Model.of("gemini-3.8-flash"))
.input(InteractionsInput.ofContent(contents))
.build();
Interaction interaction =
client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();
System.out.println(interaction.outputText().orElse(""));
package main
import (
"context"
"encoding/base64"
"fmt"
"log"
"os"
"google.golang.org/genai"
"google.golang.org/genai/interactions/models/interactions"
"google.golang.org/genai/interactions/models/operations"
)
func main() {
ctx := context.Background()
client, err := genai.NewClient(ctx, nil)
if err != nil {
log.Fatal(err)
}
videoFileName := "/path/to/your/video.mp4"
videoBytes, err := os.ReadFile(videoFileName)
if err != nil {
log.Fatal(err)
}
base64Video := base64.StdEncoding.EncodeToString(videoBytes)
contents := []interactions.Content{
interactions.NewContent(interactions.TextContent{
Text: "Please summarize the video in 3 sentences.",
}),
interactions.NewContent(interactions.VideoContent{
Data: genai.Ptr(base64Video),
MimeType: interactions.VideoContentMimeTypeVideoMp4.ToPointer(),
}),
}
res, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
Body: operations.NewCreateInteractionRequestBody(interactions.CreateModelInteraction{
Model: interactions.Model("gemini-3.8-flash"),
Input: interactions.NewInteractionsInput(contents),
}),
})
if err != nil {
log.Fatal(err)
}
if res.Interaction.OutputText != nil {
fmt.Println(*res.Interaction.OutputText)
}
}
VIDEO_PATH=/path/to/your/video.mp4
if [[ "$(base64 --version 2>&1)" = *"FreeBSD"* ]]; then
B64FLAGS="--input"
else
B64FLAGS="-w0"
fi
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "gemini-3.8-flash",
"input": [
{"type": "text", "text": "Please summarize the video in 3 sentences."},
{
"type": "video",
"data": "'$(base64 $B64FLAGS $VIDEO_PATH)'",
"mime_type": "video/mp4"
}
]
}' 2> /dev/null
참고: Argument list too long 오류가 나면 파일의 base64 인코딩이 curl 명령줄에 너무 길 수 있어요. 더 큰 파일에는 File API 방법을 사용하세요.
YouTube URL 전달
프리뷰: YouTube URL 기능은 프리뷰 상태이며 무료로 제공돼요. 가격과 속도 제한은 변경될 수 있습니다.
YouTube URL을 요청의 일부로 Gemini API에 직접 전달할 수 있어요.
from google import genai
client = genai.Client()
interaction = client.interactions.create(
model='gemini-3.8-flash',
input=[
{"type": "text", "text": "Please summarize the video in 3 sentences."},
{
"type": "video",
"uri": "https://www.youtube.com/watch?v=9hE5-98ZeCg"
}
]
)
print(interaction.output_text)
import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({});
const interaction = await ai.interactions.create({
model: "gemini-3.8-flash",
input: [
{ type: "text", text: "Please summarize the video in 3 sentences." },
{
type: "video",
uri: "https://www.youtube.com/watch?v=9hE5-98ZeCg",
}
],
});
console.log(interaction.output_text);
import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.Content;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.interactions.TextContent;
import com.google.genai.gaos.models.interactions.VideoContent;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import java.util.Arrays;
import java.util.List;
Client client = new Client();
Content textContent =
TextContent.builder().text("Please summarize the video in 3 sentences.").build();
Content videoContent =
VideoContent.builder()
.uri("https://www.youtube.com/watch?v=9hE5-98ZeCg")
.build();
List<Content> contents = Arrays.asList(textContent, videoContent);
CreateModelInteraction params =
CreateModelInteraction.builder()
.model(Model.of("gemini-3.8-flash"))
.input(InteractionsInput.ofContent(contents))
.build();
Interaction interaction =
client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();
System.out.println(interaction.outputText().orElse(""));
package main
import (
"context"
"fmt"
"log"
"google.golang.org/genai"
"google.golang.org/genai/interactions/models/interactions"
"google.golang.org/genai/interactions/models/operations"
)
func main() {
ctx := context.Background()
client, err := genai.NewClient(ctx, nil)
if err != nil {
log.Fatal(err)
}
contents := []interactions.Content{
interactions.NewContent(interactions.TextContent{
Text: "Please summarize the video in 3 sentences.",
}),
interactions.NewContent(interactions.VideoContent{
URI: genai.Ptr("https://www.youtube.com/watch?v=9hE5-98ZeCg"),
}),
}
res, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
Body: operations.NewCreateInteractionRequestBody(interactions.CreateModelInteraction{
Model: interactions.Model("gemini-3.8-flash"),
Input: interactions.NewInteractionsInput(contents),
}),
})
if err != nil {
log.Fatal(err)
}
if res.Interaction.OutputText != nil {
fmt.Println(*res.Interaction.OutputText)
}
}
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "gemini-3.8-flash",
"input": [
{"type": "text", "text": "Please summarize the video in 3 sentences."},
{
"type": "video",
"uri": "https://www.youtube.com/watch?v=9hE5-98ZeCg"
}
]
}' 2> /dev/null
제한 사항:
- 무료 계층에서는 하루에 8시간 이상의 YouTube 동영상을 업로드할 수 없어요.
- 유료 계층에서는 동영상 길이에 따른 제한이 없어요.
- Gemini 2.5 이전 모델에서는 요청당 1개 동영상만 업로드할 수 있어요. Gemini 2.5 이상 모델에서는 요청당 최대 10개 동영상을 업로드할 수 있어요.
- 공개 동영상만 업로드할 수 있어요(비공개·숨김 동영상은 안 됨).
에이전틱 동영상 이해 (Agentic video understanding)
기본적으로 동영상 입력은 정적 처리를 사용해요(1 FPS로 프레임 추출). Gemini 3.8 Flash, 3.7 Flash, 3.6 Flash, 3.5 Flash Lite 모델은 에이전틱 동영상 이해도 지원하는데, 모델이 동영상 타임라인을 동적으로 탐색하고, 프롬프트에 따라 전사본을 선택적으로 검사하고, 프레임 속도와 해상도를 적응적으로 조정합니다.
| 모드 | 설명 | 지원 모델 |
|---|---|---|
| 정적 (Static) (기본값) | 고정 속도(1 FPS)로 프레임을 추출해 한 번에 컨텍스트에 배치. 짧은 클립에 잘 맞음. | 모든 Gemini 모델 |
| 에이전틱 (Agentic) | 모델이 동영상 타임라인을 동적으로 탐색하며 프롬프트에 기반해 필요한 콘텐츠만 로드. 긴 콘텐츠에서 최대 88% 토큰 효율, 약 7% 높은 품질. | Gemini 3.8 Flash, 3.7 Flash, 3.6 Flash, 3.5 Flash Lite |
처리 모드 선택
일반 지침으로, 특히 응답 품질이나 토큰 효율을 최적화할 때 에이전틱 모드로 시작하세요.
- 에이전틱 (Agentic): 긴 형식 동영상이나 특정 순간을 대상으로 하는 쿼리. 모델이 타임라인을 동적으로 탐색해 컨텍스트 윈도우를 채우지 않고 맥락상 관련 있는 정보를 타겟팅.
- 정적 (Static): 짧은 클립(5분 미만)의 지연 시간에 민감한 쿼리, 또는 전체 클립에 걸쳐 프레임 수준 정밀도가 필요한 경우.
참고: 에이전틱 처리가 더 오래 걸리는 긴 동영상이나 복잡한 프롬프트에서는 스트리밍(
stream=True)이나 백그라운드 실행(background=True)을 사용하세요. 이렇게 하면 연결을 활성 상태로 유지하고 중간 추론 단계를 표시하며 연결·인증 타임아웃을 피할 수 있어요.
처리 모드 설정
import time
from google import genai
client = genai.Client()
# Upload a long video
video_file = client.files.upload(file="path/to/lecture.mp4")
while video_file.state.name == "PROCESSING":
time.sleep(2)
video_file = client.files.get(name=video_file.name)
# Use agentic processing
interaction = client.interactions.create(
model="gemini-3.8-flash",
input=[
{
"type": "video",
"uri": video_file.uri,
"mime_type": video_file.mime_type,
"processing": "agentic"
},
{"type": "text", "text": "What are the three main arguments presented?"}
]
)
print(interaction.output_text)
import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({});
// Upload a long video
let videoFile = await ai.files.upload({
file: "path/to/lecture.mp4",
config: { mimeType: "video/mp4" }
});
while (videoFile.state === "PROCESSING") {
await new Promise((resolve) => setTimeout(resolve, 2000));
videoFile = await ai.files.get({ name: videoFile.name });
}
// Use agentic processing
const interaction = await ai.interactions.create({
model: "gemini-3.8-flash",
input: [
{
type: "video",
uri: videoFile.uri,
mime_type: videoFile.mimeType,
processing: "agentic"
},
{ type: "text", text: "What are the three main arguments presented?" }
]
});
console.log(interaction.output_text);
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "gemini-3.8-flash",
"input": [
{
"type": "video",
"uri": "'${file_uri}'",
"mime_type": "video/mp4",
"processing": "agentic"
},
{"type": "text", "text": "What are the three main arguments presented?"}
]
}' 2> /dev/null
참고: 에이전틱 처리가 사용됐는지 확인하려면
interaction.steps를 검사하세요.processing_call과processing_result가 있으면 모델이 동영상을 동적으로 탐색했다는 뜻이에요.
응답 단계
에이전틱 처리는 steps 배열에 두 가지 새 단계 유형을 추가해요.
processing_call: 모델이id로 식별되는 동영상 세그먼트나 오디오 전사본을 요청함.processing_result: 그 로드의 결과,call_id로 연결됨.
이들은(요약이 켜져 있을 때)thought 단계와 섞여 나타나고 최종 model_output 단계보다 앞서요. UI에 진행 추적을 보여주는 데 사용할 수 있지만 응답은 필요 없어요.
처리 단계가 섞인 응답 페이로드 예시:
{
"steps": [
{
"type": "thought",
"signature": "sig_thought_1",
"summary": [
{
"type": "text",
"text": "Inspecting transcript for key discussion topics..."
}
]
},
{
"type": "processing_call",
"id": "call_01",
"signature": "sig_call_01"
},
{
"type": "processing_result",
"call_id": "call_01",
"signature": "sig_result_01"
},
{
"type": "thought",
"signature": "sig_thought_2",
"summary": [
{
"type": "text",
"text": "Loading visual frames to verify slide content..."
}
]
},
{
"type": "processing_call",
"id": "call_02",
"signature": "sig_call_02"
},
{
"type": "processing_result",
"call_id": "call_02",
"signature": "sig_result_02"
},
{
"type": "thought",
"signature": "sig_thought_3",
"summary": [
{
"type": "text",
"text": "Synthesizing answer from gathered evidence..."
}
]
},
{
"type": "model_output",
"content": [
{
"type": "text",
"text": "The three main arguments presented in the lecture are..."
}
]
}
]
}
동영상 간 처리 모드 섞기
같은 요청에서 각 동영상에 서로 다른 처리 모드를 설정할 수 있어요.
from google import genai
client = genai.Client()
lecture = client.files.upload(file="path/to/long-lecture.mp4")
experiment = client.files.upload(file="path/to/short-experiment.mp4")
interaction = client.interactions.create(
model="gemini-3.8-flash",
input=[
{
"type": "video",
"uri": lecture.uri,
"mime_type": lecture.mime_type,
"processing": "agentic" # Use agentic video understanding
},
{
"type": "video",
"uri": experiment.uri,
"mime_type": experiment.mime_type,
"processing": "static" # Use static processing
},
{"type": "text", "text": "Compare the lecture content with the experiment results."}
]
)
print(interaction.output_text)
import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({});
const lecture = await ai.files.upload({
file: "path/to/long-lecture.mp4",
config: { mimeType: "video/mp4" }
});
const experiment = await ai.files.upload({
file: "path/to/short-experiment.mp4",
config: { mimeType: "video/mp4" }
});
const interaction = await ai.interactions.create({
model: "gemini-3.8-flash",
input: [
{
type: "video",
uri: lecture.uri,
mime_type: lecture.mimeType,
processing: "agentic" // Use agentic video understanding
},
{
type: "video",
uri: experiment.uri,
mime_type: experiment.mimeType,
processing: "static" // Use static processing
},
{ type: "text", text: "Compare the lecture content with the experiment results." }
]
});
console.log(interaction.output_text);
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "gemini-3.8-flash",
"input": [
{
"type": "video",
"uri": "'${lecture_uri}'",
"mime_type": "video/mp4",
"processing": "agentic"
},
{
"type": "video",
"uri": "'${experiment_uri}'",
"mime_type": "video/mp4",
"processing": "static"
},
{"type": "text", "text": "Compare the lecture content with the experiment results."}
]
}' 2> /dev/null
다중 턴 동영상 대화
동영상 컨텍스트는 대화의 턴 간에 보존돼요. 에이전틱 처리를 사용할 때:
- 상태 유지 모드 (Stateful mode) (
previous_interaction_id사용): 서버가 동영상 컨텍스트를 보존해요. 추가 처리가 필요 없어요. - 무상태 모드 (Stateless mode) (
step_list사용): 무상태 모드에서 응답은 동영상 컨텍스트를 인코딩하는processing_call과processing_result단계를 포함해요. 다음 요청의step_list에 응답의 모든 단계를 포함해야 동영상 컨텍스트가 보존돼요. 생략하면 현재 API 오류는 반환되지 않지만 동영상 컨텍스트가 사라져 후속 질문에서 응답 품질이 크게 떨어져요. 후속 요청으로 보내는 반환 단계가 입력 토큰 수에 기여한다는 점에 유의하세요.
콘텐츠에서 타임스탬프 참조
MM:SS 형식의 타임스탬프로 동영상 안의 특정 시점에 대해 질문할 수 있어요.
prompt = "What are the examples given at 00:05 and 00:10 supposed to show us?"
const prompt = "What are the examples given at 00:05 and 00:10 supposed to show us?";
String prompt = "What are the examples given at 00:05 and 00:10 supposed to show us?";
prompt := "What are the examples given at 00:05 and 00:10 supposed to show us?"
PROMPT="What are the examples given at 00:05 and 00:10 supposed to show us?"
동영상에서 상세 인사이트 추출
Gemini 모델은 오디오와 시각적 스트림 모두의 정보를 처리해 동영상 콘텐츠를 이해하는 강력한 능력을 제공해요.
시각적 설명을 위해 모델은 동영상을 초당 1프레임(FPS) 비율로 샘플링해요. 이 기본 샘플링 비율은 대부분의 콘텐츠에 잘 맞지만, 빠른 움직임이나 빠른 장면 전환이 있는 동영상에서는 세부 사항을 놓칠 수 있음에 유의하세요.
prompt = "Describe the key events in this video, providing both audio and visual details. Include timestamps for salient moments."
const prompt = "Describe the key events in this video, providing both audio and visual details. Include timestamps for salient moments.";
String prompt =
"Describe the key events in this video, providing both audio and visual details. Include timestamps for salient moments.";
prompt := "Describe the key events in this video, providing both audio and visual details. Include timestamps for salient moments."
PROMPT="Describe the key events in this video, providing both audio and visual details. Include timestamps for salient moments."
동영상 처리 커스터마이즈
클리핑 간격을 설정하거나 커스텀 프레임 속도 샘플링을 제공해 Gemini API에서 동영상 처리를 커스터마이즈할 수 있어요. 이 커스터마이즈 옵션은 "static" 모드로 동영상을 처리할 때만 지원됩니다.
클리핑 간격 설정
processing 구성 객체에서 start_offset과 end_offset을 지정해 동영상을 클립할 수 있어요.
interaction = client.interactions.create(
model="gemini-3.8-flash",
input=[
{
"type": "video",
"uri": video_file.uri,
"mime_type": video_file.mime_type,
"processing": {
"type": "static",
"start_offset": 1200,
"end_offset": 1500,
},
},
{"type": "text", "text": "Summarize this section of the video."},
],
)
print(interaction.output_text)
const interaction = await ai.interactions.create({
model: "gemini-3.8-flash",
input: [
{
type: "video",
uri: videoFile.uri,
mime_type: videoFile.mimeType,
processing: {
type: "static",
start_offset: 1200,
end_offset: 1500,
},
},
{ type: "text", text: "Summarize this section of the video." },
],
});
console.log(interaction.output_text);
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "gemini-3.8-flash",
"input": [
{
"type": "video",
"uri": "'${file_uri}'",
"mime_type": "video/mp4",
"processing": {
"type": "static",
"start_offset": 1200,
"end_offset": 1500
}
},
{"type": "text", "text": "Summarize this section of the video."}
]
}' 2> /dev/null
커스텀 프레임 속도 설정
processing 구성 객체에서 fps 인자를 전달해 커스텀 프레임 속도 샘플링을 설정할 수 있어요.
interaction = client.interactions.create(
model="gemini-3.8-flash",
input=[
{
"type": "video",
"uri": video_file.uri,
"mime_type": video_file.mime_type,
"processing": {
"type": "static",
"fps": 0.5, # Sample 1 frame every 2 seconds
},
},
{"type": "text", "text": "Describe the scene changes in this video."},
],
)
print(interaction.output_text)
const interaction = await ai.interactions.create({
model: "gemini-3.8-flash",
input: [
{
type: "video",
uri: videoFile.uri,
mime_type: videoFile.mimeType,
processing: {
type: "static",
fps: 0.5, // Sample 1 frame every 2 seconds
},
},
{ type: "text", text: "Describe the scene changes in this video." },
],
});
console.log(interaction.output_text);
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "gemini-3.8-flash",
"input": [
{
"type": "video",
"uri": "'${file_uri}'",
"mime_type": "video/mp4",
"processing": {
"type": "static",
"fps": 0.5
}
},
{"type": "text", "text": "Describe the scene changes in this video."}
]
}' 2> /dev/null
지원 동영상 형식
Gemini는 다음 동영상 형식 MIME 타입을 지원해요.
video/mp4video/mpegvideo/movvideo/avivideo/x-flvvideo/mpgvideo/webmvideo/wmvvideo/3gpp
동영상에 대한 기술적 세부 사항
- 지원 모델과 컨텍스트: 모든 Gemini 모델이 동영상 데이터를 처리할 수 있어요.
- 1M 컨텍스트 윈도우가 있는 모델은 기본적으로(저 미디어 해상도) 최대 3시간 길이의 동영상, 또는 고 미디어 해상도에서 최대 1시간 길이의 동영상을 처리할 수 있어요.
- 처리 모드: Gemini 3.8 Flash, 3.7 Flash, 3.6 Flash, 3.5 Flash Lite와 이후 모델은 두 가지 동영상 처리 모드를 지원해요.
- 정적 (Static): 1 FPS로 프레임을 추출해 컨텍스트에 배치(모든 모델의 기본값). 오디오는 1Kbps(단일 채널)로 처리. 매초 타임스탬프 추가. 짧은 클립이나 모든 프레임이 중요할 때(프레임별 검사)에 최적. 빠른 동작 시퀀스는 1 FPS 샘플링으로 인해 세부 사항이 손실될 수 있음.
- 에이전틱 (Agentic): 모델이 동영상을 동적으로 탐색하며 전사본·프레임·오디오를 요청 시 로드. 긴 콘텐츠에서 최대 88% 적은 토큰을 사용하지만, 생성이 시작되기 전 내부 추론·도구 왕복으로 인해 짧은 클립(<5분)에서 TTFT가 약간 늘 수 있어요. 토큰 비용과 응답 품질 최적화에 긴 형식 동영상에 최적. Gemini 3.8 Flash, 3.7 Flash, 3.6 Flash, 3.5 Flash Lite에서 지원.
- 토큰 계산 (정적 모드): 동영상 1초는 다음과 같이 토큰화돼요.
- 개별 프레임(1 FPS로 샘플링):
media_resolution이 low면 프레임당 66토큰으로 토큰화.- 그 외에는 프레임당 258토큰으로 토큰화.
- 오디오: 초당 32토큰.
- 메타데이터도 포함.
- 총합: 기본(저) 미디어 해상도에서 동영상 1초당 약 100토큰, 고 미디어 해상도에서 동영상 1초당 약 300토큰.
- 개별 프레임(1 FPS로 샘플링):
- 토큰 계산 (에이전틱 모드): 토큰 사용량은 콘텐츠 복잡도와 모델의 탐색 전략에 따라 달라져요. 동영상 탐색 중 생성된 탐색 추론 토큰은 thought 토큰(
total_thought_tokens)으로 계산되고, 요청 시 로드된 프레임·오디오·전사본은 도구 사용 토큰(total_tool_use_tokens)으로 계산돼요. 에이전틱 처리는 모델이 프롬프트에 답하는 데 필요한 전사본·프레임·오디오만 로드하기 때문에 긴 콘텐츠에서 정적 처리보다 보통 최대 88% 적은 총 토큰을 사용해요(tokens 가이드 참고). - 미디어 해상도: Gemini 3는
media_resolution파라미터로 멀티모달 비전 처리에 대한 세밀한 제어를 도입했어요.media_resolution파라미터는 입력 이미지나 동영상 프레임당 할당되는 최대 토큰 수를 결정해요. 더 높은 해상도는 미세한 텍스트를 읽거나 작은 세부 사항을 식별하는 모델의 능력을 개선하지만 토큰 사용량과 지연 시간을 늘려요.media_resolution과processing파라미터는 독립적이에요. 같은 동영상 입력에 둘 다 설정할 수 있어요.
토큰 계산에 대한 자세한 내용은 tokens 가이드를 참고하세요.
- 타임스탬프 형식: 프롬프트에서 동영상의 특정 순간을 참조할 때는
MM:SS형식(예: 1분 15초는01:15)을 사용하세요. - 프롬프트 배치: 텍스트와 단일 동영상을 결합한다면
input배열에서 텍스트 프롬프트를 동영상 part 다음에 두세요. - 긴 요청의 타임아웃: 확장 처리 시간이나 복잡한 다단계 추론이 필요한 동영상에는 스트리밍(
stream=True)이나 백그라운드 실행(background=True)을 사용하세요. 고부하에서 백엔드 재시도를 겪는 동기·비스트리밍 요청은 연결이나 인증 토큰 유효 시간을 초과해 예상 밖의401 Unauthorized또는 타임아웃 오류가 표시될 수 있어요. 스트리밍은 연결을 활성 상태로 유지하고 중간 추론·도구 호출 진행을 표시해요.
다음 단계
- Media resolution: 품질과 토큰 사용을 균형 잡도록 동영상 프레임 해상도 제어.
- Tokens: 정적·에이전틱 처리 모드에서 동영상 콘텐츠가 토큰화되는 방식을 이해.
- System instructions: 시스템 지시로 특정 요구·사용 사례에 맞게 모델 동작 조종.
- Files API: Gemini에 사용할 파일 업로드·관리에 대해 더 배우기.
- File prompting strategies: Gemini API는 텍스트, 이미지, 오디오, 동영상 데이터(멀티모달 프롬프팅)로 프롬프트하는 것을 지원.
- Safety guidance: 가끔 생성형 AI 모델이 부정확·편향·공격적인 출력 같은 예상 밖의 결과를 만들 수 있음. 후처리와 인간 평가가 이런 출력의 피해 위험을 줄이는 데 필수적.
더 알아보기 (Learn more)
이 페이지는 Interactions API(interactions.create, type: video, processing 필드)를 사용한 버전이에요. GenerateContent API 버전은 generate-content/video-understanding 문서에 있어요. 긴 동영상에는 에이전틱 처리 모드가 토큰을 크게 아끼고, 다중 턴에서 동영상 컨텍스트를 보존하려면 무상태 모드에서는 step_list를 모두 포함해야 한다는 점을 기억하세요.