Gemini API से लंबे वीडियो इंडेक्स करना: टाइमस्टैम्प, विजुअल्स और गैप ऑडिटिंग
Gemini API के साथ लंबी वीडियो रिकॉर्डिंग को इंडेक्स करने का एक इंजीनियरिंग वर्कफ़्लो: Files API के ज़रिए अपलोड करना, Interactions API में एजेंटिक ड्राफ़्ट तैयार करना, प्रोग्रामेटिक रूप से स्ट्रक्चर्ड पंक्तियों को मान्य करना और कवरेज गैप का लक्षित निरीक्षण करना।
विषय-सूची

लंबी वीडियो रिकॉर्डिंग्स—जैसे टेक्निकल टॉक्स, वर्कशॉप्स, आर्किटेक्चर रिव्यू कॉल्स और स्क्रीनकास्ट—बोले गए ऑडियो और स्क्रीन पर दिखने वाले विजुअल्स में घनी जानकारी समेटे होती हैं। सामान्य हाई-लेवल सारांश केवल व्यापक विषयों को ही पकड़ पाते हैं, जिससे इंजीनियर्स को किसी खास टर्मिनल कमांड या कॉन्फ़िगरेशन पैरामीटर की तलाश में पूरे वीडियो को मैन्युअल रूप से आगे-पीछे (scrub) करके देखना पड़ता है।
Gemini मल्टीमॉडल मॉडल ऑडियो और वीडियो स्ट्रीम्स का एक साथ विश्लेषण कर सकते हैं और टाइमस्टैम्प के साथ स्ट्रक्चर्ड इवेंट इंडेक्स तैयार कर सकते हैं। हालांकि, मॉडल के शुरुआती इन्फ़रेंस से मिलने वाला कच्चा आउटपुट केवल ड्राफ़्ट उम्मीदवारों का एक सेट (draft candidate set) होता है, कोई प्रोडक्शन-रेडी रेफ़रेंस इंडेक्स नहीं। एक भरोसेमंद इंडेक्स तैयार करने के लिए एक सुव्यवस्थित पाइपलाइन की आवश्यकता होती है: Files API के ज़रिए एक बार अपलोड करना और URI का पुन: उपयोग करना, ड्राफ़्ट इंटरवल्स निकालना, आउटपुट स्कीमा को कड़ाई से मान्य करना, संदिग्ध कवरेज गैप का ऑडिट करना और लक्षित कैलिब्रेशन करना।
आर्किटेक्चर: डिलीवरी के तरीके और प्रोसेसिंग मोड्स
मौजूदा Google Video Understanding डॉक्यूमेंटेशन में मुख्य इम्प्लीमेंटेशन Interactions API और google-genai लाइब्रेरी के इर्द-गिर्द केंद्रित हैं। हालांकि बैकवर्ड कम्पैटिबिलिटी के लिए पारंपरिक generate_content मेथड अभी भी समर्थित है, लेकिन Interactions API मल्टीमॉडल प्रोसेसिंग पैरामीटर्स पर अधिक स्पष्ट नियंत्रण प्रदान करता है।
1. वीडियो डिलीवरी के तरीके (Video Delivery Methods)
- Files API (लंबे वीडियो के लिए अनुशंसित): कुछ मिनटों से लेकर कई घंटों तक की रिकॉर्डिंग्स के लिए सबसे उपयुक्त। फ़ाइल को एक बार अपलोड किया जाता है, सर्वर पर इंडेक्स किया जाता है, और कच्चे बाइट्स को दोबारा भेजे बिना बार-बार के अनुरोधों में URI द्वारा संदर्भित किया जाता है।
- Google Cloud Storage (GCS): पहले से ही Google Cloud इंफ्रास्ट्रक्चर में होस्ट किए गए मौजूदा वीडियो संग्रहों (archives) के लिए आदर्श।
- इनलाइन डेटा (Inline Data): अनुरोध पेलोड (request payload) के भीतर सीधे कच्चे बाइट्स भेजना। डॉक्यूमेंटेशन विभिन्न वातावरणों में अलग-अलग पेलोड सीमाओं को रेखांकित करता है; घंटे भर के वीडियो के स्थिर प्रबंधन के लिए, इनलाइन रॉ वीडियो से बचते हुए Files API या Cloud Storage एक व्यावहारिक विकल्प है।
2. प्रोसेसिंग मोड्स: स्टैटिक बनाम एजेंटिक (Static vs. Agentic)
- स्टैटिक प्रोसेसिंग (Static Processing):
डिफ़ॉल्ट रूप से, मॉडल 1 फ़्रेम प्रति सेकंड (1 FPS) की दर से फ़्रेम्स का सैंपल लेता है। प्रत्येक सेकंड टोकन्स में बदल जाता है, जिससे 60 मिनट की अवधि में पर्याप्त कॉन्टेक्स्ट लोड जमा हो जाता है। ध्यान रखें: 1 FPS सैंपलिंग संक्षिप्त विजुअल घटनाओं को छोड़ सकती है (जैसे एक सेकंड से भी कम समय के लिए विंडो स्विच होना या क्षणिक टूलटिप्स) और यह हर छोटे इंटरेक्शन को कैप्चर करने की गारंटी नहीं दे सकती। - एजेंटिक वीडियो अंडरस्टैंडिंग (Agentic Video Understanding):
मॉडल वीडियो में गतिशील रूप से नेविगेट करता है, और ज़रूरत के अनुसार विशिष्ट फ़्रेम्स और ऑडियो सेगमेंट निकालता है। इससे प्रोसेस किए जाने वाले कॉन्टेक्स्ट टोकन्स की मात्रा में भारी कमी आती है।
सीमा (Limitation): एजेंटिक ह्यूरिस्टिक ऑडियो संकेतों और सिमेंटिक ट्रिगर्स पर निर्भर करता है। यदि कोई प्रेजेंटर बिना बोले स्क्रीन पर चुपचाप कोई क्रिया करता है (जैसे कमांड टाइप करना या किसी आरेख का निरीक्षण करना), तो ह्यूरिस्टिक उस अंतराल को निष्क्रिय बैकग्राउंड मान सकता है और विस्तृत विजुअल फ़्रेम्स का अनुरोध करने से चूक सकता है।
चरण 1. वीडियो अपलोड और स्टेटस पोलिंग (Video Upload and Status Polling)
Files API पर भेजी गई फ़ाइलें तुरंत इन्फ़रेंस के लिए उपलब्ध नहीं होती हैं; सर्वर को कंटेनर को अनपैक करना होता है और ऑडियो-विजुअल ट्रैक्स को इंडेक्स करना होता है। आपके एप्लिकेशन को तब तक रिसोर्स को पोल (poll) करना चाहिए जब तक कि इसकी स्थिति ACTIVE न हो जाए।
import time
from google import genai
client = genai.Client()
video_path = "tech_workshop_60min.mp4"
video_file = client.files.upload(file=video_path)
while not video_file.state or video_file.state.name != "ACTIVE":
if video_file.state and video_file.state.name == "FAILED":
error_info = getattr(video_file, "error", None)
raise RuntimeError(
f"Файл перешел в статус FAILED. Детали: {error_info}. "
"Проверьте кодеки, целостность контейнера или повторите попытку."
)
time.sleep(5)
video_file = client.files.get(name=video_file.name)
print("Видео готово к обработке.")
चरण 2. Interactions API के ज़रिए ड्राफ़्ट इंडेक्स का अनुरोध करना
लंबी रिकॉर्डिंग्स के लिए, "processing": "agentic" के साथ client.interactions.create को इनवोक करें। प्रॉम्प्ट एक सख्त सारणीबद्ध (tabular) आउटपुट लागू करता है: टाइमस्टैम्प रेंज MM:SS - MM:SS, इवेंट का प्रकार (visual, speech, hybrid), भाषण का एक संक्षिप्त दावा (CLAIM), और स्क्रीन पर होने वाली गतिविधि (ACTION)।
index_prompt = """
Ты — инструмент технической индексации видеозаписей.
Сформируй хронологический индекс событий для всей 60-минутной записи от 00:00 до 60:00.
Требования к структуре ответа:
1. Выведи результат построчно в формате TSV с разделителем |.
2. Каждая строка должна содержать ровно 5 полей:
START_TIME (MM:SS) | END_TIME (MM:SS) | TYPE (visual/speech/hybrid) | CLAIM | ACTION
3. Не объединяй слишком длинные интервалы в одну запись; фиксируй смену слайдов, терминал, ошибки и выводы спикера.
4. Если речи не было, в поле CLAIM укажи NONE. Если на экране не было динамики, в ACTION укажи STATIC.
5. Выводи исключительно строки данных без вводных слов и пояснений.
"""
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": index_prompt
}
]
)
raw_index_output = interaction.output_text
एजेंटिक नेविगेशन स्टेप्स पर ध्यान दें:
interaction.stepsके अंदरprocessing_callप्रविष्टियों की उपस्थिति इस बात की पुष्टि करती है कि मॉडल ने एक निरंतर स्ट्रीम को ग्रहण करने के बजाय वीडियो टाइमलाइन को गतिशील रूप से नेविगेट किया है। हालांकि, इन कॉल्स को देखना केवल नेविगेशन गतिविधि की पुष्टि करता है—यह सभी प्रासंगिक टाइमलाइन घटनाओं में आउटपुट की पूर्णता (output completeness) की गारंटी नहीं देता है।
चरण 3. उदाहरण आउटपुट संरचना (काल्पनिक ड्राफ़्ट)
अपेक्षित डेटा स्कीमा को प्रदर्शित करने वाले मॉडल आउटपुट का एक उदाहरणात्मक काल्पनिक अंश नीचे दिया गया है:
00:00 | 02:15 | hybrid | Вводное слово, обзор повестки миграции на шардированный кластер | Титульный слайд доклада, окно спикера
02:16 | 05:40 | visual | NONE | Переключение на схему архитектуры сервиса заказов в Miro
05:41 | 09:12 | speech | Пояснение причин отказа от распределенных транзакций в пользу Saga | Статичная схема Miro, курсор неподвижен
27:30 | 29:10 | visual | NONE | Открытие консоли, запуск сценария развертывания реплик БД
29:11 | 32:45 | hybrid | Разбор сценария split-brain при потере сетевой связности | Вывод логов etcd в терминале, подсветка таймаутов
54:10 | 57:25 | speech | Ответ на вопрос о допустимой задержке репликации данных | Финальный слайд с контактами спикера
57:26 | 60:00 | hybrid | Подведение итогов и демонстрация ссылки на репозиторий | Показ QR-кода на экране, завершение созвона
चरण 4. मार्कअप वैलिडेशन और लोकल सर्च
कच्चे LLM रिस्पॉन्स को बिना सत्यापन के स्ट्रक्चर्ड डेटासेट के रूप में विश्वसनीय नहीं माना जा सकता। एक लचीले पार्सर (parser) को खराब रिकॉर्ड्स को चुपचाप हटाना नहीं चाहिए; इसके बजाय, उसे मैन्युअल संपादन के लिए उन्हें अलग कर देना चाहिए। वैलिडेटर लागू करता है: ठीक पाँच फ़ील्ड्स, मान्य इवेंट प्रकार (visual, speech, hybrid), और वीडियो सीमाओं के भीतर सही प्रारूप वाले MM:SS टाइमस्टैम्प।
import csv
import re
from typing import List, Dict, Tuple
TIME_PATTERN = re.compile(r"^(\d{2}):([0-5]\d)$")
ALLOWED_TYPES = {"visual", "speech", "hybrid"}
def time_to_seconds(t_str: str) -> int:
match = TIME_PATTERN.match(t_str)
if not match:
raise ValueError(f"Некорректный формат времени: {t_str}")
m, s = map(int, match.groups())
return m * 60 + s
def parse_and_validate_tsv(
raw_text: str,
max_duration_sec: int = 3600
) -> Tuple[List[Dict[str, str]], List[Dict[str, str]]]:
valid_rows = []
malformed_rows = []
lines = [line.strip() for line in raw_text.strip().splitlines() if line.strip()]
for idx, line in enumerate(lines, start=1):
cols = [c.strip() for c in line.split("|")]
if len(cols) != 5:
malformed_rows.append({
"line": idx,
"content": line,
"error": f"Ожидалось 5 полей, получено {len(cols)}"
})
continue
start_str, end_str, event_type, claim, action = cols
if event_type.lower() not in ALLOWED_TYPES:
malformed_rows.append({
"line": idx,
"content": line,
"error": f"Недопустимый тип события: {event_type}"
})
continue
try:
s_sec = time_to_seconds(start_str)
e_sec = time_to_seconds(end_str)
except ValueError as err:
malformed_rows.append({
"line": idx,
"content": line,
"error": str(err)
})
continue
if s_sec > e_sec:
malformed_rows.append({
"line": idx,
"content": line,
"error": f"Время начала ({start_str}) больше времени окончания ({end_str})"
})
continue
if e_sec > max_duration_sec:
malformed_rows.append({
"line": idx,
"content": line,
"error": f"Таймкод {end_str} выходит за хронометраж ({max_duration_sec} сек)"
})
continue
valid_rows.append({
"start": start_str,
"end": end_str,
"start_sec": s_sec,
"end_sec": e_sec,
"type": event_type.lower(),
"claim": claim,
"action": action
})
return valid_rows, malformed_rows
def search_index(
rows: List[Dict[str, str]],
keyword: str = None,
event_type: str = None
) -> List[Dict[str, str]]:
results = []
for r in rows:
if event_type and r["type"] != event_type.lower():
continue
if keyword:
kw = keyword.lower()
if kw not in r["claim"].lower() and kw not in r["action"].lower():
continue
results.append(r)
return results
valid_index, errors = parse_and_validate_tsv(raw_index_output, max_duration_sec=3600)
if errors:
print(f"Обнаружено некорректных строк: {len(errors)}. Требуется ручная правка:")
for err in errors:
print(f"Строка {err['line']}: {err['error']} -> {err['content']}")
else:
print(f"Все строки валидны. Записей в индексе: {len(valid_index)}")
चरण 5. कवरेज ऑडिटिंग और गैप्स की पहचान करना
इंडेक्स प्रकाशित करने से पहले, ब्लाइंड स्पॉट्स के लिए टाइमलाइन का ऑडिट करें:
- बेंचमार्क ज़ोन की स्पॉट-जांच करें (Spot-check benchmark zones):
वीडियो की शुरुआत (परिचय और शीर्षक स्लाइड), मध्य बिंदु (जहां लाइव डेमो या आर्किटेक्चर पर चर्चा आमतौर पर चरम पर होती है), और निष्कर्ष (प्रश्नोत्तर और समापन नोट्स) की मैन्युअल रूप से जांच करें। - टाइमस्टैम्प अंतरालों का विश्लेषण करें (Analyze timestamp intervals):
इंडेक्स प्रविष्टियों के बीच स्वीकार्य अंतर के लिए कोई सार्वभौमिक सीमा (threshold) नहीं है; सहनशीलता उपयोग के मामले पर निर्भर करती है। किसी गहन स्क्रीनकास्ट में, 90 सेकंड के अंतर का मतलब एक छूटा हुआ कॉन्फ़िगरेशन चरण हो सकता है। एक परिचयात्मक व्याख्यान में, 5 मिनट तक चलने वाला एक एकल बिंदु पूरी तरह से उचित हो सकता है। यदि कोई अंतराल प्रस्तुति की गति के साथ असंगत दिखता है, तो उसे संदिग्ध के रूप में चिह्नित करें। - शांत विजुअल घटनाओं का निरीक्षण करें (Inspect silent visual events):
यदि किसी वक्ता ने बिना कुछ बोले स्क्रीन पर कुछ प्रदर्शित किया, तो हो सकता है कि एजेंटिक मोड उस सेगमेंट को नज़रअंदाज़ कर गया हो। ऐसे विंडोज़ को लक्षित स्टैटिक समीक्षा के लिए भेजें।
चरण 6. स्टैटिक क्लिप के ज़रिए संदिग्ध ज़ोन का लक्षित निरीक्षण
किसी संदिग्ध सेगमेंट का पुनर्मूल्यांकन करने के लिए पूरे 60 मिनट के वीडियो को दोबारा चलाने की आवश्यकता नहीं होती है। क्लिप स्लाइसिंग स्टैटिक-मोड विश्लेषण को सटीक सेकंड सीमाओं (start_offset और end_offset) तक सीमित करती है।
तरीके की सीमा (Method Limitation):
1 FPS पर स्टैटिक मोड एक निश्चित सैंपलिंग ग्रिड प्रदान करता है, जो व्यापक एजेंटिक पास के दौरान छूटी हुई कार्रवाइयों को उजागर करने में मदद करता है। हालांकि, यह पूर्ण सटीकता और रिकॉल (absolute recall) की गारंटी नहीं देता है: एक सेकंड से भी तेज़ होने वाले विजुअल बदलाव अभी भी सैंपल किए गए फ़्रेम्स के बीच छूट सकते हैं।
start_sec = 1200
end_sec = 1380
targeted_inspection = 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": start_sec,
"end_offset": end_sec,
"fps": 1.0
}
},
{
"type": "text",
"text": (
"Хронологически опиши изменения на экране. "
"Зафиксируй команды в терминале, смену окон и системные сообщения."
)
}
]
)
print("Результат точечного досмотра отрезка:")
print(targeted_inspection.output_text)
नई निकाली गई प्रविष्टियों को मैन्युअल रूप से या सेमी-ऑटोमेटेड समीक्षा चरण के माध्यम से सत्यापित इंडेक्स में एकीकृत करें।
एक बार जब आप errors की सभी प्रविष्टियों को हल कर लें और मूल रिकॉर्डिंग के आधार पर टाइमस्टैम्प्स को सत्यापित कर लें, तो अंतिम इंडेक्स निर्यात (export) करें। नीचे दिया गया कोड स्निपेट जानबूझकर रुक जाता है यदि पार्सर शेष त्रुटियों की रिपोर्ट करता है; इसे चलाने से पहले सुनिश्चित करें कि valid_index में आपके सत्यापित सुधार शामिल हैं।
if errors:
raise ValueError("Исправьте строки из errors и повторите проверку перед экспортом")
with open("video_index.csv", "w", newline="", encoding="utf-8") as output_file:
writer = csv.DictWriter(
output_file,
fieldnames=["start", "end", "type", "claim", "action"],
extrasaction="ignore",
)
writer.writeheader()
writer.writerows(valid_index)
परिणामी CSV उपयोगकर्ताओं को विशिष्ट दावों या स्क्रीन क्रियाओं को खोजने और मूल रिकॉर्डिंग में सीधे प्रासंगिक सेगमेंट पर जाने की अनुमति देता है। यह तब तक एक ड्राफ़्ट ही रहता है जब तक कि कोई मानव संपादक मूल रिकॉर्डिंग के आधार पर केवल सैंपलिंग सीमाओं की ही नहीं, बल्कि किन घटनाओं का चयन किया गया था और उनकी घटना सीमाओं दोनों की पुष्टि न कर दे।
समस्या निवारण और एज केसेस (Troubleshooting and Edge Cases)
- Files API अपलोड के दौरान
FAILEDस्थिति:
API डायग्नोस्टिक्स के बिना समस्या का निष्कर्ष निकालने से बचें। विफलताएं असमर्थित कंटेनर प्रारूपों, विकृत फ़ाइल हेडर या अस्थायी इंफ्रास्ट्रक्चर त्रुटियों से उत्पन्न हो सकती हैं। SDK के ज़रिएfile.errorविशेषता का निरीक्षण करें,ffprobeसे स्थानीय प्लेबैक की पुष्टि करें, यदि आवश्यक हो तोffmpeg(-c:v libx264 -c:a aac) के ज़रिए स्ट्रीम्स का मानकीकरण करें, और पुन: प्रयास करें। 401 Unauthorizedया नेटवर्क ड्रॉप:
401 त्रुटि स्पष्ट रूप से प्रमाणीकरण विफलता (एक अमान्य या गायब कुंजी, या एक अनकॉन्फ़िगर किया गयाGEMINI_API_KEYपर्यावरण चर) को इंगित करती है, न कि किसी समाप्त हो चुके प्रोसेसिंग सत्र को। लंबी कॉल्स के दौरान क्लाइंट HTTP कनेक्शन टाइमआउट से बचने के लिए,stream=Trueके ज़रिए स्ट्रीमिंग सक्षम करें।- कुल अवधि से अधिक होने वाले टाइमस्टैम्प:
जैसे-जैसे संदर्भ की जटिलता बढ़ती है, यह ड्रिफ्ट हो सकता है। अपने पार्सर में सख्त प्रॉम्प्ट निर्देशों और प्रोग्रामेटिक वैलिडेशन (e_sec > max_duration_sec) के साथ इसका मुकाबला करें। - TSV संरचनात्मक ड्रिफ्ट (TSV structural drift):
जब स्वरूपण टूट जाता है, तो खराब पंक्तियों कोmalformed_rowsमें भेजें और सिस्टम प्रॉम्प्ट में 1-2 फ़्यू-शॉट (few-shot) संदर्भ पंक्तियाँ प्रदान करें।
प्रकाशन-पूर्व सत्यापन कार्यप्रवाह (Pre-Publishing Verification Workflow)
- एसेट की तत्परता सत्यापित करें (Verify asset readiness): पुष्टि करें कि फ़ाइल Files API में
ACTIVEस्थिति तक पहुंच गई है। - प्रारंभिक ड्राफ़्ट तैयार करें (Generate initial draft): Interactions API के ज़रिए
agenticप्रोसेसिंग का उपयोग करके बेसलाइन इंडेक्स बनाएं। - प्रोग्रामेटिक वैलिडेशन निष्पादित करें (Execute programmatic validation): सुनिश्चित करें कि सभी पंक्तियों में पाँच आवश्यक फ़ील्ड, मान्य प्रकार और
MM:SSप्रारूप शामिल हैं। सुधार के लिए अमान्य पंक्तियों को अलग करें। - कवरेज का ऑडिट करें (Audit coverage): बेंचमार्क ज़ोन (शुरुआत, मध्य, अंत) का निरीक्षण करें और बातचीत की गति के विरुद्ध टाइमस्टैम्प घनत्व का मूल्यांकन करें।
- लक्षित निरीक्षण करें (Conduct targeted inspection): स्टैटिक क्लिप्स (
start_offset/end_offset) का उपयोग करके संदिग्ध अंतरालों या मूक स्क्रीन अनुभागों की पुन: जांच करें। - मैन्युअल स्पॉट कैलिब्रेशन करें (Perform manual spot calibration): उपयोग के मामले की आवश्यकतानुसार प्रासंगिक स्रोत ऑडियो/वीडियो के विरुद्ध प्रत्येक घटना के वास्तविक प्रारंभ समय की जांच करें; किसी मेल खाते विजुअल परिवर्तन की मांग न करें, क्योंकि केवल-ऑडियो घटना भी हो सकती है।
अनुरोध स्कीमा, प्रोसेसिंग मोड और सैंपलिंग सीमाओं के लिए, आधिकारिक Gemini Video Understanding डॉक्यूमेंटेशन देखें।