Эндпоинты замены людей в видео
Все эндпоинты /v1/videos/replacements — загрузите видео целиком, получите его кадры и людей в нём, сопоставьте каждого человека с персонажем и получите видео обратно с выполненной заменой.
Заменяйте людей в видео целиком — со склейками, несколькими кадрами и несколькими людьми. Загрузите его один раз: в нём будут найдены кадры и все люди ($0.01 за секунду видео). Затем укажите, кто кем становится — сохранённым персонажем, человеком с изображения или никем, — и заменять ли человека целиком или только голову (лицо, волосы и всё, что на ней надето). Каждый кадр с заменённым человеком заново рендерится моделью MiniMax H3; остальные кадры остаются в точности такими, как были; затем кадры склеиваются обратно поверх исходного звука.
Эндпоинты находятся по адресу https://lovelyrouter.com/v1/videos/replacements. Аутентифицируйтесь своим API-ключом в заголовке Authorization: Bearer $LOVELY_API_KEY (Аутентификация). Модели — minimax-h3-character-swap и minimax-h3-aftermidnight, на условиях MiniMax H3: каждая загрузка передаёт consent: true. Попробуйте без кода в песочнице.
Как это работает#
- Загрузка (
POST /v1/videos/replacements): видео (или его часть междуstartиend, до 3 минут) разбивается на кадры, а все люди в нём группируются в состав, у каждого — изображение лица и поясное изображение; каждый человек отслеживается во всех кадрах, поэтому находятся и те, кого видно со спины или кто отвернулся. $0.01 за проанализированную секунду (не менее 5 с), резервируется на балансе при загрузке и списывается, когда статус становитсяready; если анализ не удался — ничего. Статусanalyzing→ready. - Рендеринг (
POST …/{id}/render): сопоставьте участников состава с персонажами. Кадры без сопоставленного человека остаются как есть; остальные заново рендерятся по фрагментам (rendering) и склеиваются обратно (stitching→succeeded). Каждый фрагмент начинается и заканчивается на склейке и длится не меньше примерно 5 с: короткие кадры подряд рендерятся вместе с сохранением склеек (короткий кадр, в котором некого заменять, может быть взят заодно — он остаётся как есть и не оплачивается); разбивается только кадр длиннее 15 с, на почти равные фрагменты. - Скачивание
…/{id}/content. Фрагменты можно смотреть по мере готовности (pieces[].url).
Перед рендерингом первого кадра модель компьютерного зрения изучает изображение каждого персонажа и записывает, что на нём есть — волосы, всё, что надето на голову, очки, а в режиме замены целиком и одежду, — и чего нет («без очков, без наушников»), чтобы в каждом кадре рисовался именно этот образ и ничего лишнего. Это оплачивается как вызов чата по вашему ключу (около $0.003 за персонажа).
Перед рендерингом каждого кадра модель смотрит и слушает его, отмечает, кто говорит, и выстраивает мизансцену: где находится каждый заменяемый человек, куда он обращён и как двигается, включая руки, чтобы новый человек сохранил позу и движения исходного. В описании кадра указан говорящий, а заменённый человек, который не говорит, держит рот неподвижно, а не проговаривает чужие реплики. Это оплачивается как вызов по вашему ключу (около $0.03 за кадр).
Кто есть кто, определяется по лицам: в каждом кадре люди, которых ведёт трекер, сопоставляются с составом по лицу, поэтому человек, которого весь кадр видно только со спины, может быть там не найден — тогда этот кадр возвращается без изменений и не оплачивается.
Цены#
Оплачиваются секунды видео, где выполнена замена: секунды фрагментов, в которых кто-то действительно был заменён, — minimax-h3-character-swap $0.20 за секунду, причём каждый фрагмент с заменой считается не меньше чем за 5 секунд (он рендерится на FastH3 Omni, у которой самый короткий рендер — 5 с); minimax-h3-aftermidnight $0.12 за секунду, каждый фрагмент с заменой не меньше чем за 2 секунды, — и любое видео не меньше чем за 3 секунды. Поиск кадров и людей стоит $0.01 за секунду (списывается один раз, при загрузке; повторный запуск и шаблоны повторно не анализируют видео); кадры, оставшиеся без изменений, бесплатны. Максимально возможная стоимость (все фрагменты с сопоставленными людьми) резервируется при запуске рендеринга, а остаток возвращается по завершении.
Объект замены#
Атрибуты
idstringrpl_ и 24 символа.
objectstringВсегда video.replacement.
statusstringanalyzing, ready, rendering, stitching, succeeded, failed или cancelled.
secondssize` numberОбрабатываемая часть и её размер, после анализа.
shotsarray{index, start, end, people} — секунды и id участников состава, видимых в кадре, слева направо.
castarray{id, seconds, shots, appearances, face_url, body_url} — по одной записи на каждого найденного человека (p1, p2, …, сначала те, кто дольше в кадре).
modebackgroundПараметры, запрошенные при рендеринге.
piecesarray | nullПосле начала рендеринга: {index, shot, shots, start, seconds, people, status, swapped, missed, last_retry, url} — shot — первый кадр фрагмента, shots — все кадры в нём, kept — взятые заодно кадры, которые остаются как есть; status — pending, rendering, replaced, unchanged (никто из сопоставленных в нём не найден), kept (никого из сопоставленных в нём не было), failed или retrying. Когда фрагмент готов, swapped и missed перечисляют его сопоставленных людей, которые были и не были найдены, — фрагмент, в котором кого-то пропустили, можно повторить (см. ниже).
progressinteger | null0–100 во время рендеринга.
replaced_secondsnumber | nullСекунды с заменой (запланированные во время рендеринга, оплаченные по завершении).
holdcharge` number | nullanalysis_chargenumber — стоимость поиска людей (0 для повторного запуска)Зарезервированная сумма в долларах и сумма, списанная после расчёта.
source_urlstring | nullВидео в том виде, в каком вы его загрузили (GET …/{id}/source, вашим ключом), хранится 7 дней после загрузки; затем null.
urlstring | nullГотовый mp4, хранится 7 дней.
rerun_untilinteger | nullВремя Unix, до которого POST …/{id}/rerun может повторно запустить завершённую замену (2 дня после загрузки); иначе null.
errorobject | null{type, message} в случае сбоя.
{
"id": "rpl_5e0c2b9a7f1d4e3b8a6c0d2f",
"object": "video.replacement",
"model": "minimax-h3-character-swap",
"status": "ready",
"seconds": 32.04,
"size": "768x1344",
"shots": [
{ "index": 0, "start": 0, "end": 5.04, "people": ["p1"] },
{ "index": 1, "start": 5.04, "end": 10.04, "people": ["p3", "p2"] }
],
"cast": [
{ "id": "p1", "seconds": 14.2, "shots": [0, 2, 6], "face_url": "https://lovelyrouter.com/v1/videos/replacements/rpl_5e0c…/cast/p1/face", "body_url": "…/cast/p1/body", "appearances": [] },
{ "id": "p2", "seconds": 10, "shots": [1, 4], "face_url": "…/cast/p2/face", "body_url": "…/cast/p2/body", "appearances": [] }
],
"pieces": null,
"url": null,
"error": null,
"powered_by": "MiniMax H3"
}Загрузка видео#
/v1/videos/replacementsВозвращает 202 с объектом замены в статусе analyzing. Опрашивайте его (?wait=), пока он не перейдёт в ready.
Параметры тела запроса
modelstringОбязательноminimax-h3-character-swap или minimax-h3-aftermidnight.
videofile | stringMP4, MOV или WebM до 95 МБ: файл в multipart или URL http(s) / data:.
templatestringШаблон (rvt_…) вместо video: без загрузки и анализа, бесплатно; замена переходит в ready за несколько секунд.
consentbooleanОбязательноtrue означает принятие условий MiniMax H3.
startend` numberСекунды: обрабатываемая часть, до 3 минут. По умолчанию — всё видео (до 3 минут).
waitinteger0–300 секунд удержания запроса, пока идёт анализ.
curl https://lovelyrouter.com/v1/videos/replacements \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-F model=minimax-h3-character-swap -F consent=true \
-F video=@party.mp4 -F start=12 -F end=72Рендеринг#
/v1/videos/replacements/{id}/renderЗапускает замену для объекта в статусе ready и возвращает его в статусе rendering. Отправляйте JSON или multipart с cast в виде текстового поля JSON и изображениями в виде файлов.
Параметры тела запроса
castobjectОбязательноId участника состава → {"character_id": "chr_…"} (сохранённый персонаж), {"image": "<http(s) or data: URL>"} (изображение — в multipart "file:<part name>") или "keep". Неуказанные люди остаются как есть. До 8 человек.
modestringПо умолчанию personperson: человек заменяется целиком — лицо, волосы, тело, одежда. face: только голова — лицо, волосы и всё, что на ней надето (очки, наушники, головные уборы); тело и одежда сохраняются.
backgroundstringПо умолчанию keepkeep: каждый кадр сохраняет место действия. new (только в режиме person): каждый кадр заново придумывается в обстановке scene.
scenestringПри background: "new": где происходит действие. До 2 000 символов.
promptstringДополнительный текст для каждого кадра. До 2 000 символов.
modelstringРендерить другой моделью замены (по умолчанию — моделью загрузки).
seedintegerДля воспроизводимых результатов.
addedarrayЛюди, которых анализ пропустил (видны только со спины, слишком мелкие): [{shot, x, y, time}] — индекс кадра, где они находятся (доли кадра) и когда (секунды в той же шкале, что и в shots; по умолчанию — середина кадра). Они по порядку получают id x1, x2, …: сопоставляйте их в cast, как и всех остальных. Найти их можно в GET …/{id}/preview.
skipobjectКадры, которые нужно пропустить для конкретного человека: {"p1": [3, 7]} — индексы кадров, где анализ отнёс к этому участнику состава кого-то другого (проверяйте appearances каждого человека). Для него эти кадры остаются как есть и не оплачиваются.
curl https://lovelyrouter.com/v1/videos/replacements/RPL_ID/render \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-H "content-type: application/json" \
-d '{
"cast": {"p1": {"character_id": "chr_3b9e1f0c7a2d4e58b6c1a9f2"}, "p2": "keep"},
"mode": "face"
}'Повтор кадра#
/v1/videos/replacements/{id}/pieces/{n}/retryПовторный рендер одного фрагмента завершённой замены — для фрагмента, в котором кого-то пропустили (pieces[].missed) или заменили не того человека. В течение 2 дней после загрузки (retry_until).
searchstring, optional Кого искать, в нескольких простых словах ("man in a black suit", не больше 60 символов), вместо любого человека. Только в режиме замены целиком.pointsarray, optional[{person, x, y, time}]— указание на сопоставленного человека:x,y— доли кадра,time— секунды от начала видео (по умолчанию — середина фрагмента). Человек под этой точкой отслеживается на протяжении фрагмента.
Цена фрагмента резервируется; она списывается, только если кто-то был заменён. Пока фрагмент рендерится, видео остаётся доступным для скачивания (status rendering, затем succeeded с новым фрагментом). Повтор, который никого не нашёл или завершился сбоем, сохраняет прежнюю версию и не оплачивается (pieces[].last_retry.outcome: swapped, none или failed).
curl https://lovelyrouter.com/v1/videos/replacements/RPL_ID/pieces/0/retry \
-H "Authorization: Bearer $LOVELY_API_KEY" -H "Content-Type: application/json" \
-d '{"search": "man in a black suit", "points": [{"person": "p2", "x": 0.18, "y": 0.43, "time": 1.4}]}'Повторный запуск#
/v1/videos/replacements/{id}/rerunНовая замена на основе завершённой (succeeded, failed или cancelled): та же загрузка, сопоставление состава, изображения, режим, фон, обстановка и промпт, но с новым seed — новые дубли каждого фрагмента. Ничего не загружается и не анализируется повторно; рендеринг начинается сразу, а цена, резерв и списание такие же, как у любого рендеринга. В течение 2 дней после первой загрузки (rerun_until). Без тела запроса.
Отвечает новым объектом замены (status rendering). Первая замена остаётся как есть. Для завершённого задания, проанализированное видео которого больше не хранится, возвращается 410: загрузите видео снова.
curl -X POST https://lovelyrouter.com/v1/videos/replacements/RPL_ID/rerun \
-H "Authorization: Bearer $LOVELY_API_KEY"Сохранение как шаблона#
/v1/videos/replacements/{id}/saveСохраните проанализированное видео как шаблон, чтобы позже делать из него новые замены — заменять других людей, использовать других персонажей — без повторной загрузки и оплаты анализа. При сохранении копируются его кадры, состав и треки людей; это бесплатно, шаблон хранится, пока вы его не удалите, — до 20 на аккаунт. Сохраните в течение 2 дней после загрузки (столько хранится проанализированное видео). Тело: name (необязательно, до 80 символов; по умолчанию — имя файла).
Отвечает 202 с шаблоном в статусе saving, затем статус становится ready (от нескольких секунд до минуты). Используйте шаблон через template в POST /v1/videos/replacements.
Объект шаблона
idstringrvt_….
namestatus` stringstatus: saving, ready или failed (с error.message).
fromstringЗамена, из которой он сохранён.
secondswidthcastarray[{id, seconds, shots, face_url, body_url}] — те же id участников состава, что и в исходной замене.
GET …/templates— ваши шаблоны, сначала новые.GET …/templates/{id}— один шаблон;PATCHс{"name"}переименовывает его;DELETEудаляет его (замены, сделанные из него, сохраняют собственную копию).GET …/templates/{id}/cast/{person}/face(или/body) — изображения участников состава.
curl -X POST https://lovelyrouter.com/v1/videos/replacements/RPL_ID/save \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-H "Content-Type: application/json" -d '{"name": "Party, take 1"}'
curl https://lovelyrouter.com/v1/videos/replacements \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "minimax-h3-character-swap", "consent": true, "template": "RVT_ID"}'Получение, список и удаление#
/v1/videos/replacements/{id}Объект замены; ?wait=1–300 удерживает запрос, пока он не изменится (смена этапа или готовый фрагмент). GET /v1/videos/replacements выводит ваши замены, сначала новые (?limit=1–100, ?after=<id>).
GET …/{id}/content— готовый mp4 (поддерживаются запросыRange).GET …/{id}/pieces/{n}/content— один фрагмент с заменой, пока рендерятся остальные.GET …/{id}/source— видео в том виде, в каком вы его загрузили (отправленная часть, под исходным именем файла), в течение 7 дней.GET …/{id}/cast/{p}/faceи…/body— изображения участника состава (JPEG).GET …/{id}/preview— проанализированная часть в виде небольшого видео (640 px, со звуком) на той же шкале времени, что иshots, чтобы найти пропущенного анализом человека; хранится 2 дня.POST …/{id}/outfit— во что одет один человек, вырезанный из кадра проанализированного видео (бесплатно; чтобы нарисовать вашего персонажа в его наряде). Тело{"person": "p3"}(необязательно"shot": один из его кадров) или{"added": {"shot", "x", "y", "time"}}→202 {"call", "shot", "shots"}: использованный кадр и все кадры, где он виден, сначала лучшие (люди переодеваются между кадрами). Затем опрашивайтеGET …/{id}/outfit/{call}:202, пока идёт обработка (~10 с; ~40 с, если нужно запустить GPU), затем JPEG — только этот человек, по его собственной маске, на белом фоне, без головы (головной убор сохраняется).422: в этом кадре его плохо видно — попробуйте другой.DELETE …/{id}— до рендеринга: отбрасывает замену (больше ничего не списывается; завершённый анализ остаётся оплаченным). Во время рендеринга: останавливает его; уже заменённые фрагменты оплачиваются. После завершения: удаляет файл.
curl "https://lovelyrouter.com/v1/videos/replacements/RPL_ID?wait=60" \
-H "Authorization: Bearer $LOVELY_API_KEY"
curl https://lovelyrouter.com/v1/videos/replacements/RPL_ID/content \
-H "Authorization: Bearer $LOVELY_API_KEY" -o swapped.mp4Как получить хороший результат#
- Люди различаются по лицам: участника состава, разделённого надвое (профиль в одном кадре, анфас в другом), можно дважды сопоставить с одним и тем же персонажем.
- Для
mode: faceлучше всего подходит изображение головы персонажа; дляmode: person— изображение в полный рост или референс-лист с разворотом. - Кадры короче 2 секунд тоже обрабатываются (они рендерятся чуть длиннее и затем обрезаются).