@amaster.ai/pi-video-gen 0.1.2-beta.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +196 -0
- package/dist/compose.d.ts +43 -0
- package/dist/compose.d.ts.map +1 -0
- package/dist/compose.js +308 -0
- package/dist/compose.js.map +1 -0
- package/dist/config.d.ts +29 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +305 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +50 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +99 -0
- package/dist/errors.js.map +1 -0
- package/dist/ffmpeg.d.ts +64 -0
- package/dist/ffmpeg.d.ts.map +1 -0
- package/dist/ffmpeg.js +292 -0
- package/dist/ffmpeg.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +837 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs/store.d.ts +124 -0
- package/dist/jobs/store.d.ts.map +1 -0
- package/dist/jobs/store.js +386 -0
- package/dist/jobs/store.js.map +1 -0
- package/dist/providers/ark.d.ts +26 -0
- package/dist/providers/ark.d.ts.map +1 -0
- package/dist/providers/ark.js +178 -0
- package/dist/providers/ark.js.map +1 -0
- package/dist/providers/dashscope.d.ts +28 -0
- package/dist/providers/dashscope.d.ts.map +1 -0
- package/dist/providers/dashscope.js +200 -0
- package/dist/providers/dashscope.js.map +1 -0
- package/dist/providers/kling.d.ts +46 -0
- package/dist/providers/kling.d.ts.map +1 -0
- package/dist/providers/kling.js +245 -0
- package/dist/providers/kling.js.map +1 -0
- package/dist/providers/models.d.ts +16 -0
- package/dist/providers/models.d.ts.map +1 -0
- package/dist/providers/models.js +152 -0
- package/dist/providers/models.js.map +1 -0
- package/dist/providers/newapi.d.ts +3 -0
- package/dist/providers/newapi.d.ts.map +1 -0
- package/dist/providers/newapi.js +203 -0
- package/dist/providers/newapi.js.map +1 -0
- package/dist/providers/openrouter.d.ts +21 -0
- package/dist/providers/openrouter.d.ts.map +1 -0
- package/dist/providers/openrouter.js +169 -0
- package/dist/providers/openrouter.js.map +1 -0
- package/dist/providers/request.d.ts +4 -0
- package/dist/providers/request.d.ts.map +1 -0
- package/dist/providers/request.js +20 -0
- package/dist/providers/request.js.map +1 -0
- package/dist/providers/task.d.ts +53 -0
- package/dist/providers/task.d.ts.map +1 -0
- package/dist/providers/task.js +209 -0
- package/dist/providers/task.js.map +1 -0
- package/dist/render.d.ts +53 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +480 -0
- package/dist/render.js.map +1 -0
- package/dist/text-layer.d.ts +18 -0
- package/dist/text-layer.d.ts.map +1 -0
- package/dist/text-layer.js +168 -0
- package/dist/text-layer.js.map +1 -0
- package/dist/timeline-render.d.ts +33 -0
- package/dist/timeline-render.d.ts.map +1 -0
- package/dist/timeline-render.js +1051 -0
- package/dist/timeline-render.js.map +1 -0
- package/dist/timeline.d.ts +64 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +246 -0
- package/dist/timeline.js.map +1 -0
- package/dist/tts/edge-tts.d.ts +22 -0
- package/dist/tts/edge-tts.d.ts.map +1 -0
- package/dist/tts/edge-tts.js +55 -0
- package/dist/tts/edge-tts.js.map +1 -0
- package/dist/types.d.ts +161 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/package.json +93 -0
- package/preview.png +0 -0
- package/skills/video-gen/SKILL.md +284 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { extname } from 'node:path';
|
|
3
|
+
import { AmbiguousSubmitError, httpStatusError, missingKeyError, networkError, RemoteTaskNotFoundError, safeBasename, VideoGenError, } from '../errors.js';
|
|
4
|
+
import { requestFingerprint } from './request.js';
|
|
5
|
+
import { CancelledError, downloadFile } from './task.js';
|
|
6
|
+
/**
|
|
7
|
+
* Kling (Kuaishou) video generation — official Kling API 2.0.
|
|
8
|
+
*
|
|
9
|
+
* POST {baseUrl}/text-to-video/{model} { prompt, settings, options }
|
|
10
|
+
* POST {baseUrl}/image-to-video/{model} { contents, settings, options }
|
|
11
|
+
* GET {baseUrl}/tasks?task_ids={id} → data[0].status / outputs[].url
|
|
12
|
+
*
|
|
13
|
+
* Verified against the official docs (kling.ai/document-api, 2026-07):
|
|
14
|
+
* - Auth: `Authorization: Bearer {apiKey}` — the older JWT ak/sk scheme is legacy.
|
|
15
|
+
* - The model lives in the PATH (`kling-3.0-turbo`, `kling-3.0`), not the body.
|
|
16
|
+
* - t2v takes a plain `prompt` string; i2v takes a `contents` array
|
|
17
|
+
* (prompt + first_frame [+ last_frame]). i2v follows the frame's ratio, so
|
|
18
|
+
* aspect_ratio is t2v-only.
|
|
19
|
+
* - `options.external_task_id` is a client-provided, account-unique id that is
|
|
20
|
+
* QUERYABLE (GET /tasks?external_task_ids=…) — we set it to our request
|
|
21
|
+
* fingerprint, so an ambiguous submit failure can be resolved by lookup
|
|
22
|
+
* instead of blindly resubmitting a paid task. See recoverByExternalId().
|
|
23
|
+
* - Kling 3.0 (Omni) adds last_frame, audio: "native"|"off", and 4k; the 3.0
|
|
24
|
+
* Turbo is first-frame-only and silent.
|
|
25
|
+
* - Default base is api-singapore.klingai.com (the documented current domain);
|
|
26
|
+
* China-region accounts can point baseUrl at their regional endpoint.
|
|
27
|
+
*/
|
|
28
|
+
export const KLING_DEFAULT_BASE_URL = 'https://api-singapore.klingai.com';
|
|
29
|
+
const MIME_BY_EXT = {
|
|
30
|
+
'.png': 'image/png',
|
|
31
|
+
'.jpg': 'image/jpeg',
|
|
32
|
+
'.jpeg': 'image/jpeg',
|
|
33
|
+
};
|
|
34
|
+
async function imageFileToDataUri(path) {
|
|
35
|
+
const mime = MIME_BY_EXT[extname(path).toLowerCase()];
|
|
36
|
+
if (!mime) {
|
|
37
|
+
throw new VideoGenError(`Reference image must be png/jpg (Kling accepts no webp): ${safeBasename(path)}`, 'kling: unsupported image extension');
|
|
38
|
+
}
|
|
39
|
+
let bytes;
|
|
40
|
+
try {
|
|
41
|
+
bytes = await readFile(path);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
throw new VideoGenError(`Reference image is not readable: ${safeBasename(path)}`, 'kling: image unreadable');
|
|
45
|
+
}
|
|
46
|
+
return `data:${mime};base64,${bytes.toString('base64')}`;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Shared ambiguous-outcome resolver with THREE honest results:
|
|
50
|
+
* - found: the task exists — adopt its handle (no double billing);
|
|
51
|
+
* - not-found: lookup CONFIRMED nothing was created — safe to retry;
|
|
52
|
+
* - unknown: lookup itself failed/timed out — a paid task MAY exist;
|
|
53
|
+
* the message must warn, not reassure. On user-cancel the same
|
|
54
|
+
* distinction applies instead of a bare CancelledError.
|
|
55
|
+
*/
|
|
56
|
+
async function resolveAmbiguous(provider, fp, taskType, fetchImpl, signal) {
|
|
57
|
+
const r = await tryRecoverByExternalId(provider, fp, taskType, fetchImpl);
|
|
58
|
+
if (r.outcome === 'found')
|
|
59
|
+
return r.handle;
|
|
60
|
+
if (signal?.aborted) {
|
|
61
|
+
if (r.outcome === 'not-found')
|
|
62
|
+
throw new CancelledError();
|
|
63
|
+
throw new AmbiguousSubmitError('Cancelled before we could verify whether the task was created. A paid task MAY exist — check the Kling console for this external id before retrying, or you may be billed twice.', 'kling submit: aborted, recovery unknown');
|
|
64
|
+
}
|
|
65
|
+
if (r.outcome === 'not-found') {
|
|
66
|
+
throw new VideoGenError('Task creation failed, but a lookup by external id confirmed NO task was created — nothing was billed. Safe to retry once.', 'kling submit: failed, verified not created');
|
|
67
|
+
}
|
|
68
|
+
throw new AmbiguousSubmitError('Task creation failed with an ambiguous result and the idempotency lookup could not complete. A paid task MAY exist — check the Kling console before retrying to avoid double billing.', 'kling submit: ambiguous, recovery unknown');
|
|
69
|
+
}
|
|
70
|
+
function checkEnvelope(envelope, action) {
|
|
71
|
+
if (envelope.code !== 0) {
|
|
72
|
+
throw new VideoGenError(`Kling ${action} rejected the request (code ${envelope.code ?? 'unknown'}). Check the model name and parameters.`, `kling ${action}: code ${envelope.code ?? 'unknown'}`);
|
|
73
|
+
}
|
|
74
|
+
return envelope.data;
|
|
75
|
+
}
|
|
76
|
+
function mapTask(task, handle) {
|
|
77
|
+
switch (task.status) {
|
|
78
|
+
case 'submitted':
|
|
79
|
+
return { phase: 'pending' };
|
|
80
|
+
case 'processing':
|
|
81
|
+
return { phase: 'running' };
|
|
82
|
+
case 'succeeded': {
|
|
83
|
+
const videoUrl = task.outputs?.find((o) => o.type === 'video')?.url;
|
|
84
|
+
if (!videoUrl) {
|
|
85
|
+
throw new VideoGenError('The task succeeded but returned no video URL. Report this with the task id.', 'kling inspect: succeeded without url');
|
|
86
|
+
}
|
|
87
|
+
return { phase: 'succeeded', videoUrl };
|
|
88
|
+
}
|
|
89
|
+
case 'failed':
|
|
90
|
+
return { phase: 'failed', message: task.message ?? 'unknown provider error' };
|
|
91
|
+
default:
|
|
92
|
+
throw new VideoGenError(`The provider returned an unknown task status. Task id kept for support: ${handle.taskId}.`, 'kling inspect: unknown status');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export const klingAdapter = {
|
|
96
|
+
async submit(provider, remoteModelId, params, fetchImpl, signal) {
|
|
97
|
+
if (!provider.apiKey)
|
|
98
|
+
throw missingKeyError('kling', 'KLING_API_KEY', provider.apiKeyPath);
|
|
99
|
+
const taskType = params.firstFramePath ? 'image-to-video' : 'text-to-video';
|
|
100
|
+
const fp = requestFingerprint(remoteModelId, params);
|
|
101
|
+
const settings = {};
|
|
102
|
+
if (params.resolution)
|
|
103
|
+
settings.resolution = params.resolution;
|
|
104
|
+
if (params.durationSec != null)
|
|
105
|
+
settings.duration = params.durationSec;
|
|
106
|
+
if (params.generateAudio === true)
|
|
107
|
+
settings.audio = 'native';
|
|
108
|
+
const body = {
|
|
109
|
+
settings,
|
|
110
|
+
options: { external_task_id: fp, watermark_info: { enabled: false } },
|
|
111
|
+
};
|
|
112
|
+
if (taskType === 'text-to-video') {
|
|
113
|
+
body.prompt = params.prompt;
|
|
114
|
+
if (params.aspectRatio)
|
|
115
|
+
settings.aspect_ratio = params.aspectRatio;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
const contents = [{ type: 'prompt', text: params.prompt }];
|
|
119
|
+
contents.push({ type: 'first_frame', url: await imageFileToDataUri(params.firstFramePath) });
|
|
120
|
+
if (params.lastFramePath) {
|
|
121
|
+
contents.push({ type: 'last_frame', url: await imageFileToDataUri(params.lastFramePath) });
|
|
122
|
+
}
|
|
123
|
+
body.contents = contents;
|
|
124
|
+
}
|
|
125
|
+
let res;
|
|
126
|
+
try {
|
|
127
|
+
res = await fetchImpl(`${provider.baseUrl}/${taskType}/${remoteModelId}`, {
|
|
128
|
+
method: 'POST',
|
|
129
|
+
headers: {
|
|
130
|
+
authorization: `Bearer ${provider.apiKey}`,
|
|
131
|
+
'content-type': 'application/json',
|
|
132
|
+
},
|
|
133
|
+
body: JSON.stringify(body),
|
|
134
|
+
signal: signal ?? null,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// Network failure = ambiguous. Recover via external-id lookup (fresh
|
|
139
|
+
// timeout, never the caller's possibly-aborted signal).
|
|
140
|
+
return resolveAmbiguous(provider, fp, taskType, fetchImpl, signal);
|
|
141
|
+
}
|
|
142
|
+
if (!res.ok) {
|
|
143
|
+
if (res.status >= 500) {
|
|
144
|
+
return resolveAmbiguous(provider, fp, taskType, fetchImpl, signal);
|
|
145
|
+
}
|
|
146
|
+
throw httpStatusError('kling', 'submit', res.status);
|
|
147
|
+
}
|
|
148
|
+
// Body read/parse failures are JUST as ambiguous as a dead connection —
|
|
149
|
+
// the task may already exist. Recover the same way.
|
|
150
|
+
let taskId;
|
|
151
|
+
try {
|
|
152
|
+
const json = (await res.json());
|
|
153
|
+
taskId = checkEnvelope(json, 'submit').id;
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
if (error instanceof VideoGenError && error.logSummary.startsWith('kling submit: code'))
|
|
157
|
+
throw error;
|
|
158
|
+
return resolveAmbiguous(provider, fp, taskType, fetchImpl, signal);
|
|
159
|
+
}
|
|
160
|
+
if (!taskId) {
|
|
161
|
+
// 2xx but no id: the task MAY exist server-side — this is ambiguous,
|
|
162
|
+
// not a clean failure, and must park the shot rather than re-submit.
|
|
163
|
+
throw new AmbiguousSubmitError('The provider accepted the request but returned no task id. Not retrying automatically; check the Kling console.', 'kling submit: no task id');
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
taskId,
|
|
167
|
+
submittedAt: new Date().toISOString(),
|
|
168
|
+
requestFingerprint: fp,
|
|
169
|
+
meta: { taskType },
|
|
170
|
+
};
|
|
171
|
+
},
|
|
172
|
+
async inspect(provider, handle, fetchImpl, signal) {
|
|
173
|
+
if (!provider.apiKey)
|
|
174
|
+
throw missingKeyError('kling', 'KLING_API_KEY', provider.apiKeyPath);
|
|
175
|
+
let res;
|
|
176
|
+
try {
|
|
177
|
+
res = await fetchImpl(`${provider.baseUrl}/tasks?task_ids=${encodeURIComponent(handle.taskId)}`, {
|
|
178
|
+
headers: { authorization: `Bearer ${provider.apiKey}` },
|
|
179
|
+
signal: signal ?? null,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
throw networkError('kling', 'inspect');
|
|
184
|
+
}
|
|
185
|
+
if (!res.ok)
|
|
186
|
+
throw httpStatusError('kling', 'inspect', res.status);
|
|
187
|
+
const json = (await res.json());
|
|
188
|
+
const tasks = checkEnvelope(json, 'inspect');
|
|
189
|
+
const task = Array.isArray(tasks) ? tasks.find((t) => t.id === handle.taskId) : undefined;
|
|
190
|
+
if (!task) {
|
|
191
|
+
throw new RemoteTaskNotFoundError(`Task ${handle.taskId} not found on the provider (results are cleared after 30 days). Start a fresh generation.`, 'kling inspect: task not found');
|
|
192
|
+
}
|
|
193
|
+
return mapTask(task, handle);
|
|
194
|
+
},
|
|
195
|
+
async downloadTo(_provider, _handle, videoUrl, destPath, fetchImpl, signal) {
|
|
196
|
+
return downloadFile({ url: videoUrl, destPath, fetchImpl, signal });
|
|
197
|
+
},
|
|
198
|
+
// cancel: no documented task-cancellation endpoint on Kling API 2.0.
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Best-effort idempotency lookup with its OWN short timeout — the caller's
|
|
202
|
+
* signal may already be aborted (that's why we're here), and the lookup must
|
|
203
|
+
* still run to tell whether a paid task exists. Returns null on any failure;
|
|
204
|
+
* callers decide between CancelledError (user aborted) and ambiguous error.
|
|
205
|
+
*/
|
|
206
|
+
/** Exported for tests: the lookup deadline is injectable (default 10s). */
|
|
207
|
+
export async function tryRecoverByExternalId(provider, fp, taskType, fetchImpl, timeoutMs = 10_000) {
|
|
208
|
+
try {
|
|
209
|
+
const res = await fetchImpl(`${provider.baseUrl}/tasks?external_task_ids=${fp}`, {
|
|
210
|
+
headers: { authorization: `Bearer ${provider.apiKey}` },
|
|
211
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
212
|
+
});
|
|
213
|
+
if (!res.ok)
|
|
214
|
+
return { outcome: 'unknown' };
|
|
215
|
+
let json;
|
|
216
|
+
try {
|
|
217
|
+
json = (await res.json());
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
return { outcome: 'unknown' };
|
|
221
|
+
}
|
|
222
|
+
// STRICT shape: a provider-side error envelope ({code: 50001, message:
|
|
223
|
+
// "busy"}) or a data payload that is not a task list tells us NOTHING
|
|
224
|
+
// about task existence — it must read as 'unknown', never as the
|
|
225
|
+
// confident 'not-found' (which green-lights a retry).
|
|
226
|
+
if (json.code !== 0 || !Array.isArray(json.data))
|
|
227
|
+
return { outcome: 'unknown' };
|
|
228
|
+
const existing = json.data.find((t) => t.id);
|
|
229
|
+
if (!existing?.id)
|
|
230
|
+
return { outcome: 'not-found' };
|
|
231
|
+
return {
|
|
232
|
+
outcome: 'found',
|
|
233
|
+
handle: {
|
|
234
|
+
taskId: existing.id,
|
|
235
|
+
submittedAt: new Date().toISOString(),
|
|
236
|
+
requestFingerprint: fp,
|
|
237
|
+
meta: { taskType },
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return { outcome: 'unknown' };
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=kling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kling.js","sourceRoot":"","sources":["../../src/providers/kling.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { BuiltInVideoModel } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Built-in video model registry. Only models with a published request contract
|
|
4
|
+
* belong here — no placeholders for announced-but-undocumented models
|
|
5
|
+
* (Seedance 2.5 stays on the roadmap until its API ID and parameter contract
|
|
6
|
+
* are officially published).
|
|
7
|
+
*
|
|
8
|
+
* Capability values reflect provider documentation as of 2026-07 and are
|
|
9
|
+
* PENDING live verification (run /video-gen doctor + a small paid clip):
|
|
10
|
+
* - Seedance 2.0: https://www.volcengine.com/docs/82379/1520757
|
|
11
|
+
* - HappyHorse: https://help.aliyun.com/zh/model-studio/happyhorse-text-to-video-api-reference
|
|
12
|
+
*/
|
|
13
|
+
export declare const BUILT_IN_VIDEO_MODELS: BuiltInVideoModel[];
|
|
14
|
+
/** Resolve a model id or alias against the built-in registry. */
|
|
15
|
+
export declare function findBuiltInModel(idOrAlias: string): BuiltInVideoModel | undefined;
|
|
16
|
+
//# sourceMappingURL=models.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/providers/models.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,EAAE,iBAAiB,EAsIpD,CAAC;AAEF,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAKjF"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in video model registry. Only models with a published request contract
|
|
3
|
+
* belong here — no placeholders for announced-but-undocumented models
|
|
4
|
+
* (Seedance 2.5 stays on the roadmap until its API ID and parameter contract
|
|
5
|
+
* are officially published).
|
|
6
|
+
*
|
|
7
|
+
* Capability values reflect provider documentation as of 2026-07 and are
|
|
8
|
+
* PENDING live verification (run /video-gen doctor + a small paid clip):
|
|
9
|
+
* - Seedance 2.0: https://www.volcengine.com/docs/82379/1520757
|
|
10
|
+
* - HappyHorse: https://help.aliyun.com/zh/model-studio/happyhorse-text-to-video-api-reference
|
|
11
|
+
*/
|
|
12
|
+
export const BUILT_IN_VIDEO_MODELS = [
|
|
13
|
+
{
|
|
14
|
+
id: 'doubao-seedance-2-0-260128',
|
|
15
|
+
aliases: ['seedance', 'seedance-2.0', 'seedance-std'],
|
|
16
|
+
provider: 'ark',
|
|
17
|
+
capabilities: {
|
|
18
|
+
maxReferenceImages: 9,
|
|
19
|
+
durations: [4, 15],
|
|
20
|
+
resolutions: ['480p', '720p', '1080p'],
|
|
21
|
+
aspectRatios: ['16:9', '4:3', '1:1', '3:4', '9:16', '21:9', 'adaptive'],
|
|
22
|
+
nativeAudio: true,
|
|
23
|
+
supportsFirstLastFrame: true,
|
|
24
|
+
},
|
|
25
|
+
defaultResolution: '1080p',
|
|
26
|
+
defaultAspectRatio: '16:9',
|
|
27
|
+
defaultDurationSec: 5,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: 'doubao-seedance-2-0-fast-260128',
|
|
31
|
+
aliases: ['seedance-fast'],
|
|
32
|
+
provider: 'ark',
|
|
33
|
+
capabilities: {
|
|
34
|
+
maxReferenceImages: 9,
|
|
35
|
+
durations: [4, 15],
|
|
36
|
+
resolutions: ['480p', '720p'],
|
|
37
|
+
aspectRatios: ['16:9', '4:3', '1:1', '3:4', '9:16', '21:9', 'adaptive'],
|
|
38
|
+
nativeAudio: true,
|
|
39
|
+
supportsFirstLastFrame: true,
|
|
40
|
+
},
|
|
41
|
+
defaultResolution: '720p',
|
|
42
|
+
defaultAspectRatio: '16:9',
|
|
43
|
+
defaultDurationSec: 5,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 'happyhorse-1.1',
|
|
47
|
+
aliases: ['happyhorse', 'happyhorse-1.1'],
|
|
48
|
+
provider: 'dashscope',
|
|
49
|
+
capabilities: {
|
|
50
|
+
maxReferenceImages: 9,
|
|
51
|
+
durations: [3, 15],
|
|
52
|
+
resolutions: ['720P', '1080P'],
|
|
53
|
+
aspectRatios: ['16:9', '9:16', '1:1', '4:3', '3:4', '4:5', '5:4', '9:21', '21:9'],
|
|
54
|
+
nativeAudio: false,
|
|
55
|
+
supportsFirstLastFrame: false,
|
|
56
|
+
},
|
|
57
|
+
defaultResolution: '1080P',
|
|
58
|
+
defaultAspectRatio: '16:9',
|
|
59
|
+
defaultDurationSec: 5,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: 'happyhorse-1.0',
|
|
63
|
+
aliases: ['happyhorse-1.0'],
|
|
64
|
+
provider: 'dashscope',
|
|
65
|
+
capabilities: {
|
|
66
|
+
maxReferenceImages: 9,
|
|
67
|
+
durations: [3, 15],
|
|
68
|
+
resolutions: ['720P', '1080P'],
|
|
69
|
+
aspectRatios: ['16:9', '9:16', '1:1', '4:3', '3:4', '4:5', '5:4', '9:21', '21:9'],
|
|
70
|
+
nativeAudio: false,
|
|
71
|
+
supportsFirstLastFrame: false,
|
|
72
|
+
},
|
|
73
|
+
defaultResolution: '1080P',
|
|
74
|
+
defaultAspectRatio: '16:9',
|
|
75
|
+
defaultDurationSec: 5,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
// Verified against kling.ai/document-api (2026-07): model id is the URL
|
|
79
|
+
// path segment. Turbo: first-frame only, silent, 720p/1080p.
|
|
80
|
+
id: 'kling-3.0-turbo',
|
|
81
|
+
aliases: ['kling', 'kling-turbo', 'kling-v3-turbo'],
|
|
82
|
+
provider: 'kling',
|
|
83
|
+
capabilities: {
|
|
84
|
+
maxReferenceImages: 1,
|
|
85
|
+
durations: [3, 15],
|
|
86
|
+
resolutions: ['720p', '1080p'],
|
|
87
|
+
aspectRatios: ['16:9', '9:16', '1:1'],
|
|
88
|
+
nativeAudio: false,
|
|
89
|
+
supportsFirstLastFrame: false,
|
|
90
|
+
},
|
|
91
|
+
defaultResolution: '1080p',
|
|
92
|
+
defaultAspectRatio: '16:9',
|
|
93
|
+
defaultDurationSec: 5,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
// Kling 3.0 "Omni": last_frame, native audio, 4k.
|
|
97
|
+
id: 'kling-3.0',
|
|
98
|
+
aliases: ['kling-omni', 'kling-v3-omni', 'kling-3.0-omni'],
|
|
99
|
+
provider: 'kling',
|
|
100
|
+
capabilities: {
|
|
101
|
+
maxReferenceImages: 2,
|
|
102
|
+
durations: [3, 15],
|
|
103
|
+
resolutions: ['720p', '1080p', '4k'],
|
|
104
|
+
aspectRatios: ['16:9', '9:16', '1:1'],
|
|
105
|
+
nativeAudio: true,
|
|
106
|
+
supportsFirstLastFrame: true,
|
|
107
|
+
},
|
|
108
|
+
defaultResolution: '1080p',
|
|
109
|
+
defaultAspectRatio: '16:9',
|
|
110
|
+
defaultDurationSec: 5,
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
// Per OpenRouter docs example (2026-07): 5s/8s, 720p, 16:9, audio, flf.
|
|
114
|
+
// Live list: GET https://openrouter.ai/api/v1/videos/models
|
|
115
|
+
id: 'google/veo-3.1',
|
|
116
|
+
aliases: ['veo', 'veo-3.1'],
|
|
117
|
+
provider: 'openrouter',
|
|
118
|
+
capabilities: {
|
|
119
|
+
maxReferenceImages: 2,
|
|
120
|
+
durations: [5, 8],
|
|
121
|
+
resolutions: ['720p'],
|
|
122
|
+
aspectRatios: ['16:9'],
|
|
123
|
+
nativeAudio: true,
|
|
124
|
+
supportsFirstLastFrame: true,
|
|
125
|
+
},
|
|
126
|
+
defaultResolution: '720p',
|
|
127
|
+
defaultAspectRatio: '16:9',
|
|
128
|
+
defaultDurationSec: 8,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: 'doubao-seedance-2-0-mini-260615',
|
|
132
|
+
aliases: ['seedance-mini'],
|
|
133
|
+
provider: 'ark',
|
|
134
|
+
capabilities: {
|
|
135
|
+
maxReferenceImages: 9,
|
|
136
|
+
durations: [4, 15],
|
|
137
|
+
resolutions: ['480p', '720p'],
|
|
138
|
+
aspectRatios: ['16:9', '4:3', '1:1', '3:4', '9:16', '21:9', 'adaptive'],
|
|
139
|
+
nativeAudio: true,
|
|
140
|
+
supportsFirstLastFrame: true,
|
|
141
|
+
},
|
|
142
|
+
defaultResolution: '720p',
|
|
143
|
+
defaultAspectRatio: '16:9',
|
|
144
|
+
defaultDurationSec: 5,
|
|
145
|
+
},
|
|
146
|
+
];
|
|
147
|
+
/** Resolve a model id or alias against the built-in registry. */
|
|
148
|
+
export function findBuiltInModel(idOrAlias) {
|
|
149
|
+
const needle = idOrAlias.trim().toLowerCase();
|
|
150
|
+
return BUILT_IN_VIDEO_MODELS.find((m) => m.id.toLowerCase() === needle || m.aliases.some((a) => a.toLowerCase() === needle));
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/providers/models.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"newapi.d.ts","sourceRoot":"","sources":["../../src/providers/newapi.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAIV,oBAAoB,EACrB,MAAM,aAAa,CAAC;AAsGrB,eAAO,MAAM,aAAa,EAAE,oBA2I3B,CAAC"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { extname } from 'node:path';
|
|
3
|
+
import { AmbiguousSubmitError, httpStatusError, missingKeyError, networkError, safeBasename, VideoGenError, } from '../errors.js';
|
|
4
|
+
import { requestFingerprint } from './request.js';
|
|
5
|
+
import { downloadFile } from './task.js';
|
|
6
|
+
/**
|
|
7
|
+
* NewAPI video generation format (self-hosted OpenAI-compatible relay:
|
|
8
|
+
* Kling / Jimeng / Gemini / Vidu channels behind one shape).
|
|
9
|
+
*
|
|
10
|
+
* POST {baseUrl}/v1/video/generations → 201 { id, task_id, status }
|
|
11
|
+
* GET {baseUrl}/v1/video/generations/{task_id} → { status, url, error }
|
|
12
|
+
*
|
|
13
|
+
* Verified against the official docs (newapi.ai/zh/docs/api/ai-model/videos,
|
|
14
|
+
* 2026-07 — createvideogeneration + getvideogeneration):
|
|
15
|
+
* - NewAPI is self-hosted, so this wire format has NO default endpoint —
|
|
16
|
+
* baseUrl is mandatory and the config layer rejects resolution without it.
|
|
17
|
+
* Both the server root ("https://host") and the OpenAI-style
|
|
18
|
+
* "https://host/v1" forms are accepted (a trailing /v1 is normalized away).
|
|
19
|
+
* - Top-level params per the docs: model/prompt (required), duration, fps,
|
|
20
|
+
* width/height, image (URL or Base64), metadata, n, response_format, seed,
|
|
21
|
+
* user. Everything channel-specific rides in `metadata` — following the
|
|
22
|
+
* doc examples we send aspect_ratio + resolution (Jimeng/Vidu style),
|
|
23
|
+
* image_tail (Kling style) and image_urls (Jimeng style) there.
|
|
24
|
+
* - Submit returns BOTH `id` and `task_id`; the query endpoint keys on
|
|
25
|
+
* `task_id`, so we prefer it and fall back to `id`.
|
|
26
|
+
* - Query status enum: queued | processing | in_progress | succeeded |
|
|
27
|
+
* failed; the mp4 URL arrives in `url` on success.
|
|
28
|
+
* - No audio toggle and no client idempotency key are documented: a
|
|
29
|
+
* capability-driven generateAudio is NOT forwarded, and ambiguous submit
|
|
30
|
+
* failures get the "check the console before retrying" treatment (same as
|
|
31
|
+
* Ark/OpenRouter).
|
|
32
|
+
*
|
|
33
|
+
* TWO response shapes exist in the wild (verified against a live NewAPI
|
|
34
|
+
* relay, 2026-07): channels proxied in the documented OpenAI-compatible way
|
|
35
|
+
* answer FLAT ({status: "succeeded", url, error}), while channels routed
|
|
36
|
+
* through NewAPI's task framework (Kling/Jimeng/Seedance-as-task) answer
|
|
37
|
+
* with the framework ENVELOPE:
|
|
38
|
+
*
|
|
39
|
+
* {code: "success", message,
|
|
40
|
+
* data: {task_id, status: "IN_PROGRESS"|"SUCCESS"|"FAILURE"|…, progress,
|
|
41
|
+
* fail_reason, result_url, data: {<raw upstream response>}}}
|
|
42
|
+
*
|
|
43
|
+
* i.e. uppercase framework statuses, the mp4 in `result_url` (or nested in
|
|
44
|
+
* the upstream payload at `data.data.content.video_url` for Ark upstreams),
|
|
45
|
+
* and the failure text in `fail_reason`. unwrapTaskRecord() peels the
|
|
46
|
+
* envelope once and the status mapping is case-insensitive, so both shapes
|
|
47
|
+
* parse identically.
|
|
48
|
+
*/
|
|
49
|
+
const MIME_BY_EXT = {
|
|
50
|
+
'.png': 'image/png',
|
|
51
|
+
'.jpg': 'image/jpeg',
|
|
52
|
+
'.jpeg': 'image/jpeg',
|
|
53
|
+
'.webp': 'image/webp',
|
|
54
|
+
};
|
|
55
|
+
async function imageFileToDataUri(path) {
|
|
56
|
+
const mime = MIME_BY_EXT[extname(path).toLowerCase()];
|
|
57
|
+
if (!mime) {
|
|
58
|
+
throw new VideoGenError(`Reference image must be png/jpg/webp: ${safeBasename(path)}`, 'newapi: unsupported image extension');
|
|
59
|
+
}
|
|
60
|
+
let bytes;
|
|
61
|
+
try {
|
|
62
|
+
bytes = await readFile(path);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
throw new VideoGenError(`Reference image is not readable: ${safeBasename(path)}`, 'newapi: image unreadable');
|
|
66
|
+
}
|
|
67
|
+
return `data:${mime};base64,${bytes.toString('base64')}`;
|
|
68
|
+
}
|
|
69
|
+
/** Server root for the API paths: trims trailing slashes and one trailing /v1. */
|
|
70
|
+
function serverRoot(baseUrl) {
|
|
71
|
+
return baseUrl.replace(/\/+$/, '').replace(/\/v1$/i, '');
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Peel the NewAPI task-framework envelope `{code, message, data}` ONE layer
|
|
75
|
+
* when present, returning the bare task record. Flat documented responses
|
|
76
|
+
* (and the nested upstream payload at `record.data`, which must NOT be
|
|
77
|
+
* peeled) pass through untouched: only a root `code` alongside an object
|
|
78
|
+
* `data` marks the envelope.
|
|
79
|
+
*/
|
|
80
|
+
function unwrapTaskRecord(json) {
|
|
81
|
+
const data = json.data;
|
|
82
|
+
if (json.code !== undefined && data != null && typeof data === 'object' && !Array.isArray(data)) {
|
|
83
|
+
return data;
|
|
84
|
+
}
|
|
85
|
+
return json;
|
|
86
|
+
}
|
|
87
|
+
function ambiguousSubmitError() {
|
|
88
|
+
return new AmbiguousSubmitError('Task creation failed with an ambiguous result (network error or server 5xx). The provider MAY have created a paid task — check the NewAPI logs/console before retrying to avoid double billing.', 'newapi submit: ambiguous outcome');
|
|
89
|
+
}
|
|
90
|
+
export const newapiAdapter = {
|
|
91
|
+
async submit(provider, remoteModelId, params, fetchImpl, signal) {
|
|
92
|
+
if (!provider.apiKey)
|
|
93
|
+
throw missingKeyError('newapi', 'NEWAPI_API_KEY', provider.apiKeyPath);
|
|
94
|
+
const body = { model: remoteModelId, prompt: params.prompt };
|
|
95
|
+
if (params.durationSec != null)
|
|
96
|
+
body.duration = params.durationSec;
|
|
97
|
+
if (params.firstFramePath) {
|
|
98
|
+
body.image = await imageFileToDataUri(params.firstFramePath);
|
|
99
|
+
}
|
|
100
|
+
const metadata = {};
|
|
101
|
+
if (params.aspectRatio)
|
|
102
|
+
metadata.aspect_ratio = params.aspectRatio;
|
|
103
|
+
if (params.resolution)
|
|
104
|
+
metadata.resolution = params.resolution;
|
|
105
|
+
if (params.lastFramePath) {
|
|
106
|
+
metadata.image_tail = await imageFileToDataUri(params.lastFramePath);
|
|
107
|
+
}
|
|
108
|
+
if (params.referenceImagePaths?.length) {
|
|
109
|
+
metadata.image_urls = await Promise.all(params.referenceImagePaths.map((path) => imageFileToDataUri(path)));
|
|
110
|
+
}
|
|
111
|
+
if (Object.keys(metadata).length > 0)
|
|
112
|
+
body.metadata = metadata;
|
|
113
|
+
let res;
|
|
114
|
+
try {
|
|
115
|
+
res = await fetchImpl(`${serverRoot(provider.baseUrl)}/v1/video/generations`, {
|
|
116
|
+
method: 'POST',
|
|
117
|
+
headers: {
|
|
118
|
+
authorization: `Bearer ${provider.apiKey}`,
|
|
119
|
+
'content-type': 'application/json',
|
|
120
|
+
},
|
|
121
|
+
body: JSON.stringify(body),
|
|
122
|
+
signal: signal ?? null,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
throw ambiguousSubmitError();
|
|
127
|
+
}
|
|
128
|
+
if (!res.ok) {
|
|
129
|
+
if (res.status >= 500)
|
|
130
|
+
throw ambiguousSubmitError();
|
|
131
|
+
throw httpStatusError('newapi', 'submit', res.status);
|
|
132
|
+
}
|
|
133
|
+
let taskId;
|
|
134
|
+
try {
|
|
135
|
+
const rec = unwrapTaskRecord((await res.json()));
|
|
136
|
+
taskId = (rec.task_id ?? rec.id);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
throw ambiguousSubmitError();
|
|
140
|
+
}
|
|
141
|
+
if (!taskId) {
|
|
142
|
+
// 2xx but no id: the task MAY exist server-side — this is ambiguous,
|
|
143
|
+
// not a clean failure, and must park the shot rather than re-submit.
|
|
144
|
+
throw new AmbiguousSubmitError('The provider accepted the request but returned no task id. Not retrying automatically; check the NewAPI logs/console.', 'newapi submit: no task id');
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
taskId,
|
|
148
|
+
submittedAt: new Date().toISOString(),
|
|
149
|
+
requestFingerprint: requestFingerprint(remoteModelId, params),
|
|
150
|
+
};
|
|
151
|
+
},
|
|
152
|
+
async inspect(provider, handle, fetchImpl, signal) {
|
|
153
|
+
if (!provider.apiKey)
|
|
154
|
+
throw missingKeyError('newapi', 'NEWAPI_API_KEY', provider.apiKeyPath);
|
|
155
|
+
let res;
|
|
156
|
+
try {
|
|
157
|
+
res = await fetchImpl(`${serverRoot(provider.baseUrl)}/v1/video/generations/${encodeURIComponent(handle.taskId)}`, {
|
|
158
|
+
headers: { authorization: `Bearer ${provider.apiKey}` },
|
|
159
|
+
signal: signal ?? null,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
throw networkError('newapi', 'inspect');
|
|
164
|
+
}
|
|
165
|
+
if (!res.ok)
|
|
166
|
+
throw httpStatusError('newapi', 'inspect', res.status);
|
|
167
|
+
const rec = unwrapTaskRecord((await res.json()));
|
|
168
|
+
// Case-insensitive: flat form uses lowercase, the task framework UPPERCASE.
|
|
169
|
+
switch (rec.status?.toUpperCase()) {
|
|
170
|
+
case 'QUEUED':
|
|
171
|
+
case 'SUBMITTED':
|
|
172
|
+
return { phase: 'pending' };
|
|
173
|
+
case 'PROCESSING':
|
|
174
|
+
case 'IN_PROGRESS':
|
|
175
|
+
return { phase: 'running' };
|
|
176
|
+
case 'SUCCEEDED':
|
|
177
|
+
case 'SUCCESS':
|
|
178
|
+
case 'COMPLETED': {
|
|
179
|
+
const videoUrl = rec.result_url ?? rec.url ?? rec.data?.content?.video_url;
|
|
180
|
+
if (!videoUrl) {
|
|
181
|
+
throw new VideoGenError('The task succeeded but returned no video URL. Report this with the task id.', 'newapi inspect: succeeded without url');
|
|
182
|
+
}
|
|
183
|
+
return { phase: 'succeeded', videoUrl };
|
|
184
|
+
}
|
|
185
|
+
case 'FAILED':
|
|
186
|
+
case 'FAILURE':
|
|
187
|
+
case 'CANCELLED':
|
|
188
|
+
case 'EXPIRED': {
|
|
189
|
+
const message = rec.fail_reason ||
|
|
190
|
+
(typeof rec.error === 'string' ? rec.error : rec.error?.message) ||
|
|
191
|
+
'unknown provider error';
|
|
192
|
+
return { phase: 'failed', message };
|
|
193
|
+
}
|
|
194
|
+
default:
|
|
195
|
+
throw new VideoGenError(`The provider returned an unknown task status. Task id kept for support: ${handle.taskId}.`, 'newapi inspect: unknown status');
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
async downloadTo(_provider, _handle, videoUrl, destPath, fetchImpl, signal) {
|
|
199
|
+
return downloadFile({ url: videoUrl, destPath, fetchImpl, signal });
|
|
200
|
+
},
|
|
201
|
+
// cancel: no documented task-cancellation endpoint in the NewAPI video format.
|
|
202
|
+
};
|
|
203
|
+
//# sourceMappingURL=newapi.js.map
|