@ai-sdk/topaz 0.0.0 → 2.0.1
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 +14 -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
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NoSuchModelError,
|
|
3
|
+
type Experimental_VideoModelV3 as VideoModelV3,
|
|
4
|
+
type ImageModelV3,
|
|
5
|
+
type ProviderV3,
|
|
6
|
+
} from '@ai-sdk/provider';
|
|
7
|
+
import {
|
|
8
|
+
loadApiKey,
|
|
9
|
+
withoutTrailingSlash,
|
|
10
|
+
withUserAgentSuffix,
|
|
11
|
+
type FetchFunction,
|
|
12
|
+
} from '@ai-sdk/provider-utils';
|
|
13
|
+
import { TopazImageModel } from './topaz-image-model';
|
|
14
|
+
import type { TopazImageModelId } from './topaz-image-settings';
|
|
15
|
+
import { TopazVideoModel } from './topaz-video-model';
|
|
16
|
+
import type { TopazVideoModelId } from './topaz-video-settings';
|
|
17
|
+
import { VERSION } from './version';
|
|
18
|
+
|
|
19
|
+
export interface TopazProviderSettings {
|
|
20
|
+
/**
|
|
21
|
+
* Topaz Labs API key. Default value is taken from the `TOPAZ_API_KEY`
|
|
22
|
+
* environment variable.
|
|
23
|
+
*
|
|
24
|
+
* @see https://developer.topazlabs.com/getting-started/api-key-setup
|
|
25
|
+
*/
|
|
26
|
+
apiKey?: string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Base URL for the API calls.
|
|
30
|
+
*/
|
|
31
|
+
baseURL?: string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Custom headers to include in the requests.
|
|
35
|
+
*/
|
|
36
|
+
headers?: Record<string, string>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Custom fetch implementation. You can use it as a middleware to intercept
|
|
40
|
+
* requests, or to provide a custom fetch implementation for e.g. testing.
|
|
41
|
+
*/
|
|
42
|
+
fetch?: FetchFunction;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface TopazProvider extends ProviderV3 {
|
|
46
|
+
/**
|
|
47
|
+
* Creates a model for image enhancement.
|
|
48
|
+
*/
|
|
49
|
+
image(modelId: TopazImageModelId): ImageModelV3;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates a model for image enhancement.
|
|
53
|
+
*/
|
|
54
|
+
imageModel(modelId: TopazImageModelId): ImageModelV3;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Creates a model for video enhancement.
|
|
58
|
+
*/
|
|
59
|
+
video(modelId: TopazVideoModelId): VideoModelV3;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Creates a model for video enhancement.
|
|
63
|
+
*/
|
|
64
|
+
videoModel(modelId: TopazVideoModelId): VideoModelV3;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const defaultBaseURL = 'https://api.topazlabs.com';
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Create a Topaz Labs provider instance.
|
|
71
|
+
*/
|
|
72
|
+
export function createTopaz(
|
|
73
|
+
options: TopazProviderSettings = {},
|
|
74
|
+
): TopazProvider {
|
|
75
|
+
const baseURL =
|
|
76
|
+
withoutTrailingSlash(options.baseURL ?? defaultBaseURL) ?? defaultBaseURL;
|
|
77
|
+
|
|
78
|
+
const getHeaders = () =>
|
|
79
|
+
withUserAgentSuffix(
|
|
80
|
+
{
|
|
81
|
+
'X-API-Key': loadApiKey({
|
|
82
|
+
apiKey: options.apiKey,
|
|
83
|
+
environmentVariableName: 'TOPAZ_API_KEY',
|
|
84
|
+
description: 'Topaz Labs',
|
|
85
|
+
}),
|
|
86
|
+
accept: 'application/json',
|
|
87
|
+
...options.headers,
|
|
88
|
+
},
|
|
89
|
+
`ai-sdk-topaz/${VERSION}`,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const createImageModel = (modelId: TopazImageModelId): ImageModelV3 =>
|
|
93
|
+
new TopazImageModel(modelId, {
|
|
94
|
+
provider: 'topaz.image',
|
|
95
|
+
baseURL,
|
|
96
|
+
headers: getHeaders,
|
|
97
|
+
fetch: options.fetch,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const createVideoModel = (modelId: TopazVideoModelId): VideoModelV3 =>
|
|
101
|
+
new TopazVideoModel(modelId, {
|
|
102
|
+
provider: 'topaz.video',
|
|
103
|
+
baseURL,
|
|
104
|
+
headers: getHeaders,
|
|
105
|
+
fetch: options.fetch,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const noSuchModel = (
|
|
109
|
+
modelId: string,
|
|
110
|
+
modelType:
|
|
111
|
+
| 'languageModel'
|
|
112
|
+
| 'embeddingModel'
|
|
113
|
+
| 'transcriptionModel'
|
|
114
|
+
| 'speechModel'
|
|
115
|
+
| 'rerankingModel',
|
|
116
|
+
): never => {
|
|
117
|
+
throw new NoSuchModelError({ modelId, modelType });
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const provider: TopazProvider = {
|
|
121
|
+
specificationVersion: 'v3' as const,
|
|
122
|
+
image: createImageModel,
|
|
123
|
+
imageModel: createImageModel,
|
|
124
|
+
video: createVideoModel,
|
|
125
|
+
videoModel: createVideoModel,
|
|
126
|
+
languageModel: (modelId: string) => noSuchModel(modelId, 'languageModel'),
|
|
127
|
+
embeddingModel: (modelId: string) => noSuchModel(modelId, 'embeddingModel'),
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
return provider;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Default Topaz Labs provider instance.
|
|
135
|
+
*/
|
|
136
|
+
export const topaz = createTopaz();
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import {
|
|
2
|
+
lazySchema,
|
|
3
|
+
zodSchema,
|
|
4
|
+
type InferSchema,
|
|
5
|
+
} from '@ai-sdk/provider-utils';
|
|
6
|
+
import { z } from 'zod/v4';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Containers Topaz accepts for the input video.
|
|
10
|
+
*/
|
|
11
|
+
export const topazSourceContainers = [
|
|
12
|
+
'3gp',
|
|
13
|
+
'avi',
|
|
14
|
+
'dv',
|
|
15
|
+
'flv',
|
|
16
|
+
'm1v',
|
|
17
|
+
'm2t',
|
|
18
|
+
'm2ts',
|
|
19
|
+
'm2v',
|
|
20
|
+
'm4v',
|
|
21
|
+
'mkv',
|
|
22
|
+
'mov',
|
|
23
|
+
'mp4',
|
|
24
|
+
'mpeg',
|
|
25
|
+
'mpg',
|
|
26
|
+
'mts',
|
|
27
|
+
'mxf',
|
|
28
|
+
'ser',
|
|
29
|
+
'ts',
|
|
30
|
+
'vob',
|
|
31
|
+
'webm',
|
|
32
|
+
'wmv',
|
|
33
|
+
] as const;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Containers Topaz can produce for the enhanced video.
|
|
37
|
+
*/
|
|
38
|
+
export const topazOutputContainers = [
|
|
39
|
+
'mp4',
|
|
40
|
+
'mov',
|
|
41
|
+
'mkv',
|
|
42
|
+
'avi',
|
|
43
|
+
'webm',
|
|
44
|
+
] as const;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Metadata about the input video.
|
|
48
|
+
*
|
|
49
|
+
* Starlight models require `width`, `height`, `duration` and `frameRate`
|
|
50
|
+
* (Topaz prices them from these values), and for other models they let Topaz
|
|
51
|
+
* estimate the cost before it has the video. The AI SDK does not inspect
|
|
52
|
+
* media files, so the values come from the caller. Setting any of them
|
|
53
|
+
* requires all four.
|
|
54
|
+
*/
|
|
55
|
+
export const topazVideoSourceSchema = z.object({
|
|
56
|
+
/**
|
|
57
|
+
* Width of the input video in pixels.
|
|
58
|
+
*/
|
|
59
|
+
width: z.number().int().positive().optional(),
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Height of the input video in pixels.
|
|
63
|
+
*/
|
|
64
|
+
height: z.number().int().positive().optional(),
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Duration of the input video in seconds.
|
|
68
|
+
*/
|
|
69
|
+
duration: z.number().positive().optional(),
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Frame rate of the input video.
|
|
73
|
+
*/
|
|
74
|
+
frameRate: z.number().positive().optional(),
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Total number of frames in the input video. Derived from
|
|
78
|
+
* `duration * frameRate` when omitted, which is only correct for
|
|
79
|
+
* constant-frame-rate input, so set it explicitly for variable-frame-rate
|
|
80
|
+
* sources.
|
|
81
|
+
*/
|
|
82
|
+
frameCount: z.number().int().positive().optional(),
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Container of the input video. Detected from the input file's media type
|
|
86
|
+
* or URL extension when omitted.
|
|
87
|
+
*/
|
|
88
|
+
container: z.enum(topazSourceContainers).optional(),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
export type TopazVideoSource = z.infer<typeof topazVideoSourceSchema>;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Output settings for the enhanced video.
|
|
95
|
+
*/
|
|
96
|
+
export const topazVideoOutputSchema = z.object({
|
|
97
|
+
/**
|
|
98
|
+
* Width of the output video in pixels. Takes precedence over the
|
|
99
|
+
* `resolution` call option.
|
|
100
|
+
*/
|
|
101
|
+
width: z.number().int().positive().optional(),
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Height of the output video in pixels. Takes precedence over the
|
|
105
|
+
* `resolution` call option.
|
|
106
|
+
*/
|
|
107
|
+
height: z.number().int().positive().optional(),
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Frame rate of the output video. Takes precedence over the `fps` call
|
|
111
|
+
* option. Topaz only changes the frame rate when a frame-interpolation
|
|
112
|
+
* filter is present.
|
|
113
|
+
*/
|
|
114
|
+
frameRate: z.number().positive().optional(),
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Audio codec of the output video. Defaults to `AAC`.
|
|
118
|
+
*/
|
|
119
|
+
audioCodec: z.enum(['AAC', 'AC3', 'PCM']).optional(),
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Audio bitrate, e.g. `192k`. Topaz uses the codec default when omitted.
|
|
123
|
+
*/
|
|
124
|
+
audioBitrate: z.string().optional(),
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* How to handle the input audio track. Defaults to `Copy`.
|
|
128
|
+
*/
|
|
129
|
+
audioTransfer: z.enum(['Copy', 'Convert', 'None']).optional(),
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Video encoder. Topaz defaults to `H265`. `ProRes` forces a `mov`
|
|
133
|
+
* container, `AV1` and `VP9` force `mp4`.
|
|
134
|
+
*/
|
|
135
|
+
videoEncoder: z.enum(['AV1', 'H264', 'H265', 'ProRes', 'VP9']).optional(),
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Encoder profile, e.g. `Main10` for H265 or `422 HQ` for ProRes. Topaz uses
|
|
139
|
+
* the encoder's default profile when omitted.
|
|
140
|
+
*/
|
|
141
|
+
videoProfile: z.string().optional(),
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Constant bitrate, e.g. `20m`. Required for `VP9`. Mutually exclusive with
|
|
145
|
+
* `dynamicCompressionLevel`.
|
|
146
|
+
*/
|
|
147
|
+
videoBitrate: z.string().optional(),
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Automatic constant-quality compression level. Topaz defaults to `High`
|
|
151
|
+
* unless `videoBitrate` is set.
|
|
152
|
+
*/
|
|
153
|
+
dynamicCompressionLevel: z.enum(['Low', 'Mid', 'High']).optional(),
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Center-crop to fit the output dimensions.
|
|
157
|
+
*/
|
|
158
|
+
cropToFit: z.boolean().optional(),
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Container of the output video. Defaults to the input container when Topaz
|
|
162
|
+
* can produce it, otherwise `mp4`.
|
|
163
|
+
*/
|
|
164
|
+
container: z.enum(topazOutputContainers).optional(),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
export type TopazVideoOutput = z.infer<typeof topazVideoOutputSchema>;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Provider options for Topaz video models.
|
|
171
|
+
*
|
|
172
|
+
* @see https://developer.topazlabs.com/video-models/proteus/proteus-1
|
|
173
|
+
* @see https://developer.topazlabs.com/video-models/starlight/starlight-precise-2.6
|
|
174
|
+
*/
|
|
175
|
+
export const topazVideoModelOptionsSchema = lazySchema(() =>
|
|
176
|
+
zodSchema(
|
|
177
|
+
z.object({
|
|
178
|
+
/** Interval between status polls, in milliseconds. Defaults to 2000. */
|
|
179
|
+
pollIntervalMillis: z.number().positive().optional(),
|
|
180
|
+
/** Maximum time to poll, in milliseconds. Defaults to 3600000 (1 hour). */
|
|
181
|
+
pollTimeoutMillis: z.number().positive().optional(),
|
|
182
|
+
source: topazVideoSourceSchema.optional(),
|
|
183
|
+
output: topazVideoOutputSchema.optional(),
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Extra `filters[]` entries to send alongside the model's own filter, e.g. a
|
|
187
|
+
* frame-interpolation filter. Each entry must include a `model` key.
|
|
188
|
+
*/
|
|
189
|
+
additionalFilters: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Escape hatch for filter settings this package does not model yet. Merged
|
|
193
|
+
* into the model's filter entry, taking precedence over the typed options
|
|
194
|
+
* below.
|
|
195
|
+
*/
|
|
196
|
+
filter: z.record(z.string(), z.unknown()).optional(),
|
|
197
|
+
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
// Proteus (`proteus`)
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
|
|
202
|
+
/** Proteus: how the input frames are encoded. */
|
|
203
|
+
videoType: z
|
|
204
|
+
.enum(['Progressive', 'Interlaced', 'ProgressiveInterlaced'])
|
|
205
|
+
.optional(),
|
|
206
|
+
|
|
207
|
+
/** Proteus: parameter estimation mode. */
|
|
208
|
+
auto: z.enum(['Auto', 'Manual', 'Relative']).optional(),
|
|
209
|
+
|
|
210
|
+
/** Proteus: field order for interlaced input. */
|
|
211
|
+
fieldOrder: z.enum(['TopFirst', 'BottomFirst', 'Auto']).optional(),
|
|
212
|
+
|
|
213
|
+
/** Proteus: focus-fix strength. */
|
|
214
|
+
focusFixLevel: z.enum(['None', 'Normal', 'Strong']).optional(),
|
|
215
|
+
|
|
216
|
+
/** Proteus: compression artifact removal, -1 to 1. */
|
|
217
|
+
compression: z.number().min(-1).max(1).optional(),
|
|
218
|
+
|
|
219
|
+
/** Proteus: detail recovery, -1 to 1. */
|
|
220
|
+
details: z.number().min(-1).max(1).optional(),
|
|
221
|
+
|
|
222
|
+
/** Proteus: pre-processing noise reduction, 0 to 0.1. */
|
|
223
|
+
prenoise: z.number().min(0).max(0.1).optional(),
|
|
224
|
+
|
|
225
|
+
/** Proteus: noise reduction, -1 to 1. */
|
|
226
|
+
noise: z.number().min(-1).max(1).optional(),
|
|
227
|
+
|
|
228
|
+
/** Proteus: halo suppression, -1 to 1. */
|
|
229
|
+
halo: z.number().min(-1).max(1).optional(),
|
|
230
|
+
|
|
231
|
+
/** Proteus: pre-processing blur, -1 to 1. */
|
|
232
|
+
preblur: z.number().min(-1).max(1).optional(),
|
|
233
|
+
|
|
234
|
+
/** Proteus: sharpening, -1 to 1. */
|
|
235
|
+
blur: z.number().min(-1).max(1).optional(),
|
|
236
|
+
|
|
237
|
+
/** Proteus: grain amount, 0 to 0.1. */
|
|
238
|
+
grain: z.number().min(0).max(0.1).optional(),
|
|
239
|
+
|
|
240
|
+
/** Proteus: grain sigma, 0 to 1. */
|
|
241
|
+
grainSigma: z.number().min(0).max(1).optional(),
|
|
242
|
+
|
|
243
|
+
/** Proteus: grain size, 0 to 5. */
|
|
244
|
+
grainSize: z.number().min(0).max(5).optional(),
|
|
245
|
+
|
|
246
|
+
/** Proteus: grain model. */
|
|
247
|
+
grainType: z.enum(['silver_rich', 'gaussian', 'grey']).optional(),
|
|
248
|
+
|
|
249
|
+
/** Proteus: original detail recovery, 0 to 1. */
|
|
250
|
+
recoverOriginalDetailValue: z.number().min(0).max(1).optional(),
|
|
251
|
+
|
|
252
|
+
// ---------------------------------------------------------------------------
|
|
253
|
+
// Starlight Precise (`starlight-precise-2.6`)
|
|
254
|
+
// ---------------------------------------------------------------------------
|
|
255
|
+
|
|
256
|
+
/** Starlight: sharpening applied to the output, 1.0 to 5.0. Defaults to 5.0. */
|
|
257
|
+
sharpness: z.number().min(1).max(5).optional(),
|
|
258
|
+
|
|
259
|
+
/** Starlight: output bit depth. */
|
|
260
|
+
videoBitDepth: z.number().int().positive().optional(),
|
|
261
|
+
|
|
262
|
+
/** Starlight: output video codec. */
|
|
263
|
+
videoCodec: z.enum(['ffv1', 'prores', 'vp9']).optional(),
|
|
264
|
+
|
|
265
|
+
/** Starlight: output chroma subsampling profile. */
|
|
266
|
+
videoProfile: z.enum(['420', '422', '444']).optional(),
|
|
267
|
+
|
|
268
|
+
/** Starlight: whether to watermark the output. Defaults to `false`. */
|
|
269
|
+
watermark: z.boolean().optional(),
|
|
270
|
+
}),
|
|
271
|
+
),
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
export type TopazVideoModelOptions = InferSchema<
|
|
275
|
+
typeof topazVideoModelOptionsSchema
|
|
276
|
+
>;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Option keys that are structural rather than filter settings, so they are not
|
|
280
|
+
* forwarded into the `filters[]` entry.
|
|
281
|
+
*/
|
|
282
|
+
export const TOPAZ_NON_FILTER_OPTION_KEYS = [
|
|
283
|
+
'pollIntervalMillis',
|
|
284
|
+
'pollTimeoutMillis',
|
|
285
|
+
'source',
|
|
286
|
+
'output',
|
|
287
|
+
'additionalFilters',
|
|
288
|
+
'filter',
|
|
289
|
+
] as const satisfies ReadonlyArray<keyof TopazVideoModelOptions>;
|