Практикум: Создание мультимодального аналитика контента

40 минут Урок 10

Практикум: Создание мультимодального аналитика контента

Добро пожаловать в практическую часть модуля. До этого момента мы обсуждали теорию мультимодальности, контекстные окна и работу с токенами. Теперь пришло время испачкать руки в коде и собрать что-то действительно полезное.

В этом уроке мы создадим Мультимодального Аналитика — инструмент, способный принимать на вход видео, аудио, изображения и текст, а затем выдавать структурированный глубокий анализ происходящего. Это не просто «описание картинки». Мы научим модель связывать визуальный ряд с аудиодорожкой, выявлять сарказм, анализировать маркетинговые метрики и возвращать результат в формате, готовом для сохранения в базу данных.

Что мы будем строить?

Мы спроектируем класс ContentAnalyst, который решает следующие задачи:

  1. Прием разнородных данных: Загрузка файлов через Gemini File API.
  2. Синхронизация контекста: Понимание того, как аудио соотносится с видеорядом.
  3. Структурированный вывод: Мы заставим модель возвращать чистый JSON, а не свободный текст, что критично для автоматизации.
  4. Масштабируемость: Подготовка архитектуры к обработке больших объемов контента.

Готовы? Давайте настроим наше окружение.

python
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.

Давайте напишем вспомогательный класс для управления загрузкой медиа.

python
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.

python
# Определение структуры выходных данных
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) — это «личность» модели. Для аналитика она должна быть объективной, внимательной к деталям и строгой.

Обратите внимание на то, как мы формируем промпт. Мы не просто даем файл, мы даем задачу. Мультимодальные модели работают лучше всего, когда вы явно просите их соотнести разные модальности: «Посмотри на выражение лица человека, когда он говорит эти слова».

python
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) после загрузки?