Wan 2.7 API
model: wan/2-7-text-to-video
model: wan/2-7-image-to-video
model: wan/2-7-r2v
model: wan/2-7-videoedit
Принимает текстовое описание и возвращает готовый ролик. Разрешение 720p, 1080p, описание до 5 000 символов. Модель Alibaba.
Принимает изображение и оживляет его, возвращая ролик. Разрешение 720p, 1080p, описание до 5 000 символов. Модель Alibaba.
Принимает изображения-образцы и переносит показанное на них в новый ролик. Разрешение 720p, 1080p, 5 соотношений сторон, от 16:9 до 3:4, описание до 5 000 символов. Модель Alibaba.
Принимает готовый ролик и переделывает его по текстовому указанию. Разрешение 720p, 1080p, 5 соотношений сторон, от 16:9 до 3:4, описание до 5 000 символов. Модель Alibaba.
Цена: за секунду, 720p — 18 кр. ($0.09), 1080p — 27 кр. ($0.135).
Цена: за секунду, 720p — 18 кр. ($0.09), 1080p — 27 кр. ($0.135).
Цена: за секунду, 720p — 18 кр. ($0.09), 1080p — 27 кр. ($0.135).
Цена: за секунду, 720p — 18 кр. ($0.09), 1080p — 27 кр. ($0.135).
кр. — кредиты, покупаются за рубли.
Песочница
Ролик собирается после входа: новому счёту начисляют 50 кредитов, и первый ролик идёт на них. Ставка у этой модели 18–27 кр. за секунду. Войдите, чтобы начать.
{ "model": "wan/2-7-text-to-video", "input": { "prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет", "resolution": "720p", "duration": 2 } }
Нажмите «Запустить» — готовый ролик появится здесь
Ролик делается минуты. Задача живёт не дольше 60 минут, после чего шлюз закрывает её сам и возвращает удержание целиком.
{
"code": 200,
"msg": "success",
"data": {
"taskId": "cm8r4t0vk0001s60p2xq7f9ab",
"model": "wan/2-7-text-to-video",
"state": "success",
"resultJson": "{\"resultUrls\":[\"https://file.example/result.mp4\"]}",
"failCode": "",
"failMsg": "",
"creditsConsumed": 18
}
}
Ролик собирается после входа: новому счёту начисляют 50 кредитов, и первый ролик идёт на них. Ставка у этой модели 18–27 кр. за секунду. Войдите, чтобы начать.
{ "model": "wan/2-7-image-to-video", "input": { "prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет", "resolution": "720p", "duration": 2 } }
Нажмите «Запустить» — готовый ролик появится здесь
Ролик делается минуты. Задача живёт не дольше 60 минут, после чего шлюз закрывает её сам и возвращает удержание целиком.
{
"code": 200,
"msg": "success",
"data": {
"taskId": "cm8r4t0vk0001s60p2xq7f9ab",
"model": "wan/2-7-image-to-video",
"state": "success",
"resultJson": "{\"resultUrls\":[\"https://file.example/result.mp4\"]}",
"failCode": "",
"failMsg": "",
"creditsConsumed": 18
}
}
Ролик собирается после входа: новому счёту начисляют 50 кредитов, и первый ролик идёт на них. Ставка у этой модели 18–27 кр. за секунду. Войдите, чтобы начать.
{ "model": "wan/2-7-r2v", "input": { "prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет", "aspect_ratio": "16:9", "resolution": "720p", "duration": 2 } }
Нажмите «Запустить» — готовый ролик появится здесь
Ролик делается минуты. Задача живёт не дольше 60 минут, после чего шлюз закрывает её сам и возвращает удержание целиком.
{
"code": 200,
"msg": "success",
"data": {
"taskId": "cm8r4t0vk0001s60p2xq7f9ab",
"model": "wan/2-7-r2v",
"state": "success",
"resultJson": "{\"resultUrls\":[\"https://file.example/result.mp4\"]}",
"failCode": "",
"failMsg": "",
"creditsConsumed": 18
}
}
Ролик собирается после входа: новому счёту начисляют 50 кредитов, и первый ролик идёт на них. Ставка у этой модели 18–27 кр. за секунду. Войдите, чтобы начать.
{ "model": "wan/2-7-videoedit", "input": { "prompt": "Заменить фон на вечернюю городскую улицу, свет тёплый", "video_url": "https://example.com/input.mp4", "aspect_ratio": "16:9", "resolution": "720p", "duration": 0 } }
Нажмите «Запустить» — готовый ролик появится здесь
Ролик делается минуты. Задача живёт не дольше 60 минут, после чего шлюз закрывает её сам и возвращает удержание целиком.
{
"code": 200,
"msg": "success",
"data": {
"taskId": "cm8r4t0vk0001s60p2xq7f9ab",
"model": "wan/2-7-videoedit",
"state": "success",
"resultJson": "{\"resultUrls\":[\"https://file.example/result.mp4\"]}",
"failCode": "",
"failMsg": "",
"creditsConsumed": 18
}
}
Цена Wan 2.7
Цена за секунду. Списывается фактический расход, о котором сообщил поставщик.
| Вариант | Наша цена | Скидка | Официальная |
|---|---|---|---|
| 720p | 18 кр. · $0.099 ₽ | −10% | $0.1 |
| 1080p | 27 кр. · $0.13513,5 ₽ | −10% | $0.15 |
В среднем на 10% ниже официальной цены поставщика. кр. — кредиты, покупаются за рубли.
Цена за секунду. Списывается фактический расход, о котором сообщил поставщик.
| Вариант | Наша цена | Скидка | Официальная |
|---|---|---|---|
| 720p | 18 кр. · $0.099 ₽ | −10% | $0.1 |
| 1080p | 27 кр. · $0.13513,5 ₽ | −10% | $0.15 |
В среднем на 10% ниже официальной цены поставщика. кр. — кредиты, покупаются за рубли.
Цена за секунду. Списывается фактический расход, о котором сообщил поставщик.
| Вариант | Наша цена | Скидка | Официальная |
|---|---|---|---|
| 720p | 18 кр. · $0.099 ₽ | −10% | $0.1 |
| 1080p | 27 кр. · $0.13513,5 ₽ | −10% | $0.15 |
В среднем на 10% ниже официальной цены поставщика. кр. — кредиты, покупаются за рубли.
Цена за секунду. Списывается фактический расход, о котором сообщил поставщик.
| Вариант | Наша цена | Скидка | Официальная |
|---|---|---|---|
| 720p | 18 кр. · $0.099 ₽ | −10% | $0.1 |
| 1080p | 27 кр. · $0.13513,5 ₽ | −10% | $0.15 |
В среднем на 10% ниже официальной цены поставщика. кр. — кредиты, покупаются за рубли.
На время работы шлюз удерживает ставку выбранного разрешения, умноженную на запрошенную длительность; больше 405 кредитов по этой модели он не удержит ни при каком запросе (duration до 15 с). Разница между удержанием и фактическим расходом возвращается на баланс тем же запросом состояния, который увидел итог.
Вызов через API
Ролик делается минуты, поэтому файл не приходит в ответ на запрос. Первый вызов
ставит задачу и сразу отвечает её номером, второй по этому номеру отдаёт состояние задачи, а когда
она готова — ссылку на результат. Ключ передаётся в обоих запросах заголовком
Authorization: Bearer sk-… и выпускается
в кабинете. На один ключ шлюз пропускает
30 постановок задачи и 300
запросов состояния в минуту.
Поля запроса
Значения проверяются до обращения к поставщику: поле не из списка модели или значение вне
перечисления возвращают 422 и кредитов не тратят.
| Поле | Тип | Обяз. | Допустимые значения |
|---|---|---|---|
| model | текст | обязательное | wan/2-7-text-to-video |
| input | объект | обязательное | Параметры генерации — поля из таблицы ниже |
Поля input
| Поле | Тип | Обяз. | Допустимые значения |
|---|---|---|---|
| prompt | текст | обязательное | от 1 до 5 000 символов |
| negative_prompt | текст | опц. | не длиннее 500 символов |
| resolution | значение из списка | опц. | 720p · 1080p |
| ratio | значение из списка | опц. | 16:9 · 9:16 · 1:1 · 4:3 · 3:4 |
| duration | целое число | опц. | целое от 2 до 15 |
| audio_url | ссылка | опц. | одна ссылка на аудио |
| prompt_extend | да или нет | опц. | true или false |
| watermark | да или нет | опц. | true или false |
| seed | целое число | опц. | целое от 0 до 2 147 483 647 |
| nsfw_checker | да или нет | опц. | true или false |
Ссылка на исходный файл принимается только полным адресом на 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": "wan/2-7-text-to-video",
"input": {
"prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет",
"resolution": "720p",
"duration": 2
}
}' | 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": "wan/2-7-text-to-video",
"input": {
"prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет",
"resolution": "720p",
"duration": 2
}
},
).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 | текст | обязательное | wan/2-7-image-to-video |
| input | объект | обязательное | Параметры генерации — поля из таблицы ниже |
Поля input
| Поле | Тип | Обяз. | Допустимые значения |
|---|---|---|---|
| prompt | текст | обязательное | от 1 до 5 000 символов |
| negative_prompt | текст | опц. | не длиннее 500 символов |
| resolution | значение из списка | опц. | 720p · 1080p |
| first_frame_url | ссылка | опц. | одна ссылка на изображение |
| last_frame_url | ссылка | опц. | одна ссылка на изображение |
| first_clip_url | ссылка | опц. | одна ссылка на видео |
| driving_audio_url | ссылка | опц. | одна ссылка на аудио |
| duration | целое число | опц. | целое от 2 до 15 |
| prompt_extend | да или нет | опц. | true или false |
| watermark | да или нет | опц. | true или false |
| seed | целое число | опц. | целое от 0 до 2 147 483 647 |
| nsfw_checker | да или нет | опц. | true или false |
Ссылка на исходный файл принимается только полным адресом на 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": "wan/2-7-image-to-video",
"input": {
"prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет",
"resolution": "720p",
"duration": 2
}
}' | 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": "wan/2-7-image-to-video",
"input": {
"prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет",
"resolution": "720p",
"duration": 2
}
},
).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 | текст | обязательное | wan/2-7-r2v |
| input | объект | обязательное | Параметры генерации — поля из таблицы ниже |
Поля input
| Поле | Тип | Обяз. | Допустимые значения |
|---|---|---|---|
| prompt | текст | обязательное | от 1 до 5 000 символов |
| negative_prompt | текст | опц. | не длиннее 500 символов |
| resolution | значение из списка | опц. | 720p · 1080p |
| reference_image | список ссылок | опц. | до 5 ссылок на изображение |
| reference_video | список ссылок | опц. | до 5 ссылок на видео |
| first_frame | ссылка | опц. | одна ссылка на изображение |
| reference_voice | ссылка | опц. | одна ссылка на аудио |
| aspect_ratio | значение из списка | опц. | 16:9 · 9:16 · 1:1 · 4:3 · 3:4 |
| duration | целое число | опц. | целое от 2 до 10 |
| prompt_extend | да или нет | опц. | true или false |
| watermark | да или нет | опц. | true или false |
| seed | целое число | опц. | целое от 0 до 2 147 483 647 |
| nsfw_checker | да или нет | опц. | true или false |
Ссылка на исходный файл принимается только полным адресом на 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": "wan/2-7-r2v",
"input": {
"prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 2
}
}' | 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": "wan/2-7-r2v",
"input": {
"prompt": "Рыжий кот в скафандре на фоне Земли, мягкий свет",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 2
}
},
).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 | текст | обязательное | wan/2-7-videoedit |
| input | объект | обязательное | Параметры генерации — поля из таблицы ниже |
Поля input
| Поле | Тип | Обяз. | Допустимые значения |
|---|---|---|---|
| video_url | ссылка | обязательное | одна ссылка на видео |
| prompt | текст | опц. | не длиннее 5 000 символов |
| negative_prompt | текст | опц. | не длиннее 500 символов |
| resolution | значение из списка | опц. | 720p · 1080p |
| reference_image | список ссылок | опц. | до 5 ссылок на изображение |
| aspect_ratio | значение из списка | опц. | 16:9 · 9:16 · 1:1 · 4:3 · 3:4 |
| duration | целое число | опц. | целое от 0 до 10 |
| audio_setting | значение из списка | опц. | auto · origin |
| prompt_extend | да или нет | опц. | true или false |
| watermark | да или нет | опц. | true или false |
| seed | целое число | опц. | целое от 0 до 2 147 483 647 |
| nsfw_checker | да или нет | опц. | true или false |
Ссылка на исходный файл принимается только полным адресом на 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": "wan/2-7-videoedit",
"input": {
"prompt": "Заменить фон на вечернюю городскую улицу, свет тёплый",
"video_url": "https://example.com/input.mp4",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 0
}
}' | 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": "wan/2-7-videoedit",
"input": {
"prompt": "Заменить фон на вечернюю городскую улицу, свет тёплый",
"video_url": "https://example.com/input.mp4",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 0
}
},
).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. В теле первого запроса стоят обязательные поля модели и значения из её
перечислений, поэтому он проходит проверку шлюза как есть.
Заменить в нём нужно два значения: свой ключ и ссылки на исходные файлы — адреса example.com стоят заполнителями, файлов по ним нет.
Пример на оболочке разбирает ответ через jq; на Python своего
ничего не нужно, кроме requests.
Остальные модели этого семейства и их поля — в разделе документации Видео.
Что делает нейросеть Wan 2.7
Wan 2.7 — нейросеть Alibaba: она снимает видео по описанию, по кадру и по образцам, а ещё правит готовое.
Работ здесь 4, и каждой отвечает своя запись каталога со своим именем в поле model: wan/2-7-text-to-video, wan/2-7-image-to-video, wan/2-7-r2v и wan/2-7-videoedit.
Новый ролик собирают режимы «текст в видео», «картинка в видео» и «по образцу», а «правка видео» переделывает готовое видео по указанию словами.
Обязательное поле у них разное: съёмке нужно описание, правке — ссылка на исходный ролик. Общих полей при этом больше, чем своих: prompt, negative_prompt, resolution, duration, prompt_extend, watermark, seed и nsfw_checker стоят у всех 4 режимов.
Можно ли скачать Wan 2.7 и снять ролик бесплатно
Wan 2.7 работает на стороне Alibaba, а запрос к ней идёт через нас — ставить и настраивать что-либо у себя не нужно. Забирают готовый ролик: под ним в песочнице появляется кнопка «Скачать», и файл приходит в mp4.
Плата считается по расходу: каждая секунда ролика стоит своих денег, и ставку поднимает разрешение. Приветственные кредиты новому счёту начисляют при первом входе, и короткий ролик снимается уже за них. Помесячной платы за доступ нет, а удержание по задаче, закончившейся отказом, возвращается на баланс целиком.
Файлами наружу выложены только ранние выпуски семейства, и считают их на своей видеокарте: какие файлы берут и сколько идёт расчёт — на странице Wan в ComfyUI. Ряд выпусков целиком, от 2.1 до 3.0, стоит на странице Wan нейросеть.
Порядок работы общий у всех 4 режимов, а разными выходят только заполненные поля.
- Выберите режим. Переключатель над формой ставит нужную запись, и от неё зависит, какие поля появятся в запросе.
- Напишите описание. В поле prompt складывают сцену, а в negative_prompt перечисляют то, чего в кадре быть не должно.
- Приложите файлы режима. Кадры, ролики и звук кладут каждый в своё поле; имена полей стоят в таблице выше.
- Задайте разрешение, длительность и форму кадра. Эти три поля решают, каким выйдет ролик, а разрешение вдобавок двигает ставку за секунду.
- Повторите удачный запуск. Поле seed возвращает прежний результат, когда описание оставляют без изменений.
Чем различаются режимы Wan 2.7
Режимы разведены тем, что кладут на вход, и тем, сколько секунд разрешено на выходе.
| Режим | Что делает | Без чего не запустится | Потолок длительности |
|---|---|---|---|
| «текст в видео» | снимает ролик по одному описанию | prompt | 15 секунд |
| «картинка в видео» | делает ролик из кадра, между двумя кадрами или продолжает присланный | prompt | 15 секунд |
| «по образцу» | держит одних и тех же героев по присланным картинкам и роликам | prompt | 10 секунд |
| «правка видео» | переделывает готовый ролик по указанию словами | video_url | 10 секунд |
Файлы разложены по своим полям: у «картинка в видео» это первый кадр, последний кадр, ролик для продолжения и звук, у «по образцу» — два списка по 5 ссылок, картинки и ролики.
Родной звук присланного ролика «правка видео» умеет оставить нетронутым — за это отвечает поле audio_setting, и образцами он берёт до 5 картинок.
Какой длины и в каком разрешении выходит ролик Wan 2.7
Потолок длительности задаёт режим: «текст в видео» и «картинка в видео» доходят до 15 секунд, «по образцу» и «правка видео» — до 10.
У правки в поле duration допускается ноль, и это не пустой ролик, а вся длина присланного.
Из разрешений доступны 720p и 1080p, и они же разводят цену секунды; строки стоят таблицей выше.
Форму кадра выбирают из 5 значений, а поле под неё называется по-разному: у режима «текст в видео» это ratio, у «по образцу» и «правка видео» — aspect_ratio. У режима «картинка в видео» такого поля нет вовсе: пропорции приходят с присланным кадром.
Что кладут в запрос Wan 2.7 кроме описания
Само описание вмещает до 5 000 знаков. Рядом стоит отрицательное описание — до 500 знаков на то, чего в кадре быть не должно.
Звук в каждом режиме заводится своим полем: audio_url при съёмке по описанию, driving_audio_url при съёмке из кадра, reference_voice при работе по образцам и audio_setting при правке готового.
Повторить прежний результат позволяет поле seed. Что кладётся в тело запроса целиком, разобрано в разделе «Wan».
Что Alibaba обещает от Wan 2.7
Продолжение ролика делается с указанием конечного кадра — ради того, чтобы движение не обрывалось на полушаге.
Работа по образцам держит одних и тех же героев от сцены к сцене: и внешность, и голос.
Правка описана двумя примерами: перевести всю сцену в пластилиновую мультипликацию и переодеть человека в одежду с присланной картинки. Там же названа смена манеры целиком.
Готовый файл приходит в MP4 с кодированием H.264.
Что в Wan 2.7 получается не с первого прогона
Справочники описывают поля запроса. Ниже — то, что всплывает уже на работе: какие сцены даются модели труднее и чем это правят.
- Быстрое движение и всё, что подчиняется физике, даётся труднее прочего: вода летит отдельно от того, кто её стряхивает, дождь застывает в воздухе, предмет в руке гнётся. Драку и бег надёжнее разложить на короткие куски с одним действием.
- Одно и то же свободное описание от прогона к прогону даёт разное. Надёжнее держать постоянный порядок — кто в кадре, что делает, как стоит камера, какой свет — и менять потом по одному слою.
- Описание с пятью действиями героя подряд выходит дёрганым, и часть заказанного в ролик не попадает. Одно действие на ролик модель выполняет точнее.
- Когда на входе свой кадр, слова про внешность мешают: возраст, цвет волос и одежды заставляют модель переписать то, что на картинке уже есть. В описании оставляют движение камеры и действие.
- В режиме из кадра оживает только то, что в кадре уже есть. Просьба про то, чего не видно, либо пропускается, либо дорисовывается наугад.
- Когда заданы и первый кадр, и последний, на середине бывает скачок, а переход к последнему выходит резким. Помогает сблизить кадры по построению и назвать движение камеры словами.
- Правка уверенно берёт одежду, свет и обстановку, а перестановка предметов в кадре и выражение лица даются ей хуже. Просить её стоит как изменение — «замени обстановку на уличное кафе, героя оставь как есть», — а не описанием желаемой картинки целиком.
- Вместе с заказанной правкой меняется и то, о чём не просили: с новой одеждой у героя уезжает лицо. В описании поэтому прямо перечисляют, что должно остаться нетронутым.
- Образцом героя надёжнее подать один чёткий лист с ним, чем набор роликов: из нескольких образцов один может просто не попасть в результат.
- Продолжение стыкуется с исходным роликом без шва: и манера съёмки, и голос переезжают в новый кусок.
Отсюда обычный порядок работы: сначала короткий кусок с одним действием, потом продолжение от его последнего кадра. Сцена набирается частями, и переснимать приходится только испорченную.