@ai-sdk/topaz 0.0.0 → 3.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.
@@ -0,0 +1,136 @@
1
+ import {
2
+ NoSuchModelError,
3
+ type Experimental_VideoModelV4 as VideoModelV4,
4
+ type ImageModelV4,
5
+ type ProviderV4,
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 ProviderV4 {
46
+ /**
47
+ * Creates a model for image enhancement.
48
+ */
49
+ image(modelId: TopazImageModelId): ImageModelV4;
50
+
51
+ /**
52
+ * Creates a model for image enhancement.
53
+ */
54
+ imageModel(modelId: TopazImageModelId): ImageModelV4;
55
+
56
+ /**
57
+ * Creates a model for video enhancement.
58
+ */
59
+ video(modelId: TopazVideoModelId): VideoModelV4;
60
+
61
+ /**
62
+ * Creates a model for video enhancement.
63
+ */
64
+ videoModel(modelId: TopazVideoModelId): VideoModelV4;
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): ImageModelV4 =>
93
+ new TopazImageModel(modelId, {
94
+ provider: 'topaz.image',
95
+ baseURL,
96
+ headers: getHeaders,
97
+ fetch: options.fetch,
98
+ });
99
+
100
+ const createVideoModel = (modelId: TopazVideoModelId): VideoModelV4 =>
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: 'v4' 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,283 @@
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
+ source: topazVideoSourceSchema.optional(),
179
+ output: topazVideoOutputSchema.optional(),
180
+
181
+ /**
182
+ * Extra `filters[]` entries to send alongside the model's own filter, e.g. a
183
+ * frame-interpolation filter. Each entry must include a `model` key.
184
+ */
185
+ additionalFilters: z.array(z.record(z.string(), z.unknown())).optional(),
186
+
187
+ /**
188
+ * Escape hatch for filter settings this package does not model yet. Merged
189
+ * into the model's filter entry, taking precedence over the typed options
190
+ * below.
191
+ */
192
+ filter: z.record(z.string(), z.unknown()).optional(),
193
+
194
+ // ---------------------------------------------------------------------------
195
+ // Proteus (`proteus`)
196
+ // ---------------------------------------------------------------------------
197
+
198
+ /** Proteus: how the input frames are encoded. */
199
+ videoType: z
200
+ .enum(['Progressive', 'Interlaced', 'ProgressiveInterlaced'])
201
+ .optional(),
202
+
203
+ /** Proteus: parameter estimation mode. */
204
+ auto: z.enum(['Auto', 'Manual', 'Relative']).optional(),
205
+
206
+ /** Proteus: field order for interlaced input. */
207
+ fieldOrder: z.enum(['TopFirst', 'BottomFirst', 'Auto']).optional(),
208
+
209
+ /** Proteus: focus-fix strength. */
210
+ focusFixLevel: z.enum(['None', 'Normal', 'Strong']).optional(),
211
+
212
+ /** Proteus: compression artifact removal, -1 to 1. */
213
+ compression: z.number().min(-1).max(1).optional(),
214
+
215
+ /** Proteus: detail recovery, -1 to 1. */
216
+ details: z.number().min(-1).max(1).optional(),
217
+
218
+ /** Proteus: pre-processing noise reduction, 0 to 0.1. */
219
+ prenoise: z.number().min(0).max(0.1).optional(),
220
+
221
+ /** Proteus: noise reduction, -1 to 1. */
222
+ noise: z.number().min(-1).max(1).optional(),
223
+
224
+ /** Proteus: halo suppression, -1 to 1. */
225
+ halo: z.number().min(-1).max(1).optional(),
226
+
227
+ /** Proteus: pre-processing blur, -1 to 1. */
228
+ preblur: z.number().min(-1).max(1).optional(),
229
+
230
+ /** Proteus: sharpening, -1 to 1. */
231
+ blur: z.number().min(-1).max(1).optional(),
232
+
233
+ /** Proteus: grain amount, 0 to 0.1. */
234
+ grain: z.number().min(0).max(0.1).optional(),
235
+
236
+ /** Proteus: grain sigma, 0 to 1. */
237
+ grainSigma: z.number().min(0).max(1).optional(),
238
+
239
+ /** Proteus: grain size, 0 to 5. */
240
+ grainSize: z.number().min(0).max(5).optional(),
241
+
242
+ /** Proteus: grain model. */
243
+ grainType: z.enum(['silver_rich', 'gaussian', 'grey']).optional(),
244
+
245
+ /** Proteus: original detail recovery, 0 to 1. */
246
+ recoverOriginalDetailValue: z.number().min(0).max(1).optional(),
247
+
248
+ // ---------------------------------------------------------------------------
249
+ // Starlight Precise (`starlight-precise-2.6`)
250
+ // ---------------------------------------------------------------------------
251
+
252
+ /** Starlight: sharpening applied to the output, 1.0 to 5.0. Defaults to 5.0. */
253
+ sharpness: z.number().min(1).max(5).optional(),
254
+
255
+ /** Starlight: output bit depth. */
256
+ videoBitDepth: z.number().int().positive().optional(),
257
+
258
+ /** Starlight: output video codec. */
259
+ videoCodec: z.enum(['ffv1', 'prores', 'vp9']).optional(),
260
+
261
+ /** Starlight: output chroma subsampling profile. */
262
+ videoProfile: z.enum(['420', '422', '444']).optional(),
263
+
264
+ /** Starlight: whether to watermark the output. Defaults to `false`. */
265
+ watermark: z.boolean().optional(),
266
+ }),
267
+ ),
268
+ );
269
+
270
+ export type TopazVideoModelOptions = InferSchema<
271
+ typeof topazVideoModelOptionsSchema
272
+ >;
273
+
274
+ /**
275
+ * Option keys that are structural rather than filter settings, so they are not
276
+ * forwarded into the `filters[]` entry.
277
+ */
278
+ export const TOPAZ_NON_FILTER_OPTION_KEYS = [
279
+ 'source',
280
+ 'output',
281
+ 'additionalFilters',
282
+ 'filter',
283
+ ] as const satisfies ReadonlyArray<keyof TopazVideoModelOptions>;