@ai-sdk/prodia 2.0.0-beta.4 → 2.0.0-beta.53
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 +406 -0
- package/README.md +2 -0
- package/dist/index.d.ts +39 -7
- package/dist/index.js +838 -222
- package/dist/index.js.map +1 -1
- package/package.json +14 -14
- package/src/index.ts +5 -1
- package/src/prodia-api.ts +201 -0
- package/src/prodia-image-model-options.ts +61 -0
- package/src/prodia-image-model.ts +34 -254
- package/src/prodia-language-model-options.ts +35 -0
- package/src/prodia-language-model-settings.ts +6 -0
- package/src/prodia-language-model.ts +423 -0
- package/src/prodia-provider.ts +42 -10
- package/src/prodia-video-model-options.ts +21 -0
- package/src/prodia-video-model-settings.ts +7 -0
- package/src/prodia-video-model.ts +266 -0
- package/dist/index.d.mts +0 -58
- package/dist/index.mjs +0 -423
- package/dist/index.mjs.map +0 -1
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import type { ImageModelV4, SharedV4Warning } from '@ai-sdk/provider';
|
|
2
|
-
import type { InferSchema, Resolvable } from '@ai-sdk/provider-utils';
|
|
3
2
|
import {
|
|
4
3
|
combineHeaders,
|
|
5
|
-
|
|
6
|
-
type FetchFunction,
|
|
7
|
-
lazySchema,
|
|
4
|
+
parseJSON,
|
|
8
5
|
parseProviderOptions,
|
|
9
6
|
postToApi,
|
|
10
7
|
resolve,
|
|
8
|
+
serializeModelOptions,
|
|
9
|
+
WORKFLOW_SERIALIZE,
|
|
10
|
+
WORKFLOW_DESERIALIZE,
|
|
11
11
|
zodSchema,
|
|
12
12
|
} from '@ai-sdk/provider-utils';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
buildProdiaProviderMetadata,
|
|
15
|
+
parseMultipart,
|
|
16
|
+
prodiaFailedResponseHandler,
|
|
17
|
+
prodiaJobResultSchema,
|
|
18
|
+
type ProdiaJobResult,
|
|
19
|
+
type ProdiaModelConfig,
|
|
20
|
+
} from './prodia-api';
|
|
21
|
+
import { prodiaImageModelOptionsSchema } from './prodia-image-model-options';
|
|
14
22
|
import type { ProdiaImageModelId } from './prodia-image-settings';
|
|
15
23
|
|
|
16
24
|
export class ProdiaImageModel implements ImageModelV4 {
|
|
@@ -21,9 +29,23 @@ export class ProdiaImageModel implements ImageModelV4 {
|
|
|
21
29
|
return this.config.provider;
|
|
22
30
|
}
|
|
23
31
|
|
|
32
|
+
static [WORKFLOW_SERIALIZE](model: ProdiaImageModel) {
|
|
33
|
+
return serializeModelOptions({
|
|
34
|
+
modelId: model.modelId,
|
|
35
|
+
config: model.config,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static [WORKFLOW_DESERIALIZE](options: {
|
|
40
|
+
modelId: ProdiaImageModelId;
|
|
41
|
+
config: ProdiaModelConfig;
|
|
42
|
+
}) {
|
|
43
|
+
return new ProdiaImageModel(options.modelId, options.config);
|
|
44
|
+
}
|
|
45
|
+
|
|
24
46
|
constructor(
|
|
25
47
|
readonly modelId: ProdiaImageModelId,
|
|
26
|
-
private readonly config:
|
|
48
|
+
private readonly config: ProdiaModelConfig,
|
|
27
49
|
) {}
|
|
28
50
|
|
|
29
51
|
private async getArgs({
|
|
@@ -109,7 +131,7 @@ export class ProdiaImageModel implements ImageModelV4 {
|
|
|
109
131
|
|
|
110
132
|
const currentDate = this.config._internal?.currentDate?.() ?? new Date();
|
|
111
133
|
const combinedHeaders = combineHeaders(
|
|
112
|
-
await resolve(this.config.headers),
|
|
134
|
+
this.config.headers ? await resolve(this.config.headers) : undefined,
|
|
113
135
|
options.headers,
|
|
114
136
|
);
|
|
115
137
|
|
|
@@ -137,29 +159,7 @@ export class ProdiaImageModel implements ImageModelV4 {
|
|
|
137
159
|
warnings,
|
|
138
160
|
providerMetadata: {
|
|
139
161
|
prodia: {
|
|
140
|
-
images: [
|
|
141
|
-
{
|
|
142
|
-
jobId: jobResult.id,
|
|
143
|
-
...(jobResult.config?.seed != null && {
|
|
144
|
-
seed: jobResult.config.seed,
|
|
145
|
-
}),
|
|
146
|
-
...(jobResult.metrics?.elapsed != null && {
|
|
147
|
-
elapsed: jobResult.metrics.elapsed,
|
|
148
|
-
}),
|
|
149
|
-
...(jobResult.metrics?.ips != null && {
|
|
150
|
-
iterationsPerSecond: jobResult.metrics.ips,
|
|
151
|
-
}),
|
|
152
|
-
...(jobResult.created_at != null && {
|
|
153
|
-
createdAt: jobResult.created_at,
|
|
154
|
-
}),
|
|
155
|
-
...(jobResult.updated_at != null && {
|
|
156
|
-
updatedAt: jobResult.updated_at,
|
|
157
|
-
}),
|
|
158
|
-
...(jobResult.price?.dollars != null && {
|
|
159
|
-
dollars: jobResult.price.dollars,
|
|
160
|
-
}),
|
|
161
|
-
},
|
|
162
|
-
],
|
|
162
|
+
images: [buildProdiaProviderMetadata(jobResult)],
|
|
163
163
|
},
|
|
164
164
|
},
|
|
165
165
|
response: {
|
|
@@ -171,103 +171,6 @@ export class ProdiaImageModel implements ImageModelV4 {
|
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
const stylePresets = [
|
|
175
|
-
'3d-model',
|
|
176
|
-
'analog-film',
|
|
177
|
-
'anime',
|
|
178
|
-
'cinematic',
|
|
179
|
-
'comic-book',
|
|
180
|
-
'digital-art',
|
|
181
|
-
'enhance',
|
|
182
|
-
'fantasy-art',
|
|
183
|
-
'isometric',
|
|
184
|
-
'line-art',
|
|
185
|
-
'low-poly',
|
|
186
|
-
'neon-punk',
|
|
187
|
-
'origami',
|
|
188
|
-
'photographic',
|
|
189
|
-
'pixel-art',
|
|
190
|
-
'texture',
|
|
191
|
-
'craft-clay',
|
|
192
|
-
] as const;
|
|
193
|
-
|
|
194
|
-
export const prodiaImageModelOptionsSchema = lazySchema(() =>
|
|
195
|
-
zodSchema(
|
|
196
|
-
z.object({
|
|
197
|
-
/**
|
|
198
|
-
* Amount of computational iterations to run. More is typically higher quality.
|
|
199
|
-
*/
|
|
200
|
-
steps: z.number().int().min(1).max(4).optional(),
|
|
201
|
-
/**
|
|
202
|
-
* Width of the output image in pixels.
|
|
203
|
-
*/
|
|
204
|
-
width: z.number().int().min(256).max(1920).optional(),
|
|
205
|
-
/**
|
|
206
|
-
* Height of the output image in pixels.
|
|
207
|
-
*/
|
|
208
|
-
height: z.number().int().min(256).max(1920).optional(),
|
|
209
|
-
/**
|
|
210
|
-
* Apply a visual theme to your output image.
|
|
211
|
-
*/
|
|
212
|
-
stylePreset: z.enum(stylePresets).optional(),
|
|
213
|
-
/**
|
|
214
|
-
* Augment the output with a LoRa model.
|
|
215
|
-
*/
|
|
216
|
-
loras: z.array(z.string()).max(3).optional(),
|
|
217
|
-
/**
|
|
218
|
-
* When using JPEG output, return a progressive JPEG.
|
|
219
|
-
*/
|
|
220
|
-
progressive: z.boolean().optional(),
|
|
221
|
-
}),
|
|
222
|
-
),
|
|
223
|
-
);
|
|
224
|
-
|
|
225
|
-
export type ProdiaImageModelOptions = InferSchema<
|
|
226
|
-
typeof prodiaImageModelOptionsSchema
|
|
227
|
-
>;
|
|
228
|
-
|
|
229
|
-
interface ProdiaImageModelConfig {
|
|
230
|
-
provider: string;
|
|
231
|
-
baseURL: string;
|
|
232
|
-
headers?: Resolvable<Record<string, string | undefined>>;
|
|
233
|
-
fetch?: FetchFunction;
|
|
234
|
-
_internal?: {
|
|
235
|
-
currentDate?: () => Date;
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const prodiaJobResultSchema = z.object({
|
|
240
|
-
id: z.string(),
|
|
241
|
-
created_at: z.string().optional(),
|
|
242
|
-
updated_at: z.string().optional(),
|
|
243
|
-
expires_at: z.string().optional(),
|
|
244
|
-
state: z
|
|
245
|
-
.object({
|
|
246
|
-
current: z.string(),
|
|
247
|
-
})
|
|
248
|
-
.optional(),
|
|
249
|
-
config: z
|
|
250
|
-
.object({
|
|
251
|
-
seed: z.number().optional(),
|
|
252
|
-
})
|
|
253
|
-
.passthrough()
|
|
254
|
-
.optional(),
|
|
255
|
-
metrics: z
|
|
256
|
-
.object({
|
|
257
|
-
elapsed: z.number().optional(),
|
|
258
|
-
ips: z.number().optional(),
|
|
259
|
-
})
|
|
260
|
-
.optional(),
|
|
261
|
-
price: z
|
|
262
|
-
.object({
|
|
263
|
-
product: z.string(),
|
|
264
|
-
dollars: z.number(),
|
|
265
|
-
})
|
|
266
|
-
.nullish(),
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
type ProdiaJobResult = z.infer<typeof prodiaJobResultSchema>;
|
|
270
|
-
|
|
271
174
|
interface MultipartResult {
|
|
272
175
|
jobResult: ProdiaJobResult;
|
|
273
176
|
imageBytes: Uint8Array;
|
|
@@ -310,7 +213,10 @@ function createMultipartResponseHandler() {
|
|
|
310
213
|
|
|
311
214
|
if (contentDisposition.includes('name="job"')) {
|
|
312
215
|
const jsonStr = new TextDecoder().decode(part.body);
|
|
313
|
-
jobResult =
|
|
216
|
+
jobResult = await parseJSON({
|
|
217
|
+
text: jsonStr,
|
|
218
|
+
schema: zodSchema(prodiaJobResultSchema),
|
|
219
|
+
});
|
|
314
220
|
} else if (contentDisposition.includes('name="output"')) {
|
|
315
221
|
imageBytes = part.body;
|
|
316
222
|
} else if (partContentType.startsWith('image/')) {
|
|
@@ -331,129 +237,3 @@ function createMultipartResponseHandler() {
|
|
|
331
237
|
};
|
|
332
238
|
};
|
|
333
239
|
}
|
|
334
|
-
|
|
335
|
-
interface MultipartPart {
|
|
336
|
-
headers: Record<string, string>;
|
|
337
|
-
body: Uint8Array;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
function parseMultipart(data: Uint8Array, boundary: string): MultipartPart[] {
|
|
341
|
-
const parts: MultipartPart[] = [];
|
|
342
|
-
const boundaryBytes = new TextEncoder().encode(`--${boundary}`);
|
|
343
|
-
const endBoundaryBytes = new TextEncoder().encode(`--${boundary}--`);
|
|
344
|
-
|
|
345
|
-
const positions: number[] = [];
|
|
346
|
-
for (let i = 0; i <= data.length - boundaryBytes.length; i++) {
|
|
347
|
-
let match = true;
|
|
348
|
-
for (let j = 0; j < boundaryBytes.length; j++) {
|
|
349
|
-
if (data[i + j] !== boundaryBytes[j]) {
|
|
350
|
-
match = false;
|
|
351
|
-
break;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
if (match) {
|
|
355
|
-
positions.push(i);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
for (let i = 0; i < positions.length - 1; i++) {
|
|
360
|
-
const start = positions[i] + boundaryBytes.length;
|
|
361
|
-
const end = positions[i + 1];
|
|
362
|
-
|
|
363
|
-
let isEndBoundary = true;
|
|
364
|
-
for (let j = 0; j < endBoundaryBytes.length && isEndBoundary; j++) {
|
|
365
|
-
if (data[positions[i] + j] !== endBoundaryBytes[j]) {
|
|
366
|
-
isEndBoundary = false;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
if (
|
|
370
|
-
isEndBoundary &&
|
|
371
|
-
positions[i] + endBoundaryBytes.length <= data.length
|
|
372
|
-
) {
|
|
373
|
-
continue;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
let partStart = start;
|
|
377
|
-
if (data[partStart] === 0x0d && data[partStart + 1] === 0x0a) {
|
|
378
|
-
partStart += 2;
|
|
379
|
-
} else if (data[partStart] === 0x0a) {
|
|
380
|
-
partStart += 1;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
let partEnd = end;
|
|
384
|
-
if (data[partEnd - 2] === 0x0d && data[partEnd - 1] === 0x0a) {
|
|
385
|
-
partEnd -= 2;
|
|
386
|
-
} else if (data[partEnd - 1] === 0x0a) {
|
|
387
|
-
partEnd -= 1;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const partData = data.slice(partStart, partEnd);
|
|
391
|
-
|
|
392
|
-
let headerEnd = -1;
|
|
393
|
-
for (let j = 0; j < partData.length - 3; j++) {
|
|
394
|
-
if (
|
|
395
|
-
partData[j] === 0x0d &&
|
|
396
|
-
partData[j + 1] === 0x0a &&
|
|
397
|
-
partData[j + 2] === 0x0d &&
|
|
398
|
-
partData[j + 3] === 0x0a
|
|
399
|
-
) {
|
|
400
|
-
headerEnd = j;
|
|
401
|
-
break;
|
|
402
|
-
}
|
|
403
|
-
if (partData[j] === 0x0a && partData[j + 1] === 0x0a) {
|
|
404
|
-
headerEnd = j;
|
|
405
|
-
break;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
if (headerEnd === -1) {
|
|
410
|
-
continue;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
const headerBytes = partData.slice(0, headerEnd);
|
|
414
|
-
const headerStr = new TextDecoder().decode(headerBytes);
|
|
415
|
-
const headers: Record<string, string> = {};
|
|
416
|
-
for (const line of headerStr.split(/\r?\n/)) {
|
|
417
|
-
const colonIdx = line.indexOf(':');
|
|
418
|
-
if (colonIdx > 0) {
|
|
419
|
-
const key = line.slice(0, colonIdx).trim().toLowerCase();
|
|
420
|
-
const value = line.slice(colonIdx + 1).trim();
|
|
421
|
-
headers[key] = value;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
let bodyStart = headerEnd + 2;
|
|
426
|
-
if (partData[headerEnd] === 0x0d) {
|
|
427
|
-
bodyStart = headerEnd + 4;
|
|
428
|
-
}
|
|
429
|
-
const body = partData.slice(bodyStart);
|
|
430
|
-
|
|
431
|
-
parts.push({ headers, body });
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
return parts;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
const prodiaErrorSchema = z.object({
|
|
438
|
-
message: z.string().optional(),
|
|
439
|
-
detail: z.unknown().optional(),
|
|
440
|
-
error: z.string().optional(),
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
const prodiaFailedResponseHandler = createJsonErrorResponseHandler({
|
|
444
|
-
errorSchema: prodiaErrorSchema,
|
|
445
|
-
errorToMessage: error => {
|
|
446
|
-
const parsed = prodiaErrorSchema.safeParse(error);
|
|
447
|
-
if (!parsed.success) return 'Unknown Prodia error';
|
|
448
|
-
const { message, detail, error: errorField } = parsed.data;
|
|
449
|
-
if (typeof detail === 'string') return detail;
|
|
450
|
-
if (detail != null) {
|
|
451
|
-
try {
|
|
452
|
-
return JSON.stringify(detail);
|
|
453
|
-
} catch {
|
|
454
|
-
// ignore
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
return errorField ?? message ?? 'Unknown Prodia error';
|
|
458
|
-
},
|
|
459
|
-
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
lazySchema,
|
|
3
|
+
zodSchema,
|
|
4
|
+
type InferSchema,
|
|
5
|
+
} from '@ai-sdk/provider-utils';
|
|
6
|
+
import { z } from 'zod/v4';
|
|
7
|
+
|
|
8
|
+
export const prodiaLanguageModelOptionsSchema = lazySchema(() =>
|
|
9
|
+
zodSchema(
|
|
10
|
+
z.object({
|
|
11
|
+
/**
|
|
12
|
+
* Aspect ratio for the output image.
|
|
13
|
+
*/
|
|
14
|
+
aspectRatio: z
|
|
15
|
+
.enum([
|
|
16
|
+
'1:1',
|
|
17
|
+
'2:3',
|
|
18
|
+
'3:2',
|
|
19
|
+
'4:5',
|
|
20
|
+
'5:4',
|
|
21
|
+
'4:7',
|
|
22
|
+
'7:4',
|
|
23
|
+
'9:16',
|
|
24
|
+
'16:9',
|
|
25
|
+
'9:21',
|
|
26
|
+
'21:9',
|
|
27
|
+
])
|
|
28
|
+
.optional(),
|
|
29
|
+
}),
|
|
30
|
+
),
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export type ProdiaLanguageModelOptions = InferSchema<
|
|
34
|
+
typeof prodiaLanguageModelOptionsSchema
|
|
35
|
+
>;
|