lightricks/ltx-2-19b-lora/image-to-video14 积分起 / 5 秒视频· 图生视频LTX-2 19B LoRA 运行 Lightricks 开源的音视频模型,可加载最多三个你自己的 LoRA,包括 Lightricks 官方的运镜 LoRA。推近揭示、横向滑过场景都能稳定实现,不用再祈祷提示词能写出那个镜头。片长 5 到 20 秒,带立体声。
在 POST /jobs/createTask 里把模型名写成 lightricks/ltx-2-19b-lora/image-to-video 即可调用,14 积分/ 5 秒视频起(US$0.14)。新账户送 30 积分,可以先在 Playground 里免费试。
- 生成视频
- 图生视频
- 最高 1080p
- 5–20 秒
- 可加载自己的 LoRA
lightricks/ltx-2-19b-lora/image-to-videoPOST https://api.popnow.ai/api/v1/jobs/createTask# 1. Create the task. Keep the Idempotency-Key if you retry after a network error.
export IDEMPOTENCY_KEY="$(uuidgen)"
curl -X POST https://api.popnow.ai/api/v1/jobs/createTask \
-H "Authorization: Bearer $POPNOW_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-d '{
"model": "lightricks/ltx-2-19b-lora/image-to-video",
"input": {
"prompt": "A slow aerial shot drifting over a misty pine forest at sunrise",
"image_url": "https://media.popnow.ai/influencer/examples/marco.webp",
"resolution": "720p",
"duration_seconds": 5
}
}'
# 2. Copy data.taskId from the response, then poll until state is succeeded, failed, canceled or expired.
TASK_ID="TASK_ID_FROM_RESPONSE"
curl "https://api.popnow.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
-H "Authorization: Bearer $POPNOW_API_KEY"// Node 18+ (or any runtime with fetch). Keep the API key on your server.
const BASE = "https://api.popnow.ai/api/v1";
const headers = { Authorization: `Bearer ${process.env.POPNOW_API_KEY}` };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function call(path, init = {}) {
const res = await fetch(BASE + path, { ...init, headers: { ...headers, ...init.headers } });
const body = await res.json();
if (body.code !== 200) throw new Error(`${body.code} ${body.msg}`);
return body.data;
}
const { taskId } = await call("/jobs/createTask", {
method: "POST",
headers: { "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({
"model": "lightricks/ltx-2-19b-lora/image-to-video",
"input": {
"prompt": "A slow aerial shot drifting over a misty pine forest at sunrise",
"image_url": "https://media.popnow.ai/influencer/examples/marco.webp",
"resolution": "720p",
"duration_seconds": 5
}
}),
});
// Poll with backoff. A finished task may still be copying files: wait while an asset is pending.
let task;
for (let delay = 2000; ; delay = Math.min(delay * 1.5, 15000)) {
await sleep(delay);
task = await call(`/jobs/recordInfo?taskId=${taskId}`);
const copying = (task.output?.assets ?? []).some((a) => a.pending && !a.unavailable);
if (["succeeded", "failed", "canceled", "expired"].includes(task.state) && !copying) break;
}
if (task.state !== "succeeded") throw new Error(`${task.state}: ${task.errorMessage ?? "no detail"}`);
// Each asset has a signed url (no API key needed) that expires at expiresAt: save the file.
for (const asset of task.output.assets) console.log(asset.url);import os, time, uuid, requests
BASE = "https://api.popnow.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['POPNOW_API_KEY']}"}
def call(method, path, **kwargs):
body = requests.request(method, BASE + path, headers={**HEADERS, **kwargs.pop("headers", {})}, timeout=30, **kwargs).json()
if body["code"] != 200:
raise RuntimeError(f'{body["code"]} {body["msg"]}')
return body["data"]
task_id = call(
"POST",
"/jobs/createTask",
headers={"Idempotency-Key": str(uuid.uuid4())}, # reuse it if you retry
json={
"model": "lightricks/ltx-2-19b-lora/image-to-video",
"input": {
"prompt": "A slow aerial shot drifting over a misty pine forest at sunrise",
"image_url": "https://media.popnow.ai/influencer/examples/marco.webp",
"resolution": "720p",
"duration_seconds": 5
}
},
)["taskId"]
# Poll with backoff. A finished task may still be copying files: wait while an asset is pending.
delay = 2.0
while True:
time.sleep(delay)
task = call("GET", "/jobs/recordInfo", params={"taskId": task_id})
assets = (task.get("output") or {}).get("assets") or []
copying = any(a.get("pending") and not a.get("unavailable") for a in assets)
if task["state"] in ("succeeded", "failed", "canceled", "expired") and not copying:
break
delay = min(delay * 1.5, 15.0)
if task["state"] != "succeeded":
raise RuntimeError(f'{task["state"]}: {task.get("errorMessage", "no detail")}')
# Each asset has a signed url (no API key needed) that expires at expiresAt: save the file.
for asset in assets:
print(asset["url"])input 按下面的 Schema 生成,原样就能通过校验。把提示词和链接换成你自己的即可。
价格
| 选项 | 积分 /秒 | ≈ 美元 |
|---|---|---|
resolution 480p | 2.7 | US$0.027 |
resolution 720p | 3.6 | US$0.036 |
resolution 1080p | 5.4 | US$0.054 |
1 积分 = $0.01 · 全部选项及价格:GET /models/lightricks/ltx-2-19b-lora/image-to-video
每个任务按整数积分向上取整,所以最低档跑一次是 14 积分/ 5 秒视频(US$0.14)。
限制
- 视频时长
- 5–20 s
- 分辨率
- 480p · 720p · 1080p
参数
这些字段来自我们校验每个请求所用的同一份 Schema。没列出的字段会被拒绝。
promptstring必填Describe what happens after the opening frame: the action, the camera and the sound.
image_urlstring必填作为起点的那张图。
resolutionstring可选影响价格输出尺寸。越大越清晰,价格也越高。
duration_secondsinteger可选影响价格视频时长,按秒计费。
lorasarray<object>可选加载你自己的 LoRA,锁定风格或角色。
内部字段
loras[].pathstring必填Direct URL of a LoRA weights file.
loras[].scalenumber必填Weight strength from zero to four.
seedinteger可选用同一个数字,结果就能复现。
原始 JSON Schema
{
"additionalProperties": false,
"properties": {
"duration_seconds": {
"default": 5,
"description": "Requested output length in whole seconds, from 5 to 20.",
"maximum": 20,
"minimum": 5,
"type": "integer"
},
"image_url": {
"contentMediaType": [
"image/jpeg",
"image/png",
"image/webp",
"image/gif"
],
"description": "Opening frame. The clip starts from this image and keeps its aspect ratio.",
"format": "uri",
"type": "string"
},
"loras": {
"default": [],
"description": "Up to three LoRA weight files trained for LTX-2 19B, each with its own strength. Files over 2 GiB are rejected.",
"items": {
"additionalProperties": false,
"properties": {
"path": {
"contentMediaType": [
"application/octet-stream"
],
"description": "Direct URL of a LoRA weights file.",
"format": "uri",
"minLength": 1,
"type": "string"
},
"scale": {
"default": 1,
"description": "Weight strength from zero to four.",
"maximum": 4,
"minimum": 0,
"type": "number"
}
},
"required": [
"path",
"scale"
],
"type": "object"
},
"maxItems": 3,
"type": "array"
},
"prompt": {
"description": "Describe what happens after the opening frame: the action, the camera and the sound.",
"minLength": 1,
"type": "string"
},
"resolution": {
"default": "720p",
"description": "Output resolution.",
"enum": [
"480p",
"720p",
"1080p"
],
"type": "string"
},
"seed": {
"description": "Random seed for controlled comparisons, not a frame-identical guarantee.",
"maximum": 2147483647,
"minimum": 0,
"type": "integer"
}
},
"required": [
"prompt",
"image_url"
],
"type": "object"
}LTX-2 19B LoRA 的真实成片
They stay where they are, holding hands and laughing softly; one swirls her bare foot through the shallows and a trail of blue sparks follows it. The camera dollies out slowly from the two of them to reveal the whole dark cave glowing around them and the starlit mouth beyond. Audio: waves booming and echoing in the cave, water lapping, drops falling from the roof, their soft laughter echoing.
{
"model": "lightricks/ltx-2-19b-lora/image-to-video",
"input": {
"prompt": "They stay where they are, holding hands and laughing softly; one swirls her bare foot through the shallows and a trail of blue sparks follows it. The camera dollies out slowly from the two of them to reveal the whole dark cave glowing around them and the starlit mouth beyond. Audio: waves booming and echoing in the cave, water lapping, drops falling from the roof, their soft laughter echoing.",
"image_url": "https://media.popnow.ai/influencer/examples/marco.webp",
"resolution": "720p",
"duration_seconds": 5,
"seed": 510526
}
}这条是从上传的文件开始的:把示例链接换成你自己的文件链接。
响应、轮询与回调
所有模型的用法都一样:先建任务,再轮询,或者等回调。
先报价
curl -X POST https://api.popnow.ai/api/v1/jobs/quote \
-H "Authorization: Bearer $POPNOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "lightricks/ltx-2-19b-lora/image-to-video",
"input": {
"prompt": "A slow aerial shot drifting over a misty pine forest at sunrise",
"image_url": "https://media.popnow.ai/influencer/examples/marco.webp",
"resolution": "720p",
"duration_seconds": 5
}
}'请求体和 createTask 相同。它返回预计扣费和最高可能扣费,不会真正运行。
已受理
HTTP/1.1 202 Accepted
{
"code": 200,
"msg": "success",
"data": {
"taskId": "task_01k3m8x9q2z4v7n5p6r8s0t1w3",
"state": "queued"
},
"request_id": "req_example_create"
}HTTP 202 表示任务已受理,积分先冻结、还没有扣。最终扣费不会超过冻结额。
查询状态
curl "https://api.popnow.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
-H "Authorization: Bearer $POPNOW_API_KEY"每隔几秒查一次并逐步拉长间隔,state 变成 succeeded、failed、canceled 或 expired 时停止。
完成的任务
{
"code": 200,
"msg": "success",
"data": {
"taskId": "task_01k3m8x9q2z4v7n5p6r8s0t1w3",
"model": "lightricks/ltx-2-19b-lora/image-to-video",
"state": "succeeded",
"output": {
"assets": [
{
"url": "https://cdn.popnow.ai/tasks/task_01k3m8x9q2z4v7n5p6r8s0t1w3/output.mp4?signature=FROM_RESPONSE",
"expiresAt": "2026-10-17T12:20:00Z",
"mime": "video/mp4",
"width": 1280,
"height": 720,
"durationSeconds": 5
}
]
},
"settled": true
},
"request_id": "req_example_record"
}在 expiresAt 之前从 url 下载。之后要新链接,请调用 POST /common/download-url。
校验回调
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
import express from "express";
const app = express();
// express.raw keeps the exact bytes that were signed; express.json would not match.
app.post("/hooks/popnow", express.raw({ type: "application/json" }), (req, res) => {
const timestamp = req.header("X-Webhook-Timestamp");
const signature = req.header("X-Webhook-Signature") ?? "";
const body = JSON.parse(req.body.toString("utf8"));
const taskId = body.data?.taskId ?? body.task_id;
const digest = createHash("sha256").update(req.body).digest("hex");
const expected = createHmac("sha256", process.env.POPNOW_WEBHOOK_SECRET)
.update(`${taskId}.${timestamp}.${digest}`)
.digest("base64");
const ok = expected.length === signature.length && timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
// Check the signature first, then reject anything older than five minutes.
if (!ok || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return res.status(401).end();
res.status(200).end(); // answer fast, then fetch the task and store its files
});设置了 callBackUrl,我们会把完成的任务发给你。先用原始请求体校验签名,再信任它。
上传本地文件
curl -X POST https://api.popnow.ai/api/v1/common/upload-url \
-H "Authorization: Bearer $POPNOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"contentType": "image/png", "bytes": 482113}'
# PUT the file bytes to data.uploadUrl with every header in data.headers, then commit it:
curl -X POST https://api.popnow.ai/api/v1/files/$FILE_ID/commit \
-H "Authorization: Bearer $POPNOW_API_KEY"
# The commit returns a popnow://f/... reference. Put it in any image, video or
# audio field of the task input instead of a public https URL.公开的 https 链接可以直接用。本地文件要先经过 upload-url 和 commit。

