@ai-sdk/prodia 2.0.0-beta.1 → 2.0.0-beta.11

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/dist/index.mjs CHANGED
@@ -11,19 +11,167 @@ import {
11
11
  // src/prodia-image-model.ts
12
12
  import {
13
13
  combineHeaders,
14
- createJsonErrorResponseHandler,
15
14
  lazySchema,
15
+ parseJSON,
16
16
  parseProviderOptions,
17
17
  postToApi,
18
18
  resolve,
19
19
  zodSchema
20
20
  } from "@ai-sdk/provider-utils";
21
+ import { z as z2 } from "zod/v4";
22
+
23
+ // src/prodia-api.ts
24
+ import { createJsonErrorResponseHandler } from "@ai-sdk/provider-utils";
21
25
  import { z } from "zod/v4";
26
+ var prodiaJobResultSchema = z.object({
27
+ id: z.string(),
28
+ created_at: z.string().optional(),
29
+ updated_at: z.string().optional(),
30
+ expires_at: z.string().optional(),
31
+ state: z.object({
32
+ current: z.string()
33
+ }).optional(),
34
+ config: z.object({
35
+ seed: z.number().optional()
36
+ }).passthrough().optional(),
37
+ metrics: z.object({
38
+ elapsed: z.number().optional(),
39
+ ips: z.number().optional()
40
+ }).optional(),
41
+ price: z.object({
42
+ product: z.string(),
43
+ dollars: z.number()
44
+ }).nullish()
45
+ });
46
+ function buildProdiaProviderMetadata(jobResult) {
47
+ var _a, _b, _c, _d;
48
+ return {
49
+ jobId: jobResult.id,
50
+ ...((_a = jobResult.config) == null ? void 0 : _a.seed) != null && {
51
+ seed: jobResult.config.seed
52
+ },
53
+ ...((_b = jobResult.metrics) == null ? void 0 : _b.elapsed) != null && {
54
+ elapsed: jobResult.metrics.elapsed
55
+ },
56
+ ...((_c = jobResult.metrics) == null ? void 0 : _c.ips) != null && {
57
+ iterationsPerSecond: jobResult.metrics.ips
58
+ },
59
+ ...jobResult.created_at != null && {
60
+ createdAt: jobResult.created_at
61
+ },
62
+ ...jobResult.updated_at != null && {
63
+ updatedAt: jobResult.updated_at
64
+ },
65
+ ...((_d = jobResult.price) == null ? void 0 : _d.dollars) != null && {
66
+ dollars: jobResult.price.dollars
67
+ }
68
+ };
69
+ }
70
+ function parseMultipart(data, boundary) {
71
+ const parts = [];
72
+ const boundaryBytes = new TextEncoder().encode(`--${boundary}`);
73
+ const endBoundaryBytes = new TextEncoder().encode(`--${boundary}--`);
74
+ const positions = [];
75
+ for (let i = 0; i <= data.length - boundaryBytes.length; i++) {
76
+ let match = true;
77
+ for (let j = 0; j < boundaryBytes.length; j++) {
78
+ if (data[i + j] !== boundaryBytes[j]) {
79
+ match = false;
80
+ break;
81
+ }
82
+ }
83
+ if (match) {
84
+ positions.push(i);
85
+ }
86
+ }
87
+ for (let i = 0; i < positions.length - 1; i++) {
88
+ const start = positions[i] + boundaryBytes.length;
89
+ const end = positions[i + 1];
90
+ let isEndBoundary = true;
91
+ for (let j = 0; j < endBoundaryBytes.length && isEndBoundary; j++) {
92
+ if (data[positions[i] + j] !== endBoundaryBytes[j]) {
93
+ isEndBoundary = false;
94
+ }
95
+ }
96
+ if (isEndBoundary && positions[i] + endBoundaryBytes.length <= data.length) {
97
+ continue;
98
+ }
99
+ let partStart = start;
100
+ if (data[partStart] === 13 && data[partStart + 1] === 10) {
101
+ partStart += 2;
102
+ } else if (data[partStart] === 10) {
103
+ partStart += 1;
104
+ }
105
+ let partEnd = end;
106
+ if (data[partEnd - 2] === 13 && data[partEnd - 1] === 10) {
107
+ partEnd -= 2;
108
+ } else if (data[partEnd - 1] === 10) {
109
+ partEnd -= 1;
110
+ }
111
+ const partData = data.slice(partStart, partEnd);
112
+ let headerEnd = -1;
113
+ for (let j = 0; j < partData.length - 3; j++) {
114
+ if (partData[j] === 13 && partData[j + 1] === 10 && partData[j + 2] === 13 && partData[j + 3] === 10) {
115
+ headerEnd = j;
116
+ break;
117
+ }
118
+ if (partData[j] === 10 && partData[j + 1] === 10) {
119
+ headerEnd = j;
120
+ break;
121
+ }
122
+ }
123
+ if (headerEnd === -1) {
124
+ continue;
125
+ }
126
+ const headerBytes = partData.slice(0, headerEnd);
127
+ const headerStr = new TextDecoder().decode(headerBytes);
128
+ const headers = {};
129
+ for (const line of headerStr.split(/\r?\n/)) {
130
+ const colonIdx = line.indexOf(":");
131
+ if (colonIdx > 0) {
132
+ const key = line.slice(0, colonIdx).trim().toLowerCase();
133
+ const value = line.slice(colonIdx + 1).trim();
134
+ headers[key] = value;
135
+ }
136
+ }
137
+ let bodyStart = headerEnd + 2;
138
+ if (partData[headerEnd] === 13) {
139
+ bodyStart = headerEnd + 4;
140
+ }
141
+ const body = partData.slice(bodyStart);
142
+ parts.push({ headers, body });
143
+ }
144
+ return parts;
145
+ }
146
+ var prodiaErrorSchema = z.object({
147
+ message: z.string().optional(),
148
+ detail: z.unknown().optional(),
149
+ error: z.string().optional()
150
+ });
151
+ var prodiaFailedResponseHandler = createJsonErrorResponseHandler({
152
+ errorSchema: prodiaErrorSchema,
153
+ errorToMessage: (error) => {
154
+ var _a;
155
+ const parsed = prodiaErrorSchema.safeParse(error);
156
+ if (!parsed.success) return "Unknown Prodia error";
157
+ const { message, detail, error: errorField } = parsed.data;
158
+ if (typeof detail === "string") return detail;
159
+ if (detail != null) {
160
+ try {
161
+ return JSON.stringify(detail);
162
+ } catch (e) {
163
+ }
164
+ }
165
+ return (_a = errorField != null ? errorField : message) != null ? _a : "Unknown Prodia error";
166
+ }
167
+ });
168
+
169
+ // src/prodia-image-model.ts
22
170
  var ProdiaImageModel = class {
23
171
  constructor(modelId, config) {
24
172
  this.modelId = modelId;
25
173
  this.config = config;
26
- this.specificationVersion = "v3";
174
+ this.specificationVersion = "v4";
27
175
  this.maxImagesPerCall = 1;
28
176
  }
29
177
  get provider() {
@@ -92,7 +240,7 @@ var ProdiaImageModel = class {
92
240
  return { body, warnings };
93
241
  }
94
242
  async doGenerate(options) {
95
- var _a, _b, _c, _d, _e, _f, _g;
243
+ var _a, _b, _c;
96
244
  const { body, warnings } = await this.getArgs(options);
97
245
  const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
98
246
  const combinedHeaders = combineHeaders(
@@ -121,29 +269,7 @@ var ProdiaImageModel = class {
121
269
  warnings,
122
270
  providerMetadata: {
123
271
  prodia: {
124
- images: [
125
- {
126
- jobId: jobResult.id,
127
- ...((_d = jobResult.config) == null ? void 0 : _d.seed) != null && {
128
- seed: jobResult.config.seed
129
- },
130
- ...((_e = jobResult.metrics) == null ? void 0 : _e.elapsed) != null && {
131
- elapsed: jobResult.metrics.elapsed
132
- },
133
- ...((_f = jobResult.metrics) == null ? void 0 : _f.ips) != null && {
134
- iterationsPerSecond: jobResult.metrics.ips
135
- },
136
- ...jobResult.created_at != null && {
137
- createdAt: jobResult.created_at
138
- },
139
- ...jobResult.updated_at != null && {
140
- updatedAt: jobResult.updated_at
141
- },
142
- ...((_g = jobResult.price) == null ? void 0 : _g.dollars) != null && {
143
- dollars: jobResult.price.dollars
144
- }
145
- }
146
- ]
272
+ images: [buildProdiaProviderMetadata(jobResult)]
147
273
  }
148
274
  },
149
275
  response: {
@@ -175,54 +301,34 @@ var stylePresets = [
175
301
  ];
176
302
  var prodiaImageModelOptionsSchema = lazySchema(
177
303
  () => zodSchema(
178
- z.object({
304
+ z2.object({
179
305
  /**
180
306
  * Amount of computational iterations to run. More is typically higher quality.
181
307
  */
182
- steps: z.number().int().min(1).max(4).optional(),
308
+ steps: z2.number().int().min(1).max(4).optional(),
183
309
  /**
184
310
  * Width of the output image in pixels.
185
311
  */
186
- width: z.number().int().min(256).max(1920).optional(),
312
+ width: z2.number().int().min(256).max(1920).optional(),
187
313
  /**
188
314
  * Height of the output image in pixels.
189
315
  */
190
- height: z.number().int().min(256).max(1920).optional(),
316
+ height: z2.number().int().min(256).max(1920).optional(),
191
317
  /**
192
318
  * Apply a visual theme to your output image.
193
319
  */
194
- stylePreset: z.enum(stylePresets).optional(),
320
+ stylePreset: z2.enum(stylePresets).optional(),
195
321
  /**
196
322
  * Augment the output with a LoRa model.
197
323
  */
198
- loras: z.array(z.string()).max(3).optional(),
324
+ loras: z2.array(z2.string()).max(3).optional(),
199
325
  /**
200
326
  * When using JPEG output, return a progressive JPEG.
201
327
  */
202
- progressive: z.boolean().optional()
328
+ progressive: z2.boolean().optional()
203
329
  })
204
330
  )
205
331
  );
206
- var prodiaJobResultSchema = z.object({
207
- id: z.string(),
208
- created_at: z.string().optional(),
209
- updated_at: z.string().optional(),
210
- expires_at: z.string().optional(),
211
- state: z.object({
212
- current: z.string()
213
- }).optional(),
214
- config: z.object({
215
- seed: z.number().optional()
216
- }).passthrough().optional(),
217
- metrics: z.object({
218
- elapsed: z.number().optional(),
219
- ips: z.number().optional()
220
- }).optional(),
221
- price: z.object({
222
- product: z.string(),
223
- dollars: z.number()
224
- }).nullish()
225
- });
226
332
  function createMultipartResponseHandler() {
227
333
  return async ({
228
334
  response
@@ -250,7 +356,10 @@ function createMultipartResponseHandler() {
250
356
  const partContentType = (_c = part.headers["content-type"]) != null ? _c : "";
251
357
  if (contentDisposition.includes('name="job"')) {
252
358
  const jsonStr = new TextDecoder().decode(part.body);
253
- jobResult = prodiaJobResultSchema.parse(JSON.parse(jsonStr));
359
+ jobResult = await parseJSON({
360
+ text: jsonStr,
361
+ schema: zodSchema(prodiaJobResultSchema)
362
+ });
254
363
  } else if (contentDisposition.includes('name="output"')) {
255
364
  imageBytes = part.body;
256
365
  } else if (partContentType.startsWith("image/")) {
@@ -269,107 +378,543 @@ function createMultipartResponseHandler() {
269
378
  };
270
379
  };
271
380
  }
272
- function parseMultipart(data, boundary) {
273
- const parts = [];
274
- const boundaryBytes = new TextEncoder().encode(`--${boundary}`);
275
- const endBoundaryBytes = new TextEncoder().encode(`--${boundary}--`);
276
- const positions = [];
277
- for (let i = 0; i <= data.length - boundaryBytes.length; i++) {
278
- let match = true;
279
- for (let j = 0; j < boundaryBytes.length; j++) {
280
- if (data[i + j] !== boundaryBytes[j]) {
281
- match = false;
282
- break;
283
- }
381
+
382
+ // src/prodia-language-model.ts
383
+ import {
384
+ combineHeaders as combineHeaders2,
385
+ isCustomReasoning,
386
+ convertBase64ToUint8Array,
387
+ generateId,
388
+ lazySchema as lazySchema2,
389
+ parseJSON as parseJSON2,
390
+ parseProviderOptions as parseProviderOptions2,
391
+ postFormDataToApi,
392
+ resolve as resolve2,
393
+ zodSchema as zodSchema2
394
+ } from "@ai-sdk/provider-utils";
395
+ import { z as z3 } from "zod/v4";
396
+ var ProdiaLanguageModel = class {
397
+ constructor(modelId, config) {
398
+ this.modelId = modelId;
399
+ this.config = config;
400
+ this.specificationVersion = "v4";
401
+ this.supportedUrls = {};
402
+ }
403
+ get provider() {
404
+ return this.config.provider;
405
+ }
406
+ async doGenerate(options) {
407
+ var _a, _b, _c, _d;
408
+ const warnings = [];
409
+ if (options.temperature !== void 0) {
410
+ warnings.push({ type: "unsupported", feature: "temperature" });
284
411
  }
285
- if (match) {
286
- positions.push(i);
412
+ if (options.topP !== void 0) {
413
+ warnings.push({ type: "unsupported", feature: "topP" });
287
414
  }
288
- }
289
- for (let i = 0; i < positions.length - 1; i++) {
290
- const start = positions[i] + boundaryBytes.length;
291
- const end = positions[i + 1];
292
- let isEndBoundary = true;
293
- for (let j = 0; j < endBoundaryBytes.length && isEndBoundary; j++) {
294
- if (data[positions[i] + j] !== endBoundaryBytes[j]) {
295
- isEndBoundary = false;
296
- }
415
+ if (options.topK !== void 0) {
416
+ warnings.push({ type: "unsupported", feature: "topK" });
297
417
  }
298
- if (isEndBoundary && positions[i] + endBoundaryBytes.length <= data.length) {
299
- continue;
418
+ if (options.maxOutputTokens !== void 0) {
419
+ warnings.push({ type: "unsupported", feature: "maxOutputTokens" });
300
420
  }
301
- let partStart = start;
302
- if (data[partStart] === 13 && data[partStart + 1] === 10) {
303
- partStart += 2;
304
- } else if (data[partStart] === 10) {
305
- partStart += 1;
421
+ if (options.stopSequences !== void 0) {
422
+ warnings.push({ type: "unsupported", feature: "stopSequences" });
306
423
  }
307
- let partEnd = end;
308
- if (data[partEnd - 2] === 13 && data[partEnd - 1] === 10) {
309
- partEnd -= 2;
310
- } else if (data[partEnd - 1] === 10) {
311
- partEnd -= 1;
424
+ if (options.presencePenalty !== void 0) {
425
+ warnings.push({ type: "unsupported", feature: "presencePenalty" });
312
426
  }
313
- const partData = data.slice(partStart, partEnd);
314
- let headerEnd = -1;
315
- for (let j = 0; j < partData.length - 3; j++) {
316
- if (partData[j] === 13 && partData[j + 1] === 10 && partData[j + 2] === 13 && partData[j + 3] === 10) {
317
- headerEnd = j;
427
+ if (options.frequencyPenalty !== void 0) {
428
+ warnings.push({ type: "unsupported", feature: "frequencyPenalty" });
429
+ }
430
+ if (options.tools !== void 0 && options.tools.length > 0) {
431
+ warnings.push({ type: "unsupported", feature: "tools" });
432
+ }
433
+ if (options.toolChoice !== void 0) {
434
+ warnings.push({ type: "unsupported", feature: "toolChoice" });
435
+ }
436
+ if (options.responseFormat !== void 0 && options.responseFormat.type !== "text") {
437
+ warnings.push({ type: "unsupported", feature: "responseFormat" });
438
+ }
439
+ if (isCustomReasoning(options.reasoning)) {
440
+ warnings.push({
441
+ type: "unsupported",
442
+ feature: "reasoning",
443
+ details: "This provider does not support reasoning configuration."
444
+ });
445
+ }
446
+ const prodiaOptions = await parseProviderOptions2({
447
+ provider: "prodia",
448
+ providerOptions: options.providerOptions,
449
+ schema: prodiaLanguageModelOptionsSchema
450
+ });
451
+ let prompt = "";
452
+ let systemMessage = "";
453
+ for (const message of options.prompt) {
454
+ if (message.role === "system") {
455
+ systemMessage = message.content;
456
+ }
457
+ }
458
+ for (let i = options.prompt.length - 1; i >= 0; i--) {
459
+ const message = options.prompt[i];
460
+ if (message.role === "user") {
461
+ for (const part of message.content) {
462
+ if (part.type === "text") {
463
+ prompt += (prompt ? "\n" : "") + part.text;
464
+ }
465
+ }
318
466
  break;
319
467
  }
320
- if (partData[j] === 10 && partData[j + 1] === 10) {
321
- headerEnd = j;
468
+ }
469
+ if (systemMessage) {
470
+ prompt = systemMessage + "\n" + prompt;
471
+ }
472
+ let imageBytes;
473
+ let imageMediaType = "image/png";
474
+ for (let i = options.prompt.length - 1; i >= 0; i--) {
475
+ const message = options.prompt[i];
476
+ if (message.role === "user") {
477
+ for (const part of message.content) {
478
+ if (part.type === "file" && part.mediaType.startsWith("image/")) {
479
+ if (part.data instanceof Uint8Array) {
480
+ imageBytes = part.data;
481
+ } else if (typeof part.data === "string") {
482
+ imageBytes = convertBase64ToUint8Array(part.data);
483
+ } else if (part.data instanceof URL) {
484
+ const fetchFn = (_a = this.config.fetch) != null ? _a : globalThis.fetch;
485
+ const response = await fetchFn(part.data.toString());
486
+ const arrayBuffer = await response.arrayBuffer();
487
+ imageBytes = new Uint8Array(arrayBuffer);
488
+ }
489
+ imageMediaType = part.mediaType;
490
+ break;
491
+ }
492
+ }
322
493
  break;
323
494
  }
324
495
  }
325
- if (headerEnd === -1) {
326
- continue;
496
+ const jobConfig = {
497
+ prompt,
498
+ include_messages: true
499
+ };
500
+ if ((prodiaOptions == null ? void 0 : prodiaOptions.aspectRatio) !== void 0) {
501
+ jobConfig.aspect_ratio = prodiaOptions.aspectRatio;
327
502
  }
328
- const headerBytes = partData.slice(0, headerEnd);
329
- const headerStr = new TextDecoder().decode(headerBytes);
330
- const headers = {};
331
- for (const line of headerStr.split(/\r?\n/)) {
332
- const colonIdx = line.indexOf(":");
333
- if (colonIdx > 0) {
334
- const key = line.slice(0, colonIdx).trim().toLowerCase();
335
- const value = line.slice(colonIdx + 1).trim();
336
- headers[key] = value;
503
+ const body = {
504
+ type: this.modelId,
505
+ config: jobConfig
506
+ };
507
+ const currentDate = (_d = (_c = (_b = this.config._internal) == null ? void 0 : _b.currentDate) == null ? void 0 : _c.call(_b)) != null ? _d : /* @__PURE__ */ new Date();
508
+ const combinedHeaders = combineHeaders2(
509
+ await resolve2(this.config.headers),
510
+ options.headers
511
+ );
512
+ const formData = new FormData();
513
+ formData.append(
514
+ "job",
515
+ new Blob([JSON.stringify(body)], { type: "application/json" }),
516
+ "job.json"
517
+ );
518
+ if (imageBytes) {
519
+ const ext = imageMediaType === "image/png" ? ".png" : imageMediaType === "image/jpeg" ? ".jpg" : imageMediaType === "image/webp" ? ".webp" : "";
520
+ formData.append(
521
+ "input",
522
+ new Blob([imageBytes], { type: imageMediaType }),
523
+ "input" + ext
524
+ );
525
+ }
526
+ const { value: multipartResult, responseHeaders } = await postFormDataToApi(
527
+ {
528
+ url: `${this.config.baseURL}/job?price=true`,
529
+ headers: {
530
+ ...combinedHeaders,
531
+ Accept: "multipart/form-data"
532
+ },
533
+ formData,
534
+ failedResponseHandler: prodiaFailedResponseHandler,
535
+ successfulResponseHandler: createLanguageMultipartResponseHandler(),
536
+ abortSignal: options.abortSignal,
537
+ fetch: this.config.fetch
337
538
  }
539
+ );
540
+ const { jobResult, textContent, fileContent } = multipartResult;
541
+ const content = [];
542
+ if (textContent !== void 0) {
543
+ content.push({ type: "text", text: textContent });
338
544
  }
339
- let bodyStart = headerEnd + 2;
340
- if (partData[headerEnd] === 13) {
341
- bodyStart = headerEnd + 4;
545
+ for (const file of fileContent) {
546
+ content.push({
547
+ type: "file",
548
+ mediaType: file.mediaType,
549
+ data: file.data
550
+ });
342
551
  }
343
- const body = partData.slice(bodyStart);
344
- parts.push({ headers, body });
552
+ return {
553
+ content,
554
+ finishReason: { unified: "stop", raw: void 0 },
555
+ usage: {
556
+ inputTokens: {
557
+ total: void 0,
558
+ noCache: void 0,
559
+ cacheRead: void 0,
560
+ cacheWrite: void 0
561
+ },
562
+ outputTokens: {
563
+ total: void 0,
564
+ text: void 0,
565
+ reasoning: void 0
566
+ }
567
+ },
568
+ warnings,
569
+ providerMetadata: {
570
+ prodia: buildProdiaProviderMetadata(jobResult)
571
+ },
572
+ response: {
573
+ modelId: this.modelId,
574
+ timestamp: currentDate,
575
+ headers: responseHeaders
576
+ }
577
+ };
345
578
  }
346
- return parts;
347
- }
348
- var prodiaErrorSchema = z.object({
349
- message: z.string().optional(),
350
- detail: z.unknown().optional(),
351
- error: z.string().optional()
352
- });
353
- var prodiaFailedResponseHandler = createJsonErrorResponseHandler({
354
- errorSchema: prodiaErrorSchema,
355
- errorToMessage: (error) => {
579
+ async doStream(options) {
356
580
  var _a;
357
- const parsed = prodiaErrorSchema.safeParse(error);
358
- if (!parsed.success) return "Unknown Prodia error";
359
- const { message, detail, error: errorField } = parsed.data;
360
- if (typeof detail === "string") return detail;
361
- if (detail != null) {
362
- try {
363
- return JSON.stringify(detail);
364
- } catch (e) {
581
+ const result = await this.doGenerate(options);
582
+ const stream = new ReadableStream({
583
+ start(controller) {
584
+ var _a2, _b;
585
+ controller.enqueue({
586
+ type: "stream-start",
587
+ warnings: result.warnings
588
+ });
589
+ controller.enqueue({
590
+ type: "response-metadata",
591
+ modelId: (_a2 = result.response) == null ? void 0 : _a2.modelId,
592
+ timestamp: (_b = result.response) == null ? void 0 : _b.timestamp
593
+ });
594
+ for (const part of result.content) {
595
+ if (part.type === "text") {
596
+ const id = generateId();
597
+ controller.enqueue({ type: "text-start", id });
598
+ controller.enqueue({
599
+ type: "text-delta",
600
+ id,
601
+ delta: part.text
602
+ });
603
+ controller.enqueue({ type: "text-end", id });
604
+ } else if (part.type === "file") {
605
+ controller.enqueue({
606
+ type: "file",
607
+ mediaType: part.mediaType,
608
+ data: part.data
609
+ });
610
+ }
611
+ }
612
+ controller.enqueue({
613
+ type: "finish",
614
+ usage: result.usage,
615
+ finishReason: result.finishReason,
616
+ providerMetadata: result.providerMetadata
617
+ });
618
+ controller.close();
365
619
  }
620
+ });
621
+ return {
622
+ stream,
623
+ response: {
624
+ headers: (_a = result.response) == null ? void 0 : _a.headers
625
+ }
626
+ };
627
+ }
628
+ };
629
+ var prodiaLanguageModelOptionsSchema = lazySchema2(
630
+ () => zodSchema2(
631
+ z3.object({
632
+ /**
633
+ * Aspect ratio for the output image.
634
+ */
635
+ aspectRatio: z3.enum([
636
+ "1:1",
637
+ "2:3",
638
+ "3:2",
639
+ "4:5",
640
+ "5:4",
641
+ "4:7",
642
+ "7:4",
643
+ "9:16",
644
+ "16:9",
645
+ "9:21",
646
+ "21:9"
647
+ ]).optional()
648
+ })
649
+ )
650
+ );
651
+ function createLanguageMultipartResponseHandler() {
652
+ return async ({
653
+ response
654
+ }) => {
655
+ var _a, _b, _c;
656
+ const contentType = (_a = response.headers.get("content-type")) != null ? _a : "";
657
+ const responseHeaders = {};
658
+ response.headers.forEach((value, key) => {
659
+ responseHeaders[key] = value;
660
+ });
661
+ const boundaryMatch = contentType.match(/boundary=([^\s;]+)/);
662
+ if (!boundaryMatch) {
663
+ throw new Error(
664
+ `Prodia response missing multipart boundary in content-type: ${contentType}`
665
+ );
366
666
  }
367
- return (_a = errorField != null ? errorField : message) != null ? _a : "Unknown Prodia error";
667
+ const boundary = boundaryMatch[1];
668
+ const arrayBuffer = await response.arrayBuffer();
669
+ const bytes = new Uint8Array(arrayBuffer);
670
+ const parts = parseMultipart(bytes, boundary);
671
+ let jobResult;
672
+ let textContent;
673
+ const fileContent = [];
674
+ for (const part of parts) {
675
+ const contentDisposition = (_b = part.headers["content-disposition"]) != null ? _b : "";
676
+ const partContentType = (_c = part.headers["content-type"]) != null ? _c : "";
677
+ if (contentDisposition.includes('name="job"')) {
678
+ const jsonStr = new TextDecoder().decode(part.body);
679
+ jobResult = await parseJSON2({
680
+ text: jsonStr,
681
+ schema: zodSchema2(prodiaJobResultSchema)
682
+ });
683
+ } else if (contentDisposition.includes('name="output"')) {
684
+ if (partContentType.startsWith("text/") || contentDisposition.includes(".txt")) {
685
+ textContent = new TextDecoder().decode(part.body);
686
+ } else if (partContentType.startsWith("image/")) {
687
+ fileContent.push({
688
+ mediaType: partContentType,
689
+ data: part.body
690
+ });
691
+ }
692
+ }
693
+ }
694
+ if (!jobResult) {
695
+ throw new Error("Prodia multipart response missing job part");
696
+ }
697
+ return {
698
+ value: { jobResult, textContent, fileContent },
699
+ responseHeaders
700
+ };
701
+ };
702
+ }
703
+
704
+ // src/prodia-video-model.ts
705
+ import {
706
+ combineHeaders as combineHeaders3,
707
+ convertBase64ToUint8Array as convertBase64ToUint8Array2,
708
+ lazySchema as lazySchema3,
709
+ parseJSON as parseJSON3,
710
+ parseProviderOptions as parseProviderOptions3,
711
+ postFormDataToApi as postFormDataToApi2,
712
+ postToApi as postToApi2,
713
+ resolve as resolve3,
714
+ zodSchema as zodSchema3
715
+ } from "@ai-sdk/provider-utils";
716
+ import { z as z4 } from "zod/v4";
717
+ var ProdiaVideoModel = class {
718
+ constructor(modelId, config) {
719
+ this.modelId = modelId;
720
+ this.config = config;
721
+ this.specificationVersion = "v4";
722
+ this.maxVideosPerCall = 1;
368
723
  }
369
- });
724
+ get provider() {
725
+ return this.config.provider;
726
+ }
727
+ async doGenerate(options) {
728
+ var _a, _b, _c;
729
+ const warnings = [];
730
+ const prodiaOptions = await parseProviderOptions3({
731
+ provider: "prodia",
732
+ providerOptions: options.providerOptions,
733
+ schema: prodiaVideoModelOptionsSchema
734
+ });
735
+ const jobConfig = {};
736
+ if (options.prompt !== void 0) {
737
+ jobConfig.prompt = options.prompt;
738
+ }
739
+ if (options.seed !== void 0) {
740
+ jobConfig.seed = options.seed;
741
+ }
742
+ if ((prodiaOptions == null ? void 0 : prodiaOptions.resolution) !== void 0) {
743
+ jobConfig.resolution = prodiaOptions.resolution;
744
+ }
745
+ const body = {
746
+ type: this.modelId,
747
+ config: jobConfig
748
+ };
749
+ const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
750
+ const combinedHeaders = combineHeaders3(
751
+ await resolve3(this.config.headers),
752
+ options.headers
753
+ );
754
+ let multipartResult;
755
+ let responseHeaders;
756
+ if (options.image) {
757
+ const imageData = await resolveVideoFileData(
758
+ options.image,
759
+ this.config.fetch
760
+ );
761
+ const formData = new FormData();
762
+ formData.append(
763
+ "job",
764
+ new Blob([JSON.stringify(body)], { type: "application/json" }),
765
+ "job.json"
766
+ );
767
+ formData.append(
768
+ "input",
769
+ new Blob([imageData.bytes], { type: imageData.mediaType }),
770
+ "input" + getExtension(imageData.mediaType)
771
+ );
772
+ const result = await postFormDataToApi2({
773
+ url: `${this.config.baseURL}/job?price=true`,
774
+ headers: {
775
+ ...combinedHeaders,
776
+ Accept: "multipart/form-data; video/mp4"
777
+ },
778
+ formData,
779
+ failedResponseHandler: prodiaFailedResponseHandler,
780
+ successfulResponseHandler: createVideoMultipartResponseHandler(),
781
+ abortSignal: options.abortSignal,
782
+ fetch: this.config.fetch
783
+ });
784
+ multipartResult = result.value;
785
+ responseHeaders = result.responseHeaders;
786
+ } else {
787
+ const result = await postToApi2({
788
+ url: `${this.config.baseURL}/job?price=true`,
789
+ headers: {
790
+ ...combinedHeaders,
791
+ Accept: "multipart/form-data; video/mp4",
792
+ "Content-Type": "application/json"
793
+ },
794
+ body: {
795
+ content: JSON.stringify(body),
796
+ values: body
797
+ },
798
+ failedResponseHandler: prodiaFailedResponseHandler,
799
+ successfulResponseHandler: createVideoMultipartResponseHandler(),
800
+ abortSignal: options.abortSignal,
801
+ fetch: this.config.fetch
802
+ });
803
+ multipartResult = result.value;
804
+ responseHeaders = result.responseHeaders;
805
+ }
806
+ const { jobResult, videoBytes, videoMediaType } = multipartResult;
807
+ return {
808
+ videos: [
809
+ {
810
+ type: "binary",
811
+ data: videoBytes,
812
+ mediaType: videoMediaType
813
+ }
814
+ ],
815
+ warnings,
816
+ providerMetadata: {
817
+ prodia: {
818
+ videos: [buildProdiaProviderMetadata(jobResult)]
819
+ }
820
+ },
821
+ response: {
822
+ modelId: this.modelId,
823
+ timestamp: currentDate,
824
+ headers: responseHeaders
825
+ }
826
+ };
827
+ }
828
+ };
829
+ var prodiaVideoModelOptionsSchema = lazySchema3(
830
+ () => zodSchema3(
831
+ z4.object({
832
+ /**
833
+ * Video resolution (e.g. "480p", "720p").
834
+ */
835
+ resolution: z4.string().optional()
836
+ })
837
+ )
838
+ );
839
+ function createVideoMultipartResponseHandler() {
840
+ return async ({
841
+ response
842
+ }) => {
843
+ var _a, _b, _c;
844
+ const contentType = (_a = response.headers.get("content-type")) != null ? _a : "";
845
+ const responseHeaders = {};
846
+ response.headers.forEach((value, key) => {
847
+ responseHeaders[key] = value;
848
+ });
849
+ const boundaryMatch = contentType.match(/boundary=([^\s;]+)/);
850
+ if (!boundaryMatch) {
851
+ throw new Error(
852
+ `Prodia response missing multipart boundary in content-type: ${contentType}`
853
+ );
854
+ }
855
+ const boundary = boundaryMatch[1];
856
+ const arrayBuffer = await response.arrayBuffer();
857
+ const bytes = new Uint8Array(arrayBuffer);
858
+ const parts = parseMultipart(bytes, boundary);
859
+ let jobResult;
860
+ let videoBytes;
861
+ let videoMediaType = "video/mp4";
862
+ for (const part of parts) {
863
+ const contentDisposition = (_b = part.headers["content-disposition"]) != null ? _b : "";
864
+ const partContentType = (_c = part.headers["content-type"]) != null ? _c : "";
865
+ if (contentDisposition.includes('name="job"')) {
866
+ const jsonStr = new TextDecoder().decode(part.body);
867
+ jobResult = await parseJSON3({
868
+ text: jsonStr,
869
+ schema: zodSchema3(prodiaJobResultSchema)
870
+ });
871
+ } else if (contentDisposition.includes('name="output"')) {
872
+ videoBytes = part.body;
873
+ if (partContentType.startsWith("video/")) {
874
+ videoMediaType = partContentType;
875
+ }
876
+ } else if (partContentType.startsWith("video/")) {
877
+ videoBytes = part.body;
878
+ videoMediaType = partContentType;
879
+ }
880
+ }
881
+ if (!jobResult) {
882
+ throw new Error("Prodia multipart response missing job part");
883
+ }
884
+ if (!videoBytes) {
885
+ throw new Error("Prodia multipart response missing output video");
886
+ }
887
+ return {
888
+ value: { jobResult, videoBytes, videoMediaType },
889
+ responseHeaders
890
+ };
891
+ };
892
+ }
893
+ async function resolveVideoFileData(file, fetchFunction) {
894
+ var _a;
895
+ if (file.type === "file") {
896
+ const data = typeof file.data === "string" ? convertBase64ToUint8Array2(file.data) : file.data;
897
+ return { bytes: data, mediaType: file.mediaType };
898
+ }
899
+ const response = await (fetchFunction != null ? fetchFunction : globalThis.fetch)(file.url);
900
+ const arrayBuffer = await response.arrayBuffer();
901
+ const mediaType = (_a = response.headers.get("content-type")) != null ? _a : "application/octet-stream";
902
+ return { bytes: new Uint8Array(arrayBuffer), mediaType };
903
+ }
904
+ function getExtension(mediaType) {
905
+ var _a;
906
+ const map = {
907
+ "image/png": ".png",
908
+ "image/jpeg": ".jpg",
909
+ "image/webp": ".webp",
910
+ "video/mp4": ".mp4",
911
+ "video/webm": ".webm"
912
+ };
913
+ return (_a = map[mediaType]) != null ? _a : "";
914
+ }
370
915
 
371
916
  // src/version.ts
372
- var VERSION = true ? "2.0.0-beta.1" : "0.0.0-test";
917
+ var VERSION = true ? "2.0.0-beta.11" : "0.0.0-test";
373
918
 
374
919
  // src/prodia-provider.ts
375
920
  var defaultBaseURL = "https://inference.prodia.com/v2";
@@ -393,23 +938,31 @@ function createProdia(options = {}) {
393
938
  headers: getHeaders,
394
939
  fetch: options.fetch
395
940
  });
941
+ const createLanguageModel = (modelId) => new ProdiaLanguageModel(modelId, {
942
+ provider: "prodia.language",
943
+ baseURL: baseURL != null ? baseURL : defaultBaseURL,
944
+ headers: getHeaders,
945
+ fetch: options.fetch
946
+ });
947
+ const createVideoModel = (modelId) => new ProdiaVideoModel(modelId, {
948
+ provider: "prodia.video",
949
+ baseURL: baseURL != null ? baseURL : defaultBaseURL,
950
+ headers: getHeaders,
951
+ fetch: options.fetch
952
+ });
396
953
  const embeddingModel = (modelId) => {
397
954
  throw new NoSuchModelError({
398
955
  modelId,
399
956
  modelType: "embeddingModel"
400
957
  });
401
958
  };
402
- const languageModel = (modelId) => {
403
- throw new NoSuchModelError({
404
- modelId,
405
- modelType: "languageModel"
406
- });
407
- };
408
959
  return {
409
- specificationVersion: "v3",
960
+ specificationVersion: "v4",
961
+ languageModel: createLanguageModel,
410
962
  imageModel: createImageModel,
411
963
  image: createImageModel,
412
- languageModel,
964
+ videoModel: createVideoModel,
965
+ video: createVideoModel,
413
966
  embeddingModel,
414
967
  textEmbeddingModel: embeddingModel
415
968
  };