@ai-sdk/topaz 0.0.0 → 2.0.0
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 +7 -0
- package/LICENSE +13 -0
- package/README.md +67 -3
- package/dist/index.d.ts +244 -0
- package/dist/index.js +1348 -0
- package/dist/index.js.map +1 -0
- package/docs/210-topaz.mdx +248 -0
- package/package.json +64 -10
- package/src/index.ts +11 -0
- package/src/topaz-config.ts +11 -0
- package/src/topaz-error.ts +61 -0
- package/src/topaz-get-from-api.ts +53 -0
- package/src/topaz-image-model-options.ts +107 -0
- package/src/topaz-image-model.ts +449 -0
- package/src/topaz-image-settings.ts +22 -0
- package/src/topaz-provider.ts +136 -0
- package/src/topaz-video-model-options.ts +289 -0
- package/src/topaz-video-model.ts +851 -0
- package/src/topaz-video-settings.ts +27 -0
- package/src/version.ts +6 -0
- package/index.js +0 -1
package/dist/index.js
ADDED
|
@@ -0,0 +1,1348 @@
|
|
|
1
|
+
// src/topaz-provider.ts
|
|
2
|
+
import {
|
|
3
|
+
NoSuchModelError
|
|
4
|
+
} from "@ai-sdk/provider";
|
|
5
|
+
import {
|
|
6
|
+
loadApiKey,
|
|
7
|
+
withoutTrailingSlash,
|
|
8
|
+
withUserAgentSuffix as withUserAgentSuffix2
|
|
9
|
+
} from "@ai-sdk/provider-utils";
|
|
10
|
+
|
|
11
|
+
// src/topaz-image-model.ts
|
|
12
|
+
import {
|
|
13
|
+
AISDKError,
|
|
14
|
+
InvalidArgumentError,
|
|
15
|
+
InvalidResponseDataError
|
|
16
|
+
} from "@ai-sdk/provider";
|
|
17
|
+
import {
|
|
18
|
+
combineHeaders,
|
|
19
|
+
convertBase64ToUint8Array,
|
|
20
|
+
createBinaryResponseHandler,
|
|
21
|
+
createJsonResponseHandler,
|
|
22
|
+
delay,
|
|
23
|
+
mediaTypeToExtension,
|
|
24
|
+
parseProviderOptions,
|
|
25
|
+
postFormDataToApi,
|
|
26
|
+
removeUndefinedEntries,
|
|
27
|
+
resolve
|
|
28
|
+
} from "@ai-sdk/provider-utils";
|
|
29
|
+
import { z as z3 } from "zod/v4";
|
|
30
|
+
|
|
31
|
+
// src/topaz-error.ts
|
|
32
|
+
import { createJsonErrorResponseHandler } from "@ai-sdk/provider-utils";
|
|
33
|
+
import { z } from "zod/v4";
|
|
34
|
+
var topazErrorDataSchema = z.object({
|
|
35
|
+
detail: z.union([
|
|
36
|
+
z.string(),
|
|
37
|
+
z.array(z.object({ msg: z.string().nullish() }).loose())
|
|
38
|
+
]).nullish(),
|
|
39
|
+
message: z.string().nullish(),
|
|
40
|
+
error: z.string().nullish(),
|
|
41
|
+
errorCode: z.string().nullish(),
|
|
42
|
+
errors: z.array(z.object({ msg: z.string().nullish() }).loose()).nullish()
|
|
43
|
+
});
|
|
44
|
+
function topazErrorToMessage(data) {
|
|
45
|
+
var _a;
|
|
46
|
+
const message = baseErrorMessage(data);
|
|
47
|
+
const withCode = data.errorCode != null ? `${message} (${data.errorCode})` : message;
|
|
48
|
+
const issues = ((_a = data.errors) != null ? _a : []).map((issue) => issue.msg).filter((msg) => msg != null);
|
|
49
|
+
return issues.length > 0 ? `${withCode}: ${issues.join("; ")}` : withCode;
|
|
50
|
+
}
|
|
51
|
+
function baseErrorMessage(data) {
|
|
52
|
+
var _a, _b;
|
|
53
|
+
const { detail } = data;
|
|
54
|
+
if (typeof detail === "string") {
|
|
55
|
+
return detail;
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(detail)) {
|
|
58
|
+
const messages = detail.map((issue) => issue.msg).filter((msg) => msg != null);
|
|
59
|
+
if (messages.length > 0) {
|
|
60
|
+
return messages.join("; ");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return (_b = (_a = data.message) != null ? _a : data.error) != null ? _b : "Unknown Topaz API error";
|
|
64
|
+
}
|
|
65
|
+
var topazFailedResponseHandler = createJsonErrorResponseHandler({
|
|
66
|
+
errorSchema: topazErrorDataSchema,
|
|
67
|
+
errorToMessage: topazErrorToMessage
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// src/topaz-get-from-api.ts
|
|
71
|
+
import {
|
|
72
|
+
fetchWithValidatedEndpoint,
|
|
73
|
+
fetchWithValidatedRedirects,
|
|
74
|
+
getFromApi,
|
|
75
|
+
isSameOrigin
|
|
76
|
+
} from "@ai-sdk/provider-utils";
|
|
77
|
+
async function topazGetFromApi({
|
|
78
|
+
validateUrl,
|
|
79
|
+
credentialedOrigin,
|
|
80
|
+
trustedOrigin,
|
|
81
|
+
...options
|
|
82
|
+
}) {
|
|
83
|
+
const validatedFetch = (url, init) => {
|
|
84
|
+
var _a;
|
|
85
|
+
return fetchWithValidatedRedirects({
|
|
86
|
+
url: url.toString(),
|
|
87
|
+
headers: init == null ? void 0 : init.headers,
|
|
88
|
+
abortSignal: (_a = init == null ? void 0 : init.signal) != null ? _a : void 0,
|
|
89
|
+
trustedOrigin,
|
|
90
|
+
fetch: (hopUrl, hopInit) => fetchWithValidatedEndpoint({
|
|
91
|
+
url: hopUrl.toString(),
|
|
92
|
+
init: {
|
|
93
|
+
...hopInit,
|
|
94
|
+
headers: credentialedOrigin != null && isSameOrigin(hopUrl.toString(), credentialedOrigin) ? hopInit == null ? void 0 : hopInit.headers : void 0
|
|
95
|
+
},
|
|
96
|
+
trustedOrigin,
|
|
97
|
+
redirect: "manual",
|
|
98
|
+
fetch: options.fetch
|
|
99
|
+
})
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
const requestOptions = {
|
|
103
|
+
...options,
|
|
104
|
+
validateUrl: false,
|
|
105
|
+
fetch: validateUrl ? validatedFetch : options.fetch
|
|
106
|
+
};
|
|
107
|
+
return getFromApi(requestOptions);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/topaz-image-model-options.ts
|
|
111
|
+
import {
|
|
112
|
+
lazySchema,
|
|
113
|
+
zodSchema
|
|
114
|
+
} from "@ai-sdk/provider-utils";
|
|
115
|
+
import { z as z2 } from "zod/v4";
|
|
116
|
+
var topazImageModelOptionsSchema = lazySchema(
|
|
117
|
+
() => zodSchema(
|
|
118
|
+
z2.object({
|
|
119
|
+
/**
|
|
120
|
+
* How aggressively the model enhances the image. Defaults to `high`.
|
|
121
|
+
*/
|
|
122
|
+
enhancementStrength: z2.enum(["low", "medium", "high"]).optional(),
|
|
123
|
+
/**
|
|
124
|
+
* Whether to add grain to the output. Defaults to `false`.
|
|
125
|
+
*/
|
|
126
|
+
grain: z2.boolean().optional(),
|
|
127
|
+
/**
|
|
128
|
+
* Grain intensity, 0.0 to 1.0. Defaults to 0.5.
|
|
129
|
+
*/
|
|
130
|
+
grainDensity: z2.number().min(0).max(1).optional(),
|
|
131
|
+
/**
|
|
132
|
+
* Grain model. Defaults to `silver`.
|
|
133
|
+
*/
|
|
134
|
+
grainModel: z2.enum(["silver", "gaussian", "grey"]).optional(),
|
|
135
|
+
/**
|
|
136
|
+
* Grain particle size, 1 to 5. Defaults to 1.
|
|
137
|
+
*/
|
|
138
|
+
grainSize: z2.number().min(1).max(5).optional(),
|
|
139
|
+
/**
|
|
140
|
+
* Grain effect strength, 0.0 to 1.0. Defaults to 0.5.
|
|
141
|
+
*/
|
|
142
|
+
grainStrength: z2.number().min(0).max(1).optional(),
|
|
143
|
+
/**
|
|
144
|
+
* Width of the input image in pixels. Topaz infers this from the upload when
|
|
145
|
+
* omitted.
|
|
146
|
+
*/
|
|
147
|
+
inputWidth: z2.number().int().positive().optional(),
|
|
148
|
+
/**
|
|
149
|
+
* Height of the input image in pixels. Topaz infers this from the upload
|
|
150
|
+
* when omitted.
|
|
151
|
+
*/
|
|
152
|
+
inputHeight: z2.number().int().positive().optional(),
|
|
153
|
+
/**
|
|
154
|
+
* Width of the output image in pixels, 1 to 32000. Takes precedence over the
|
|
155
|
+
* width derived from the `size` call option.
|
|
156
|
+
*/
|
|
157
|
+
outputWidth: z2.number().int().min(1).max(32e3).optional(),
|
|
158
|
+
/**
|
|
159
|
+
* Height of the output image in pixels, 1 to 32000. Takes precedence over
|
|
160
|
+
* the height derived from the `size` call option.
|
|
161
|
+
*/
|
|
162
|
+
outputHeight: z2.number().int().min(1).max(32e3).optional(),
|
|
163
|
+
/**
|
|
164
|
+
* Output image format. Defaults to the Topaz API default.
|
|
165
|
+
*/
|
|
166
|
+
outputFormat: z2.enum(["jpeg", "jpg", "png", "tiff", "tif"]).optional(),
|
|
167
|
+
/**
|
|
168
|
+
* Whether to crop the output to fill the requested dimensions. Defaults to
|
|
169
|
+
* `false`.
|
|
170
|
+
*/
|
|
171
|
+
cropToFill: z2.boolean().optional(),
|
|
172
|
+
/**
|
|
173
|
+
* URL to receive job-status webhooks.
|
|
174
|
+
*/
|
|
175
|
+
webhookUrl: z2.string().optional(),
|
|
176
|
+
/**
|
|
177
|
+
* How often to poll the Topaz status endpoint, in milliseconds. Defaults to
|
|
178
|
+
* 2000.
|
|
179
|
+
*/
|
|
180
|
+
pollIntervalMillis: z2.number().int().positive().optional(),
|
|
181
|
+
/**
|
|
182
|
+
* How long to wait for the job to finish before failing, in milliseconds.
|
|
183
|
+
* Defaults to 600000 (10 minutes).
|
|
184
|
+
*/
|
|
185
|
+
pollTimeoutMillis: z2.number().int().positive().optional()
|
|
186
|
+
})
|
|
187
|
+
)
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
// src/topaz-image-settings.ts
|
|
191
|
+
var topazImageApiModelIds = {
|
|
192
|
+
"wonder-3.5": "Wonder 3.5"
|
|
193
|
+
};
|
|
194
|
+
function resolveTopazImageApiModelId(modelId) {
|
|
195
|
+
var _a;
|
|
196
|
+
return (_a = topazImageApiModelIds[modelId]) != null ? _a : modelId;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/topaz-image-model.ts
|
|
200
|
+
var DEFAULT_POLL_INTERVAL_MILLIS = 2e3;
|
|
201
|
+
var DEFAULT_POLL_TIMEOUT_MILLIS = 6e5;
|
|
202
|
+
var TopazImageModel = class {
|
|
203
|
+
constructor(modelId, config) {
|
|
204
|
+
this.modelId = modelId;
|
|
205
|
+
this.config = config;
|
|
206
|
+
this.specificationVersion = "v3";
|
|
207
|
+
this.maxImagesPerCall = 1;
|
|
208
|
+
this.supportsFileInputs = true;
|
|
209
|
+
this.supportsMaskInputs = false;
|
|
210
|
+
}
|
|
211
|
+
get provider() {
|
|
212
|
+
return this.config.provider;
|
|
213
|
+
}
|
|
214
|
+
async doGenerate(options) {
|
|
215
|
+
var _a, _b, _c, _d, _e, _f;
|
|
216
|
+
const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
|
|
217
|
+
const warnings = [];
|
|
218
|
+
const topazOptions = await parseProviderOptions({
|
|
219
|
+
provider: "topaz",
|
|
220
|
+
providerOptions: options.providerOptions,
|
|
221
|
+
schema: topazImageModelOptionsSchema
|
|
222
|
+
});
|
|
223
|
+
const headers = combineHeaders(
|
|
224
|
+
await resolve(this.config.headers),
|
|
225
|
+
options.headers
|
|
226
|
+
);
|
|
227
|
+
this.addUnsupportedWarnings(options, warnings);
|
|
228
|
+
const formData = await this.buildFormData(options, topazOptions, warnings);
|
|
229
|
+
const { value: submitResponse } = await postFormDataToApi({
|
|
230
|
+
url: `${this.config.baseURL}/image/v1/enhance-gen/async`,
|
|
231
|
+
headers,
|
|
232
|
+
formData,
|
|
233
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
234
|
+
topazImageSubmitResponseSchema
|
|
235
|
+
),
|
|
236
|
+
failedResponseHandler: topazFailedResponseHandler,
|
|
237
|
+
abortSignal: options.abortSignal,
|
|
238
|
+
fetch: this.config.fetch
|
|
239
|
+
});
|
|
240
|
+
const processId = submitResponse.process_id;
|
|
241
|
+
if (processId == null) {
|
|
242
|
+
throw new InvalidResponseDataError({
|
|
243
|
+
data: submitResponse,
|
|
244
|
+
message: "Topaz did not return a process_id for the enhance request."
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
let status;
|
|
248
|
+
try {
|
|
249
|
+
status = await this.waitForCompletion({
|
|
250
|
+
processId,
|
|
251
|
+
headers,
|
|
252
|
+
abortSignal: options.abortSignal,
|
|
253
|
+
pollIntervalMillis: (_d = topazOptions == null ? void 0 : topazOptions.pollIntervalMillis) != null ? _d : DEFAULT_POLL_INTERVAL_MILLIS,
|
|
254
|
+
pollTimeoutMillis: (_e = topazOptions == null ? void 0 : topazOptions.pollTimeoutMillis) != null ? _e : DEFAULT_POLL_TIMEOUT_MILLIS
|
|
255
|
+
});
|
|
256
|
+
} catch (error) {
|
|
257
|
+
if ((_f = options.abortSignal) == null ? void 0 : _f.aborted) {
|
|
258
|
+
await this.cancelQuietly(processId, headers);
|
|
259
|
+
}
|
|
260
|
+
throw error;
|
|
261
|
+
}
|
|
262
|
+
const { image, responseHeaders } = await this.download({
|
|
263
|
+
processId,
|
|
264
|
+
headers,
|
|
265
|
+
abortSignal: options.abortSignal
|
|
266
|
+
});
|
|
267
|
+
return {
|
|
268
|
+
images: [image],
|
|
269
|
+
warnings,
|
|
270
|
+
response: {
|
|
271
|
+
timestamp: currentDate,
|
|
272
|
+
modelId: this.modelId,
|
|
273
|
+
headers: responseHeaders
|
|
274
|
+
},
|
|
275
|
+
providerMetadata: {
|
|
276
|
+
topaz: {
|
|
277
|
+
images: [
|
|
278
|
+
{
|
|
279
|
+
processId,
|
|
280
|
+
// Topaz bills exactly the credits reported on the completed job.
|
|
281
|
+
...status.credits != null ? { credits: status.credits } : {},
|
|
282
|
+
...status.output_width != null ? { width: status.output_width } : {},
|
|
283
|
+
...status.output_height != null ? { height: status.output_height } : {},
|
|
284
|
+
...status.output_format != null ? { format: status.output_format } : {}
|
|
285
|
+
}
|
|
286
|
+
]
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
addUnsupportedWarnings(options, warnings) {
|
|
292
|
+
if (options.prompt != null) {
|
|
293
|
+
warnings.push({
|
|
294
|
+
type: "unsupported",
|
|
295
|
+
feature: "prompt",
|
|
296
|
+
details: "Topaz image models enhance an existing image and do not take a text prompt. The prompt was ignored."
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
if (options.aspectRatio != null) {
|
|
300
|
+
warnings.push({
|
|
301
|
+
type: "unsupported",
|
|
302
|
+
feature: "aspectRatio",
|
|
303
|
+
details: "Topaz image models do not support aspectRatio. Use `size`, or the `outputWidth` / `outputHeight` provider options, to set output dimensions."
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
if (options.seed != null) {
|
|
307
|
+
warnings.push({
|
|
308
|
+
type: "unsupported",
|
|
309
|
+
feature: "seed",
|
|
310
|
+
details: "Topaz image models do not support seed."
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
if (options.mask != null) {
|
|
314
|
+
warnings.push({
|
|
315
|
+
type: "unsupported",
|
|
316
|
+
feature: "mask",
|
|
317
|
+
details: "Topaz image models do not support masks. The mask was ignored."
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
if (options.n > 1) {
|
|
321
|
+
warnings.push({
|
|
322
|
+
type: "unsupported",
|
|
323
|
+
feature: "n",
|
|
324
|
+
details: "Topaz image models enhance one image per call. Only 1 image will be returned."
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
async buildFormData(options, topazOptions, warnings) {
|
|
329
|
+
var _a, _b, _c, _d;
|
|
330
|
+
const file = (_a = options.files) == null ? void 0 : _a[0];
|
|
331
|
+
if (file == null) {
|
|
332
|
+
throw new InvalidArgumentError({
|
|
333
|
+
argument: "files",
|
|
334
|
+
message: "Topaz image models enhance an existing image. Pass the input image via `prompt.images`."
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
if (options.files != null && options.files.length > 1) {
|
|
338
|
+
warnings.push({
|
|
339
|
+
type: "unsupported",
|
|
340
|
+
feature: "files",
|
|
341
|
+
details: "Topaz image models enhance one image per call. Only the first file was used."
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
const formData = new FormData();
|
|
345
|
+
formData.append("model", resolveTopazImageApiModelId(this.modelId));
|
|
346
|
+
if (file.type === "url") {
|
|
347
|
+
formData.append("source_url", file.url);
|
|
348
|
+
} else {
|
|
349
|
+
const bytes = typeof file.data === "string" ? convertBase64ToUint8Array(file.data) : file.data;
|
|
350
|
+
const extension = (_b = mediaTypeToExtension(file.mediaType)) != null ? _b : "png";
|
|
351
|
+
formData.append(
|
|
352
|
+
"image",
|
|
353
|
+
new File([bytes], `image.${extension}`, {
|
|
354
|
+
type: file.mediaType
|
|
355
|
+
})
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
const { width, height } = parseSize(options.size);
|
|
359
|
+
appendIfDefined(
|
|
360
|
+
formData,
|
|
361
|
+
"output_width",
|
|
362
|
+
(_c = topazOptions == null ? void 0 : topazOptions.outputWidth) != null ? _c : width
|
|
363
|
+
);
|
|
364
|
+
appendIfDefined(
|
|
365
|
+
formData,
|
|
366
|
+
"output_height",
|
|
367
|
+
(_d = topazOptions == null ? void 0 : topazOptions.outputHeight) != null ? _d : height
|
|
368
|
+
);
|
|
369
|
+
appendIfDefined(formData, "output_format", topazOptions == null ? void 0 : topazOptions.outputFormat);
|
|
370
|
+
appendIfDefined(formData, "crop_to_fill", topazOptions == null ? void 0 : topazOptions.cropToFill);
|
|
371
|
+
appendIfDefined(formData, "webhook_url", topazOptions == null ? void 0 : topazOptions.webhookUrl);
|
|
372
|
+
appendIfDefined(
|
|
373
|
+
formData,
|
|
374
|
+
"enhancementStrength",
|
|
375
|
+
topazOptions == null ? void 0 : topazOptions.enhancementStrength
|
|
376
|
+
);
|
|
377
|
+
appendIfDefined(formData, "grain", topazOptions == null ? void 0 : topazOptions.grain);
|
|
378
|
+
appendIfDefined(formData, "grainDensity", topazOptions == null ? void 0 : topazOptions.grainDensity);
|
|
379
|
+
appendIfDefined(formData, "grainModel", topazOptions == null ? void 0 : topazOptions.grainModel);
|
|
380
|
+
appendIfDefined(formData, "grainSize", topazOptions == null ? void 0 : topazOptions.grainSize);
|
|
381
|
+
appendIfDefined(formData, "grainStrength", topazOptions == null ? void 0 : topazOptions.grainStrength);
|
|
382
|
+
appendIfDefined(formData, "inputWidth", topazOptions == null ? void 0 : topazOptions.inputWidth);
|
|
383
|
+
appendIfDefined(formData, "inputHeight", topazOptions == null ? void 0 : topazOptions.inputHeight);
|
|
384
|
+
return formData;
|
|
385
|
+
}
|
|
386
|
+
async waitForCompletion({
|
|
387
|
+
processId,
|
|
388
|
+
headers,
|
|
389
|
+
abortSignal,
|
|
390
|
+
pollIntervalMillis,
|
|
391
|
+
pollTimeoutMillis
|
|
392
|
+
}) {
|
|
393
|
+
var _a;
|
|
394
|
+
const deadline = Date.now() + pollTimeoutMillis;
|
|
395
|
+
while (true) {
|
|
396
|
+
const { value: status } = await topazGetFromApi({
|
|
397
|
+
url: `${this.config.baseURL}/image/v1/status/${processId}`,
|
|
398
|
+
// Built from the configured baseURL, not from response data.
|
|
399
|
+
validateUrl: false,
|
|
400
|
+
headers,
|
|
401
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
402
|
+
topazImageStatusResponseSchema
|
|
403
|
+
),
|
|
404
|
+
failedResponseHandler: topazFailedResponseHandler,
|
|
405
|
+
abortSignal,
|
|
406
|
+
fetch: this.config.fetch
|
|
407
|
+
});
|
|
408
|
+
if (status.status === "Completed") {
|
|
409
|
+
return status;
|
|
410
|
+
}
|
|
411
|
+
if (status.status === "Failed" || status.status === "Cancelled") {
|
|
412
|
+
throw new AISDKError({
|
|
413
|
+
name: "TOPAZ_IMAGE_ENHANCEMENT_FAILED",
|
|
414
|
+
message: `Topaz image enhancement ${status.status.toLowerCase()} for process ${processId}.`
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
if (Date.now() + pollIntervalMillis > deadline) {
|
|
418
|
+
await this.cancelQuietly(processId, headers != null ? headers : {});
|
|
419
|
+
throw new AISDKError({
|
|
420
|
+
name: "TOPAZ_IMAGE_ENHANCEMENT_TIMEOUT",
|
|
421
|
+
message: `Topaz image enhancement did not finish within ${pollTimeoutMillis}ms (process ${processId}, last status ${(_a = status.status) != null ? _a : "unknown"}). Increase the \`pollTimeoutMillis\` provider option if the job needs longer.`
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
await delay(pollIntervalMillis, { abortSignal });
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
async cancelQuietly(processId, headers) {
|
|
428
|
+
var _a;
|
|
429
|
+
const fetchImpl = (_a = this.config.fetch) != null ? _a : globalThis.fetch;
|
|
430
|
+
try {
|
|
431
|
+
await fetchImpl(`${this.config.baseURL}/image/v1/cancel/${processId}`, {
|
|
432
|
+
method: "DELETE",
|
|
433
|
+
headers: removeUndefinedEntries(headers)
|
|
434
|
+
});
|
|
435
|
+
} catch (e) {
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
async download({
|
|
439
|
+
processId,
|
|
440
|
+
headers,
|
|
441
|
+
abortSignal
|
|
442
|
+
}) {
|
|
443
|
+
const { value: downloadResponse } = await topazGetFromApi({
|
|
444
|
+
url: `${this.config.baseURL}/image/v1/download/${processId}`,
|
|
445
|
+
// Built from the configured baseURL, not from response data.
|
|
446
|
+
validateUrl: false,
|
|
447
|
+
headers,
|
|
448
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
449
|
+
topazImageDownloadResponseSchema
|
|
450
|
+
),
|
|
451
|
+
failedResponseHandler: topazFailedResponseHandler,
|
|
452
|
+
abortSignal,
|
|
453
|
+
fetch: this.config.fetch
|
|
454
|
+
});
|
|
455
|
+
const downloadUrl = downloadResponse.download_url;
|
|
456
|
+
if (downloadUrl == null) {
|
|
457
|
+
throw new InvalidResponseDataError({
|
|
458
|
+
data: downloadResponse,
|
|
459
|
+
message: `Topaz did not return a download URL for process ${processId}.`
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
const { value: image, responseHeaders } = await topazGetFromApi({
|
|
463
|
+
url: downloadUrl,
|
|
464
|
+
// Comes from the Topaz response body and normally points at object
|
|
465
|
+
// storage, so it is validated and the API key is withheld off-origin.
|
|
466
|
+
validateUrl: true,
|
|
467
|
+
credentialedOrigin: this.config.baseURL,
|
|
468
|
+
trustedOrigin: this.config.baseURL,
|
|
469
|
+
headers,
|
|
470
|
+
successfulResponseHandler: createBinaryResponseHandler(),
|
|
471
|
+
failedResponseHandler: topazFailedResponseHandler,
|
|
472
|
+
abortSignal,
|
|
473
|
+
fetch: this.config.fetch
|
|
474
|
+
});
|
|
475
|
+
return { image, responseHeaders };
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
function parseSize(size) {
|
|
479
|
+
if (size == null) {
|
|
480
|
+
return { width: void 0, height: void 0 };
|
|
481
|
+
}
|
|
482
|
+
const [width, height] = size.split("x").map(Number);
|
|
483
|
+
return { width, height };
|
|
484
|
+
}
|
|
485
|
+
function appendIfDefined(formData, key, value) {
|
|
486
|
+
if (value !== void 0) {
|
|
487
|
+
formData.append(key, String(value));
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
var topazImageSubmitResponseSchema = z3.object({
|
|
491
|
+
process_id: z3.string().nullish()
|
|
492
|
+
});
|
|
493
|
+
var topazImageStatusResponseSchema = z3.object({
|
|
494
|
+
// Documented values are Pending, Processing, Completed, Cancelled and Failed.
|
|
495
|
+
// Unknown values keep polling rather than failing the parse.
|
|
496
|
+
status: z3.string().nullish(),
|
|
497
|
+
credits: z3.number().nullish(),
|
|
498
|
+
output_width: z3.number().nullish(),
|
|
499
|
+
output_height: z3.number().nullish(),
|
|
500
|
+
output_format: z3.string().nullish()
|
|
501
|
+
});
|
|
502
|
+
var topazImageDownloadResponseSchema = z3.object({
|
|
503
|
+
download_url: z3.string().nullish()
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
// src/topaz-video-model.ts
|
|
507
|
+
import {
|
|
508
|
+
AISDKError as AISDKError2,
|
|
509
|
+
APICallError,
|
|
510
|
+
InvalidArgumentError as InvalidArgumentError2,
|
|
511
|
+
InvalidResponseDataError as InvalidResponseDataError2
|
|
512
|
+
} from "@ai-sdk/provider";
|
|
513
|
+
import {
|
|
514
|
+
combineHeaders as combineHeaders2,
|
|
515
|
+
convertBase64ToUint8Array as convertBase64ToUint8Array2,
|
|
516
|
+
createJsonResponseHandler as createJsonResponseHandler2,
|
|
517
|
+
delay as delay2,
|
|
518
|
+
isSameOrigin as isSameOrigin2,
|
|
519
|
+
parseProviderOptions as parseProviderOptions2,
|
|
520
|
+
postJsonToApi,
|
|
521
|
+
removeUndefinedEntries as removeUndefinedEntries2,
|
|
522
|
+
resolve as resolve2,
|
|
523
|
+
validateDownloadUrl,
|
|
524
|
+
withUserAgentSuffix
|
|
525
|
+
} from "@ai-sdk/provider-utils";
|
|
526
|
+
import { z as z5 } from "zod/v4";
|
|
527
|
+
|
|
528
|
+
// src/topaz-video-model-options.ts
|
|
529
|
+
import {
|
|
530
|
+
lazySchema as lazySchema2,
|
|
531
|
+
zodSchema as zodSchema2
|
|
532
|
+
} from "@ai-sdk/provider-utils";
|
|
533
|
+
import { z as z4 } from "zod/v4";
|
|
534
|
+
var topazSourceContainers = [
|
|
535
|
+
"3gp",
|
|
536
|
+
"avi",
|
|
537
|
+
"dv",
|
|
538
|
+
"flv",
|
|
539
|
+
"m1v",
|
|
540
|
+
"m2t",
|
|
541
|
+
"m2ts",
|
|
542
|
+
"m2v",
|
|
543
|
+
"m4v",
|
|
544
|
+
"mkv",
|
|
545
|
+
"mov",
|
|
546
|
+
"mp4",
|
|
547
|
+
"mpeg",
|
|
548
|
+
"mpg",
|
|
549
|
+
"mts",
|
|
550
|
+
"mxf",
|
|
551
|
+
"ser",
|
|
552
|
+
"ts",
|
|
553
|
+
"vob",
|
|
554
|
+
"webm",
|
|
555
|
+
"wmv"
|
|
556
|
+
];
|
|
557
|
+
var topazOutputContainers = [
|
|
558
|
+
"mp4",
|
|
559
|
+
"mov",
|
|
560
|
+
"mkv",
|
|
561
|
+
"avi",
|
|
562
|
+
"webm"
|
|
563
|
+
];
|
|
564
|
+
var topazVideoSourceSchema = z4.object({
|
|
565
|
+
/**
|
|
566
|
+
* Width of the input video in pixels.
|
|
567
|
+
*/
|
|
568
|
+
width: z4.number().int().positive().optional(),
|
|
569
|
+
/**
|
|
570
|
+
* Height of the input video in pixels.
|
|
571
|
+
*/
|
|
572
|
+
height: z4.number().int().positive().optional(),
|
|
573
|
+
/**
|
|
574
|
+
* Duration of the input video in seconds.
|
|
575
|
+
*/
|
|
576
|
+
duration: z4.number().positive().optional(),
|
|
577
|
+
/**
|
|
578
|
+
* Frame rate of the input video.
|
|
579
|
+
*/
|
|
580
|
+
frameRate: z4.number().positive().optional(),
|
|
581
|
+
/**
|
|
582
|
+
* Total number of frames in the input video. Derived from
|
|
583
|
+
* `duration * frameRate` when omitted, which is only correct for
|
|
584
|
+
* constant-frame-rate input, so set it explicitly for variable-frame-rate
|
|
585
|
+
* sources.
|
|
586
|
+
*/
|
|
587
|
+
frameCount: z4.number().int().positive().optional(),
|
|
588
|
+
/**
|
|
589
|
+
* Container of the input video. Detected from the input file's media type
|
|
590
|
+
* or URL extension when omitted.
|
|
591
|
+
*/
|
|
592
|
+
container: z4.enum(topazSourceContainers).optional()
|
|
593
|
+
});
|
|
594
|
+
var topazVideoOutputSchema = z4.object({
|
|
595
|
+
/**
|
|
596
|
+
* Width of the output video in pixels. Takes precedence over the
|
|
597
|
+
* `resolution` call option.
|
|
598
|
+
*/
|
|
599
|
+
width: z4.number().int().positive().optional(),
|
|
600
|
+
/**
|
|
601
|
+
* Height of the output video in pixels. Takes precedence over the
|
|
602
|
+
* `resolution` call option.
|
|
603
|
+
*/
|
|
604
|
+
height: z4.number().int().positive().optional(),
|
|
605
|
+
/**
|
|
606
|
+
* Frame rate of the output video. Takes precedence over the `fps` call
|
|
607
|
+
* option. Topaz only changes the frame rate when a frame-interpolation
|
|
608
|
+
* filter is present.
|
|
609
|
+
*/
|
|
610
|
+
frameRate: z4.number().positive().optional(),
|
|
611
|
+
/**
|
|
612
|
+
* Audio codec of the output video. Defaults to `AAC`.
|
|
613
|
+
*/
|
|
614
|
+
audioCodec: z4.enum(["AAC", "AC3", "PCM"]).optional(),
|
|
615
|
+
/**
|
|
616
|
+
* Audio bitrate, e.g. `192k`. Topaz uses the codec default when omitted.
|
|
617
|
+
*/
|
|
618
|
+
audioBitrate: z4.string().optional(),
|
|
619
|
+
/**
|
|
620
|
+
* How to handle the input audio track. Defaults to `Copy`.
|
|
621
|
+
*/
|
|
622
|
+
audioTransfer: z4.enum(["Copy", "Convert", "None"]).optional(),
|
|
623
|
+
/**
|
|
624
|
+
* Video encoder. Topaz defaults to `H265`. `ProRes` forces a `mov`
|
|
625
|
+
* container, `AV1` and `VP9` force `mp4`.
|
|
626
|
+
*/
|
|
627
|
+
videoEncoder: z4.enum(["AV1", "H264", "H265", "ProRes", "VP9"]).optional(),
|
|
628
|
+
/**
|
|
629
|
+
* Encoder profile, e.g. `Main10` for H265 or `422 HQ` for ProRes. Topaz uses
|
|
630
|
+
* the encoder's default profile when omitted.
|
|
631
|
+
*/
|
|
632
|
+
videoProfile: z4.string().optional(),
|
|
633
|
+
/**
|
|
634
|
+
* Constant bitrate, e.g. `20m`. Required for `VP9`. Mutually exclusive with
|
|
635
|
+
* `dynamicCompressionLevel`.
|
|
636
|
+
*/
|
|
637
|
+
videoBitrate: z4.string().optional(),
|
|
638
|
+
/**
|
|
639
|
+
* Automatic constant-quality compression level. Topaz defaults to `High`
|
|
640
|
+
* unless `videoBitrate` is set.
|
|
641
|
+
*/
|
|
642
|
+
dynamicCompressionLevel: z4.enum(["Low", "Mid", "High"]).optional(),
|
|
643
|
+
/**
|
|
644
|
+
* Center-crop to fit the output dimensions.
|
|
645
|
+
*/
|
|
646
|
+
cropToFit: z4.boolean().optional(),
|
|
647
|
+
/**
|
|
648
|
+
* Container of the output video. Defaults to the input container when Topaz
|
|
649
|
+
* can produce it, otherwise `mp4`.
|
|
650
|
+
*/
|
|
651
|
+
container: z4.enum(topazOutputContainers).optional()
|
|
652
|
+
});
|
|
653
|
+
var topazVideoModelOptionsSchema = lazySchema2(
|
|
654
|
+
() => zodSchema2(
|
|
655
|
+
z4.object({
|
|
656
|
+
/** Interval between status polls, in milliseconds. Defaults to 2000. */
|
|
657
|
+
pollIntervalMillis: z4.number().positive().optional(),
|
|
658
|
+
/** Maximum time to poll, in milliseconds. Defaults to 3600000 (1 hour). */
|
|
659
|
+
pollTimeoutMillis: z4.number().positive().optional(),
|
|
660
|
+
source: topazVideoSourceSchema.optional(),
|
|
661
|
+
output: topazVideoOutputSchema.optional(),
|
|
662
|
+
/**
|
|
663
|
+
* Extra `filters[]` entries to send alongside the model's own filter, e.g. a
|
|
664
|
+
* frame-interpolation filter. Each entry must include a `model` key.
|
|
665
|
+
*/
|
|
666
|
+
additionalFilters: z4.array(z4.record(z4.string(), z4.unknown())).optional(),
|
|
667
|
+
/**
|
|
668
|
+
* Escape hatch for filter settings this package does not model yet. Merged
|
|
669
|
+
* into the model's filter entry, taking precedence over the typed options
|
|
670
|
+
* below.
|
|
671
|
+
*/
|
|
672
|
+
filter: z4.record(z4.string(), z4.unknown()).optional(),
|
|
673
|
+
// ---------------------------------------------------------------------------
|
|
674
|
+
// Proteus (`proteus`)
|
|
675
|
+
// ---------------------------------------------------------------------------
|
|
676
|
+
/** Proteus: how the input frames are encoded. */
|
|
677
|
+
videoType: z4.enum(["Progressive", "Interlaced", "ProgressiveInterlaced"]).optional(),
|
|
678
|
+
/** Proteus: parameter estimation mode. */
|
|
679
|
+
auto: z4.enum(["Auto", "Manual", "Relative"]).optional(),
|
|
680
|
+
/** Proteus: field order for interlaced input. */
|
|
681
|
+
fieldOrder: z4.enum(["TopFirst", "BottomFirst", "Auto"]).optional(),
|
|
682
|
+
/** Proteus: focus-fix strength. */
|
|
683
|
+
focusFixLevel: z4.enum(["None", "Normal", "Strong"]).optional(),
|
|
684
|
+
/** Proteus: compression artifact removal, -1 to 1. */
|
|
685
|
+
compression: z4.number().min(-1).max(1).optional(),
|
|
686
|
+
/** Proteus: detail recovery, -1 to 1. */
|
|
687
|
+
details: z4.number().min(-1).max(1).optional(),
|
|
688
|
+
/** Proteus: pre-processing noise reduction, 0 to 0.1. */
|
|
689
|
+
prenoise: z4.number().min(0).max(0.1).optional(),
|
|
690
|
+
/** Proteus: noise reduction, -1 to 1. */
|
|
691
|
+
noise: z4.number().min(-1).max(1).optional(),
|
|
692
|
+
/** Proteus: halo suppression, -1 to 1. */
|
|
693
|
+
halo: z4.number().min(-1).max(1).optional(),
|
|
694
|
+
/** Proteus: pre-processing blur, -1 to 1. */
|
|
695
|
+
preblur: z4.number().min(-1).max(1).optional(),
|
|
696
|
+
/** Proteus: sharpening, -1 to 1. */
|
|
697
|
+
blur: z4.number().min(-1).max(1).optional(),
|
|
698
|
+
/** Proteus: grain amount, 0 to 0.1. */
|
|
699
|
+
grain: z4.number().min(0).max(0.1).optional(),
|
|
700
|
+
/** Proteus: grain sigma, 0 to 1. */
|
|
701
|
+
grainSigma: z4.number().min(0).max(1).optional(),
|
|
702
|
+
/** Proteus: grain size, 0 to 5. */
|
|
703
|
+
grainSize: z4.number().min(0).max(5).optional(),
|
|
704
|
+
/** Proteus: grain model. */
|
|
705
|
+
grainType: z4.enum(["silver_rich", "gaussian", "grey"]).optional(),
|
|
706
|
+
/** Proteus: original detail recovery, 0 to 1. */
|
|
707
|
+
recoverOriginalDetailValue: z4.number().min(0).max(1).optional(),
|
|
708
|
+
// ---------------------------------------------------------------------------
|
|
709
|
+
// Starlight Precise (`starlight-precise-2.6`)
|
|
710
|
+
// ---------------------------------------------------------------------------
|
|
711
|
+
/** Starlight: sharpening applied to the output, 1.0 to 5.0. Defaults to 5.0. */
|
|
712
|
+
sharpness: z4.number().min(1).max(5).optional(),
|
|
713
|
+
/** Starlight: output bit depth. */
|
|
714
|
+
videoBitDepth: z4.number().int().positive().optional(),
|
|
715
|
+
/** Starlight: output video codec. */
|
|
716
|
+
videoCodec: z4.enum(["ffv1", "prores", "vp9"]).optional(),
|
|
717
|
+
/** Starlight: output chroma subsampling profile. */
|
|
718
|
+
videoProfile: z4.enum(["420", "422", "444"]).optional(),
|
|
719
|
+
/** Starlight: whether to watermark the output. Defaults to `false`. */
|
|
720
|
+
watermark: z4.boolean().optional()
|
|
721
|
+
})
|
|
722
|
+
)
|
|
723
|
+
);
|
|
724
|
+
var TOPAZ_NON_FILTER_OPTION_KEYS = [
|
|
725
|
+
"pollIntervalMillis",
|
|
726
|
+
"pollTimeoutMillis",
|
|
727
|
+
"source",
|
|
728
|
+
"output",
|
|
729
|
+
"additionalFilters",
|
|
730
|
+
"filter"
|
|
731
|
+
];
|
|
732
|
+
|
|
733
|
+
// src/topaz-video-settings.ts
|
|
734
|
+
var topazVideoApiModelIds = {
|
|
735
|
+
proteus: "prob-4",
|
|
736
|
+
"starlight-precise-2.6": "slp-2.6"
|
|
737
|
+
};
|
|
738
|
+
function resolveTopazVideoApiModelId(modelId) {
|
|
739
|
+
var _a;
|
|
740
|
+
return (_a = topazVideoApiModelIds[modelId]) != null ? _a : modelId;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// src/version.ts
|
|
744
|
+
var VERSION = true ? "2.0.0" : "0.0.0-test";
|
|
745
|
+
|
|
746
|
+
// src/topaz-video-model.ts
|
|
747
|
+
var DEFAULT_POLL_INTERVAL_MILLIS2 = 2e3;
|
|
748
|
+
var DEFAULT_POLL_TIMEOUT_MILLIS2 = 36e5;
|
|
749
|
+
var mediaTypeContainers = {
|
|
750
|
+
"video/mp4": "mp4",
|
|
751
|
+
"video/quicktime": "mov",
|
|
752
|
+
"video/mov": "mov",
|
|
753
|
+
"video/x-matroska": "mkv",
|
|
754
|
+
"video/matroska": "mkv",
|
|
755
|
+
"video/webm": "webm",
|
|
756
|
+
"video/x-msvideo": "avi",
|
|
757
|
+
"video/avi": "avi",
|
|
758
|
+
"video/mpeg": "mpeg",
|
|
759
|
+
"video/mp2t": "ts",
|
|
760
|
+
"video/x-ms-wmv": "wmv",
|
|
761
|
+
"video/x-flv": "flv",
|
|
762
|
+
"video/3gpp": "3gp",
|
|
763
|
+
"video/x-m4v": "m4v",
|
|
764
|
+
"application/mxf": "mxf"
|
|
765
|
+
};
|
|
766
|
+
var extensionContainers = {
|
|
767
|
+
...Object.fromEntries(topazSourceContainers.map((c) => [c, c])),
|
|
768
|
+
qt: "mov"
|
|
769
|
+
};
|
|
770
|
+
var containerMediaTypes = {
|
|
771
|
+
mp4: "video/mp4",
|
|
772
|
+
m4v: "video/mp4",
|
|
773
|
+
mov: "video/quicktime",
|
|
774
|
+
mkv: "video/x-matroska",
|
|
775
|
+
webm: "video/webm",
|
|
776
|
+
avi: "video/x-msvideo",
|
|
777
|
+
mpeg: "video/mpeg",
|
|
778
|
+
mpg: "video/mpeg",
|
|
779
|
+
ts: "video/mp2t",
|
|
780
|
+
wmv: "video/x-ms-wmv",
|
|
781
|
+
flv: "video/x-flv",
|
|
782
|
+
"3gp": "video/3gpp",
|
|
783
|
+
mxf: "application/mxf"
|
|
784
|
+
};
|
|
785
|
+
var TopazVideoModel = class {
|
|
786
|
+
constructor(modelId, config) {
|
|
787
|
+
this.modelId = modelId;
|
|
788
|
+
this.config = config;
|
|
789
|
+
this.specificationVersion = "v3";
|
|
790
|
+
this.maxVideosPerCall = 1;
|
|
791
|
+
}
|
|
792
|
+
get provider() {
|
|
793
|
+
return this.config.provider;
|
|
794
|
+
}
|
|
795
|
+
async doGenerate(options) {
|
|
796
|
+
var _a, _b, _c;
|
|
797
|
+
const topazOptions = await parseProviderOptions2({
|
|
798
|
+
provider: "topaz",
|
|
799
|
+
providerOptions: options.providerOptions,
|
|
800
|
+
schema: topazVideoModelOptionsSchema
|
|
801
|
+
});
|
|
802
|
+
const started = await this.start(options);
|
|
803
|
+
const pollIntervalMillis = (_a = topazOptions == null ? void 0 : topazOptions.pollIntervalMillis) != null ? _a : DEFAULT_POLL_INTERVAL_MILLIS2;
|
|
804
|
+
const pollTimeoutMillis = (_b = topazOptions == null ? void 0 : topazOptions.pollTimeoutMillis) != null ? _b : DEFAULT_POLL_TIMEOUT_MILLIS2;
|
|
805
|
+
const deadline = Date.now() + pollTimeoutMillis;
|
|
806
|
+
try {
|
|
807
|
+
while (true) {
|
|
808
|
+
const result = await this.getStatus({
|
|
809
|
+
operation: started.operation,
|
|
810
|
+
headers: options.headers,
|
|
811
|
+
abortSignal: options.abortSignal
|
|
812
|
+
});
|
|
813
|
+
if (result != null) {
|
|
814
|
+
return {
|
|
815
|
+
...result,
|
|
816
|
+
warnings: [...started.warnings, ...result.warnings],
|
|
817
|
+
response: {
|
|
818
|
+
...result.response,
|
|
819
|
+
timestamp: started.response.timestamp
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
if (Date.now() + pollIntervalMillis > deadline) {
|
|
824
|
+
const headers = combineHeaders2(
|
|
825
|
+
await resolve2(this.config.headers),
|
|
826
|
+
options.headers
|
|
827
|
+
);
|
|
828
|
+
await this.cancelQuietly(started.operation.requestId, headers);
|
|
829
|
+
throw new AISDKError2({
|
|
830
|
+
name: "TOPAZ_VIDEO_ENHANCEMENT_TIMEOUT",
|
|
831
|
+
message: `Topaz video enhancement did not finish within ${pollTimeoutMillis}ms (request ${started.operation.requestId}). Increase the \`pollTimeoutMillis\` provider option if the job needs longer.`
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
await delay2(pollIntervalMillis, { abortSignal: options.abortSignal });
|
|
835
|
+
}
|
|
836
|
+
} catch (error) {
|
|
837
|
+
if ((_c = options.abortSignal) == null ? void 0 : _c.aborted) {
|
|
838
|
+
const headers = combineHeaders2(
|
|
839
|
+
await resolve2(this.config.headers),
|
|
840
|
+
options.headers
|
|
841
|
+
);
|
|
842
|
+
await this.cancelQuietly(started.operation.requestId, headers);
|
|
843
|
+
}
|
|
844
|
+
throw error;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
async start(options) {
|
|
848
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
849
|
+
const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
|
|
850
|
+
const warnings = [];
|
|
851
|
+
const topazOptions = await parseProviderOptions2({
|
|
852
|
+
provider: "topaz",
|
|
853
|
+
providerOptions: options.providerOptions,
|
|
854
|
+
schema: topazVideoModelOptionsSchema
|
|
855
|
+
});
|
|
856
|
+
const headers = combineHeaders2(
|
|
857
|
+
await resolve2(this.config.headers),
|
|
858
|
+
options.headers
|
|
859
|
+
);
|
|
860
|
+
this.addUnsupportedWarnings(options, warnings);
|
|
861
|
+
const input = this.selectInputVideo(options, warnings);
|
|
862
|
+
const container = resolveContainer(input, (_d = topazOptions == null ? void 0 : topazOptions.source) == null ? void 0 : _d.container);
|
|
863
|
+
const source = resolveSource(topazOptions, container);
|
|
864
|
+
const output = buildOutput({ options, topazOptions, source });
|
|
865
|
+
const filters = [
|
|
866
|
+
buildFilter(this.modelId, topazOptions),
|
|
867
|
+
...(_e = topazOptions == null ? void 0 : topazOptions.additionalFilters) != null ? _e : []
|
|
868
|
+
];
|
|
869
|
+
const contentType = (_f = containerMediaTypes[source.container]) != null ? _f : "application/octet-stream";
|
|
870
|
+
const metadata = source.metadata;
|
|
871
|
+
const bytes = input.type === "file" ? fileBytes(input) : void 0;
|
|
872
|
+
let requestId;
|
|
873
|
+
try {
|
|
874
|
+
const { value: created, responseHeaders } = await postJsonToApi({
|
|
875
|
+
url: `${this.config.baseURL}/video/express`,
|
|
876
|
+
headers,
|
|
877
|
+
body: {
|
|
878
|
+
source: {
|
|
879
|
+
container: source.container,
|
|
880
|
+
...metadata != null ? {
|
|
881
|
+
duration: metadata.duration,
|
|
882
|
+
frameCount: metadata.frameCount,
|
|
883
|
+
frameRate: metadata.frameRate,
|
|
884
|
+
resolution: {
|
|
885
|
+
width: metadata.width,
|
|
886
|
+
height: metadata.height
|
|
887
|
+
}
|
|
888
|
+
} : {},
|
|
889
|
+
...input.type === "url" ? (
|
|
890
|
+
// Topaz fetches URL inputs itself, so, like other providers,
|
|
891
|
+
// the SDK never downloads them.
|
|
892
|
+
{ external: { provider: "s3", presignedUrl: input.url } }
|
|
893
|
+
) : { size: bytes == null ? void 0 : bytes.byteLength }
|
|
894
|
+
},
|
|
895
|
+
output,
|
|
896
|
+
filters
|
|
897
|
+
},
|
|
898
|
+
successfulResponseHandler: createJsonResponseHandler2(
|
|
899
|
+
topazVideoExpressResponseSchema
|
|
900
|
+
),
|
|
901
|
+
failedResponseHandler: topazFailedResponseHandler,
|
|
902
|
+
abortSignal: options.abortSignal,
|
|
903
|
+
fetch: this.config.fetch
|
|
904
|
+
});
|
|
905
|
+
requestId = requireRequestId(created.requestId);
|
|
906
|
+
if (bytes != null) {
|
|
907
|
+
await this.uploadVideo({
|
|
908
|
+
requestId,
|
|
909
|
+
bytes,
|
|
910
|
+
urls: created.uploadUrls,
|
|
911
|
+
contentType,
|
|
912
|
+
abortSignal: options.abortSignal
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
return {
|
|
916
|
+
// The output container travels with the operation so the polling code can
|
|
917
|
+
// report the right media type without re-deriving it.
|
|
918
|
+
operation: { requestId, outputContainer: output.container },
|
|
919
|
+
warnings,
|
|
920
|
+
providerMetadata: {
|
|
921
|
+
topaz: {
|
|
922
|
+
requestId,
|
|
923
|
+
// Preliminary: Topaz estimates up front only when it gets source
|
|
924
|
+
// metadata, and the completed status carries the billed value.
|
|
925
|
+
...((_g = created.estimates) == null ? void 0 : _g.cost) != null ? { estimatedCredits: created.estimates.cost } : {}
|
|
926
|
+
}
|
|
927
|
+
},
|
|
928
|
+
response: {
|
|
929
|
+
timestamp: currentDate,
|
|
930
|
+
modelId: this.modelId,
|
|
931
|
+
headers: responseHeaders
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
} catch (error) {
|
|
935
|
+
if (requestId != null) {
|
|
936
|
+
await this.cancelQuietly(requestId, headers);
|
|
937
|
+
}
|
|
938
|
+
throw error;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
async getStatus(options) {
|
|
942
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
943
|
+
const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
|
|
944
|
+
const { requestId, outputContainer } = options.operation;
|
|
945
|
+
const { value: status, responseHeaders } = await topazGetFromApi({
|
|
946
|
+
url: `${this.config.baseURL}/video/${requestId}/status`,
|
|
947
|
+
// Built from the configured baseURL, not from response data.
|
|
948
|
+
validateUrl: false,
|
|
949
|
+
headers: combineHeaders2(
|
|
950
|
+
await resolve2(this.config.headers),
|
|
951
|
+
options.headers
|
|
952
|
+
),
|
|
953
|
+
successfulResponseHandler: createJsonResponseHandler2(
|
|
954
|
+
topazVideoStatusResponseSchema
|
|
955
|
+
),
|
|
956
|
+
failedResponseHandler: topazFailedResponseHandler,
|
|
957
|
+
abortSignal: options.abortSignal,
|
|
958
|
+
fetch: this.config.fetch
|
|
959
|
+
});
|
|
960
|
+
const response = {
|
|
961
|
+
timestamp: currentDate,
|
|
962
|
+
modelId: this.modelId,
|
|
963
|
+
headers: responseHeaders
|
|
964
|
+
};
|
|
965
|
+
if (status.status === "complete") {
|
|
966
|
+
const credits = lowerBoundCredits((_d = status.estimates) == null ? void 0 : _d.cost);
|
|
967
|
+
const url = (_e = status.download) == null ? void 0 : _e.url;
|
|
968
|
+
if (url == null) {
|
|
969
|
+
throw new InvalidResponseDataError2({
|
|
970
|
+
data: status,
|
|
971
|
+
message: `Topaz reported request ${requestId} complete but returned no download URL.`
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
return {
|
|
975
|
+
videos: [
|
|
976
|
+
{
|
|
977
|
+
type: "url",
|
|
978
|
+
url,
|
|
979
|
+
mediaType: (_f = outputContainer != null ? containerMediaTypes[outputContainer] : void 0) != null ? _f : "video/mp4"
|
|
980
|
+
}
|
|
981
|
+
],
|
|
982
|
+
warnings: [],
|
|
983
|
+
response,
|
|
984
|
+
providerMetadata: {
|
|
985
|
+
topaz: {
|
|
986
|
+
requestId,
|
|
987
|
+
...credits != null ? { credits } : {},
|
|
988
|
+
...((_g = status.estimates) == null ? void 0 : _g.cost) != null ? { estimatedCredits: status.estimates.cost } : {},
|
|
989
|
+
...status.outputSize != null ? { outputSize: status.outputSize } : {},
|
|
990
|
+
...((_h = status.download) == null ? void 0 : _h.expiresAt) != null ? { expiresAt: status.download.expiresAt } : {}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
if (status.status === "failed" || status.status === "canceled") {
|
|
996
|
+
throw new AISDKError2({
|
|
997
|
+
name: "TOPAZ_VIDEO_ENHANCEMENT_FAILED",
|
|
998
|
+
message: `Topaz video request ${requestId} ${status.status}` + (status.errorCode != null ? ` (${status.errorCode})` : "") + (status.message != null ? `: ${status.message}` : ".")
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
return void 0;
|
|
1002
|
+
}
|
|
1003
|
+
addUnsupportedWarnings(options, warnings) {
|
|
1004
|
+
if (options.prompt != null && options.prompt.trim() !== "") {
|
|
1005
|
+
warnings.push({
|
|
1006
|
+
type: "unsupported",
|
|
1007
|
+
feature: "prompt",
|
|
1008
|
+
details: "Topaz video models enhance an existing video and do not take a text prompt. The prompt was ignored."
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
if (options.aspectRatio != null) {
|
|
1012
|
+
warnings.push({
|
|
1013
|
+
type: "unsupported",
|
|
1014
|
+
feature: "aspectRatio",
|
|
1015
|
+
details: "Topaz video models do not support aspectRatio. Use `resolution`, or the `output` provider option, to set the output dimensions."
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
if (options.seed != null) {
|
|
1019
|
+
warnings.push({
|
|
1020
|
+
type: "unsupported",
|
|
1021
|
+
feature: "seed",
|
|
1022
|
+
details: "Topaz video models do not support seed."
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
if (options.duration != null) {
|
|
1026
|
+
warnings.push({
|
|
1027
|
+
type: "unsupported",
|
|
1028
|
+
feature: "duration",
|
|
1029
|
+
details: "Topaz video models enhance the whole input video, so duration was ignored. Pass the input duration via the `source.duration` provider option instead."
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
if (options.generateAudio != null) {
|
|
1033
|
+
warnings.push({
|
|
1034
|
+
type: "unsupported",
|
|
1035
|
+
feature: "generateAudio",
|
|
1036
|
+
details: "Topaz video models do not generate audio. Use the `output.audioTransfer` provider option to control how the input audio track is carried over."
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
if (options.frameImages != null && options.frameImages.length > 0) {
|
|
1040
|
+
warnings.push({
|
|
1041
|
+
type: "unsupported",
|
|
1042
|
+
feature: "frameImages",
|
|
1043
|
+
details: "Topaz video models do not support first/last frame generation. The frame images were ignored."
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
if (options.n > 1) {
|
|
1047
|
+
warnings.push({
|
|
1048
|
+
type: "unsupported",
|
|
1049
|
+
feature: "n",
|
|
1050
|
+
details: "Topaz video models enhance one video per call. Only 1 video will be produced."
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
selectInputVideo(options, warnings) {
|
|
1055
|
+
var _a;
|
|
1056
|
+
const references = (_a = options.inputReferences) != null ? _a : [];
|
|
1057
|
+
const videos = references.filter(isVideoReference);
|
|
1058
|
+
if (videos.length === 0) {
|
|
1059
|
+
if (options.image != null) {
|
|
1060
|
+
throw new InvalidArgumentError2({
|
|
1061
|
+
argument: "image",
|
|
1062
|
+
message: "Topaz video models enhance an existing video, not a still image. Pass the input video via `inputReferences`."
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
throw new InvalidArgumentError2({
|
|
1066
|
+
argument: "inputReferences",
|
|
1067
|
+
message: 'Topaz video models require an input video. Pass it via `inputReferences`, e.g. `inputReferences: [{ type: "file", mediaType: "video/mp4", data: bytes }]`. For URL references, include `mediaType` so the reference is recognized as a video.'
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
if (references.length > 1) {
|
|
1071
|
+
warnings.push({
|
|
1072
|
+
type: "unsupported",
|
|
1073
|
+
feature: "inputReferences",
|
|
1074
|
+
details: "Topaz video models enhance a single video. Only the first video reference was used."
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
return videos[0];
|
|
1078
|
+
}
|
|
1079
|
+
async uploadVideo({
|
|
1080
|
+
requestId,
|
|
1081
|
+
bytes,
|
|
1082
|
+
urls,
|
|
1083
|
+
contentType,
|
|
1084
|
+
abortSignal
|
|
1085
|
+
}) {
|
|
1086
|
+
var _a;
|
|
1087
|
+
const url = urls == null ? void 0 : urls[0];
|
|
1088
|
+
if (url == null) {
|
|
1089
|
+
throw new InvalidResponseDataError2({
|
|
1090
|
+
data: urls,
|
|
1091
|
+
message: `Topaz returned no upload URL for request ${requestId}.`
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
if (!isSameOrigin2(url, this.config.baseURL)) {
|
|
1095
|
+
validateDownloadUrl(url);
|
|
1096
|
+
}
|
|
1097
|
+
const fetchImpl = (_a = this.config.fetch) != null ? _a : globalThis.fetch;
|
|
1098
|
+
const response = await fetchImpl(url, {
|
|
1099
|
+
method: "PUT",
|
|
1100
|
+
headers: withUserAgentSuffix(
|
|
1101
|
+
{ "Content-Type": contentType },
|
|
1102
|
+
`ai-sdk-topaz/${VERSION}`
|
|
1103
|
+
),
|
|
1104
|
+
body: bytes,
|
|
1105
|
+
signal: abortSignal
|
|
1106
|
+
});
|
|
1107
|
+
if (!response.ok) {
|
|
1108
|
+
throw new APICallError({
|
|
1109
|
+
message: `Uploading the input video failed with status ${response.status}.`,
|
|
1110
|
+
url,
|
|
1111
|
+
requestBodyValues: {},
|
|
1112
|
+
statusCode: response.status,
|
|
1113
|
+
responseHeaders: Object.fromEntries(response.headers.entries()),
|
|
1114
|
+
responseBody: await response.text()
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
async cancelQuietly(requestId, headers) {
|
|
1119
|
+
var _a;
|
|
1120
|
+
const fetchImpl = (_a = this.config.fetch) != null ? _a : globalThis.fetch;
|
|
1121
|
+
try {
|
|
1122
|
+
await fetchImpl(`${this.config.baseURL}/video/${requestId}`, {
|
|
1123
|
+
method: "DELETE",
|
|
1124
|
+
headers: removeUndefinedEntries2(headers)
|
|
1125
|
+
});
|
|
1126
|
+
} catch (e) {
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1130
|
+
function lowerBoundCredits(cost) {
|
|
1131
|
+
return cost != null && cost.length > 0 ? Math.min(...cost) : void 0;
|
|
1132
|
+
}
|
|
1133
|
+
function fileBytes(input) {
|
|
1134
|
+
return typeof input.data === "string" ? convertBase64ToUint8Array2(input.data) : input.data;
|
|
1135
|
+
}
|
|
1136
|
+
function resolveContainer(input, declaredContainer) {
|
|
1137
|
+
var _a;
|
|
1138
|
+
if (declaredContainer != null) {
|
|
1139
|
+
return declaredContainer;
|
|
1140
|
+
}
|
|
1141
|
+
if (input.type === "file") {
|
|
1142
|
+
const container2 = mediaTypeContainers[input.mediaType.toLowerCase()];
|
|
1143
|
+
if (container2 == null) {
|
|
1144
|
+
throw new InvalidArgumentError2({
|
|
1145
|
+
argument: "inputReferences",
|
|
1146
|
+
message: `Could not map the media type "${input.mediaType}" onto a Topaz container. Set the \`source.container\` provider option explicitly.`
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
return container2;
|
|
1150
|
+
}
|
|
1151
|
+
const container = (_a = input.mediaType != null ? mediaTypeContainers[input.mediaType.toLowerCase()] : void 0) != null ? _a : containerFromUrl(input.url);
|
|
1152
|
+
if (container == null) {
|
|
1153
|
+
throw new InvalidArgumentError2({
|
|
1154
|
+
argument: "inputReferences",
|
|
1155
|
+
message: `Could not determine the container of the input video at "${input.url}". Set the \`source.container\` provider option, or pass \`mediaType\` on the reference.`
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
return container;
|
|
1159
|
+
}
|
|
1160
|
+
function isVideoReference(reference) {
|
|
1161
|
+
if (reference.type === "file") {
|
|
1162
|
+
return reference.mediaType.toLowerCase().startsWith("video/");
|
|
1163
|
+
}
|
|
1164
|
+
if (reference.mediaType != null) {
|
|
1165
|
+
return reference.mediaType.toLowerCase().startsWith("video/");
|
|
1166
|
+
}
|
|
1167
|
+
return containerFromUrl(reference.url) != null;
|
|
1168
|
+
}
|
|
1169
|
+
function containerFromUrl(url) {
|
|
1170
|
+
var _a;
|
|
1171
|
+
const withoutQuery = url.split(/[?#]/)[0];
|
|
1172
|
+
const extension = (_a = withoutQuery.split(".").pop()) == null ? void 0 : _a.toLowerCase();
|
|
1173
|
+
return extension != null ? extensionContainers[extension] : void 0;
|
|
1174
|
+
}
|
|
1175
|
+
function resolveSource(topazOptions, container) {
|
|
1176
|
+
var _a;
|
|
1177
|
+
const source = topazOptions == null ? void 0 : topazOptions.source;
|
|
1178
|
+
const { width, height, duration, frameRate } = source != null ? source : {};
|
|
1179
|
+
if (width == null && height == null && duration == null && frameRate == null && (source == null ? void 0 : source.frameCount) == null) {
|
|
1180
|
+
return { container, metadata: void 0 };
|
|
1181
|
+
}
|
|
1182
|
+
const frameCount = (_a = source == null ? void 0 : source.frameCount) != null ? _a : duration != null && frameRate != null ? Math.round(duration * frameRate) : void 0;
|
|
1183
|
+
const missing = [
|
|
1184
|
+
width == null ? "source.width" : void 0,
|
|
1185
|
+
height == null ? "source.height" : void 0,
|
|
1186
|
+
duration == null ? "source.duration" : void 0,
|
|
1187
|
+
frameRate == null ? "source.frameRate" : void 0
|
|
1188
|
+
].filter((field) => field != null);
|
|
1189
|
+
if (width == null || height == null || duration == null || frameRate == null || frameCount == null) {
|
|
1190
|
+
throw new InvalidArgumentError2({
|
|
1191
|
+
argument: "providerOptions.topaz.source",
|
|
1192
|
+
message: `Source metadata must be complete. Missing: ${missing.join(", ")}.`
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
return {
|
|
1196
|
+
container,
|
|
1197
|
+
metadata: { duration, frameRate, frameCount, width, height }
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
function parseResolution(resolution) {
|
|
1201
|
+
if (resolution == null) {
|
|
1202
|
+
return { width: void 0, height: void 0 };
|
|
1203
|
+
}
|
|
1204
|
+
const [width, height] = resolution.split("x").map(Number);
|
|
1205
|
+
return { width, height };
|
|
1206
|
+
}
|
|
1207
|
+
function buildOutput({
|
|
1208
|
+
options,
|
|
1209
|
+
topazOptions,
|
|
1210
|
+
source
|
|
1211
|
+
}) {
|
|
1212
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
1213
|
+
const output = topazOptions == null ? void 0 : topazOptions.output;
|
|
1214
|
+
const resolution = parseResolution(options.resolution);
|
|
1215
|
+
const width = (_c = (_a = output == null ? void 0 : output.width) != null ? _a : resolution.width) != null ? _c : (_b = source.metadata) == null ? void 0 : _b.width;
|
|
1216
|
+
const height = (_f = (_d = output == null ? void 0 : output.height) != null ? _d : resolution.height) != null ? _f : (_e = source.metadata) == null ? void 0 : _e.height;
|
|
1217
|
+
if (width == null || height == null) {
|
|
1218
|
+
throw new InvalidArgumentError2({
|
|
1219
|
+
argument: "resolution",
|
|
1220
|
+
message: "Topaz needs the output resolution. Set the `resolution` call option or the `output.width` / `output.height` provider options."
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
const frameRate = (_i = (_g = output == null ? void 0 : output.frameRate) != null ? _g : options.fps) != null ? _i : (_h = source.metadata) == null ? void 0 : _h.frameRate;
|
|
1224
|
+
const audioTransfer = (_j = output == null ? void 0 : output.audioTransfer) != null ? _j : "Copy";
|
|
1225
|
+
return {
|
|
1226
|
+
resolution: { width, height },
|
|
1227
|
+
...frameRate != null ? { frameRate } : {},
|
|
1228
|
+
audioTransfer,
|
|
1229
|
+
...audioTransfer !== "None" ? { audioCodec: (_k = output == null ? void 0 : output.audioCodec) != null ? _k : "AAC" } : (output == null ? void 0 : output.audioCodec) != null ? { audioCodec: output.audioCodec } : {},
|
|
1230
|
+
...(output == null ? void 0 : output.audioBitrate) != null ? { audioBitrate: output.audioBitrate } : {},
|
|
1231
|
+
...(output == null ? void 0 : output.videoEncoder) != null ? { videoEncoder: output.videoEncoder } : {},
|
|
1232
|
+
...(output == null ? void 0 : output.videoProfile) != null ? { videoProfile: output.videoProfile } : {},
|
|
1233
|
+
...(output == null ? void 0 : output.videoBitrate) != null ? { videoBitrate: output.videoBitrate } : {},
|
|
1234
|
+
...(output == null ? void 0 : output.dynamicCompressionLevel) != null ? { dynamicCompressionLevel: output.dynamicCompressionLevel } : {},
|
|
1235
|
+
...(output == null ? void 0 : output.cropToFit) != null ? { cropToFit: output.cropToFit } : {},
|
|
1236
|
+
container: resolveOutputContainer(output, source.container)
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
function resolveOutputContainer(output, sourceContainer) {
|
|
1240
|
+
switch (output == null ? void 0 : output.videoEncoder) {
|
|
1241
|
+
case "ProRes":
|
|
1242
|
+
return "mov";
|
|
1243
|
+
case "AV1":
|
|
1244
|
+
case "VP9":
|
|
1245
|
+
return "mp4";
|
|
1246
|
+
}
|
|
1247
|
+
if ((output == null ? void 0 : output.container) != null) {
|
|
1248
|
+
return output.container;
|
|
1249
|
+
}
|
|
1250
|
+
return sourceContainer === "mov" || sourceContainer === "mkv" ? sourceContainer : "mp4";
|
|
1251
|
+
}
|
|
1252
|
+
function requireRequestId(requestId) {
|
|
1253
|
+
if (requestId == null) {
|
|
1254
|
+
throw new InvalidResponseDataError2({
|
|
1255
|
+
data: requestId,
|
|
1256
|
+
message: "Topaz did not return a requestId for the video request."
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
return requestId;
|
|
1260
|
+
}
|
|
1261
|
+
function buildFilter(modelId, topazOptions) {
|
|
1262
|
+
var _a;
|
|
1263
|
+
const filter = {
|
|
1264
|
+
model: resolveTopazVideoApiModelId(modelId)
|
|
1265
|
+
};
|
|
1266
|
+
if (topazOptions != null) {
|
|
1267
|
+
const nonFilterKeys = new Set(TOPAZ_NON_FILTER_OPTION_KEYS);
|
|
1268
|
+
for (const [key, value] of Object.entries(topazOptions)) {
|
|
1269
|
+
if (!nonFilterKeys.has(key) && value !== void 0) {
|
|
1270
|
+
filter[key] = value;
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
Object.assign(filter, (_a = topazOptions.filter) != null ? _a : {});
|
|
1274
|
+
}
|
|
1275
|
+
return filter;
|
|
1276
|
+
}
|
|
1277
|
+
var topazVideoEstimatesSchema = z5.object({
|
|
1278
|
+
cost: z5.array(z5.number()).nullish(),
|
|
1279
|
+
time: z5.array(z5.number()).nullish()
|
|
1280
|
+
}).nullish();
|
|
1281
|
+
var topazVideoExpressResponseSchema = z5.object({
|
|
1282
|
+
requestId: z5.string().nullish(),
|
|
1283
|
+
uploadUrls: z5.array(z5.string()).nullish(),
|
|
1284
|
+
estimates: topazVideoEstimatesSchema
|
|
1285
|
+
});
|
|
1286
|
+
var topazVideoStatusResponseSchema = z5.object({
|
|
1287
|
+
status: z5.string().nullish(),
|
|
1288
|
+
message: z5.string().nullish(),
|
|
1289
|
+
errorCode: z5.string().nullish(),
|
|
1290
|
+
// Documented as a string, accepted as a number too.
|
|
1291
|
+
outputSize: z5.union([z5.string(), z5.number()]).nullish(),
|
|
1292
|
+
estimates: topazVideoEstimatesSchema,
|
|
1293
|
+
download: z5.object({
|
|
1294
|
+
url: z5.string().nullish(),
|
|
1295
|
+
expiresAt: z5.union([z5.string(), z5.number()]).nullish()
|
|
1296
|
+
}).nullish()
|
|
1297
|
+
});
|
|
1298
|
+
|
|
1299
|
+
// src/topaz-provider.ts
|
|
1300
|
+
var defaultBaseURL = "https://api.topazlabs.com";
|
|
1301
|
+
function createTopaz(options = {}) {
|
|
1302
|
+
var _a, _b;
|
|
1303
|
+
const baseURL = (_b = withoutTrailingSlash((_a = options.baseURL) != null ? _a : defaultBaseURL)) != null ? _b : defaultBaseURL;
|
|
1304
|
+
const getHeaders = () => withUserAgentSuffix2(
|
|
1305
|
+
{
|
|
1306
|
+
"X-API-Key": loadApiKey({
|
|
1307
|
+
apiKey: options.apiKey,
|
|
1308
|
+
environmentVariableName: "TOPAZ_API_KEY",
|
|
1309
|
+
description: "Topaz Labs"
|
|
1310
|
+
}),
|
|
1311
|
+
accept: "application/json",
|
|
1312
|
+
...options.headers
|
|
1313
|
+
},
|
|
1314
|
+
`ai-sdk-topaz/${VERSION}`
|
|
1315
|
+
);
|
|
1316
|
+
const createImageModel = (modelId) => new TopazImageModel(modelId, {
|
|
1317
|
+
provider: "topaz.image",
|
|
1318
|
+
baseURL,
|
|
1319
|
+
headers: getHeaders,
|
|
1320
|
+
fetch: options.fetch
|
|
1321
|
+
});
|
|
1322
|
+
const createVideoModel = (modelId) => new TopazVideoModel(modelId, {
|
|
1323
|
+
provider: "topaz.video",
|
|
1324
|
+
baseURL,
|
|
1325
|
+
headers: getHeaders,
|
|
1326
|
+
fetch: options.fetch
|
|
1327
|
+
});
|
|
1328
|
+
const noSuchModel = (modelId, modelType) => {
|
|
1329
|
+
throw new NoSuchModelError({ modelId, modelType });
|
|
1330
|
+
};
|
|
1331
|
+
const provider = {
|
|
1332
|
+
specificationVersion: "v3",
|
|
1333
|
+
image: createImageModel,
|
|
1334
|
+
imageModel: createImageModel,
|
|
1335
|
+
video: createVideoModel,
|
|
1336
|
+
videoModel: createVideoModel,
|
|
1337
|
+
languageModel: (modelId) => noSuchModel(modelId, "languageModel"),
|
|
1338
|
+
embeddingModel: (modelId) => noSuchModel(modelId, "embeddingModel")
|
|
1339
|
+
};
|
|
1340
|
+
return provider;
|
|
1341
|
+
}
|
|
1342
|
+
var topaz = createTopaz();
|
|
1343
|
+
export {
|
|
1344
|
+
VERSION,
|
|
1345
|
+
createTopaz,
|
|
1346
|
+
topaz
|
|
1347
|
+
};
|
|
1348
|
+
//# sourceMappingURL=index.js.map
|