Как перевести генерацию видео с Veo 3.1 на Gemini Omni Flash: Interactions API, роли картинок и сравнение качества

Я генерирую видео для рекламы и коротких роликов через Gemini API. На Veo 3.1 у меня держалось три сценария: картинка в видео, переход между первым и последним кадром и клипы с героем по референсам. 22 октября 2026 Google отключает preview-версии Veo 3.1 в Gemini API (veo-3.1-generate-preview, veo-3.1-fast-generate-preview и veo-3.1-lite-generate-preview), рекомендованная замена — Gemini Omni Flash (gemini-omni-1.1-flash). У неё другой API, другая схема передачи картинок и нет параметра длительности, так что простой заменой имени модели не обойтись.
В статье разбираю, как устроен запрос к Omni, какие ошибки я поймал при переносе, где новая модель не хуже старой, где проигрывает и как посчитать цену клипа по ответу API.
Что поменялось в API
Veo жил на predictLongRunning: отправляешь задачу, получаешь операцию, опрашиваешь её, пока не будет готово. Omni работает через Interactions API: POST на /v1beta/interactions, и при background: false ответ приходит, когда видео готово. В моих четырёх тестах клип 4-6 секунд в 720p генерировался около 40 секунд. Синхронный вызов удобен для скрипта и демонстрации. Для прода в документации есть фоновый режим (background: true): ответ сразу возвращает id, а статус опрашивают по нему. Я его пока не использовал.
Картинки, текст и роли картинок передаются одним массивом input. Роль задаётся тегами прямо в начале промпта:
[# Sources <FIRST_FRAME>@Image1 <LAST_FRAME>@Image2] [# References <IMAGE_REF_0>@Image3]
Image1, Image2, Image3 — порядок картинок в массиве. Так в одном запросе можно задать первый кадр, последний кадр и референсы героя, что в Veo требовало разных режимов. В коде ниже одна картинка. Для перехода между кадрами добавь в input вторую картинку и тег <LAST_FRAME>@Image2. Для референсов героя — картинки следом и теги <IMAGE_REF_0>@Image2, <IMAGE_REF_1>@Image3.
Минимальный рабочий запрос на Python: картинка как первый кадр, видео приходит в ответе и сохраняется в файл:
import base64, json, urllib.request
KEY = "..." # ключ Gemini API
img = base64.b64encode(open("start.png", "rb").read()).decode()
body = {
"model": "gemini-omni-1.1-flash",
"input": [
{"type": "image", "data": img, "mime_type": "image/png"},
{"type": "text", "text": "[# Sources <FIRST_FRAME>@Image1] She lifts her cup and takes a sip. "
"A 4-second video. A single continuous shot, no scene cuts."},
],
"response_format": {"type": "video", "aspect_ratio": "9:16", "resolution": "720p"},
"background": False, "stream": False,
}
req = urllib.request.Request("https://generativelanguage.googleapis.com/v1beta/interactions",
data=json.dumps(body).encode(),
headers={"x-goog-api-key": KEY, "Content-Type": "application/json"})
res = json.load(urllib.request.urlopen(req, timeout=900))
video = next(c for s in res["steps"] if s["type"] == "model_output" for c in s["content"] if c["type"] == "video")
open("clip.mp4", "wb").write(base64.b64decode(video["data"]))
print(res.get("usage")) # токены: из них считается цена
Так работает, пока файл видео меньше 4 МБ. У меня клипы 4-6 секунд в 720p в это укладывались, но граница по размеру, а не по длине. Если файл может выйти больше, добавь в response_format поле "delivery": "uri": в ответе придёт ссылка, её надо опрашивать через Files API до состояния ACTIVE (или FAILED) и только потом скачивать.
Подводные камни, на которые я наступил
Нет параметра длительности. У Veo были durationSeconds 4, 6 или 8. У Omni длину задаёт промпт: «A 4-second video», модель выдаёт от 3 до 10 секунд. В моих тестах она попала в длину: 4,01, 5,01 и 6,01 секунды. Это не гарантия, поэтому после генерации проверяй фактическую длину файла.
delivery: "uri" требует хранения. Документация советует store: false ради скорости. Вместе с выдачей ссылкой получишь:
400: store=true is required when response format has video delivery set to URI.
Либо храни (по умолчанию так и есть), либо забирай видео в base64.
Модель любит склейки. Без подсказки Omni собирает ролик из нескольких планов: это прямо написано в руководстве по промптам. Для одного плана нужна фраза «A single continuous shot, no scene cuts». Я добавляю её автоматически, если не прошу склейки явно.
Английский — единственный проверенный язык. Google пишет, что английский поддерживается полностью, а остальные языки не оценивались. Русский промпт работает, но предсказуемость ниже, поэтому видео я запускаю на английском.
Переход между двумя кадрами: в моём тесте Omni хуже
Самый показательный тест — таймлапс ремонта. Просил плавный ремонт, получил демонтаж по щелчку. Два кадра одной комнаты: «до ремонта» и «демонтаж». Промпт одинаковый: неподвижная камера, комната плавно меняется от первого кадра к последнему.

В этом дубле Veo сделал честную интерполяцию: мусор появляется постепенно, рабочие мелькают размытыми силуэтами. Omni держит ракурс и окно, но посередине клипа комната перескакивает в почти пустое состояние, хотя в промпте было «без склеек». Дубль один на модель, так что это наблюдение, а не статистика. Для таймлапса это терпимо, он и так рубленый. Для плавных переходов между планами — нет. Где плавность важна, я переношу переход на другую модель с режимом первого и последнего кадра или делаю растворение в монтаже.
Картинка в видео: в моём тесте Omni не хуже
Оживление одного кадра с героиней: она берёт чашку, делает глоток, смотрит в окно.

Лицо героини держится до конца клипа, руки и чашка целые. Отдельно проверил клип с двумя героями: первый кадр плюс два фото-референса с тегами <IMAGE_REF_0> и <IMAGE_REF_1>. Лица не поменялись местами и не смешались. Расстановку людей модель слушает хуже: просил посадить героя напротив, он сел рядом.
Промпт этого клипа целиком, как он ушёл в API: тег первого кадра, сцена, длительность и запрет склеек. Даю обе версии: видео я генерировал на английской, русская - перевод для разбора.
На русском:
[# Sources <FIRST_FRAME>@Image1] Молодая рыжая женщина медленно поднимает чашку, делает маленький глоток, ставит её и смотрит в окно с лёгкой полуулыбкой. Медленный мягкий наезд. Естественный фон кафе: тихие голоса и звон чашек, без музыки и речи. Видео на 4 секунды. Один непрерывный план, без склеек.
In English:
[# Sources <FIRST_FRAME>@Image1] The young red-haired woman slowly lifts her cup, takes a small sip, puts it down and looks out of the window with a soft half-smile. Slow gentle push-in. Natural cafe ambience, quiet chatter and cups clinking, no music, no speech. A 4-second video. A single continuous shot, no scene cuts.
Сколько стоит
Omni тарифицируется по токенам: $17,50 за миллион токенов видео на выходе, $9 за миллион текстовых токенов на выходе (включая размышления модели) и $1,50 за миллион на входе. Секунда видео 720p - 5792 токена, то есть около $0,10 за секунду. Столько же стоил Veo 3.1 Fast.
Клип | Длина | Цена по счёту |
|---|---|---|
Переход между двумя кадрами | 4 с | $0,43 |
Картинка в видео | 4 с | $0,42 |
Эмоция героини, первый кадр | 5 с | $0,52 |
Двое в кадре, первый кадр и два референса | 6 с | $0,63 |
Разница с «чистыми» $0,10 за секунду складывается из входа (картинки и промпт) и размышлений модели: в моих запросах она тратила около 1700 текстовых токенов, это примерно цент. Цены на 8 октября 2026, тариф Gemini API без налогов.
Стоимость считаю по полю usage в ответе: каждый вид токенов по своей ставке, вход по $1,50, видео по $17,50, текст и размышления по $9, всё за миллион. Полезно писать это в лог каждой генерации: через месяц видно, какие сцены съедают бюджет.
Итог
Переезд занял день и одну переписку скрипта. Перед тем как выключать Veo, прогони по три дубля каждого из трёх сценариев: картинка в видео, первый и последний кадр, первый кадр плюс два референса. Для каждого смотри статус ответа, фактическую длину, нет ли склеек, совпадают ли крайние кадры и лица, и цену из usage.
У меня картинка в видео и клипы с референсами на Omni прошли не хуже Veo, а переход между двумя кадрами — хуже, для него держу запасной вариант: другую модель с режимом первого и последнего кадра или растворение в монтаже.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.