Практикум: Создание мультимодального аналитика контента
Практикум: Создание мультимодального аналитика контента
Добро пожаловать в практическую часть модуля. До этого момента мы обсуждали теорию мультимодальности, контекстные окна и работу с токенами. Теперь пришло время испачкать руки в коде и собрать что-то действительно полезное.
В этом уроке мы создадим Мультимодального Аналитика — инструмент, способный принимать на вход видео, аудио, изображения и текст, а затем выдавать структурированный глубокий анализ происходящего. Это не просто «описание картинки». Мы научим модель связывать визуальный ряд с аудиодорожкой, выявлять сарказм, анализировать маркетинговые метрики и возвращать результат в формате, готовом для сохранения в базу данных.
Что мы будем строить?
Мы спроектируем класс ContentAnalyst, который решает следующие задачи:
- Прием разнородных данных: Загрузка файлов через Gemini File API.
- Синхронизация контекста: Понимание того, как аудио соотносится с видеорядом.
- Структурированный вывод: Мы заставим модель возвращать чистый JSON, а не свободный текст, что критично для автоматизации.
- Масштабируемость: Подготовка архитектуры к обработке больших объемов контента.
Готовы? Давайте настроим наше окружение.
import os
import time
import json
import typing_extensions as typing
import google.generativeai as genai
from google.api_core import retry
# Настройка API ключа (предполагается, что он в переменных окружения)
# В реальном проекте используйте безопасное хранение секретов
genai.configure(api_key=os.environ["GOOGLE_API_KEY"])
# Выбор модели. Для мультимодальных задач с видео лучше всего подходит
# версия Pro из-за большого контекстного окна и лучшего 'зрения'.
MODEL_NAME = "gemini-1.5-pro-latest"
print(f"Окружение настроено. Используем модель: {MODEL_NAME}")
Архитектура работы с файлами
Одна из самых частых ошибок новичков при работе с мультимодальными моделями Gemini — попытка передать видео или большие аудиофайлы напрямую в запрос (inline data). Это работает для маленьких картинок, но для серьезного контента мы обязаны использовать File API.
Почему это важно?
- Экономия ресурсов клиента: Вам не нужно кодировать гигабайты видео в base64 и отправлять их в теле HTTP-запроса.
- Кэширование и обработка: Google обрабатывает файл на своей стороне (токенизирует видео, разбивая на кадры), после чего файл становится доступен для модели как ссылка (URI).
- Состояние файла: Видео требует времени на обработку. Нельзя отправить файл и сразу спросить «что там?». Нужно дождаться статуса
ACTIVE.
Давайте напишем вспомогательный класс для управления загрузкой медиа.
class MediaManager:
"""
Отвечает за загрузку файлов в Gemini File API и контроль их готовности.
"""
@staticmethod
def upload_file(path: str, mime_type: str = None):
"""
Загружает файл и ждет завершения его обработки на серверах Google.
"""
print(f"Начинаю загрузку файла: {path}...")
file_ref = genai.upload_file(path, mime_type=mime_type)
print(f"Файл загружен: {file_ref.display_name} ({file_ref.uri})")
# Проверка состояния. Видео и аудио требуют времени на процессинг.
while file_ref.state.name == "PROCESSING":
print("Файл обрабатывается... ждем 2 секунды.")
time.sleep(2)
file_ref = genai.get_file(file_ref.name)
if file_ref.state.name == "FAILED":
raise ValueError(f"Ошибка обработки файла: {file_ref.state.name}")
print(f"Файл готов к использованию: {file_ref.state.name}")
return file_ref
@staticmethod
def list_active_files():
"""Утилита для просмотра загруженных файлов"""
print("Активные файлы в хранилище:")
for f in genai.list_files():
print(f"- {f.display_name} ({f.mime_type})")
Проектирование схемы данных (JSON Schema)
Наш аналитик не должен просто болтать. Мы хотим получить конкретные метрики. Допустим, мы анализируем рекламный ролик. Нам нужно знать:
- Краткое содержание (Summary): О чем видео?
- Настроение (Sentiment): Позитивное, негативное или нейтральное?
- Ключевые объекты: Что показано в кадре?
- Оценка безопасности: Есть ли нарушения контент-политики?
В Gemini мы можем использовать параметр response_schema (или response_mime_type="application/json"), чтобы гарантировать формат вывода. Это критически важно для интеграции в продакшн-пайплайны.
Определим структуру ответа, используя типизацию Python. Это делает код чистым и понятным для IDE.
# Определение структуры выходных данных
class VideoAnalysis(typing.TypedDict):
title: str
summary: str
sentiment_score: float # От 0.0 до 1.0
key_visual_elements: list[str]
audio_transcript_snippet: str
marketing_potential: str
safety_flags: list[str]
# Это мы передадим в конфигурацию модели
analysis_schema = {
"response_mime_type": "application/json",
"response_schema": VideoAnalysis
}
Сборка класса ContentAnalyst
Теперь соберем все воедино. Наш класс будет инициализировать модель с системными инструкциями. Системная инструкция (System Instruction) — это «личность» модели. Для аналитика она должна быть объективной, внимательной к деталям и строгой.
Обратите внимание на то, как мы формируем промпт. Мы не просто даем файл, мы даем задачу. Мультимодальные модели работают лучше всего, когда вы явно просите их соотнести разные модальности: «Посмотри на выражение лица человека, когда он говорит эти слова».
class ContentAnalyst:
def __init__(self, model_name: str = "gemini-1.5-pro-latest"):
self.model = genai.GenerativeModel(
model_name=model_name,
generation_config=analysis_schema,
system_instruction=(
"Ты — экспертный аналитик медиа-контента. Твоя задача — "
"глубоко анализировать предоставленные видео, аудио или изображения. "
"Ты обращаешь внимание на мелкие детали, тон голоса, визуальный контекст "
"и скрытые смыслы. Твой вывод всегда строго структурирован."
)
)
self.media_manager = MediaManager()
def analyze_video(self, video_path: str, specific_focus: str = None) -> dict:
"""
Полный цикл анализа видео: загрузка -> генерация -> парсинг.
"""
# 1. Загрузка
try:
video_file = self.media_manager.upload_file(video_path, mime_type="video/mp4")
except Exception as e:
return {"error": f"Не удалось загрузить файл: {str(e)}"}
# 2. Формирование промпта
base_prompt = (
"Проанализируй это видео. Сопоставь визуальный ряд с аудиодорожкой. "
"Выдели ключевые моменты."
)
if specific_focus:
base_prompt += f" Особое внимание удели следующему аспекту: {specific_focus}"
# 3. Генерация
# Передаем список: [файл, текст промпта]
try:
response = self.model.generate_content([video_file, base_prompt])
# 4. Обработка результата (парсинг JSON)
# Благодаря response_schema, response.text уже будет валидным JSON
result_json = json.loads(response.text)
return result_json
except Exception as e:
return {"error": f"Ошибка генерации: {str(e)}"}
finally:
# Хорошая практика: удалять файлы после анализа, если они не нужны для кэша
# genai.delete_file(video_file.name)
pass
Глубокое погружение: Проблема галлюцинаций в видео
Даже самые мощные модели, такие как Gemini 1.5 Pro, могут галлюцинировать при работе с видео, особенно если видео длинное или низкого качества. Модель не «смотрит» видео как человек (24 кадра в секунду). Она сэмплирует кадры (обычно 1 кадр в секунду) и анализирует их последовательность.
Как повысить точность?
- Явные таймкоды: Попросите модель указывать таймкоды для каждого утверждения. Например: «На 00:15 пользователь улыбается». Это заставляет модель «заземлять» (ground) свои ответы на конкретные фреймы.
- Специфичность запроса: Вместо «Опиши видео» спросите «Опиши последовательность действий главного героя в красной рубашке».
- Аудио как якорь: Часто аудио содержит больше информации, чем видео. Попросите модель использовать транскрипцию (которую она делает внутри себя) для подтверждения визуальных догадок.
Доработайте класс ContentAnalyst. Добавьте метод `analyze_comparison`, который принимает ДВА изображения (например, слайд презентации 'До' и 'После') и возвращает анализ изменений. Схема ответа должна содержать поля: `changes_detected` (список), `improvement_score` (int 1-10) и `verdict` (str).
Заключение
Мы создали основу для мощного инструмента. Этот ContentAnalyst может быть развернут как микросервис, который мониторит папку с входящими медиафайлами и складывает отчеты в базу данных.
Ключевые выводы урока:
- Всегда используйте
File APIдля видео и больших аудиофайлов. - Ждите статуса
ACTIVEперед генерацией. - Используйте JSON Schema для получения предсказуемого, машиночитаемого результата.
- Мультимодальность требует четких инструкций по связыванию аудио и видео контекста.
В следующем модуле мы пойдем дальше и научим нашего аналитика не просто наблюдать, но и использовать внешние инструменты (Function Calling) для проверки фактов из видео в интернете.
Почему при работе с видео через Gemini API необходимо проверять состояние файла (file_ref.state) после загрузки?