Convide e ganhe

Como funcionam as recompensas

Compartilhe seu link. Quando um amigo se cadastrar por ele e adicionar saldo, você receberá a recompensa exibida nas recargas posteriores.

Indexando Vídeos Longos com a API Gemini: Timestamps, Recursos Visuais e Auditoria de Lacunas

Um fluxo de trabalho de engenharia para indexar gravações de vídeo longas com a API Gemini: upload pela Files API, geração de rascunhos agênticos na Interactions API, validação programática de linhas estruturadas e inspeção direcionada de lacunas de cobertura.

Conteúdo
Indexando Vídeos Longos com a API Gemini: Timestamps, Recursos Visuais e Auditoria de Lacunas

Gravações de vídeo longas — como palestras técnicas, workshops, chamadas de revisão de arquitetura e screencasts — concentram uma densidade alta de informações distribuídas entre o áudio da fala e os elementos visuais na tela. Resumos convencionais de alto nível capturam somente temas gerais, forçando os engenheiros a avançar e retroceder manualmente pela gravação sempre que precisam encontrar um comando específico de terminal ou um parâmetro de configuração.

Os modelos multimodais Gemini conseguem analisar fluxos de áudio e vídeo de forma simultânea, gerando índices estruturados de eventos com timestamps. Contudo, o resultado bruto da inferência inicial do modelo representa apenas um conjunto preliminar de candidatos, e não um índice de referência pronto para produção. Construir um índice confiável exige um pipeline rigoroso: upload único via Files API e reutilização de URI, extração de intervalos preliminares, validação estrita do esquema de saída, auditoria de lacunas suspeitas de cobertura e calibração direcionada.


Arquitetura: Métodos de Entrega e Modos de Processamento

Na documentação atual do Google Video Understanding, as implementações principais giram em torno da Interactions API e da biblioteca google-genai. Embora o método clássico generate_content permaneça suportado para compatibilidade retroativa, a Interactions API oferece um controle mais claro sobre os parâmetros de processamento multimodal.

1. Métodos de Entrega de Vídeo

  • Files API (Recomendada para vídeos longos): Mais indicada para gravações com duração de vários minutos a várias horas. O arquivo é enviado uma única vez, indexado no servidor e referenciado por URI em requisições consecutivas sem o reenvio de bytes brutos.
  • Google Cloud Storage (GCS): Ideal para acervos de vídeo que já residem na infraestrutura do Google Cloud.
  • Dados Embutidos (Inline Data): Transmissão direta dos bytes brutos no payload da requisição. A documentação aponta restrições de payload variadas conforme o ambiente; para uma manipulação estável de gravações de uma hora ou mais, convém apoiar-se na Files API ou no Cloud Storage, evitando a transmissão do fluxo de vídeo inline.

2. Modos de Processamento: Estático vs. Agêntico

  • Processamento Estático (Static Processing):
    Por padrão, o modelo realiza uma amostragem discreta de quadros a uma taxa de 1 quadro por segundo (1 FPS). Cada segundo se converte em tokens, acumulando uma carga substancial de contexto ao longo de 60 minutos de gravação. Tenha em mente: a amostragem a 1 FPS pode perder eventos visuais rápidos (como alternâncias de janelas em frações de segundo ou tooltips passageiros) e não garante a captura de cada microinteração.
  • Compreensão de Vídeo Agêntica (Agentic Video Understanding):
    O modelo navega pelo vídeo de forma dinâmica, recuperando quadros específicos e trechos da faixa de áudio sob demanda. Isso reduz consideravelmente o volume de tokens de contexto processados.
    Limitação: A heurística agêntica apoia-se em pistas de áudio e gatilhos semânticos. Se o apresentador executar ações silenciosamente na tela (como digitar um comando ou analisar um diagrama) sem falar nada, a heurística pode tratar esse intervalo como ocioso em segundo plano e deixar de solicitar quadros visuais detalhados.

Passo 1. Upload do Vídeo e Consulta de Status

Arquivos enviados para a Files API não ficam disponíveis para inferência imediatamente; o servidor precisa descompactar o contêiner e indexar as faixas de áudio e vídeo. Sua aplicação precisa consultar o recurso periodicamente (polling) até que o estado se torne 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("Видео готово к обработке.")

Passo 2. Solicitação de um Rascunho de Índice via Interactions API

Para gravações extensas, acione client.interactions.create especificando "processing": "agentic". O prompt estabelece uma saída tabular estrita: intervalo de timestamps MM:SS - MM:SS, tipo de evento (visual, speech, hybrid), uma declaração concisa da fala (CLAIM) e a ação executada na tela (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

Sobre as Etapas de Navegação Agêntica:
A presença de entradas processing_call dentro de interaction.steps confirma que o modelo navegou dinamicamente pela linha do tempo do vídeo em vez de ingerir um fluxo contínuo. No entanto, observar essas chamadas atesta apenas a ocorrência da navegação — não garante a completude da saída em relação a todos os eventos relevantes da cronologia.


Passo 3. Exemplo de Estrutura de Saída (Rascunho Hipotético)

Veja a seguir um trecho hipotético ilustrativo da saída do modelo demonstrando o esquema de dados esperado:

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-кода на экране, завершение созвона

Passo 4. Validação da Marcação e Busca Local

Respostas brutas de LLMs não devem ser tratadas como conjuntos estruturados confiáveis sem validação. Um analisador resiliente não deve descartar registros corrompidos de forma silenciosa; em vez disso, deve isolá-los para correção manual. O validador confere: presença exata de cinco campos, tipos de eventos permitidos (visual, speech, hybrid) e timestamps MM:SS válidos e contidos na duração total do vídeo.

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)}")

Passo 5. Auditoria de Cobertura e Identificação de Lacunas

Antes de publicar o índice, inspecione a linha do tempo em busca de pontos cegos:

  1. Faça inspeções por amostragem em zonas de referência:
    Verifique manualmente o início do vídeo (introdução e slides iniciais), o ponto intermediário (onde demonstrações ao vivo ou debates de arquitetura atingem o pico) e a conclusão (sessão de perguntas e respostas e encerramento).
  2. Analise os intervalos de timestamps:
    Não há um limite universal para o espaçamento ideal entre entradas do índice; a tolerância varia com o caso de uso. Em um screencast detalhado, uma lacuna de 90 segundos pode significar uma etapa de configuração omitida. Em uma exposição teórica panorâmica, uma única tese estendendo-se por 5 minutos pode ser inteiramente aceitável. Caso um intervalo pareça desalinhado ao ritmo da apresentação, marque-o como suspeito.
  3. Inspecione eventos visuais silenciosos:
    Se o apresentador realizou demonstrações na tela sem acompanhamento em voz alta, o modo agêntico pode ter ignorado o trecho. Direcione essas janelas para revisão estática pontual.

Passo 6. Inspeção Direcionada de Zonas Suspeitas com Clipe Estático

Reavaliar um segmento suspeito não requer reprocessar a íntegra dos 60 minutos de vídeo. O recorte de clipes delimita a análise no modo estático a pontos exatos em segundos (start_offset e end_offset).

Limitação do Método:
O modo estático a 1 FPS disponibiliza uma grade regular de amostragem, facilitando o resgate de ações negligenciadas durante a análise agêntica ampla. No entanto, ele não garante recuperação absoluta (recall): variações visuais que ocorram mais rápido do que um segundo ainda podem passar despercebidas entre os quadros capturados.

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)

Incorpore as novas entradas resgatadas ao índice validado manualmente ou por meio de uma etapa de revisão semiautomatizada.

Após corrigir todas as ocorrências em errors e verificar os timestamps correspondentes na gravação original, exporte o índice final. O trecho de código abaixo aborta propositalmente caso o validador ainda aponte inconsistências; certifique-se de que valid_index contenha os dados verificados e corrigidos antes da execução.

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)

O arquivo CSV resultante possibilita aos usuários buscar por afirmações ou ações de tela específicas e saltar diretamente para os momentos correspondentes na gravação original. O arquivo permanece como rascunho até que um editor humano confirme tanto quais eventos foram selecionados quanto seus limites de eventos, e não meramente limites de amostragem.


Diagnóstico de Problemas e Casos de Borda

  • Status FAILED durante o upload na Files API:
    Evite presumir o motivo da falha sem checar os diagnósticos da API. Erros podem decorrer de contêineres não suportados, cabeçalhos corrompidos ou instabilidades temporárias de infraestrutura. Inspecione o atributo file.error via SDK, teste a reprodução local do arquivo com ffprobe, padronize os fluxos com ffmpeg (-c:v libx264 -c:a aac) se indispensável e refaça o envio.
  • Erro 401 Unauthorized ou quedas de rede:
    O código 401 aponta expressamente para falha de autenticação (chave inválida ou ausente, ou problemas na variável de ambiente GEMINI_API_KEY), e não para término da sessão de processamento. Para evitar timeouts nas conexões HTTP do cliente durante requisições demoradas, habilite o streaming com stream=True.
  • Timestamps que ultrapassam a duração total do vídeo:
    Esse desvio pode se manifestar conforme a complexidade do contexto se eleva. Neutralize o comportamento com regras firmes no prompt e validação programática (e_sec > max_duration_sec) no analisador.
  • Desvio estrutural no formato TSV:
    Se a formatação quebrar, encaminhe as linhas defeituosas para malformed_rows e inclua de 1 a 2 linhas de referência (few-shot) nas diretrizes de sistema do prompt.

Fluxo de Trabalho de Verificação Pré-Publicação

  1. Confirmar prontidão do arquivo: Certifique-se de que o recurso alcançou o status ACTIVE na Files API.
  2. Gerar rascunho inicial: Obtenha o índice base configurando o processamento agentic na Interactions API.
  3. Executar validação programática: Verifique se todas as linhas possuem os cinco campos mandatórios, tipos aceitos e a formatação MM:SS. Isole registros inválidos para tratamento.
  4. Auditar cobertura: Inspecione as zonas de referência (começo, meio e fim) e contraste a frequência dos timestamps com a dinâmica da fala.
  5. Realizar inspeção direcionada: Reavalie intervalos suspeitos ou trechos silenciosos com clipes estáticos (start_offset/end_offset).
  6. Executar calibração manual por amostragem: Verifique o horário de início real de cada evento em relação ao áudio/vídeo de origem relevante conforme o caso de uso exigir; não exija uma alteração visual correspondente, já que pode ocorrer um evento apenas de áudio.

Para detalhes sobre esquemas de requisição, modos de processamento e restrições de amostragem, consulte a documentação oficial do Gemini Video Understanding.

Quer otimizar seu fluxo de trabalho com LLMs?

Conecte modelos por uma única API, gerencie chaves e controle os gastos com IA.

Começar grátis