@shop-os/modelkit 0.4.4 → 0.4.6
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/CHANGELOG.md +10 -0
- package/README.md +4 -0
- package/dist/catalog.cjs +23 -6
- package/dist/catalog.cjs.map +1 -1
- package/dist/catalog.js +23 -6
- package/dist/catalog.js.map +1 -1
- package/dist/index.cjs +178 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +178 -101
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1144,6 +1144,8 @@ interface Adapter {
|
|
|
1144
1144
|
id: string;
|
|
1145
1145
|
generateImage?(req: ImageRequest, ctx: AdapterContext): Promise<ImageResult>;
|
|
1146
1146
|
generateVideo?(req: VideoRequest, ctx: AdapterContext): Promise<VideoJob>;
|
|
1147
|
+
/** Reconnect to a job `generateVideo` submitted earlier; never submits. */
|
|
1148
|
+
resumeVideo?(req: VideoRequest, jobId: string, ctx: AdapterContext): VideoJob;
|
|
1147
1149
|
generateAudio?(req: AudioRequest, ctx: AdapterContext): Promise<AudioResult>;
|
|
1148
1150
|
/** Video tools run as provider jobs the caller tracks; see ModelKit.submitVideoTool. */
|
|
1149
1151
|
submitVideoTool?(req: VideoToolRequest, ctx: AdapterContext, opts: {
|
|
@@ -1350,6 +1352,12 @@ interface ModelKit extends TextMethods {
|
|
|
1350
1352
|
* `model` is a catalog id or an AI SDK video model instance.
|
|
1351
1353
|
*/
|
|
1352
1354
|
generateVideo(req: VideoCallOptions, call?: CallContext): Promise<VideoCallJob>;
|
|
1355
|
+
/**
|
|
1356
|
+
* Reconnect to a video job submitted earlier with `generateVideo` (same request), by its
|
|
1357
|
+
* `jobId`. Never submits a new job. Await `job.result()` as usual; usage is emitted once.
|
|
1358
|
+
* A resumed job reports only the resumed wait in `latencyMs`.
|
|
1359
|
+
*/
|
|
1360
|
+
resumeVideo(req: VideoCallOptions, jobId: string, call?: CallContext): Promise<VideoCallJob>;
|
|
1353
1361
|
/** AI SDK LanguageModel for chat models. Pair with the catalog's providerOptions. */
|
|
1354
1362
|
languageModel(modelId: string, call?: CallContext): LanguageModelHandle;
|
|
1355
1363
|
/** Usage-event `provider` for a catalog model, without building it: "bedrock" on Bedrock, else the vendor. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1144,6 +1144,8 @@ interface Adapter {
|
|
|
1144
1144
|
id: string;
|
|
1145
1145
|
generateImage?(req: ImageRequest, ctx: AdapterContext): Promise<ImageResult>;
|
|
1146
1146
|
generateVideo?(req: VideoRequest, ctx: AdapterContext): Promise<VideoJob>;
|
|
1147
|
+
/** Reconnect to a job `generateVideo` submitted earlier; never submits. */
|
|
1148
|
+
resumeVideo?(req: VideoRequest, jobId: string, ctx: AdapterContext): VideoJob;
|
|
1147
1149
|
generateAudio?(req: AudioRequest, ctx: AdapterContext): Promise<AudioResult>;
|
|
1148
1150
|
/** Video tools run as provider jobs the caller tracks; see ModelKit.submitVideoTool. */
|
|
1149
1151
|
submitVideoTool?(req: VideoToolRequest, ctx: AdapterContext, opts: {
|
|
@@ -1350,6 +1352,12 @@ interface ModelKit extends TextMethods {
|
|
|
1350
1352
|
* `model` is a catalog id or an AI SDK video model instance.
|
|
1351
1353
|
*/
|
|
1352
1354
|
generateVideo(req: VideoCallOptions, call?: CallContext): Promise<VideoCallJob>;
|
|
1355
|
+
/**
|
|
1356
|
+
* Reconnect to a video job submitted earlier with `generateVideo` (same request), by its
|
|
1357
|
+
* `jobId`. Never submits a new job. Await `job.result()` as usual; usage is emitted once.
|
|
1358
|
+
* A resumed job reports only the resumed wait in `latencyMs`.
|
|
1359
|
+
*/
|
|
1360
|
+
resumeVideo(req: VideoCallOptions, jobId: string, call?: CallContext): Promise<VideoCallJob>;
|
|
1353
1361
|
/** AI SDK LanguageModel for chat models. Pair with the catalog's providerOptions. */
|
|
1354
1362
|
languageModel(modelId: string, call?: CallContext): LanguageModelHandle;
|
|
1355
1363
|
/** Usage-event `provider` for a catalog model, without building it: "bedrock" on Bedrock, else the vendor. */
|
package/dist/index.js
CHANGED
|
@@ -3651,6 +3651,11 @@ var arkAdapter = {
|
|
|
3651
3651
|
async generateVideo(req, ctx) {
|
|
3652
3652
|
throwIfAborted(ctx.signal);
|
|
3653
3653
|
return generateSeedanceVideo(req, ctx);
|
|
3654
|
+
},
|
|
3655
|
+
resumeVideo(req, jobId, ctx) {
|
|
3656
|
+
throwIfAborted(ctx.signal);
|
|
3657
|
+
const key = arkKey(ctx);
|
|
3658
|
+
return seedanceJob(ctx, key, jobId, seedanceUsage(ctx, req, seedanceInitialDuration(req)));
|
|
3654
3659
|
}
|
|
3655
3660
|
};
|
|
3656
3661
|
function arkKey(ctx) {
|
|
@@ -3820,6 +3825,9 @@ function seedanceUsage(ctx, req, duration) {
|
|
|
3820
3825
|
if (req.resolution !== void 0) usage2.resolution = req.resolution;
|
|
3821
3826
|
return usage2;
|
|
3822
3827
|
}
|
|
3828
|
+
function seedanceInitialDuration(req) {
|
|
3829
|
+
return req.durationSeconds ?? 5;
|
|
3830
|
+
}
|
|
3823
3831
|
function seedanceErrorMessage(error, status) {
|
|
3824
3832
|
const asString = z7.string().safeParse(error);
|
|
3825
3833
|
if (asString.success) return asString.data;
|
|
@@ -3827,6 +3835,78 @@ function seedanceErrorMessage(error, status) {
|
|
|
3827
3835
|
if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
|
|
3828
3836
|
return `Seedance task ${status}`;
|
|
3829
3837
|
}
|
|
3838
|
+
function seedanceJob(ctx, key, jobId, usage2) {
|
|
3839
|
+
const modelId = ctx.model.id;
|
|
3840
|
+
const fetchStatus = async () => {
|
|
3841
|
+
const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
|
|
3842
|
+
headers: { Authorization: `Bearer ${key}` }
|
|
3843
|
+
});
|
|
3844
|
+
if (!res.ok) {
|
|
3845
|
+
if (ctx.call.maxRetries !== 0 && (res.status === 429 || res.status >= 500))
|
|
3846
|
+
return void 0;
|
|
3847
|
+
const text2 = await res.text().catch(() => "");
|
|
3848
|
+
throwArkError(res.status, text2, modelId);
|
|
3849
|
+
}
|
|
3850
|
+
const parsed = SeedanceResponseSchema.safeParse(await res.json());
|
|
3851
|
+
if (!parsed.success) return {};
|
|
3852
|
+
return parsed.data;
|
|
3853
|
+
};
|
|
3854
|
+
return {
|
|
3855
|
+
jobId,
|
|
3856
|
+
async poll() {
|
|
3857
|
+
const polled = await fetchStatus();
|
|
3858
|
+
if (!polled) return { status: "running" };
|
|
3859
|
+
const status = (polled.status ?? "queued").toLowerCase();
|
|
3860
|
+
if (status === "succeeded") return { status: "succeeded", raw: polled };
|
|
3861
|
+
if (status === "failed" || status === "expired" || status === "cancelled") {
|
|
3862
|
+
return { status: "failed", raw: polled };
|
|
3863
|
+
}
|
|
3864
|
+
if (status === "queued" || status === "pending")
|
|
3865
|
+
return { status: "pending", raw: polled };
|
|
3866
|
+
return { status: "running", raw: polled };
|
|
3867
|
+
},
|
|
3868
|
+
async result(opts) {
|
|
3869
|
+
const optSignal = opts?.signal ?? ctx.signal;
|
|
3870
|
+
const pollOpts = {
|
|
3871
|
+
intervalMs: opts?.pollIntervalMs ?? SEEDANCE_POLL_INTERVAL_MS,
|
|
3872
|
+
timeoutMs: opts?.timeoutMs ?? RESULT_TIMEOUT_MS
|
|
3873
|
+
};
|
|
3874
|
+
if (optSignal !== void 0) pollOpts.signal = optSignal;
|
|
3875
|
+
return pollUntil(async () => {
|
|
3876
|
+
const polled = await fetchStatus();
|
|
3877
|
+
if (!polled) return void 0;
|
|
3878
|
+
const status = (polled.status ?? "queued").toLowerCase();
|
|
3879
|
+
if (status === "succeeded") {
|
|
3880
|
+
const url = polled.content?.video_url;
|
|
3881
|
+
if (!url)
|
|
3882
|
+
throwArkError(
|
|
3883
|
+
void 0,
|
|
3884
|
+
"Seedance task succeeded but returned no video_url",
|
|
3885
|
+
modelId
|
|
3886
|
+
);
|
|
3887
|
+
if (polled.duration !== void 0 && polled.duration > 0) {
|
|
3888
|
+
usage2.quantity = polled.duration;
|
|
3889
|
+
usage2.durationSeconds = polled.duration;
|
|
3890
|
+
}
|
|
3891
|
+
const tokens = polled.usage;
|
|
3892
|
+
if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
|
|
3893
|
+
usage2.inputTokens = tokens.total_tokens - tokens.completion_tokens;
|
|
3894
|
+
usage2.outputTokens = tokens.completion_tokens;
|
|
3895
|
+
}
|
|
3896
|
+
return {
|
|
3897
|
+
video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
|
|
3898
|
+
usage: usage2,
|
|
3899
|
+
raw: polled
|
|
3900
|
+
};
|
|
3901
|
+
}
|
|
3902
|
+
if (status === "failed" || status === "expired" || status === "cancelled") {
|
|
3903
|
+
throwArkError(void 0, seedanceErrorMessage(polled.error, status), modelId);
|
|
3904
|
+
}
|
|
3905
|
+
return void 0;
|
|
3906
|
+
}, pollOpts);
|
|
3907
|
+
}
|
|
3908
|
+
};
|
|
3909
|
+
}
|
|
3830
3910
|
async function generateSeedanceVideo(req, ctx) {
|
|
3831
3911
|
const modelId = ctx.model.id;
|
|
3832
3912
|
const taskType = req.taskType;
|
|
@@ -3841,7 +3921,7 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
3841
3921
|
});
|
|
3842
3922
|
}
|
|
3843
3923
|
const key = arkKey(ctx);
|
|
3844
|
-
const requestedDuration = req
|
|
3924
|
+
const requestedDuration = seedanceInitialDuration(req);
|
|
3845
3925
|
let duration = requestedDuration;
|
|
3846
3926
|
if (taskType === "edit") duration = -1;
|
|
3847
3927
|
const resolution = req.resolution ?? "720p";
|
|
@@ -3922,75 +4002,7 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
3922
4002
|
if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
|
|
3923
4003
|
const jobId = submit.id;
|
|
3924
4004
|
const usage2 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
|
|
3925
|
-
|
|
3926
|
-
const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
|
|
3927
|
-
headers: { Authorization: `Bearer ${key}` }
|
|
3928
|
-
});
|
|
3929
|
-
if (!res.ok) {
|
|
3930
|
-
if (ctx.call.maxRetries !== 0 && (res.status === 429 || res.status >= 500))
|
|
3931
|
-
return void 0;
|
|
3932
|
-
const text2 = await res.text().catch(() => "");
|
|
3933
|
-
throwArkError(res.status, text2, modelId);
|
|
3934
|
-
}
|
|
3935
|
-
const parsed = SeedanceResponseSchema.safeParse(await res.json());
|
|
3936
|
-
if (!parsed.success) return {};
|
|
3937
|
-
return parsed.data;
|
|
3938
|
-
};
|
|
3939
|
-
return {
|
|
3940
|
-
jobId,
|
|
3941
|
-
async poll() {
|
|
3942
|
-
const polled = await fetchStatus();
|
|
3943
|
-
if (!polled) return { status: "running" };
|
|
3944
|
-
const status = (polled.status ?? "queued").toLowerCase();
|
|
3945
|
-
if (status === "succeeded") return { status: "succeeded", raw: polled };
|
|
3946
|
-
if (status === "failed" || status === "expired" || status === "cancelled") {
|
|
3947
|
-
return { status: "failed", raw: polled };
|
|
3948
|
-
}
|
|
3949
|
-
if (status === "queued" || status === "pending")
|
|
3950
|
-
return { status: "pending", raw: polled };
|
|
3951
|
-
return { status: "running", raw: polled };
|
|
3952
|
-
},
|
|
3953
|
-
async result(opts) {
|
|
3954
|
-
const optSignal = opts?.signal ?? ctx.signal;
|
|
3955
|
-
const pollOpts = {
|
|
3956
|
-
intervalMs: opts?.pollIntervalMs ?? SEEDANCE_POLL_INTERVAL_MS,
|
|
3957
|
-
timeoutMs: opts?.timeoutMs ?? RESULT_TIMEOUT_MS
|
|
3958
|
-
};
|
|
3959
|
-
if (optSignal !== void 0) pollOpts.signal = optSignal;
|
|
3960
|
-
return pollUntil(async () => {
|
|
3961
|
-
const polled = await fetchStatus();
|
|
3962
|
-
if (!polled) return void 0;
|
|
3963
|
-
const status = (polled.status ?? "queued").toLowerCase();
|
|
3964
|
-
if (status === "succeeded") {
|
|
3965
|
-
const url = polled.content?.video_url;
|
|
3966
|
-
if (!url)
|
|
3967
|
-
throwArkError(
|
|
3968
|
-
void 0,
|
|
3969
|
-
"Seedance task succeeded but returned no video_url",
|
|
3970
|
-
modelId
|
|
3971
|
-
);
|
|
3972
|
-
if (polled.duration !== void 0 && polled.duration > 0) {
|
|
3973
|
-
usage2.quantity = polled.duration;
|
|
3974
|
-
usage2.durationSeconds = polled.duration;
|
|
3975
|
-
}
|
|
3976
|
-
const tokens = polled.usage;
|
|
3977
|
-
if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
|
|
3978
|
-
usage2.inputTokens = tokens.total_tokens - tokens.completion_tokens;
|
|
3979
|
-
usage2.outputTokens = tokens.completion_tokens;
|
|
3980
|
-
}
|
|
3981
|
-
return {
|
|
3982
|
-
video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
|
|
3983
|
-
usage: usage2,
|
|
3984
|
-
raw: polled
|
|
3985
|
-
};
|
|
3986
|
-
}
|
|
3987
|
-
if (status === "failed" || status === "expired" || status === "cancelled") {
|
|
3988
|
-
throwArkError(void 0, seedanceErrorMessage(polled.error, status), modelId);
|
|
3989
|
-
}
|
|
3990
|
-
return void 0;
|
|
3991
|
-
}, pollOpts);
|
|
3992
|
-
}
|
|
3993
|
-
};
|
|
4005
|
+
return seedanceJob(ctx, key, jobId, usage2);
|
|
3994
4006
|
}
|
|
3995
4007
|
|
|
3996
4008
|
// src/adapters/fal.ts
|
|
@@ -4132,6 +4144,20 @@ import { z as z11 } from "zod";
|
|
|
4132
4144
|
|
|
4133
4145
|
// src/catalog/video-tools-spec.ts
|
|
4134
4146
|
import { z as z10 } from "zod";
|
|
4147
|
+
|
|
4148
|
+
// src/video-length.ts
|
|
4149
|
+
function tenths(seconds2) {
|
|
4150
|
+
return Math.round(seconds2 * 10) / 10;
|
|
4151
|
+
}
|
|
4152
|
+
function overMax(seconds2, max) {
|
|
4153
|
+
return seconds2 > max && tenths(seconds2) > max;
|
|
4154
|
+
}
|
|
4155
|
+
function overTotal(lengths, total) {
|
|
4156
|
+
const sum = (values) => values.reduce((acc, len) => acc + len, 0);
|
|
4157
|
+
return sum(lengths) > total && tenths(sum(lengths.map(tenths))) > total;
|
|
4158
|
+
}
|
|
4159
|
+
|
|
4160
|
+
// src/catalog/video-tools-spec.ts
|
|
4135
4161
|
var RangeSchema2 = z10.object({ min: z10.number(), max: z10.number() });
|
|
4136
4162
|
var ToolSchema = z10.object({
|
|
4137
4163
|
kind: z10.enum(["upscale", "interpolate", "hdr"]),
|
|
@@ -4175,7 +4201,7 @@ function planVideoTool(row, req) {
|
|
|
4175
4201
|
return fail("The source video's width, height and duration are required");
|
|
4176
4202
|
}
|
|
4177
4203
|
const maxSeconds = row.constraints.sourceVideoSeconds?.max;
|
|
4178
|
-
if (maxSeconds !== void 0 && durationSeconds
|
|
4204
|
+
if (maxSeconds !== void 0 && overMax(durationSeconds, maxSeconds)) {
|
|
4179
4205
|
return fail(`${row.label} takes source videos up to ${maxSeconds} seconds.`);
|
|
4180
4206
|
}
|
|
4181
4207
|
const base = {
|
|
@@ -8579,7 +8605,7 @@ function videoLengthViolation(model, input) {
|
|
|
8579
8605
|
const lengths = (input.referenceVideos ?? []).map(knownLength);
|
|
8580
8606
|
if (limits?.max !== void 0) {
|
|
8581
8607
|
const max = limits.max;
|
|
8582
|
-
const i = lengths.findIndex((len) => len !== void 0 && len
|
|
8608
|
+
const i = lengths.findIndex((len) => len !== void 0 && overMax(len, max));
|
|
8583
8609
|
if (i >= 0)
|
|
8584
8610
|
return `${model.label} takes reference videos up to ${String(max)} s each; video ${i + 1} is ${seconds(lengths[i], max)} s.`;
|
|
8585
8611
|
}
|
|
@@ -8591,14 +8617,17 @@ function videoLengthViolation(model, input) {
|
|
|
8591
8617
|
const source = knownLength(input.sourceVideo);
|
|
8592
8618
|
const sourceLimits = model.constraints.sourceVideoSeconds;
|
|
8593
8619
|
if (limits?.total !== void 0) {
|
|
8594
|
-
const
|
|
8595
|
-
|
|
8596
|
-
|
|
8620
|
+
const counted = [
|
|
8621
|
+
...lengths.filter((len) => len !== void 0),
|
|
8622
|
+
...sourceLimits?.inReferenceTotal && source !== void 0 ? [source] : []
|
|
8623
|
+
];
|
|
8624
|
+
const sum = counted.reduce((acc, len) => acc + len, 0);
|
|
8625
|
+
if (overTotal(counted, limits.total))
|
|
8597
8626
|
return `${model.label} takes reference videos up to ${String(limits.total)} s combined; these add up to ${seconds(sum, limits.total)} s.`;
|
|
8598
8627
|
}
|
|
8599
8628
|
if (source === void 0) return void 0;
|
|
8600
8629
|
const sourceMin = effectiveMin(sourceLimits, input.taskType);
|
|
8601
|
-
if (sourceLimits?.max !== void 0 && source
|
|
8630
|
+
if (sourceLimits?.max !== void 0 && overMax(source, sourceLimits.max))
|
|
8602
8631
|
return `${model.label} takes a source video up to ${String(sourceLimits.max)} s; this one is ${seconds(source, sourceLimits.max)} s.`;
|
|
8603
8632
|
if (sourceMin !== void 0 && source < sourceMin)
|
|
8604
8633
|
return `${model.label} takes a source video of at least ${String(sourceMin)} s; this one is ${seconds(source, sourceMin)} s.`;
|
|
@@ -9562,6 +9591,33 @@ function createModelKit(config, adapters) {
|
|
|
9562
9591
|
result: () => done
|
|
9563
9592
|
};
|
|
9564
9593
|
}
|
|
9594
|
+
function wrapVideoJob(model, job, warnings, startedAt) {
|
|
9595
|
+
const result = job.result.bind(job);
|
|
9596
|
+
let settled;
|
|
9597
|
+
return {
|
|
9598
|
+
...job,
|
|
9599
|
+
warnings,
|
|
9600
|
+
result(opts) {
|
|
9601
|
+
if (settled) return settled;
|
|
9602
|
+
const pending = result(opts).then(
|
|
9603
|
+
async (out) => {
|
|
9604
|
+
const usage2 = timed(
|
|
9605
|
+
{ ...out.usage, model: model.id, unit: model.usage.unit },
|
|
9606
|
+
startedAt
|
|
9607
|
+
);
|
|
9608
|
+
await emit(usage2);
|
|
9609
|
+
return { ...out, usage: usage2 };
|
|
9610
|
+
},
|
|
9611
|
+
(cause) => {
|
|
9612
|
+
settled = void 0;
|
|
9613
|
+
throw cause;
|
|
9614
|
+
}
|
|
9615
|
+
);
|
|
9616
|
+
settled = pending;
|
|
9617
|
+
return pending;
|
|
9618
|
+
}
|
|
9619
|
+
};
|
|
9620
|
+
}
|
|
9565
9621
|
return {
|
|
9566
9622
|
catalog,
|
|
9567
9623
|
describe: (id) => catalog.require(id),
|
|
@@ -9646,31 +9702,52 @@ function createModelKit(config, adapters) {
|
|
|
9646
9702
|
});
|
|
9647
9703
|
const startedAt = Date.now();
|
|
9648
9704
|
const job = await adapter.generateVideo(request, ctx);
|
|
9649
|
-
|
|
9650
|
-
|
|
9651
|
-
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
|
|
9655
|
-
|
|
9656
|
-
|
|
9657
|
-
|
|
9658
|
-
|
|
9659
|
-
|
|
9660
|
-
|
|
9661
|
-
|
|
9662
|
-
|
|
9663
|
-
|
|
9664
|
-
|
|
9665
|
-
|
|
9666
|
-
|
|
9667
|
-
|
|
9668
|
-
|
|
9669
|
-
|
|
9670
|
-
|
|
9671
|
-
|
|
9672
|
-
}
|
|
9673
|
-
}
|
|
9705
|
+
return wrapVideoJob(model, job, warnings, startedAt);
|
|
9706
|
+
},
|
|
9707
|
+
async resumeVideo(req, jobId, call = {}) {
|
|
9708
|
+
mediaRetryOptions(call);
|
|
9709
|
+
if (!jobId) {
|
|
9710
|
+
throw new ModelKitError({
|
|
9711
|
+
code: "missing_input",
|
|
9712
|
+
message: "resumeVideo needs a jobId",
|
|
9713
|
+
retryable: false
|
|
9714
|
+
});
|
|
9715
|
+
}
|
|
9716
|
+
if (!isCatalogId(req.model)) {
|
|
9717
|
+
throw new ModelKitError({
|
|
9718
|
+
code: "unsupported_option",
|
|
9719
|
+
message: "resumeVideo needs a catalog model id"
|
|
9720
|
+
});
|
|
9721
|
+
}
|
|
9722
|
+
const model = catalog.require(req.model);
|
|
9723
|
+
if (model.type !== "video")
|
|
9724
|
+
throw new ModelKitError({
|
|
9725
|
+
code: "unsupported_option",
|
|
9726
|
+
message: `${model.id} is not a video model`,
|
|
9727
|
+
model: model.id
|
|
9728
|
+
});
|
|
9729
|
+
const { request: input, warnings: inputWarnings } = videoRequestOf({
|
|
9730
|
+
...req,
|
|
9731
|
+
model: req.model
|
|
9732
|
+
});
|
|
9733
|
+
const { request, warnings } = resolveVideoOptions(
|
|
9734
|
+
model,
|
|
9735
|
+
input,
|
|
9736
|
+
call.onUnsupported ?? "error"
|
|
9737
|
+
);
|
|
9738
|
+
warnings.push(...inputWarnings);
|
|
9739
|
+
logCoercions(logger, model.id, warnings);
|
|
9740
|
+
const signal = combineSignals(req.abortSignal, call.signal);
|
|
9741
|
+
const { adapter, ctx } = context(model, signal ? { ...call, signal } : call, warnings);
|
|
9742
|
+
if (!adapter.resumeVideo)
|
|
9743
|
+
throw new ModelKitError({
|
|
9744
|
+
code: "unsupported_option",
|
|
9745
|
+
message: `${adapter.id} cannot resume a video job`,
|
|
9746
|
+
model: model.id
|
|
9747
|
+
});
|
|
9748
|
+
const startedAt = Date.now();
|
|
9749
|
+
const job = adapter.resumeVideo(request, jobId, ctx);
|
|
9750
|
+
return wrapVideoJob(model, { ...job, jobId }, warnings, startedAt);
|
|
9674
9751
|
},
|
|
9675
9752
|
async generateAudio(req, call = {}) {
|
|
9676
9753
|
mediaRetryOptions(call);
|