curl --request POST \
--url https://api.apimart.ai/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "gemini-omni-1.2-flash",
"prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 15
}'
import time
import requests
base_url = "https://api.apimart.ai"
headers = {"Authorization": "Bearer <token>"}
payload = {
"model": "gemini-omni-1.2-flash",
"prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 15,
}
response = requests.post(
f"{base_url}/v1/videos/generations",
headers=headers, json=payload, timeout=30,
)
response.raise_for_status()
task_id = response.json()["data"][0]["task_id"]
print(task_id)
deadline = time.monotonic() + 600
while time.monotonic() < deadline:
response = requests.get(
f"{base_url}/v1/tasks/{task_id}", headers=headers, timeout=30,
)
response.raise_for_status()
task = response.json()["data"]
if task["status"] == "completed":
print(task["result"]["videos"][0]["url"][0])
break
if task["status"] == "failed":
raise RuntimeError(task["error"]["message"])
time.sleep(5)
else:
raise TimeoutError(f"Continue polling task {task_id}")
const baseUrl = "https://api.apimart.ai";
const headers = {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
};
const response = await fetch(`${baseUrl}/v1/videos/generations`, {
method: "POST",
headers,
signal: AbortSignal.timeout(30_000),
body: JSON.stringify({
model: "gemini-omni-1.2-flash",
prompt: "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
aspect_ratio: "16:9",
resolution: "720p",
duration: 15,
}),
});
if (!response.ok) throw new Error(await response.text());
const taskId = (await response.json()).data[0].task_id;
console.log(taskId);
async function waitForTask(taskId) {
const deadline = Date.now() + 600_000;
while (Date.now() < deadline) {
const response = await fetch(`${baseUrl}/v1/tasks/${taskId}`, {
headers,
signal: AbortSignal.timeout(30_000),
});
if (!response.ok) throw new Error(await response.text());
const task = (await response.json()).data;
if (task.status === "completed") return task.result.videos[0].url[0];
if (task.status === "failed") throw new Error(task.error.message);
await new Promise(resolve => setTimeout(resolve, 5000));
}
throw new Error(`Continue polling task ${taskId}`);
}
console.log(await waitForTask(taskId));
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01EXAMPLE"
}
]
}
Gemini Omni 1.2 Flash
Генерация видео Gemini Omni 1.2 Flash
Видео по тексту и изображениям, референсы нескольких объектов, интерполяция первого и последнего кадров, редактирование и продолжение. До 4K, 24fps, со звуком.
POST
/
v1
/
videos
/
generations
curl --request POST \
--url https://api.apimart.ai/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "gemini-omni-1.2-flash",
"prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 15
}'
import time
import requests
base_url = "https://api.apimart.ai"
headers = {"Authorization": "Bearer <token>"}
payload = {
"model": "gemini-omni-1.2-flash",
"prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 15,
}
response = requests.post(
f"{base_url}/v1/videos/generations",
headers=headers, json=payload, timeout=30,
)
response.raise_for_status()
task_id = response.json()["data"][0]["task_id"]
print(task_id)
deadline = time.monotonic() + 600
while time.monotonic() < deadline:
response = requests.get(
f"{base_url}/v1/tasks/{task_id}", headers=headers, timeout=30,
)
response.raise_for_status()
task = response.json()["data"]
if task["status"] == "completed":
print(task["result"]["videos"][0]["url"][0])
break
if task["status"] == "failed":
raise RuntimeError(task["error"]["message"])
time.sleep(5)
else:
raise TimeoutError(f"Continue polling task {task_id}")
const baseUrl = "https://api.apimart.ai";
const headers = {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
};
const response = await fetch(`${baseUrl}/v1/videos/generations`, {
method: "POST",
headers,
signal: AbortSignal.timeout(30_000),
body: JSON.stringify({
model: "gemini-omni-1.2-flash",
prompt: "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
aspect_ratio: "16:9",
resolution: "720p",
duration: 15,
}),
});
if (!response.ok) throw new Error(await response.text());
const taskId = (await response.json()).data[0].task_id;
console.log(taskId);
async function waitForTask(taskId) {
const deadline = Date.now() + 600_000;
while (Date.now() < deadline) {
const response = await fetch(`${baseUrl}/v1/tasks/${taskId}`, {
headers,
signal: AbortSignal.timeout(30_000),
});
if (!response.ok) throw new Error(await response.text());
const task = (await response.json()).data;
if (task.status === "completed") return task.result.videos[0].url[0];
if (task.status === "failed") throw new Error(task.error.message);
await new Promise(resolve => setTimeout(resolve, 5000));
}
throw new Error(`Continue polling task ${taskId}`);
}
console.log(await waitForTask(taskId));
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01EXAMPLE"
}
]
}
Генерация по тексту и изображениям поддерживает целое число секунд от 3 до 15, по умолчанию 10. Интерполяция первого и последнего кадров и добавляемая часть продолжения ограничены 10 секундами. При редактировании
duration игнорируется, а длительность исходного видео сохраняется. Входное видео по умолчанию редактируется; для продолжения требуется "omni_reference_task_type": "extend".curl --request POST \
--url https://api.apimart.ai/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "gemini-omni-1.2-flash",
"prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 15
}'
import time
import requests
base_url = "https://api.apimart.ai"
headers = {"Authorization": "Bearer <token>"}
payload = {
"model": "gemini-omni-1.2-flash",
"prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 15,
}
response = requests.post(
f"{base_url}/v1/videos/generations",
headers=headers, json=payload, timeout=30,
)
response.raise_for_status()
task_id = response.json()["data"][0]["task_id"]
print(task_id)
deadline = time.monotonic() + 600
while time.monotonic() < deadline:
response = requests.get(
f"{base_url}/v1/tasks/{task_id}", headers=headers, timeout=30,
)
response.raise_for_status()
task = response.json()["data"]
if task["status"] == "completed":
print(task["result"]["videos"][0]["url"][0])
break
if task["status"] == "failed":
raise RuntimeError(task["error"]["message"])
time.sleep(5)
else:
raise TimeoutError(f"Continue polling task {task_id}")
const baseUrl = "https://api.apimart.ai";
const headers = {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
};
const response = await fetch(`${baseUrl}/v1/videos/generations`, {
method: "POST",
headers,
signal: AbortSignal.timeout(30_000),
body: JSON.stringify({
model: "gemini-omni-1.2-flash",
prompt: "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
aspect_ratio: "16:9",
resolution: "720p",
duration: 15,
}),
});
if (!response.ok) throw new Error(await response.text());
const taskId = (await response.json()).data[0].task_id;
console.log(taskId);
async function waitForTask(taskId) {
const deadline = Date.now() + 600_000;
while (Date.now() < deadline) {
const response = await fetch(`${baseUrl}/v1/tasks/${taskId}`, {
headers,
signal: AbortSignal.timeout(30_000),
});
if (!response.ok) throw new Error(await response.text());
const task = (await response.json()).data;
if (task.status === "completed") return task.result.videos[0].url[0];
if (task.status === "failed") throw new Error(task.error.message);
await new Promise(resolve => setTimeout(resolve, 5000));
}
throw new Error(`Continue polling task ${taskId}`);
}
console.log(await waitForTask(taskId));
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01EXAMPLE"
}
]
}
Аутентификация
string
обязательно
Используйте Bearer Token. Получите ключ на странице управления API Key. Отправляйте запросы с
Content-Type: application/json.Параметры запроса
string
обязательно
Укажите
gemini-omni-1.2-flash.string
обязательно
Обязательные текстовые инструкции: описание сцены для генерации по тексту либо движения, стиля и изменений для остальных режимов.
prompt обязателен даже при передаче референсов, первого/последнего кадра, видео или extend_from_task_id. Без него возвращается HTTP 400.integer
по умолчанию:"10"
Длительность видео, создаваемого по тексту или изображениям: целое число от
3 до 15, по умолчанию 10. Для интерполяции первого/последнего кадров и продолжения допустимы только 3–10 секунд. При продолжении это длина добавляемого фрагмента; результат включает исходное видео и добавленную часть. При редактировании duration игнорируется, а длительность исходного видео сохраняется. Значения параметра вне допустимого диапазона приводят к ошибке задачи invalid_duration.string
по умолчанию:"720p"
360p / 720p / 1080p / 4k, без учёта регистра. 2160p соответствует 4k. 1080p и 4k получаются повышением разрешения. Разрешение влияет на выходные токены и резервируемую сумму. Другие значения приводят к ошибке задачи invalid_resolution.string
по умолчанию:"16:9"
Только
16:9 (горизонтальное, по умолчанию) и 9:16 (вертикальное). Другие значения обрабатываются как 16:9.string[]
Массив референсов: только общедоступные прямые HTTP(S)-ссылки на изображения. Data URL и Base64 не поддерживаются. Одно изображение служит начальным кадром, несколько — референсами объектов. Всего до 10 изображений, включая первый и последний кадры. Для персонажей рекомендуется не более 2 персонажей и до 3 изображений каждого, суммарно не более 6.
string
Первый кадр. Самостоятельно задаёт начальное изображение, а вместе с
last_frame_image включает интерполяцию между кадрами. Поддерживаются только общедоступные прямые HTTP(S)-ссылки на изображения.string
Последний кадр. Требует
first_frame_image, иначе задача завершается с invalid_frame_images. Соотношение сторон обоих изображений должно совпадать с aspect_ratio. Поддерживаются только общедоступные прямые HTTP(S)-ссылки на изображения.object[]
Массив изображений с ролями — альтернатива прямым полям первого/последнего кадров. Выберите один способ указания. Все используемые изображения входят в общий лимит 10.
string[]
Видео для редактирования или продолжения: максимум 1 ролик длительностью до 15 секунд. Поддерживаются только общедоступные прямые HTTP(S)-ссылки на видео. Data URL и Base64 не поддерживаются. По умолчанию выполняется редактирование.
string
по умолчанию:"auto"
Тип задачи:
auto (по умолчанию, определяется по входным данным) / edit (редактирование) / extend (продолжение) / reference (несколько изображений-референсов). Также принимаются text_to_video / image_to_video / reference_to_video. Если параметр не задан или равен auto, video_urls и extend_from_task_id по умолчанию запускают редактирование. Для продолжения явно укажите extend.string
ID вашей предыдущей задачи генерации для повторного использования видео без загрузки. По умолчанию видео редактируется. С
"omni_reference_task_type": "extend" в конец добавляется фрагмент длиной до 10 секунд.Возможности и ограничения
- Выходное видео имеет 24fps и содержит речь, музыку или звуковые эффекты. Нужный звук можно описать в
prompt. - Аудиовход, системные промпты,
temperatureи параметры негативного промпта не поддерживаются. Исключения указывайте прямо вprompt. - Региональные ограничения поставщика: в ЕЭЗ, Швейцарии и Великобритании не поддерживаются редактирование и продолжение загруженных видео, а также редактирование изображений с несовершеннолетними.
- Все результаты содержат невидимый водяной знак SynthID.
Примеры
Отправляйте каждый JSON вPOST /v1/videos/generations. Замените ссылки и ID задач из примеров своими доступными материалами.
Вертикальное видео 4K на 15 секунд
{
"model": "gemini-omni-1.2-flash",
"prompt": "Aerial shot over a misty mountain lake at sunrise, birds flying, slow forward camera move.",
"aspect_ratio": "9:16",
"resolution": "4k",
"duration": 15
}
Генерация по изображениям и референсы объектов
{
"model": "gemini-omni-1.2-flash",
"prompt": "The cat playfully bats at the ball of yarn.",
"image_urls": [
"https://example.com/cat.png",
"https://example.com/yarn.png"
],
"duration": 12
}
Интерполяция первого и последнего кадров
{
"model": "gemini-omni-1.2-flash",
"prompt": "Smooth transition, camera slowly pushes in.",
"first_frame_image": "https://example.com/start.jpg",
"last_frame_image": "https://example.com/end.jpg",
"aspect_ratio": "16:9",
"duration": 8
}
Указание кадров через роли
{
"model": "gemini-omni-1.2-flash",
"prompt": "A smooth cinematic transition from sunrise to a starry night.",
"image_with_roles": [
{
"url": "https://example.com/sunrise.jpg",
"role": "first_frame"
},
{
"url": "https://example.com/night.jpg",
"role": "last_frame"
}
],
"duration": 8
}
Редактирование видео
{
"model": "gemini-omni-1.2-flash",
"prompt": "Make the violin invisible. Keep everything else the same.",
"video_urls": [
"https://example.com/clip.mp4"
]
}
duration не влияет на неё.
Используйте короткие и конкретные инструкции. Для локального изменения можно добавить Keep everything else the same.
Продолжение существующей задачи
{
"model": "gemini-omni-1.2-flash",
"prompt": "The camera continues panning across the mountains.",
"extend_from_task_id": "task_01PREVIOUS",
"omni_reference_task_type": "extend",
"duration": 8
}
extend_from_task_id на video_urls, сохранив "omni_reference_task_type": "extend". Результат содержит исходное видео и фрагмент, добавленный в конец. duration задаёт только длину новой части, не более 10 секунд; оплачиваются только добавленные секунды. Например, исходное видео длиной 5 секунд с duration: 4 даёт результат около 9 секунд.
Ответ на отправку и проверка задачи
Успешная отправка возвращает HTTP 200. ID находится вdata[0].task_id. Проверяйте статус задачи каждые 5–10 секунд до completed или failed. Рекомендуемое общее ожидание — 10 минут. При тайм-ауте клиента продолжайте проверять исходную задачу, не отправляя её повторно.
curl --request GET \
--url https://api.apimart.ai/v1/tasks/task_01EXAMPLE \
--header 'Authorization: Bearer <token>'
{
"code": 200,
"data": {
"id": "task_01EXAMPLE",
"status": "completed",
"progress": 100,
"result": {
"videos": [
{
"url": [
"https://cdn.example.com/gemini_omni_video.mp4"
]
}
]
}
}
}
data в ответе проверки — объект задачи. data.result.videos[0].url — массив; первая ссылка находится в data.result.videos[0].url[0]. Видео можно воспроизвести или скачать; для долгого хранения сохраните его у себя. data.cost — итоговая стоимость в долларах США.
| Статус | Действие |
|---|---|
pending / processing | Продолжайте опрос; прогресс доступен в data.progress. |
completed | Получите ссылку и сохраните видео. |
failed | Прочитайте data.error.message. Неуспешные задачи не оплачиваются. |
Оплата и резервирование баланса
Оплата по токенам: разрешение влияет на число выходных токенов в секунду. При генерации по тексту или изображениямduration задаёт длительность результата. При редактировании параметр игнорируется и сохраняется длительность исходного видео; при продолжении он задаёт только длину добавляемой части. Актуальные ставки указаны в тарифах APIMart.
При отправке резерв рассчитывается по разрешению и max(10, duration) секундам; при входном видео используется оценка в 15 секунд. Резерв не является итоговой оплатой. После успеха разница пересчитывается по фактическому использованию; итог находится в data.cost.
При продолжении оплачиваются только добавленные секунды. Неуспешные задачи не оплачиваются. Если баланса недостаточно для резерва, возвращается HTTP 402.
Обработка ошибок
Ошибки параметров (invalid_* / unsupported_*) сразу переводят задачу в failed без оплаты. Проверяйте статус даже после успешной отправки.
| Ошибка / статус | Причина и действие |
|---|---|
invalid_duration | duration вне диапазона 3–15 либо интерполяция / продолжение дольше 10 секунд. Укажите допустимое целое число. |
invalid_task_type | Неподдерживаемое значение omni_reference_task_type. Используйте auto / edit / extend / reference; также принимаются text_to_video / image_to_video / reference_to_video. |
invalid_resolution | Используйте 360p / 720p / 1080p / 4k; также допускается 2160p. |
invalid_frame_images | Передан только последний кадр. Добавьте первый. |
unsupported_image_count | Более 10 изображений, включая первый/последний кадры. Уменьшите количество. |
unsupported_video_count | Более 1 входного видео. Оставьте один ролик длиной до 15 секунд. |
HTTP 400 | Отсутствует обязательный prompt. Передавайте текстовые инструкции даже при наличии медиа. |
HTTP 401 | Недействительный ключ. Проверьте Authorization. |
HTTP 402 | Не хватает баланса для резерва. Пополните счёт или уменьшите разрешение. |
HTTP 429 | Превышен лимит запросов. Повторите с увеличивающейся задержкой. |
status: failed | Ошибка поставщика или отклонение по правилам контента. Прочитайте data.error.message и измените запрос. |
Частые вопросы
Нужен ли prompt, если я передаю изображения или видео?
Да. prompt обязателен во всех режимах: генерация по изображениям, интерполяция первого/последнего кадра, редактирование, продолжение и повторное использование видео через extend_from_task_id. Если поле отсутствует, возвращается HTTP 400.
Можно ли передавать изображения или видео напрямую в Base64?
Нет.image_urls, first_frame_image, last_frame_image, image_with_roles[].url и video_urls принимают только общедоступные прямые HTTP(S)-ссылки. Не передавайте data:image/..., data:video/... или строки Base64 без префикса.