Kling 3.0 API
model: kling/3-0-video
model: kling/3-turbo-text-to-video
model: kling/3-turbo-image-to-video
Одной моделью делает и ролик по описанию, и ролик из присланного изображения. Соотношение сторон 16:9, 9:16, 1:1, на вход до 2 изображений, описание до 20 000 символов. Модель Kuaishou.
Принимает текстовое описание и возвращает готовый ролик. Разрешение 720p, 1080p, соотношение сторон 1:1, 9:16, 16:9, описание до 2 500 символов. Модель Kuaishou.
Принимает изображение и оживляет его, возвращая ролик. Разрешение 720p, 1080p, на вход до 2 изображений, описание до 2 500 символов. Модель Kuaishou.
Цена: за секунду, от 15.12 кр. ($0.0756) до 75.6 кр. ($0.378).
Цена: за секунду, 720P — 20.16 кр. ($0.1008), 1080P — 25.2 кр. ($0.126).
Цена: за секунду, 720P — 20.16 кр. ($0.1008), 1080P — 25.2 кр. ($0.126).
кр. — кредиты, покупаются за рубли.
Песочница
Поля multi_prompt, kling_elements задаются структурой и доступны только через API.
Ролик собирается после входа: новому счёту начисляют 50 кредитов, и первый ролик идёт на них. Ставка у этой модели 15.12–75.6 кр. за секунду. Войдите, чтобы начать.
{ "model": "kling/3-0-video", "input": { "prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет", "aspect_ratio": "16:9", "duration": 3 } }
Нажмите «Запустить» — готовый ролик появится здесь
Ролик делается минуты. Задача живёт не дольше 60 минут, после чего шлюз закрывает её сам и возвращает удержание целиком.
{
"code": 200,
"msg": "success",
"data": {
"taskId": "cm8r4t0vk0001s60p2xq7f9ab",
"model": "kling/3-0-video",
"state": "success",
"resultJson": "{\"resultUrls\":[\"https://file.example/result.mp4\"]}",
"failCode": "",
"failMsg": "",
"creditsConsumed": 15.12
}
}
Ролик собирается после входа: новому счёту начисляют 50 кредитов, и первый ролик идёт на них. Ставка у этой модели 20.16–25.2 кр. за секунду. Войдите, чтобы начать.
{ "model": "kling/3-turbo-text-to-video", "input": { "prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет", "duration": 3, "aspect_ratio": "1:1", "resolution": "720p" } }
Нажмите «Запустить» — готовый ролик появится здесь
Ролик делается минуты. Задача живёт не дольше 60 минут, после чего шлюз закрывает её сам и возвращает удержание целиком.
{
"code": 200,
"msg": "success",
"data": {
"taskId": "cm8r4t0vk0001s60p2xq7f9ab",
"model": "kling/3-turbo-text-to-video",
"state": "success",
"resultJson": "{\"resultUrls\":[\"https://file.example/result.mp4\"]}",
"failCode": "",
"failMsg": "",
"creditsConsumed": 20.16
}
}
Ролик собирается после входа: новому счёту начисляют 50 кредитов, и первый ролик идёт на них. Ставка у этой модели 20.16–25.2 кр. за секунду. Войдите, чтобы начать.
{ "model": "kling/3-turbo-image-to-video", "input": { "prompt": "Заменить фон на вечернюю городскую улицу, свет тёплый", "image_urls": [ "https://gen202.com/assets/sample-nano-banana-2.jpg" ], "duration": 3, "resolution": "720p" } }
Нажмите «Запустить» — готовый ролик появится здесь
Ролик делается минуты. Задача живёт не дольше 60 минут, после чего шлюз закрывает её сам и возвращает удержание целиком.
{
"code": 200,
"msg": "success",
"data": {
"taskId": "cm8r4t0vk0001s60p2xq7f9ab",
"model": "kling/3-turbo-image-to-video",
"state": "success",
"resultJson": "{\"resultUrls\":[\"https://file.example/result.mp4\"]}",
"failCode": "",
"failMsg": "",
"creditsConsumed": 20.16
}
}
Цена Kling 3.0
Цена за секунду. Списывается фактический расход, о котором сообщил поставщик.
| Вариант | Наша цена | Скидка | Официальная |
|---|---|---|---|
| without audio-720P | 15.12 кр. · $0.07567,56 ₽ | −10% | $0.084 |
| without audio-1080P | 20.16 кр. · $0.100810,08 ₽ | −10% | $0.112 |
| with audio-720P | 22.68 кр. · $0.113411,34 ₽ | −10% | $0.126 |
| with audio-1080P | 30.24 кр. · $0.151215,12 ₽ | −10% | $0.168 |
| 4K | 75.6 кр. · $0.37837,8 ₽ | −10% | $0.42 |
В среднем на 10% ниже официальной цены поставщика. кр. — кредиты, покупаются за рубли.
Цена за секунду. Списывается фактический расход, о котором сообщил поставщик.
| Вариант | Наша цена | Скидка | Официальная |
|---|---|---|---|
| 720P | 20.16 кр. · $0.100810,08 ₽ | −10% | $0.112 |
| 1080P | 25.2 кр. · $0.12612,6 ₽ | −10% | $0.14 |
В среднем на 10% ниже официальной цены поставщика. кр. — кредиты, покупаются за рубли.
Цена за секунду. Списывается фактический расход, о котором сообщил поставщик.
| Вариант | Наша цена | Скидка | Официальная |
|---|---|---|---|
| 720P | 20.16 кр. · $0.100810,08 ₽ | −10% | $0.112 |
| 1080P | 25.2 кр. · $0.12612,6 ₽ | −10% | $0.14 |
В среднем на 10% ниже официальной цены поставщика. кр. — кредиты, покупаются за рубли.
На время работы шлюз удерживает ставку выбранного разрешения, умноженную на запрошенную длительность; больше 1134 кредита по этой модели он не удержит ни при каком запросе (duration до 15 с). Разница между удержанием и фактическим расходом возвращается на баланс тем же запросом состояния, который увидел итог.
Вызов через API
Ролик делается минуты, поэтому файл не приходит в ответ на запрос. Первый вызов
ставит задачу и сразу отвечает её номером, второй по этому номеру отдаёт состояние задачи, а когда
она готова — ссылку на результат. Ключ передаётся в обоих запросах заголовком
Authorization: Bearer sk-… и выпускается
в кабинете. На один ключ шлюз пропускает
30 постановок задачи и 300
запросов состояния в минуту.
Поля запроса
Значения проверяются до обращения к поставщику: поле не из списка модели или значение вне
перечисления возвращают 422 и кредитов не тратят.
| Поле | Тип | Обяз. | Допустимые значения |
|---|---|---|---|
| model | текст | обязательное | kling/3-0-video |
| input | объект | обязательное | Параметры генерации — поля из таблицы ниже |
Поля input
| Поле | Тип | Обяз. | Допустимые значения |
|---|---|---|---|
| prompt | текст | обязательное | от 1 до 20 000 символов |
| image_urls | список ссылок | опц. | до 2 ссылок на изображение |
| sound | да или нет | опц. | true или false |
| duration | целое число | опц. | целое от 3 до 15 |
| aspect_ratio | значение из списка | опц. | 16:9 · 9:16 · 1:1 |
| mode | значение из списка | опц. | std · pro · 4K |
| multi_shots | да или нет | опц. | true или false |
| multi_prompt | структура | опц. | структура по документации поставщика, проверяется у него |
| kling_elements | структура | опц. | структура по документации поставщика, проверяется у него |
Ссылка на изображение принимается только полным адресом на http или https: не длиннее 2048 символов, на общедоступном сайте, без имени и пароля перед адресом и без порта, кроме 80 и 443. Относительный путь, а также адреса внутри сети — localhost, 127.0.0.1, 10.0.0.5, 192.168.1.2 — и имена без точки шлюз отклоняет ответом 422, к поставщику не обращаясь.
Ответ
Оба запроса отвечают одним конвертом: {"code":…,"msg":…,"data":…}, где
code повторяет HTTP-статус, а полезное лежит в
data. Тот же конверт приходит и при отказе — разбирать две формы ответа
не нужно.
/api/v1/jobs/createTask
| Поле | Тип | Что в нём |
|---|---|---|
| data.taskId | строка | Номер задачи. Больше в ответе ничего нет и быть не может — работа только началась. |
/api/v1/jobs/recordInfo
| Поле | Тип | Что в нём |
|---|---|---|
| data.taskId | строка | Номер задачи — тот же, что вернул createTask. |
| data.model | строка | Имя модели в том виде, в каком его прислал клиент. |
| data.state | строка | Состояние задачи: waiting, queuing, generating, success или fail. |
| data.param | строка | Параметры, с которыми задача создана, — строкой JSON внутри JSON. |
| data.resultJson | строка | Результат строкой JSON внутри JSON: {"resultUrls":["https://…"]} — разбирается вторым разбором. До завершения задачи — пустая строка. |
| data.failCode | строка | Код неудачи из таблицы ниже. У остальных задач — пустая строка. |
| data.failMsg | строка | Причина неудачи словами. Иначе пустая строка. |
| data.costTime | число | Сколько задача заняла, миллисекунды. Пока не завершилась — null. |
| data.completeTime | число | Когда завершилась, миллисекунды эпохи Unix. Пока не завершилась — null. |
| data.createTime | число | Когда создана, миллисекунды эпохи Unix. |
| data.updateTime | число | Когда состояние менялось в последний раз, миллисекунды эпохи Unix. |
| data.creditsConsumed | число | Сколько кредитов списано. Ноль, пока задача не завершилась, и ноль у неудачной. |
Состояния задачи
Состояние лежит в поле state ответа
/api/v1/jobs/recordInfo. Первые три означают, что работа идёт: запрос надо
повторить примерно через 3 секунды — чаще спрашивать нечего, столько же
ждёт между опросами сам шлюз. Два последних состояния окончательные: после них задача не меняется.
| state | Что происходит |
|---|---|
| waiting | Задача принята и стоит в очереди шлюза; поставщику она ещё не отправлена. |
| queuing | Поставщик задачу принял и поставил в свою очередь. |
| generating | Генерация идёт. |
| success | Готово: ссылки на результат лежат в resultJson, в creditsConsumed — сколько списано. |
| fail | Задача не удалась: причина в failCode и failMsg, удержанные кредиты возвращены целиком. |
Опрос не бывает бесконечным: задача на видео живёт не дольше 60
минут, после чего шлюз закрывает её сам состоянием fail и возвращает
удержанные кредиты целиком. Причина неудачи приходит двумя полями:
failCode из таблицы ниже и failMsg словами.
| failCode | Что произошло |
|---|---|
| 501 | Поставщик вернул отказ: генерация не удалась. |
| 408 | Результата нет дольше крайнего срока задачи (60 минут для видео). |
| 404 | Поставщик не знает такой задачи. |
| 429 | Поставщик отбил создание задачи по своему лимиту. |
| 500 | Поломка на нашей стороне; подробности остаются в журнале шлюза. |
Ссылка на готовый файл живёт 14 дней — столько его хранит поставщик. Файл,
который нужен дольше, скачивайте к себе сразу после того, как задача пришла в состояние
success.
Отказы
Тело отказа одно на все случаи: {"code":…,"msg":…,"data":null}. Задача, не
дошедшая до результата, не тарифицируется — удержанные кредиты возвращаются целиком.
| Код | Адрес | Когда |
|---|---|---|
| 400 | /api/v1/jobs/createTask | Тело запроса — не разбираемый JSON. |
| 401 | /api/v1/jobs/createTask | Ключа нет в заголовке Authorization, либо он неверный или отключён. |
| 402 | /api/v1/jobs/createTask | Свободных кредитов меньше, чем удерживается под задачу. |
| 413 | /api/v1/jobs/createTask | Тело запроса больше 512 КиБ. |
| 415 | /api/v1/jobs/createTask | Тело отправлено не как application/json или заголовок Content-Type не передан. |
| 422 | /api/v1/jobs/createTask | Поле model пустое или его имени нет в каталоге, input — не объект, поле не из списка модели либо значение вне её перечисления. В сообщении перечислено, что принимается. |
| 429 | /api/v1/jobs/createTask | Больше 30 запросов в минуту на один ключ либо больше 50 незавершённых задач на аккаунте. |
| 500 | /api/v1/jobs/createTask | Поломка на нашей стороне. Подробности остаются в журнале шлюза и наружу не уходят. |
| 401 | /api/v1/jobs/recordInfo | Ключа нет в заголовке Authorization, либо он неверный или отключён. |
| 404 | /api/v1/jobs/recordInfo | Задачи с таким номером нет или она создана другим аккаунтом. |
| 422 | /api/v1/jobs/recordInfo | Параметр taskId не передан. |
| 429 | /api/v1/jobs/recordInfo | Больше 300 запросов в минуту на один ключ. |
| 500 | /api/v1/jobs/recordInfo | Поломка на нашей стороне. Подробности остаются в журнале шлюза и наружу не уходят. |
Пример вызова
# 1. Поставить задачу — в ответе придёт её номер
TASK=$(curl -s https://api.gen202.com/api/v1/jobs/createTask \
-H "Authorization: Bearer sk-ваш-ключ" \
-H "Content-Type: application/json" \
-d '{
"model": "kling/3-0-video",
"input": {
"prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет",
"aspect_ratio": "16:9",
"duration": 3
}
}' | jq -r '.data.taskId')
# 2. Спрашивать состояние, пока задача не закончится: waiting, queuing и
# generating означают «работа идёт», success и fail — окончательные
while true; do
RECORD=$(curl -s "https://api.gen202.com/api/v1/jobs/recordInfo?taskId=$TASK" \
-H "Authorization: Bearer sk-ваш-ключ")
STATE=$(echo "$RECORD" | jq -r '.data.state')
case "$STATE" in success|fail) break;; esac
sleep 3
done
# 3. Забрать результат. Ссылка на файл лежит в resultJson — это строка JSON
# внутри JSON, поэтому её разбирают вторым разбором (fromjson)
echo "$RECORD" | jq -r '.data |
if .state == "fail"
then "отказ \(.failCode): \(.failMsg)"
else .resultJson | fromjson | .resultUrls[0]
end'
import json
import time
import requests
headers = {"Authorization": "Bearer sk-ваш-ключ"}
# 1. Поставить задачу — в ответе придёт её номер
created = requests.post(
"https://api.gen202.com/api/v1/jobs/createTask",
headers=headers,
json={
"model": "kling/3-0-video",
"input": {
"prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет",
"aspect_ratio": "16:9",
"duration": 3
}
},
).json()
task_id = created["data"]["taskId"]
# 2. Спрашивать состояние, пока задача не закончится: waiting, queuing и
# generating означают «работа идёт», success и fail — окончательные
while True:
task = requests.get(
"https://api.gen202.com/api/v1/jobs/recordInfo",
headers=headers,
params={"taskId": task_id},
).json()["data"]
if task["state"] in ("success", "fail"):
break
time.sleep(3)
# 3. Разобрать итог. У неудачи причина в failCode и failMsg
if task["state"] == "fail":
raise SystemExit("отказ " + task["failCode"] + ": " + task["failMsg"])
# resultJson — строка JSON внутри JSON, поэтому разбор второй
result = json.loads(task["resultJson"])
print(result["resultUrls"][0])
print("списано кредитов:", task["creditsConsumed"])
Пример проходит весь путь: ставит задачу, повторяет запрос состояния раз в
3 секунды, пока задача не закончится, и разбирает ответ до ссылки
на файл. Разборов два, потому что поле resultJson — строка JSON
внутри JSON. В теле первого запроса стоят обязательные поля модели и значения из её
перечислений, поэтому он проходит проверку шлюза как есть.
Подставить остаётся только свой ключ.
Пример на оболочке разбирает ответ через jq; на Python своего
ничего не нужно, кроме requests.
Ролик делается минуты, поэтому файл не приходит в ответ на запрос. Первый вызов
ставит задачу и сразу отвечает её номером, второй по этому номеру отдаёт состояние задачи, а когда
она готова — ссылку на результат. Ключ передаётся в обоих запросах заголовком
Authorization: Bearer sk-… и выпускается
в кабинете. На один ключ шлюз пропускает
30 постановок задачи и 300
запросов состояния в минуту.
Поля запроса
Значения проверяются до обращения к поставщику: поле не из списка модели или значение вне
перечисления возвращают 422 и кредитов не тратят.
| Поле | Тип | Обяз. | Допустимые значения |
|---|---|---|---|
| model | текст | обязательное | kling/3-turbo-text-to-video |
| input | объект | обязательное | Параметры генерации — поля из таблицы ниже |
Поля input
| Поле | Тип | Обяз. | Допустимые значения |
|---|---|---|---|
| prompt | текст | обязательное | от 1 до 2 500 символов |
| duration | целое число | обязательное | целое от 3 до 15 |
| aspect_ratio | значение из списка | обязательное | 1:1 · 9:16 · 16:9 |
| resolution | значение из списка | опц. | 720p · 1080p |
Ответ
Оба запроса отвечают одним конвертом: {"code":…,"msg":…,"data":…}, где
code повторяет HTTP-статус, а полезное лежит в
data. Тот же конверт приходит и при отказе — разбирать две формы ответа
не нужно.
/api/v1/jobs/createTask
| Поле | Тип | Что в нём |
|---|---|---|
| data.taskId | строка | Номер задачи. Больше в ответе ничего нет и быть не может — работа только началась. |
/api/v1/jobs/recordInfo
| Поле | Тип | Что в нём |
|---|---|---|
| data.taskId | строка | Номер задачи — тот же, что вернул createTask. |
| data.model | строка | Имя модели в том виде, в каком его прислал клиент. |
| data.state | строка | Состояние задачи: waiting, queuing, generating, success или fail. |
| data.param | строка | Параметры, с которыми задача создана, — строкой JSON внутри JSON. |
| data.resultJson | строка | Результат строкой JSON внутри JSON: {"resultUrls":["https://…"]} — разбирается вторым разбором. До завершения задачи — пустая строка. |
| data.failCode | строка | Код неудачи из таблицы ниже. У остальных задач — пустая строка. |
| data.failMsg | строка | Причина неудачи словами. Иначе пустая строка. |
| data.costTime | число | Сколько задача заняла, миллисекунды. Пока не завершилась — null. |
| data.completeTime | число | Когда завершилась, миллисекунды эпохи Unix. Пока не завершилась — null. |
| data.createTime | число | Когда создана, миллисекунды эпохи Unix. |
| data.updateTime | число | Когда состояние менялось в последний раз, миллисекунды эпохи Unix. |
| data.creditsConsumed | число | Сколько кредитов списано. Ноль, пока задача не завершилась, и ноль у неудачной. |
Состояния задачи
Состояние лежит в поле state ответа
/api/v1/jobs/recordInfo. Первые три означают, что работа идёт: запрос надо
повторить примерно через 3 секунды — чаще спрашивать нечего, столько же
ждёт между опросами сам шлюз. Два последних состояния окончательные: после них задача не меняется.
| state | Что происходит |
|---|---|
| waiting | Задача принята и стоит в очереди шлюза; поставщику она ещё не отправлена. |
| queuing | Поставщик задачу принял и поставил в свою очередь. |
| generating | Генерация идёт. |
| success | Готово: ссылки на результат лежат в resultJson, в creditsConsumed — сколько списано. |
| fail | Задача не удалась: причина в failCode и failMsg, удержанные кредиты возвращены целиком. |
Опрос не бывает бесконечным: задача на видео живёт не дольше 60
минут, после чего шлюз закрывает её сам состоянием fail и возвращает
удержанные кредиты целиком. Причина неудачи приходит двумя полями:
failCode из таблицы ниже и failMsg словами.
| failCode | Что произошло |
|---|---|
| 501 | Поставщик вернул отказ: генерация не удалась. |
| 408 | Результата нет дольше крайнего срока задачи (60 минут для видео). |
| 404 | Поставщик не знает такой задачи. |
| 429 | Поставщик отбил создание задачи по своему лимиту. |
| 500 | Поломка на нашей стороне; подробности остаются в журнале шлюза. |
Ссылка на готовый файл живёт 14 дней — столько его хранит поставщик. Файл,
который нужен дольше, скачивайте к себе сразу после того, как задача пришла в состояние
success.
Отказы
Тело отказа одно на все случаи: {"code":…,"msg":…,"data":null}. Задача, не
дошедшая до результата, не тарифицируется — удержанные кредиты возвращаются целиком.
| Код | Адрес | Когда |
|---|---|---|
| 400 | /api/v1/jobs/createTask | Тело запроса — не разбираемый JSON. |
| 401 | /api/v1/jobs/createTask | Ключа нет в заголовке Authorization, либо он неверный или отключён. |
| 402 | /api/v1/jobs/createTask | Свободных кредитов меньше, чем удерживается под задачу. |
| 413 | /api/v1/jobs/createTask | Тело запроса больше 512 КиБ. |
| 415 | /api/v1/jobs/createTask | Тело отправлено не как application/json или заголовок Content-Type не передан. |
| 422 | /api/v1/jobs/createTask | Поле model пустое или его имени нет в каталоге, input — не объект, поле не из списка модели либо значение вне её перечисления. В сообщении перечислено, что принимается. |
| 429 | /api/v1/jobs/createTask | Больше 30 запросов в минуту на один ключ либо больше 50 незавершённых задач на аккаунте. |
| 500 | /api/v1/jobs/createTask | Поломка на нашей стороне. Подробности остаются в журнале шлюза и наружу не уходят. |
| 401 | /api/v1/jobs/recordInfo | Ключа нет в заголовке Authorization, либо он неверный или отключён. |
| 404 | /api/v1/jobs/recordInfo | Задачи с таким номером нет или она создана другим аккаунтом. |
| 422 | /api/v1/jobs/recordInfo | Параметр taskId не передан. |
| 429 | /api/v1/jobs/recordInfo | Больше 300 запросов в минуту на один ключ. |
| 500 | /api/v1/jobs/recordInfo | Поломка на нашей стороне. Подробности остаются в журнале шлюза и наружу не уходят. |
Пример вызова
# 1. Поставить задачу — в ответе придёт её номер
TASK=$(curl -s https://api.gen202.com/api/v1/jobs/createTask \
-H "Authorization: Bearer sk-ваш-ключ" \
-H "Content-Type: application/json" \
-d '{
"model": "kling/3-turbo-text-to-video",
"input": {
"prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет",
"duration": 3,
"aspect_ratio": "1:1",
"resolution": "720p"
}
}' | jq -r '.data.taskId')
# 2. Спрашивать состояние, пока задача не закончится: waiting, queuing и
# generating означают «работа идёт», success и fail — окончательные
while true; do
RECORD=$(curl -s "https://api.gen202.com/api/v1/jobs/recordInfo?taskId=$TASK" \
-H "Authorization: Bearer sk-ваш-ключ")
STATE=$(echo "$RECORD" | jq -r '.data.state')
case "$STATE" in success|fail) break;; esac
sleep 3
done
# 3. Забрать результат. Ссылка на файл лежит в resultJson — это строка JSON
# внутри JSON, поэтому её разбирают вторым разбором (fromjson)
echo "$RECORD" | jq -r '.data |
if .state == "fail"
then "отказ \(.failCode): \(.failMsg)"
else .resultJson | fromjson | .resultUrls[0]
end'
import json
import time
import requests
headers = {"Authorization": "Bearer sk-ваш-ключ"}
# 1. Поставить задачу — в ответе придёт её номер
created = requests.post(
"https://api.gen202.com/api/v1/jobs/createTask",
headers=headers,
json={
"model": "kling/3-turbo-text-to-video",
"input": {
"prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет",
"duration": 3,
"aspect_ratio": "1:1",
"resolution": "720p"
}
},
).json()
task_id = created["data"]["taskId"]
# 2. Спрашивать состояние, пока задача не закончится: waiting, queuing и
# generating означают «работа идёт», success и fail — окончательные
while True:
task = requests.get(
"https://api.gen202.com/api/v1/jobs/recordInfo",
headers=headers,
params={"taskId": task_id},
).json()["data"]
if task["state"] in ("success", "fail"):
break
time.sleep(3)
# 3. Разобрать итог. У неудачи причина в failCode и failMsg
if task["state"] == "fail":
raise SystemExit("отказ " + task["failCode"] + ": " + task["failMsg"])
# resultJson — строка JSON внутри JSON, поэтому разбор второй
result = json.loads(task["resultJson"])
print(result["resultUrls"][0])
print("списано кредитов:", task["creditsConsumed"])
Пример проходит весь путь: ставит задачу, повторяет запрос состояния раз в
3 секунды, пока задача не закончится, и разбирает ответ до ссылки
на файл. Разборов два, потому что поле resultJson — строка JSON
внутри JSON. В теле первого запроса стоят обязательные поля модели и значения из её
перечислений, поэтому он проходит проверку шлюза как есть.
Подставить остаётся только свой ключ.
Пример на оболочке разбирает ответ через jq; на Python своего
ничего не нужно, кроме requests.
Ролик делается минуты, поэтому файл не приходит в ответ на запрос. Первый вызов
ставит задачу и сразу отвечает её номером, второй по этому номеру отдаёт состояние задачи, а когда
она готова — ссылку на результат. Ключ передаётся в обоих запросах заголовком
Authorization: Bearer sk-… и выпускается
в кабинете. На один ключ шлюз пропускает
30 постановок задачи и 300
запросов состояния в минуту.
Поля запроса
Значения проверяются до обращения к поставщику: поле не из списка модели или значение вне
перечисления возвращают 422 и кредитов не тратят.
| Поле | Тип | Обяз. | Допустимые значения |
|---|---|---|---|
| model | текст | обязательное | kling/3-turbo-image-to-video |
| input | объект | обязательное | Параметры генерации — поля из таблицы ниже |
Поля input
| Поле | Тип | Обяз. | Допустимые значения |
|---|---|---|---|
| prompt | текст | обязательное | от 1 до 2 500 символов |
| image_urls | список ссылок | обязательное | от 1 до 2 ссылок на изображение |
| duration | целое число | обязательное | целое от 3 до 15 |
| resolution | значение из списка | опц. | 720p · 1080p |
Ссылка на изображение принимается только полным адресом на http или https: не длиннее 2048 символов, на общедоступном сайте, без имени и пароля перед адресом и без порта, кроме 80 и 443. Относительный путь, а также адреса внутри сети — localhost, 127.0.0.1, 10.0.0.5, 192.168.1.2 — и имена без точки шлюз отклоняет ответом 422, к поставщику не обращаясь.
Ответ
Оба запроса отвечают одним конвертом: {"code":…,"msg":…,"data":…}, где
code повторяет HTTP-статус, а полезное лежит в
data. Тот же конверт приходит и при отказе — разбирать две формы ответа
не нужно.
/api/v1/jobs/createTask
| Поле | Тип | Что в нём |
|---|---|---|
| data.taskId | строка | Номер задачи. Больше в ответе ничего нет и быть не может — работа только началась. |
/api/v1/jobs/recordInfo
| Поле | Тип | Что в нём |
|---|---|---|
| data.taskId | строка | Номер задачи — тот же, что вернул createTask. |
| data.model | строка | Имя модели в том виде, в каком его прислал клиент. |
| data.state | строка | Состояние задачи: waiting, queuing, generating, success или fail. |
| data.param | строка | Параметры, с которыми задача создана, — строкой JSON внутри JSON. |
| data.resultJson | строка | Результат строкой JSON внутри JSON: {"resultUrls":["https://…"]} — разбирается вторым разбором. До завершения задачи — пустая строка. |
| data.failCode | строка | Код неудачи из таблицы ниже. У остальных задач — пустая строка. |
| data.failMsg | строка | Причина неудачи словами. Иначе пустая строка. |
| data.costTime | число | Сколько задача заняла, миллисекунды. Пока не завершилась — null. |
| data.completeTime | число | Когда завершилась, миллисекунды эпохи Unix. Пока не завершилась — null. |
| data.createTime | число | Когда создана, миллисекунды эпохи Unix. |
| data.updateTime | число | Когда состояние менялось в последний раз, миллисекунды эпохи Unix. |
| data.creditsConsumed | число | Сколько кредитов списано. Ноль, пока задача не завершилась, и ноль у неудачной. |
Состояния задачи
Состояние лежит в поле state ответа
/api/v1/jobs/recordInfo. Первые три означают, что работа идёт: запрос надо
повторить примерно через 3 секунды — чаще спрашивать нечего, столько же
ждёт между опросами сам шлюз. Два последних состояния окончательные: после них задача не меняется.
| state | Что происходит |
|---|---|
| waiting | Задача принята и стоит в очереди шлюза; поставщику она ещё не отправлена. |
| queuing | Поставщик задачу принял и поставил в свою очередь. |
| generating | Генерация идёт. |
| success | Готово: ссылки на результат лежат в resultJson, в creditsConsumed — сколько списано. |
| fail | Задача не удалась: причина в failCode и failMsg, удержанные кредиты возвращены целиком. |
Опрос не бывает бесконечным: задача на видео живёт не дольше 60
минут, после чего шлюз закрывает её сам состоянием fail и возвращает
удержанные кредиты целиком. Причина неудачи приходит двумя полями:
failCode из таблицы ниже и failMsg словами.
| failCode | Что произошло |
|---|---|
| 501 | Поставщик вернул отказ: генерация не удалась. |
| 408 | Результата нет дольше крайнего срока задачи (60 минут для видео). |
| 404 | Поставщик не знает такой задачи. |
| 429 | Поставщик отбил создание задачи по своему лимиту. |
| 500 | Поломка на нашей стороне; подробности остаются в журнале шлюза. |
Ссылка на готовый файл живёт 14 дней — столько его хранит поставщик. Файл,
который нужен дольше, скачивайте к себе сразу после того, как задача пришла в состояние
success.
Отказы
Тело отказа одно на все случаи: {"code":…,"msg":…,"data":null}. Задача, не
дошедшая до результата, не тарифицируется — удержанные кредиты возвращаются целиком.
| Код | Адрес | Когда |
|---|---|---|
| 400 | /api/v1/jobs/createTask | Тело запроса — не разбираемый JSON. |
| 401 | /api/v1/jobs/createTask | Ключа нет в заголовке Authorization, либо он неверный или отключён. |
| 402 | /api/v1/jobs/createTask | Свободных кредитов меньше, чем удерживается под задачу. |
| 413 | /api/v1/jobs/createTask | Тело запроса больше 512 КиБ. |
| 415 | /api/v1/jobs/createTask | Тело отправлено не как application/json или заголовок Content-Type не передан. |
| 422 | /api/v1/jobs/createTask | Поле model пустое или его имени нет в каталоге, input — не объект, поле не из списка модели либо значение вне её перечисления. В сообщении перечислено, что принимается. |
| 429 | /api/v1/jobs/createTask | Больше 30 запросов в минуту на один ключ либо больше 50 незавершённых задач на аккаунте. |
| 500 | /api/v1/jobs/createTask | Поломка на нашей стороне. Подробности остаются в журнале шлюза и наружу не уходят. |
| 401 | /api/v1/jobs/recordInfo | Ключа нет в заголовке Authorization, либо он неверный или отключён. |
| 404 | /api/v1/jobs/recordInfo | Задачи с таким номером нет или она создана другим аккаунтом. |
| 422 | /api/v1/jobs/recordInfo | Параметр taskId не передан. |
| 429 | /api/v1/jobs/recordInfo | Больше 300 запросов в минуту на один ключ. |
| 500 | /api/v1/jobs/recordInfo | Поломка на нашей стороне. Подробности остаются в журнале шлюза и наружу не уходят. |
Пример вызова
# 1. Поставить задачу — в ответе придёт её номер
TASK=$(curl -s https://api.gen202.com/api/v1/jobs/createTask \
-H "Authorization: Bearer sk-ваш-ключ" \
-H "Content-Type: application/json" \
-d '{
"model": "kling/3-turbo-image-to-video",
"input": {
"prompt": "Заменить фон на вечернюю городскую улицу, свет тёплый",
"image_urls": [
"https://gen202.com/assets/sample-nano-banana-2.jpg"
],
"duration": 3,
"resolution": "720p"
}
}' | jq -r '.data.taskId')
# 2. Спрашивать состояние, пока задача не закончится: waiting, queuing и
# generating означают «работа идёт», success и fail — окончательные
while true; do
RECORD=$(curl -s "https://api.gen202.com/api/v1/jobs/recordInfo?taskId=$TASK" \
-H "Authorization: Bearer sk-ваш-ключ")
STATE=$(echo "$RECORD" | jq -r '.data.state')
case "$STATE" in success|fail) break;; esac
sleep 3
done
# 3. Забрать результат. Ссылка на файл лежит в resultJson — это строка JSON
# внутри JSON, поэтому её разбирают вторым разбором (fromjson)
echo "$RECORD" | jq -r '.data |
if .state == "fail"
then "отказ \(.failCode): \(.failMsg)"
else .resultJson | fromjson | .resultUrls[0]
end'
import json
import time
import requests
headers = {"Authorization": "Bearer sk-ваш-ключ"}
# 1. Поставить задачу — в ответе придёт её номер
created = requests.post(
"https://api.gen202.com/api/v1/jobs/createTask",
headers=headers,
json={
"model": "kling/3-turbo-image-to-video",
"input": {
"prompt": "Заменить фон на вечернюю городскую улицу, свет тёплый",
"image_urls": [
"https://gen202.com/assets/sample-nano-banana-2.jpg"
],
"duration": 3,
"resolution": "720p"
}
},
).json()
task_id = created["data"]["taskId"]
# 2. Спрашивать состояние, пока задача не закончится: waiting, queuing и
# generating означают «работа идёт», success и fail — окончательные
while True:
task = requests.get(
"https://api.gen202.com/api/v1/jobs/recordInfo",
headers=headers,
params={"taskId": task_id},
).json()["data"]
if task["state"] in ("success", "fail"):
break
time.sleep(3)
# 3. Разобрать итог. У неудачи причина в failCode и failMsg
if task["state"] == "fail":
raise SystemExit("отказ " + task["failCode"] + ": " + task["failMsg"])
# resultJson — строка JSON внутри JSON, поэтому разбор второй
result = json.loads(task["resultJson"])
print(result["resultUrls"][0])
print("списано кредитов:", task["creditsConsumed"])
Пример проходит весь путь: ставит задачу, повторяет запрос состояния раз в
3 секунды, пока задача не закончится, и разбирает ответ до ссылки
на файл. Разборов два, потому что поле resultJson — строка JSON
внутри JSON. В теле первого запроса стоят обязательные поля модели и значения из её
перечислений, поэтому он проходит проверку шлюза как есть.
Заменить в нём нужно два значения: свой ключ и ссылку на изображение — в примере стоит образец с нашего сайта.
Пример на оболочке разбирает ответ через jq; на Python своего
ничего не нужно, кроме requests.
Остальные модели этого семейства и их поля — в разделе документации Видео.
Что делает нейросеть Kling 3.0
Kling 3.0 — нейросеть Kuaishou: она снимает видео с родным звуком, одним кадром или несколькими подряд.
Старшая запись идёт под одним именем и берёт обе работы сразу: видео из текста и видео из изображения. Кадр для второй передаётся ссылкой, и список image_urls берёт до 2 ссылок.
Kling 3.0 Turbo стоит на этой же странице двумя отдельными записями, и в поле model у них разные имена: kling/3-turbo-text-to-video и kling/3-turbo-image-to-video.
Родной звук включается флагом sound, а ролик со звуком и без него стоит в таблице цен порознь: строки на то и другое разные.
Кадры многокадрового ролика и закреплённые элементы приходят своими полями — multi_prompt и kling_elements. Как устроено каждое из них, разбирает поставщик, а не наш шлюз; остальные поля перечислены в разделе «Kling».
Как пользоваться Kling 3.0 бесплатно и можно ли её скачать
У Kling 3.0 платят по расходу: с баланса уходит ставка за каждую секунду готового ролика, а поднимают её разрешение и звук. Новому счёту при первом входе начисляют приветственные кредиты, и первый ролик снимают на них. Ежемесячного платежа нет, а задача, закончившаяся отказом, возвращает удержание на баланс целиком.
Сама модель работает на стороне Kuaishou и запускается по сети, поэтому у себя разворачивать нечего. Через нас забирают результат: готовый ролик из песочницы приходит файлом mp4.
Официальный сайт Kling 3.0 принадлежит Kuaishou, а мы — независимый продавец доступа к его моделям. Имена полей и допустимые значения при этом взяты у разработчика: их видно в таблице выше.
Порядок работы одинаков у всех трёх записей страницы, и меняются в нём только значения полей.
- Соберите описание кадра. Поле prompt принимает сцену целиком: героя, его действие, обстановку вокруг и движение камеры.
- Приложите исходный кадр. Ссылку на картинку кладут в поле image_urls, и тогда ролик отталкивается от неё, а не сочиняется с нуля.
- Выберите разрешение и длительность. Разрешение у старшей записи выбирает поле mode, у Kling 3.0 Turbo — поле resolution, а секунды ставят в duration.
- Решите, нужен ли родной звук. Флаг sound добавляет к картинке звуковую дорожку, и от него же зависит строка цены.
- Разложите рассказ по кадрам. Флаг multi_shots отдаёт переходы между планами модели, а поле multi_prompt описывает каждый план по отдельности.
Чем Kling 3.0 Turbo отличается от Kling 3.0
Разницу между записями Kuaishou свёл в свою таблицу возможностей, и видна она прямо в полях запроса.
| Что | Kling 3.0 | Kling 3.0 Turbo |
|---|---|---|
| Разрешения | поле mode: std, pro и 4K | поле resolution: 720p и 1080p |
| Кадры на входе | первый и последний | первый |
| Закрепление элементов | поле kling_elements | — |
| Перенос движения с готового ролика | есть | — |
| Многокадровый рассказ | есть | есть |
| Родной звук | есть | есть |
| Обязательные поля | prompt | Kling 3.0 Turbo text-to-video — prompt, duration и aspect_ratio; Kling 3.0 Turbo image-to-video — prompt, image_urls и duration |
Многокадровый рассказ и родной звук Kuaishou называет общими для обеих записей, а 4K, последний кадр и закрепление элементов оставил старшей.
Какой длины и в каком разрешении выходит ролик Kling 3.0
Ролик выходит от 3 до 15 секунд, и вилка эта общая для старшей записи и для обоих Turbo.
Разрешение у Kling 3.0 выбирают режимом: Kling 3.0 pro — это 1080p, std — 720p, а 4K назван прямо. У Turbo выбор из двух: 720p и 1080p.
Форм кадра у старшей записи 3: 16:9, 9:16, 1:1.
Что Kuaishou заложил в Kling 3.0
Модель собрана единым обучением на двух прошлых — VIDEO O1 и VIDEO 2.6. От них ей достались звук и удержание облика, а предел длительности при этом подняли.
С включённым многокадровым режимом переходы между кадрами модель планирует сама. С выключенным выходит один кадр без склеек.
Элемент — это закреплённый персонаж или предмет, и заводят его двумя способами. Первый: прислать ролик с ним, откуда сама модель вытащит внешность и голос. Второй: прислать несколько его снимков.
Кадры многокадрового рассказа описываются по отдельности: у каждого своё описание и своя длительность.
Чего Kuaishou не обещает от Kling 3.0 Turbo
Из двух кадров Turbo принимает только первый: связки «первый и последний» и «только последний» названы пока не сделанными.
Родное 4K объявлено для Kling 3.0, и работы, где оно есть, — это видео из текста и видео из изображения.
Перенос движения и мимики с готового ролика вынесен отдельной записью каталога: за ним идут на Kling 3.0 Motion Control.
Что чаще всего идёт не так в Kling 3.0 и как это обходят
Ниже — то, что видно на съёмке и о чём документация молчит: места, где ролик выходит не тем, и обходы, которые для них нашли.
- К концу длинного ролика речь расходится с губами: герой замолкает раньше, чем договорил. Реплики поэтому ставят в начало, а последние планы делают без слов.
- Много реплик в одном описании модель старается уместить целиком и торопится. Разговор надёжнее разложить по нескольким коротким планам.
- Модель договаривает за автора: в кадре появляются лишний человек, лишняя сцена или надпись, которых не просили. Иногда герой заговаривает сам собой — тогда в описании прямо пишут, что он молчит.
- Закреплённый элемент и многокадровый рассказ спорят между собой: элемент держит облик героя, а заказанная смена планов при этом выполняется не вся.
- Подробное описание, собранное чат-ботом, модель понимает слишком буквально: от слова «стоит» герой замирает совсем. Короткое описание одного действия срабатывает точнее.
- Движение камеры уходит не туда: вместо камеры едет предмет или кадр начинает мелко трястись. Помогает прямое указание, что предмет остаётся на месте.
- Когда заданы и первый кадр, и последний, действие между ними выполняется хуже. Тот же замысел выходит лучше с одного кадра и многокадрового режима.
- На общем плане лицо героя расползается, а люди на дальнем плане движутся одинаково и дёргано. Крупность плана поэтому выбирают под лицо, а массовку оставляют спокойной.
- Звук сцены иногда не сходится с картинкой: за закрытой дверью слышна улица. Такой ролик переснимают, а не правят описанием.
- Годный ролик редко выходит с первой попытки. Сломавшийся план переснимают отдельно или вырезают при монтаже, а не переделывают всё целиком.
Общий порядок из этого складывается такой: одно действие на план, короткое описание и проверка замысла на низком разрешении, где секунда стоит меньше.