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