@ai-sdk/prodia 2.0.0-beta.3 → 2.0.0-beta.31

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.
@@ -1,5 +1,7 @@
1
1
  import {
2
+ type Experimental_VideoModelV4,
2
3
  type ImageModelV4,
4
+ type LanguageModelV4,
3
5
  NoSuchModelError,
4
6
  type ProviderV4,
5
7
  } from '@ai-sdk/provider';
@@ -11,6 +13,10 @@ import {
11
13
  } from '@ai-sdk/provider-utils';
12
14
  import { ProdiaImageModel } from './prodia-image-model';
13
15
  import type { ProdiaImageModelId } from './prodia-image-settings';
16
+ import { ProdiaLanguageModel } from './prodia-language-model';
17
+ import type { ProdiaLanguageModelId } from './prodia-language-model-settings';
18
+ import { ProdiaVideoModel } from './prodia-video-model';
19
+ import type { ProdiaVideoModelId } from './prodia-video-model-settings';
14
20
  import { VERSION } from './version';
15
21
 
16
22
  export interface ProdiaProviderSettings {
@@ -37,6 +43,11 @@ export interface ProdiaProviderSettings {
37
43
  }
38
44
 
39
45
  export interface ProdiaProvider extends ProviderV4 {
46
+ /**
47
+ * Creates a language model for multimodal generation (img2img with text+image output).
48
+ */
49
+ languageModel(modelId: ProdiaLanguageModelId): LanguageModelV4;
50
+
40
51
  /**
41
52
  * Creates a model for image generation.
42
53
  */
@@ -47,6 +58,16 @@ export interface ProdiaProvider extends ProviderV4 {
47
58
  */
48
59
  imageModel(modelId: ProdiaImageModelId): ImageModelV4;
49
60
 
61
+ /**
62
+ * Creates a model for video generation.
63
+ */
64
+ video(modelId: ProdiaVideoModelId): Experimental_VideoModelV4;
65
+
66
+ /**
67
+ * Creates a model for video generation.
68
+ */
69
+ videoModel(modelId: ProdiaVideoModelId): Experimental_VideoModelV4;
70
+
50
71
  /**
51
72
  * @deprecated Use `embeddingModel` instead.
52
73
  */
@@ -80,25 +101,36 @@ export function createProdia(
80
101
  fetch: options.fetch,
81
102
  });
82
103
 
83
- const embeddingModel = (modelId: string) => {
84
- throw new NoSuchModelError({
85
- modelId,
86
- modelType: 'embeddingModel',
104
+ const createLanguageModel = (modelId: ProdiaLanguageModelId) =>
105
+ new ProdiaLanguageModel(modelId, {
106
+ provider: 'prodia.language',
107
+ baseURL: baseURL ?? defaultBaseURL,
108
+ headers: getHeaders,
109
+ fetch: options.fetch,
110
+ });
111
+
112
+ const createVideoModel = (modelId: ProdiaVideoModelId) =>
113
+ new ProdiaVideoModel(modelId, {
114
+ provider: 'prodia.video',
115
+ baseURL: baseURL ?? defaultBaseURL,
116
+ headers: getHeaders,
117
+ fetch: options.fetch,
87
118
  });
88
- };
89
119
 
90
- const languageModel = (modelId: string) => {
120
+ const embeddingModel = (modelId: string) => {
91
121
  throw new NoSuchModelError({
92
122
  modelId,
93
- modelType: 'languageModel',
123
+ modelType: 'embeddingModel',
94
124
  });
95
125
  };
96
126
 
97
127
  return {
98
128
  specificationVersion: 'v4',
129
+ languageModel: createLanguageModel,
99
130
  imageModel: createImageModel,
100
131
  image: createImageModel,
101
- languageModel,
132
+ videoModel: createVideoModel,
133
+ video: createVideoModel,
102
134
  embeddingModel,
103
135
  textEmbeddingModel: embeddingModel,
104
136
  };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Prodia job types for video generation.
3
+ */
4
+ export type ProdiaVideoModelId =
5
+ | 'inference.wan2-2.lightning.txt2vid.v0'
6
+ | 'inference.wan2-2.lightning.img2vid.v0'
7
+ | (string & {});
@@ -0,0 +1,282 @@
1
+ import type {
2
+ Experimental_VideoModelV4,
3
+ SharedV4Warning,
4
+ } from '@ai-sdk/provider';
5
+ import type { InferSchema } from '@ai-sdk/provider-utils';
6
+ import type { FetchFunction } from '@ai-sdk/provider-utils';
7
+ import {
8
+ combineHeaders,
9
+ convertBase64ToUint8Array,
10
+ lazySchema,
11
+ parseJSON,
12
+ parseProviderOptions,
13
+ postFormDataToApi,
14
+ postToApi,
15
+ resolve,
16
+ zodSchema,
17
+ } from '@ai-sdk/provider-utils';
18
+ import { z } from 'zod/v4';
19
+ import type { ProdiaModelConfig } from './prodia-api';
20
+ import {
21
+ buildProdiaProviderMetadata,
22
+ parseMultipart,
23
+ prodiaFailedResponseHandler,
24
+ prodiaJobResultSchema,
25
+ } from './prodia-api';
26
+ import type { ProdiaJobResult } from './prodia-api';
27
+ import type { ProdiaVideoModelId } from './prodia-video-model-settings';
28
+
29
+ export class ProdiaVideoModel implements Experimental_VideoModelV4 {
30
+ readonly specificationVersion = 'v4';
31
+ readonly maxVideosPerCall = 1;
32
+
33
+ get provider(): string {
34
+ return this.config.provider;
35
+ }
36
+
37
+ constructor(
38
+ readonly modelId: ProdiaVideoModelId,
39
+ private readonly config: ProdiaModelConfig,
40
+ ) {}
41
+
42
+ async doGenerate(
43
+ options: Parameters<Experimental_VideoModelV4['doGenerate']>[0],
44
+ ): Promise<Awaited<ReturnType<Experimental_VideoModelV4['doGenerate']>>> {
45
+ const warnings: Array<SharedV4Warning> = [];
46
+
47
+ const prodiaOptions = await parseProviderOptions({
48
+ provider: 'prodia',
49
+ providerOptions: options.providerOptions,
50
+ schema: prodiaVideoModelOptionsSchema,
51
+ });
52
+
53
+ const jobConfig: Record<string, unknown> = {};
54
+
55
+ if (options.prompt !== undefined) {
56
+ jobConfig.prompt = options.prompt;
57
+ }
58
+ if (options.seed !== undefined) {
59
+ jobConfig.seed = options.seed;
60
+ }
61
+ if (prodiaOptions?.resolution !== undefined) {
62
+ jobConfig.resolution = prodiaOptions.resolution;
63
+ }
64
+
65
+ const body = {
66
+ type: this.modelId,
67
+ config: jobConfig,
68
+ };
69
+
70
+ const currentDate = this.config._internal?.currentDate?.() ?? new Date();
71
+ const combinedHeaders = combineHeaders(
72
+ await resolve(this.config.headers),
73
+ options.headers,
74
+ );
75
+
76
+ let multipartResult: {
77
+ jobResult: ProdiaJobResult;
78
+ videoBytes: Uint8Array;
79
+ videoMediaType: string;
80
+ };
81
+ let responseHeaders: Record<string, string> | undefined;
82
+
83
+ if (options.image) {
84
+ // img2vid: multipart form-data request
85
+ const imageData = await resolveVideoFileData(
86
+ options.image,
87
+ this.config.fetch,
88
+ );
89
+ const formData = new FormData();
90
+ formData.append(
91
+ 'job',
92
+ new Blob([JSON.stringify(body)], { type: 'application/json' }),
93
+ 'job.json',
94
+ );
95
+ formData.append(
96
+ 'input',
97
+ new Blob([imageData.bytes], { type: imageData.mediaType }),
98
+ 'input' + getExtension(imageData.mediaType),
99
+ );
100
+
101
+ const result = await postFormDataToApi({
102
+ url: `${this.config.baseURL}/job?price=true`,
103
+ headers: {
104
+ ...combinedHeaders,
105
+ Accept: 'multipart/form-data; video/mp4',
106
+ },
107
+ formData,
108
+ failedResponseHandler: prodiaFailedResponseHandler,
109
+ successfulResponseHandler: createVideoMultipartResponseHandler(),
110
+ abortSignal: options.abortSignal,
111
+ fetch: this.config.fetch,
112
+ });
113
+
114
+ multipartResult = result.value;
115
+ responseHeaders = result.responseHeaders;
116
+ } else {
117
+ // txt2vid: JSON request
118
+ const result = await postToApi({
119
+ url: `${this.config.baseURL}/job?price=true`,
120
+ headers: {
121
+ ...combinedHeaders,
122
+ Accept: 'multipart/form-data; video/mp4',
123
+ 'Content-Type': 'application/json',
124
+ },
125
+ body: {
126
+ content: JSON.stringify(body),
127
+ values: body,
128
+ },
129
+ failedResponseHandler: prodiaFailedResponseHandler,
130
+ successfulResponseHandler: createVideoMultipartResponseHandler(),
131
+ abortSignal: options.abortSignal,
132
+ fetch: this.config.fetch,
133
+ });
134
+
135
+ multipartResult = result.value;
136
+ responseHeaders = result.responseHeaders;
137
+ }
138
+
139
+ const { jobResult, videoBytes, videoMediaType } = multipartResult;
140
+
141
+ return {
142
+ videos: [
143
+ {
144
+ type: 'binary',
145
+ data: videoBytes,
146
+ mediaType: videoMediaType,
147
+ },
148
+ ],
149
+ warnings,
150
+ providerMetadata: {
151
+ prodia: {
152
+ videos: [buildProdiaProviderMetadata(jobResult)],
153
+ },
154
+ },
155
+ response: {
156
+ modelId: this.modelId,
157
+ timestamp: currentDate,
158
+ headers: responseHeaders,
159
+ },
160
+ };
161
+ }
162
+ }
163
+
164
+ export const prodiaVideoModelOptionsSchema = lazySchema(() =>
165
+ zodSchema(
166
+ z.object({
167
+ /**
168
+ * Video resolution (e.g. "480p", "720p").
169
+ */
170
+ resolution: z.string().optional(),
171
+ }),
172
+ ),
173
+ );
174
+
175
+ export type ProdiaVideoModelOptions = InferSchema<
176
+ typeof prodiaVideoModelOptionsSchema
177
+ >;
178
+
179
+ interface VideoMultipartResult {
180
+ jobResult: ProdiaJobResult;
181
+ videoBytes: Uint8Array;
182
+ videoMediaType: string;
183
+ }
184
+
185
+ function createVideoMultipartResponseHandler() {
186
+ return async ({
187
+ response,
188
+ }: {
189
+ response: Response;
190
+ }): Promise<{
191
+ value: VideoMultipartResult;
192
+ responseHeaders: Record<string, string>;
193
+ }> => {
194
+ const contentType = response.headers.get('content-type') ?? '';
195
+ const responseHeaders: Record<string, string> = {};
196
+ response.headers.forEach((value, key) => {
197
+ responseHeaders[key] = value;
198
+ });
199
+
200
+ const boundaryMatch = contentType.match(/boundary=([^\s;]+)/);
201
+ if (!boundaryMatch) {
202
+ throw new Error(
203
+ `Prodia response missing multipart boundary in content-type: ${contentType}`,
204
+ );
205
+ }
206
+ const boundary = boundaryMatch[1];
207
+
208
+ const arrayBuffer = await response.arrayBuffer();
209
+ const bytes = new Uint8Array(arrayBuffer);
210
+
211
+ const parts = parseMultipart(bytes, boundary);
212
+
213
+ let jobResult: ProdiaJobResult | undefined;
214
+ let videoBytes: Uint8Array | undefined;
215
+ let videoMediaType = 'video/mp4';
216
+
217
+ for (const part of parts) {
218
+ const contentDisposition = part.headers['content-disposition'] ?? '';
219
+ const partContentType = part.headers['content-type'] ?? '';
220
+
221
+ if (contentDisposition.includes('name="job"')) {
222
+ const jsonStr = new TextDecoder().decode(part.body);
223
+ jobResult = await parseJSON({
224
+ text: jsonStr,
225
+ schema: zodSchema(prodiaJobResultSchema),
226
+ });
227
+ } else if (contentDisposition.includes('name="output"')) {
228
+ videoBytes = part.body;
229
+ if (partContentType.startsWith('video/')) {
230
+ videoMediaType = partContentType;
231
+ }
232
+ } else if (partContentType.startsWith('video/')) {
233
+ videoBytes = part.body;
234
+ videoMediaType = partContentType;
235
+ }
236
+ }
237
+
238
+ if (!jobResult) {
239
+ throw new Error('Prodia multipart response missing job part');
240
+ }
241
+ if (!videoBytes) {
242
+ throw new Error('Prodia multipart response missing output video');
243
+ }
244
+
245
+ return {
246
+ value: { jobResult, videoBytes, videoMediaType },
247
+ responseHeaders,
248
+ };
249
+ };
250
+ }
251
+
252
+ async function resolveVideoFileData(
253
+ file: NonNullable<
254
+ Parameters<Experimental_VideoModelV4['doGenerate']>[0]['image']
255
+ >,
256
+ fetchFunction?: FetchFunction,
257
+ ): Promise<{ bytes: Uint8Array; mediaType: string }> {
258
+ if (file.type === 'file') {
259
+ const data =
260
+ typeof file.data === 'string'
261
+ ? convertBase64ToUint8Array(file.data)
262
+ : file.data;
263
+ return { bytes: data, mediaType: file.mediaType };
264
+ }
265
+ // URL type - fetch the data
266
+ const response = await (fetchFunction ?? globalThis.fetch)(file.url);
267
+ const arrayBuffer = await response.arrayBuffer();
268
+ const mediaType =
269
+ response.headers.get('content-type') ?? 'application/octet-stream';
270
+ return { bytes: new Uint8Array(arrayBuffer), mediaType };
271
+ }
272
+
273
+ function getExtension(mediaType: string): string {
274
+ const map: Record<string, string> = {
275
+ 'image/png': '.png',
276
+ 'image/jpeg': '.jpg',
277
+ 'image/webp': '.webp',
278
+ 'video/mp4': '.mp4',
279
+ 'video/webm': '.webm',
280
+ };
281
+ return map[mediaType] ?? '';
282
+ }
package/dist/index.d.mts DELETED
@@ -1,58 +0,0 @@
1
- import * as _ai_sdk_provider_utils from '@ai-sdk/provider-utils';
2
- import { InferSchema, FetchFunction } from '@ai-sdk/provider-utils';
3
- import { ProviderV4, ImageModelV4 } from '@ai-sdk/provider';
4
-
5
- /**
6
- * Prodia job types for image generation.
7
- */
8
- type ProdiaImageModelId = 'inference.flux-fast.schnell.txt2img.v2' | 'inference.flux.schnell.txt2img.v2' | (string & {});
9
-
10
- declare const prodiaImageModelOptionsSchema: _ai_sdk_provider_utils.LazySchema<{
11
- steps?: number | undefined;
12
- width?: number | undefined;
13
- height?: number | undefined;
14
- stylePreset?: "3d-model" | "analog-film" | "anime" | "cinematic" | "comic-book" | "digital-art" | "enhance" | "fantasy-art" | "isometric" | "line-art" | "low-poly" | "neon-punk" | "origami" | "photographic" | "pixel-art" | "texture" | "craft-clay" | undefined;
15
- loras?: string[] | undefined;
16
- progressive?: boolean | undefined;
17
- }>;
18
- type ProdiaImageModelOptions = InferSchema<typeof prodiaImageModelOptionsSchema>;
19
-
20
- interface ProdiaProviderSettings {
21
- /**
22
- * Prodia API key. Default value is taken from the `PRODIA_TOKEN` environment variable.
23
- */
24
- apiKey?: string;
25
- /**
26
- * Base URL for the API calls. Defaults to `https://inference.prodia.com/v2`.
27
- */
28
- baseURL?: string;
29
- /**
30
- * Custom headers to include in the requests.
31
- */
32
- headers?: Record<string, string>;
33
- /**
34
- * Custom fetch implementation. You can use it as a middleware to intercept
35
- * requests, or to provide a custom fetch implementation for e.g. testing.
36
- */
37
- fetch?: FetchFunction;
38
- }
39
- interface ProdiaProvider extends ProviderV4 {
40
- /**
41
- * Creates a model for image generation.
42
- */
43
- image(modelId: ProdiaImageModelId): ImageModelV4;
44
- /**
45
- * Creates a model for image generation.
46
- */
47
- imageModel(modelId: ProdiaImageModelId): ImageModelV4;
48
- /**
49
- * @deprecated Use `embeddingModel` instead.
50
- */
51
- textEmbeddingModel(modelId: string): never;
52
- }
53
- declare function createProdia(options?: ProdiaProviderSettings): ProdiaProvider;
54
- declare const prodia: ProdiaProvider;
55
-
56
- declare const VERSION: string;
57
-
58
- export { type ProdiaImageModelId, type ProdiaImageModelOptions, type ProdiaImageModelOptions as ProdiaImageProviderOptions, type ProdiaProvider, type ProdiaProviderSettings, VERSION, createProdia, prodia };