@ai-sdk/quiverai 2.0.43 → 2.0.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +164 -5
- package/dist/index.js.map +1 -1
- package/docs/180-quiverai.mdx +42 -4
- package/package.json +2 -2
- package/src/quiverai-image-model-options.ts +3 -1
- package/src/quiverai-image-model.ts +196 -3
- package/src/quiverai-image-settings.ts +2 -1
package/CHANGELOG.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -53,7 +53,7 @@ declare const quiverai: QuiverAIProvider;
|
|
|
53
53
|
* @see https://quiver.ai/
|
|
54
54
|
*/
|
|
55
55
|
declare const quiveraiImageModelOptionsSchema: _ai_sdk_provider_utils.LazySchema<{
|
|
56
|
-
operation?: "generate" | "vectorize" | undefined;
|
|
56
|
+
operation?: "generate" | "vectorize" | "animate" | undefined;
|
|
57
57
|
instructions?: string | undefined;
|
|
58
58
|
reasoningEffort?: "low" | "medium" | "high" | "xhigh" | undefined;
|
|
59
59
|
attributes?: {
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from "@ai-sdk/provider";
|
|
16
16
|
import {
|
|
17
17
|
combineHeaders,
|
|
18
|
+
convertBase64ToUint8Array,
|
|
18
19
|
convertUint8ArrayToBase64,
|
|
19
20
|
createJsonErrorResponseHandler,
|
|
20
21
|
createJsonResponseHandler,
|
|
@@ -41,8 +42,10 @@ var quiveraiImageModelOptionsSchema = lazySchema(
|
|
|
41
42
|
* - `generate`: Text-to-SVG generation. Requires `prompt`.
|
|
42
43
|
* - `vectorize`: Convert an input raster image into an SVG. Requires a
|
|
43
44
|
* single image in `prompt.images` / `files`.
|
|
45
|
+
* - `animate`: Animate an input SVG. Requires a single SVG in
|
|
46
|
+
* `prompt.images` / `files`; the text prompt is optional.
|
|
44
47
|
*/
|
|
45
|
-
operation: z.enum(["generate", "vectorize"]).optional(),
|
|
48
|
+
operation: z.enum(["generate", "vectorize", "animate"]).optional(),
|
|
46
49
|
/**
|
|
47
50
|
* Extra style guidance for prompt-based generation.
|
|
48
51
|
*/
|
|
@@ -138,6 +141,7 @@ var QuiverAIImageModel = class _QuiverAIImageModel {
|
|
|
138
141
|
n,
|
|
139
142
|
prompt,
|
|
140
143
|
files,
|
|
144
|
+
mask,
|
|
141
145
|
operation,
|
|
142
146
|
options: quiveraiOptions != null ? quiveraiOptions : {}
|
|
143
147
|
});
|
|
@@ -164,7 +168,13 @@ var QuiverAIImageModel = class _QuiverAIImageModel {
|
|
|
164
168
|
...response.credits != null && { credits: response.credits },
|
|
165
169
|
images: response.data.map((image, index) => ({
|
|
166
170
|
index,
|
|
167
|
-
mimeType: image.mime_type
|
|
171
|
+
mimeType: image.mime_type,
|
|
172
|
+
...image.loop_period_ms !== void 0 && {
|
|
173
|
+
loopPeriodMs: image.loop_period_ms
|
|
174
|
+
},
|
|
175
|
+
...image.opening_animation_ms !== void 0 && {
|
|
176
|
+
openingAnimationMs: image.opening_animation_ms
|
|
177
|
+
}
|
|
168
178
|
}))
|
|
169
179
|
}
|
|
170
180
|
},
|
|
@@ -184,7 +194,14 @@ var QuiverAIImageModel = class _QuiverAIImageModel {
|
|
|
184
194
|
}
|
|
185
195
|
};
|
|
186
196
|
function getOperationPath(operation) {
|
|
187
|
-
|
|
197
|
+
switch (operation) {
|
|
198
|
+
case "generate":
|
|
199
|
+
return "/svgs/generations";
|
|
200
|
+
case "vectorize":
|
|
201
|
+
return "/svgs/vectorizations";
|
|
202
|
+
case "animate":
|
|
203
|
+
return "/svgs/animations";
|
|
204
|
+
}
|
|
188
205
|
}
|
|
189
206
|
function getGenerateReferenceLimit(modelId) {
|
|
190
207
|
return ["arrow-1", "arrow-1.0", "arrow-1.1"].includes(modelId) ? 4 : 16;
|
|
@@ -197,11 +214,71 @@ function toQuiverAIImageReference(image) {
|
|
|
197
214
|
base64: typeof image.data === "string" ? image.data : convertUint8ArrayToBase64(image.data)
|
|
198
215
|
};
|
|
199
216
|
}
|
|
217
|
+
var maxAnimationSourceBase64Length = 1066668;
|
|
218
|
+
function toQuiverAIAnimationSource(image) {
|
|
219
|
+
var _a;
|
|
220
|
+
if (image.type === "url") {
|
|
221
|
+
let url;
|
|
222
|
+
try {
|
|
223
|
+
url = new URL(image.url);
|
|
224
|
+
} catch (e) {
|
|
225
|
+
throw new InvalidArgumentError({
|
|
226
|
+
argument: "files",
|
|
227
|
+
message: "QuiverAI animate requires a valid HTTP or HTTPS SVG URL."
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
231
|
+
throw new InvalidArgumentError({
|
|
232
|
+
argument: "files",
|
|
233
|
+
message: "QuiverAI animate requires an HTTP or HTTPS SVG URL."
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
return { url: image.url };
|
|
237
|
+
}
|
|
238
|
+
let base64;
|
|
239
|
+
let bytes;
|
|
240
|
+
if (typeof image.data === "string") {
|
|
241
|
+
const dataUrlMatch = /^data:image\/svg\+xml(?:;[^,]*)?;base64,([\s\S]+)$/i.exec(image.data);
|
|
242
|
+
const encodedData = (_a = dataUrlMatch == null ? void 0 : dataUrlMatch[1]) != null ? _a : image.data;
|
|
243
|
+
try {
|
|
244
|
+
bytes = convertBase64ToUint8Array(encodedData);
|
|
245
|
+
} catch (e) {
|
|
246
|
+
throw new InvalidArgumentError({
|
|
247
|
+
argument: "files",
|
|
248
|
+
message: "QuiverAI animate requires the source SVG string to be valid base64 or an SVG data URL."
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
base64 = convertUint8ArrayToBase64(bytes);
|
|
252
|
+
} else {
|
|
253
|
+
bytes = image.data;
|
|
254
|
+
base64 = convertUint8ArrayToBase64(bytes);
|
|
255
|
+
}
|
|
256
|
+
if (!isSvg(bytes)) {
|
|
257
|
+
throw new InvalidArgumentError({
|
|
258
|
+
argument: "files",
|
|
259
|
+
message: "QuiverAI animate requires the input file to contain SVG data."
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
if (base64.length > maxAnimationSourceBase64Length) {
|
|
263
|
+
throw new InvalidArgumentError({
|
|
264
|
+
argument: "files",
|
|
265
|
+
message: `QuiverAI animate accepts at most ${maxAnimationSourceBase64Length} base64 characters for the source SVG.`
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
return { base64 };
|
|
269
|
+
}
|
|
270
|
+
function isSvg(data) {
|
|
271
|
+
const head = new TextDecoder("utf-8", { fatal: false }).decode(data.subarray(0, 4096)).trimStart();
|
|
272
|
+
return /^(?:(?:<\?xml[\s\S]*?\?>|<!--[\s\S]*?-->|<!DOCTYPE[\s\S]*?>)\s*)*<svg(?:\s|>)/i.test(
|
|
273
|
+
head
|
|
274
|
+
);
|
|
275
|
+
}
|
|
200
276
|
function buildRequestBody({
|
|
201
277
|
modelId,
|
|
202
278
|
n,
|
|
203
279
|
prompt,
|
|
204
280
|
files,
|
|
281
|
+
mask,
|
|
205
282
|
operation,
|
|
206
283
|
options
|
|
207
284
|
}) {
|
|
@@ -244,6 +321,16 @@ function buildRequestBody({
|
|
|
244
321
|
references
|
|
245
322
|
};
|
|
246
323
|
}
|
|
324
|
+
if (operation === "animate") {
|
|
325
|
+
return buildAnimationRequestBody({
|
|
326
|
+
modelId,
|
|
327
|
+
n,
|
|
328
|
+
prompt,
|
|
329
|
+
files,
|
|
330
|
+
mask,
|
|
331
|
+
options
|
|
332
|
+
});
|
|
333
|
+
}
|
|
247
334
|
if (files == null || files.length === 0) {
|
|
248
335
|
throw new InvalidArgumentError({
|
|
249
336
|
argument: "files",
|
|
@@ -270,6 +357,76 @@ function buildRequestBody({
|
|
|
270
357
|
target_size: options.targetSize
|
|
271
358
|
};
|
|
272
359
|
}
|
|
360
|
+
function buildAnimationRequestBody({
|
|
361
|
+
modelId,
|
|
362
|
+
n,
|
|
363
|
+
prompt,
|
|
364
|
+
files,
|
|
365
|
+
mask,
|
|
366
|
+
options
|
|
367
|
+
}) {
|
|
368
|
+
if (modelId !== "arrow-2" && modelId !== "arrow-2-telos") {
|
|
369
|
+
throw new InvalidArgumentError({
|
|
370
|
+
argument: "modelId",
|
|
371
|
+
message: 'QuiverAI animate is supported by the "arrow-2" and "arrow-2-telos" models.'
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
if (files == null || files.length === 0) {
|
|
375
|
+
throw new InvalidArgumentError({
|
|
376
|
+
argument: "files",
|
|
377
|
+
message: "QuiverAI animate requires exactly one source SVG in prompt.images."
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
if (files.length !== 1) {
|
|
381
|
+
throw new InvalidArgumentError({
|
|
382
|
+
argument: "files",
|
|
383
|
+
message: "QuiverAI animate accepts exactly one source SVG in prompt.images."
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
if (n !== 1) {
|
|
387
|
+
throw new InvalidArgumentError({
|
|
388
|
+
argument: "n",
|
|
389
|
+
message: "QuiverAI animate returns one SVG per request. Set maxImagesPerCall to 1 in generateImage to animate multiple times."
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
if (mask != null) {
|
|
393
|
+
throw new InvalidArgumentError({
|
|
394
|
+
argument: "mask",
|
|
395
|
+
message: "QuiverAI animate does not support masks."
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
if (prompt != null && prompt.trim().length === 0) {
|
|
399
|
+
throw new InvalidArgumentError({
|
|
400
|
+
argument: "prompt",
|
|
401
|
+
message: "QuiverAI animate requires a non-empty prompt when an animation instruction is provided."
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
const unsupportedOptions = [
|
|
405
|
+
["instructions", options.instructions],
|
|
406
|
+
["topP", options.topP],
|
|
407
|
+
["presencePenalty", options.presencePenalty],
|
|
408
|
+
["attributes", options.attributes],
|
|
409
|
+
["autoCrop", options.autoCrop],
|
|
410
|
+
["targetSize", options.targetSize]
|
|
411
|
+
].filter((option) => {
|
|
412
|
+
return option[1] !== void 0;
|
|
413
|
+
});
|
|
414
|
+
if (unsupportedOptions.length > 0) {
|
|
415
|
+
throw new InvalidArgumentError({
|
|
416
|
+
argument: `providerOptions.quiverai.${unsupportedOptions[0][0]}`,
|
|
417
|
+
message: `QuiverAI animate does not support providerOptions.quiverai.${unsupportedOptions[0][0]}.`
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
return {
|
|
421
|
+
model: modelId,
|
|
422
|
+
svg_source: toQuiverAIAnimationSource(files[0]),
|
|
423
|
+
prompt,
|
|
424
|
+
temperature: options.temperature,
|
|
425
|
+
max_output_tokens: options.maxOutputTokens,
|
|
426
|
+
reasoning_effort: options.reasoningEffort,
|
|
427
|
+
stream: false
|
|
428
|
+
};
|
|
429
|
+
}
|
|
273
430
|
function collectWarnings({
|
|
274
431
|
size,
|
|
275
432
|
aspectRatio,
|
|
@@ -314,7 +471,9 @@ var svgUsageSchema = z2.object({
|
|
|
314
471
|
});
|
|
315
472
|
var svgDocumentSchema = z2.object({
|
|
316
473
|
svg: z2.string().min(1),
|
|
317
|
-
mime_type: z2.literal("image/svg+xml")
|
|
474
|
+
mime_type: z2.literal("image/svg+xml"),
|
|
475
|
+
loop_period_ms: z2.number().int().nonnegative().nullish(),
|
|
476
|
+
opening_animation_ms: z2.number().int().nonnegative().nullish()
|
|
318
477
|
});
|
|
319
478
|
var svgGenerationResponseSchema = z2.object({
|
|
320
479
|
id: z2.string().min(1),
|
|
@@ -336,7 +495,7 @@ var quiveraiFailedResponseHandler = createJsonErrorResponseHandler({
|
|
|
336
495
|
});
|
|
337
496
|
|
|
338
497
|
// src/version.ts
|
|
339
|
-
var VERSION = true ? "2.0.
|
|
498
|
+
var VERSION = true ? "2.0.44" : "0.0.0-test";
|
|
340
499
|
|
|
341
500
|
// src/quiverai-provider.ts
|
|
342
501
|
var defaultBaseURL = "https://api.quiver.ai/v1";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/quiverai-provider.ts","../src/quiverai-image-model.ts","../src/quiverai-image-model-options.ts","../src/version.ts"],"sourcesContent":["import {\n NoSuchModelError,\n type ImageModelV4,\n type ProviderV4,\n} from '@ai-sdk/provider';\nimport {\n loadApiKey,\n loadOptionalSetting,\n withoutTrailingSlash,\n withUserAgentSuffix,\n type FetchFunction,\n} from '@ai-sdk/provider-utils';\nimport { QuiverAIImageModel } from './quiverai-image-model';\nimport type { QuiverAIImageModelId } from './quiverai-image-settings';\nimport { VERSION } from './version';\n\nexport interface QuiverAIProviderSettings {\n /**\n * QuiverAI API key. Default value is taken from the `QUIVERAI_API_KEY`\n * environment variable.\n */\n apiKey?: string;\n\n /**\n * Base URL for the API calls. Defaults to `https://api.quiver.ai/v1` and\n * falls back to the `QUIVERAI_BASE_URL` environment variable.\n */\n baseURL?: string;\n\n /**\n * Custom headers to include in the requests.\n */\n headers?: Record<string, string>;\n\n /**\n * Custom fetch implementation. You can use it as a middleware to intercept\n * requests, or to provide a custom fetch implementation for e.g. testing.\n */\n fetch?: FetchFunction;\n}\n\nexport interface QuiverAIProvider extends ProviderV4 {\n /**\n * Creates a model for image generation.\n */\n image(modelId: QuiverAIImageModelId): ImageModelV4;\n\n /**\n * Creates a model for image generation.\n */\n imageModel(modelId: QuiverAIImageModelId): ImageModelV4;\n\n /**\n * @deprecated Use `embeddingModel` instead.\n */\n textEmbeddingModel(modelId: string): never;\n}\n\nconst defaultBaseURL = 'https://api.quiver.ai/v1';\n\nexport function createQuiverAI(\n options: QuiverAIProviderSettings = {},\n): QuiverAIProvider {\n const baseURL =\n withoutTrailingSlash(\n loadOptionalSetting({\n settingValue: options.baseURL,\n environmentVariableName: 'QUIVERAI_BASE_URL',\n }),\n ) ?? defaultBaseURL;\n\n const getHeaders = () =>\n withUserAgentSuffix(\n {\n Authorization: `Bearer ${loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'QUIVERAI_API_KEY',\n description: 'QuiverAI',\n })}`,\n ...options.headers,\n },\n `ai-sdk/quiverai/${VERSION}`,\n );\n\n const createImageModel = (modelId: QuiverAIImageModelId) =>\n new QuiverAIImageModel(modelId, {\n provider: 'quiverai.image',\n baseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n\n const embeddingModel = (modelId: string) => {\n throw new NoSuchModelError({\n modelId,\n modelType: 'embeddingModel',\n });\n };\n\n return {\n specificationVersion: 'v4',\n image: createImageModel,\n imageModel: createImageModel,\n languageModel: (modelId: string) => {\n throw new NoSuchModelError({\n modelId,\n modelType: 'languageModel',\n });\n },\n embeddingModel,\n textEmbeddingModel: embeddingModel,\n };\n}\n\nexport const quiverai = createQuiverAI();\n","import {\n InvalidArgumentError,\n type ImageModelV4,\n type ImageModelV4CallOptions,\n type ImageModelV4File,\n type SharedV4Warning,\n} from '@ai-sdk/provider';\nimport {\n combineHeaders,\n convertUint8ArrayToBase64,\n createJsonErrorResponseHandler,\n createJsonResponseHandler,\n parseProviderOptions,\n postJsonToApi,\n serializeModelOptions,\n WORKFLOW_DESERIALIZE,\n WORKFLOW_SERIALIZE,\n type FetchFunction,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\nimport {\n quiveraiImageModelOptionsSchema,\n type QuiverAIImageModelOptions,\n} from './quiverai-image-model-options';\nimport type {\n QuiverAIImageModelId,\n QuiverAIOperation,\n} from './quiverai-image-settings';\n\ninterface QuiverAIImageModelConfig {\n provider: string;\n baseURL: string;\n headers?: () => Record<string, string>;\n fetch?: FetchFunction;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\nexport class QuiverAIImageModel implements ImageModelV4 {\n readonly specificationVersion = 'v4';\n readonly maxImagesPerCall = 16;\n\n get provider(): string {\n return this.config.provider;\n }\n\n static [WORKFLOW_SERIALIZE](model: QuiverAIImageModel) {\n return serializeModelOptions({\n modelId: model.modelId,\n config: model.config,\n });\n }\n\n static [WORKFLOW_DESERIALIZE](options: {\n modelId: QuiverAIImageModelId;\n config: QuiverAIImageModelConfig;\n }) {\n return new QuiverAIImageModel(options.modelId, options.config);\n }\n\n constructor(\n readonly modelId: QuiverAIImageModelId,\n private readonly config: QuiverAIImageModelConfig,\n ) {}\n\n async doGenerate({\n prompt,\n n,\n files,\n mask,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: ImageModelV4CallOptions): Promise<\n Awaited<ReturnType<ImageModelV4['doGenerate']>>\n > {\n const quiveraiOptions = await parseProviderOptions({\n provider: 'quiverai',\n providerOptions,\n schema: quiveraiImageModelOptionsSchema,\n });\n\n const operation: QuiverAIOperation =\n quiveraiOptions?.operation ?? 'generate';\n\n const warnings = collectWarnings({ size, aspectRatio, seed, mask });\n\n const body = buildRequestBody({\n modelId: this.modelId,\n n,\n prompt,\n files,\n operation,\n options: quiveraiOptions ?? {},\n });\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const combinedHeaders = combineHeaders(this.config.headers?.(), headers);\n\n const { value: response, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}${getOperationPath(operation)}`,\n headers: combinedHeaders,\n body,\n failedResponseHandler: quiveraiFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n svgGenerationResponseSchema,\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const encoder = new TextEncoder();\n const images = response.data.map(image => encoder.encode(image.svg));\n\n return {\n images,\n warnings,\n providerMetadata: {\n quiverai: {\n ...(response.credits != null && { credits: response.credits }),\n images: response.data.map((image, index) => ({\n index,\n mimeType: image.mime_type,\n })),\n },\n },\n response: {\n timestamp: response.created\n ? new Date(response.created * 1000)\n : currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n ...(response.usage && {\n usage: {\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n totalTokens: response.usage.total_tokens,\n },\n }),\n };\n }\n}\n\nfunction getOperationPath(operation: QuiverAIOperation) {\n return operation === 'generate'\n ? '/svgs/generations'\n : '/svgs/vectorizations';\n}\n\nfunction getGenerateReferenceLimit(modelId: string) {\n // Only apply the lower limit to documented Arrow 1.x models. The API\n // enforces model-specific limits within its 16-reference request limit.\n return ['arrow-1', 'arrow-1.0', 'arrow-1.1'].includes(modelId) ? 4 : 16;\n}\n\nfunction toQuiverAIImageReference(image: ImageModelV4File) {\n if (image.type === 'url') {\n return { url: image.url };\n }\n return {\n base64:\n typeof image.data === 'string'\n ? image.data\n : convertUint8ArrayToBase64(image.data),\n };\n}\n\nfunction buildRequestBody({\n modelId,\n n,\n prompt,\n files,\n operation,\n options,\n}: {\n modelId: string;\n n: number;\n prompt: string | undefined;\n files: ImageModelV4File[] | undefined;\n operation: QuiverAIOperation;\n options: QuiverAIImageModelOptions;\n}) {\n if (\n (modelId === 'arrow-2' || modelId === 'arrow-2-telos') &&\n options.maxOutputTokens != null &&\n options.maxOutputTokens > 65536\n ) {\n throw new InvalidArgumentError({\n argument: 'maxOutputTokens',\n message: `QuiverAI model \"${modelId}\" supports at most 65536 output tokens.`,\n });\n }\n\n const sharedOptions = {\n temperature: options.temperature,\n top_p: options.topP,\n presence_penalty: options.presencePenalty,\n max_output_tokens: options.maxOutputTokens,\n reasoning_effort: options.reasoningEffort,\n attributes: options.attributes,\n stream: false as const,\n };\n\n if (operation === 'generate') {\n if (prompt == null || prompt.trim().length === 0) {\n throw new InvalidArgumentError({\n argument: 'prompt',\n message:\n 'QuiverAI image generation requires a non-empty prompt for generateImage.',\n });\n }\n\n const references = files?.map(toQuiverAIImageReference);\n const maxReferences = getGenerateReferenceLimit(modelId);\n\n if (references != null && references.length > maxReferences) {\n throw new InvalidArgumentError({\n argument: 'files',\n message: `QuiverAI generate supports up to ${maxReferences} reference images for model \"${modelId}\".`,\n });\n }\n\n return {\n model: modelId,\n n,\n prompt,\n ...sharedOptions,\n instructions: options.instructions,\n references,\n };\n }\n\n if (files == null || files.length === 0) {\n throw new InvalidArgumentError({\n argument: 'files',\n message:\n 'QuiverAI vectorize requires an input image. Pass an image in the generateImage prompt and set providerOptions.quiverai.operation to \"vectorize\".',\n });\n }\n\n if (files.length > 1) {\n throw new InvalidArgumentError({\n argument: 'files',\n message: 'QuiverAI vectorize accepts a single input image.',\n });\n }\n\n if (n !== 1) {\n throw new InvalidArgumentError({\n argument: 'n',\n message:\n 'QuiverAI vectorize returns one SVG per request. Set maxImagesPerCall to 1 in generateImage to vectorize multiple times.',\n });\n }\n\n return {\n model: modelId,\n image: toQuiverAIImageReference(files[0]),\n ...sharedOptions,\n auto_crop: options.autoCrop,\n target_size: options.targetSize,\n };\n}\n\nfunction collectWarnings({\n size,\n aspectRatio,\n seed,\n mask,\n}: {\n size: `${number}x${number}` | undefined;\n aspectRatio: `${number}:${number}` | undefined;\n seed: number | undefined;\n mask: ImageModelV4File | undefined;\n}): SharedV4Warning[] {\n const warnings: SharedV4Warning[] = [];\n\n if (size != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'size',\n details:\n 'QuiverAI SVG generation does not support the `size` option. The setting was ignored.',\n });\n }\n\n if (aspectRatio != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'aspectRatio',\n details:\n 'QuiverAI SVG generation does not support the `aspectRatio` option. The setting was ignored.',\n });\n }\n\n if (seed != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'seed',\n details:\n 'QuiverAI SVG generation does not support the `seed` option. The setting was ignored.',\n });\n }\n\n if (mask != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'mask',\n details:\n 'QuiverAI SVG generation does not support masks. The mask was ignored.',\n });\n }\n\n return warnings;\n}\n\n// Limited schemas focused on what is needed for the implementation.\n// This approach limits breakages when the API changes and keeps the\n// response handler efficient.\nconst svgUsageSchema = z.object({\n total_tokens: z.number().int().nonnegative(),\n input_tokens: z.number().int().nonnegative(),\n output_tokens: z.number().int().nonnegative(),\n});\n\nconst svgDocumentSchema = z.object({\n svg: z.string().min(1),\n mime_type: z.literal('image/svg+xml'),\n});\n\nconst svgGenerationResponseSchema = z.object({\n id: z.string().min(1),\n created: z.number().int().nonnegative(),\n data: z.array(svgDocumentSchema).min(1),\n usage: svgUsageSchema.nullish(),\n credits: z.number().int().nonnegative().nullish(),\n});\n\nconst quiveraiErrorSchema = z.object({\n status: z.number().int(),\n code: z.string().min(1),\n message: z.string().min(1),\n request_id: z.string().min(1),\n});\n\nexport const quiveraiFailedResponseHandler = createJsonErrorResponseHandler({\n errorSchema: quiveraiErrorSchema,\n errorToMessage: error => error.message,\n isRetryable: response => response.status === 429 || response.status >= 500,\n});\n","import {\n lazySchema,\n zodSchema,\n type InferSchema,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\n\n/**\n * Provider options schema for QuiverAI image generation.\n *\n * @see https://quiver.ai/\n */\nexport const quiveraiImageModelOptionsSchema = lazySchema(() =>\n zodSchema(\n z.object({\n /**\n * The operation to perform. Defaults to `generate`.\n *\n * - `generate`: Text-to-SVG generation. Requires `prompt`.\n * - `vectorize`: Convert an input raster image into an SVG. Requires a\n * single image in `prompt.images` / `files`.\n */\n operation: z.enum(['generate', 'vectorize']).optional(),\n\n /**\n * Extra style guidance for prompt-based generation.\n */\n instructions: z.string().min(1).optional(),\n\n /**\n * Reasoning effort applied to generation or vectorization.\n */\n reasoningEffort: z.enum(['low', 'medium', 'high', 'xhigh']).optional(),\n\n /**\n * SVG root attributes requested for generation or vectorization.\n */\n attributes: z\n .object({\n viewBox: z\n .object({\n minX: z.number(),\n minY: z.number(),\n width: z.number().positive(),\n height: z.number().positive(),\n })\n .optional(),\n })\n .optional(),\n\n /**\n * Sampling temperature (0-2).\n */\n temperature: z.number().min(0).max(2).optional(),\n\n /**\n * Nucleus sampling top-p (0-1).\n */\n topP: z.number().min(0).max(1).optional(),\n\n /**\n * Presence penalty (-2 to 2).\n */\n presencePenalty: z.number().min(-2).max(2).nullable().optional(),\n\n /**\n * Maximum number of output tokens (1 - 65536 for Arrow 2 models).\n * The legacy upper bound of 131072 is retained for other model IDs.\n */\n maxOutputTokens: z.number().int().min(1).max(131072).optional(),\n\n /**\n * Whether to auto-crop the input image before vectorization.\n * Only used when `operation` is `vectorize`.\n */\n autoCrop: z.boolean().optional(),\n\n /**\n * Target canvas size in pixels for vectorization (128 - 4096).\n * Only used when `operation` is `vectorize`.\n */\n targetSize: z.number().int().min(128).max(4096).optional(),\n }),\n ),\n);\n\nexport type QuiverAIImageModelOptions = InferSchema<\n typeof quiveraiImageModelOptionsSchema\n>;\n","// Version string of this package injected at build time.\ndeclare const __PACKAGE_VERSION__: string | undefined;\nexport const VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n"],"mappings":"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","names":["z","z"]}
|
|
1
|
+
{"version":3,"sources":["../src/quiverai-provider.ts","../src/quiverai-image-model.ts","../src/quiverai-image-model-options.ts","../src/version.ts"],"sourcesContent":["import {\n NoSuchModelError,\n type ImageModelV4,\n type ProviderV4,\n} from '@ai-sdk/provider';\nimport {\n loadApiKey,\n loadOptionalSetting,\n withoutTrailingSlash,\n withUserAgentSuffix,\n type FetchFunction,\n} from '@ai-sdk/provider-utils';\nimport { QuiverAIImageModel } from './quiverai-image-model';\nimport type { QuiverAIImageModelId } from './quiverai-image-settings';\nimport { VERSION } from './version';\n\nexport interface QuiverAIProviderSettings {\n /**\n * QuiverAI API key. Default value is taken from the `QUIVERAI_API_KEY`\n * environment variable.\n */\n apiKey?: string;\n\n /**\n * Base URL for the API calls. Defaults to `https://api.quiver.ai/v1` and\n * falls back to the `QUIVERAI_BASE_URL` environment variable.\n */\n baseURL?: string;\n\n /**\n * Custom headers to include in the requests.\n */\n headers?: Record<string, string>;\n\n /**\n * Custom fetch implementation. You can use it as a middleware to intercept\n * requests, or to provide a custom fetch implementation for e.g. testing.\n */\n fetch?: FetchFunction;\n}\n\nexport interface QuiverAIProvider extends ProviderV4 {\n /**\n * Creates a model for image generation.\n */\n image(modelId: QuiverAIImageModelId): ImageModelV4;\n\n /**\n * Creates a model for image generation.\n */\n imageModel(modelId: QuiverAIImageModelId): ImageModelV4;\n\n /**\n * @deprecated Use `embeddingModel` instead.\n */\n textEmbeddingModel(modelId: string): never;\n}\n\nconst defaultBaseURL = 'https://api.quiver.ai/v1';\n\nexport function createQuiverAI(\n options: QuiverAIProviderSettings = {},\n): QuiverAIProvider {\n const baseURL =\n withoutTrailingSlash(\n loadOptionalSetting({\n settingValue: options.baseURL,\n environmentVariableName: 'QUIVERAI_BASE_URL',\n }),\n ) ?? defaultBaseURL;\n\n const getHeaders = () =>\n withUserAgentSuffix(\n {\n Authorization: `Bearer ${loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'QUIVERAI_API_KEY',\n description: 'QuiverAI',\n })}`,\n ...options.headers,\n },\n `ai-sdk/quiverai/${VERSION}`,\n );\n\n const createImageModel = (modelId: QuiverAIImageModelId) =>\n new QuiverAIImageModel(modelId, {\n provider: 'quiverai.image',\n baseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n\n const embeddingModel = (modelId: string) => {\n throw new NoSuchModelError({\n modelId,\n modelType: 'embeddingModel',\n });\n };\n\n return {\n specificationVersion: 'v4',\n image: createImageModel,\n imageModel: createImageModel,\n languageModel: (modelId: string) => {\n throw new NoSuchModelError({\n modelId,\n modelType: 'languageModel',\n });\n },\n embeddingModel,\n textEmbeddingModel: embeddingModel,\n };\n}\n\nexport const quiverai = createQuiverAI();\n","import {\n InvalidArgumentError,\n type ImageModelV4,\n type ImageModelV4CallOptions,\n type ImageModelV4File,\n type SharedV4Warning,\n} from '@ai-sdk/provider';\nimport {\n combineHeaders,\n convertBase64ToUint8Array,\n convertUint8ArrayToBase64,\n createJsonErrorResponseHandler,\n createJsonResponseHandler,\n parseProviderOptions,\n postJsonToApi,\n serializeModelOptions,\n WORKFLOW_DESERIALIZE,\n WORKFLOW_SERIALIZE,\n type FetchFunction,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\nimport {\n quiveraiImageModelOptionsSchema,\n type QuiverAIImageModelOptions,\n} from './quiverai-image-model-options';\nimport type {\n QuiverAIImageModelId,\n QuiverAIOperation,\n} from './quiverai-image-settings';\n\ninterface QuiverAIImageModelConfig {\n provider: string;\n baseURL: string;\n headers?: () => Record<string, string>;\n fetch?: FetchFunction;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\nexport class QuiverAIImageModel implements ImageModelV4 {\n readonly specificationVersion = 'v4';\n readonly maxImagesPerCall = 16;\n\n get provider(): string {\n return this.config.provider;\n }\n\n static [WORKFLOW_SERIALIZE](model: QuiverAIImageModel) {\n return serializeModelOptions({\n modelId: model.modelId,\n config: model.config,\n });\n }\n\n static [WORKFLOW_DESERIALIZE](options: {\n modelId: QuiverAIImageModelId;\n config: QuiverAIImageModelConfig;\n }) {\n return new QuiverAIImageModel(options.modelId, options.config);\n }\n\n constructor(\n readonly modelId: QuiverAIImageModelId,\n private readonly config: QuiverAIImageModelConfig,\n ) {}\n\n async doGenerate({\n prompt,\n n,\n files,\n mask,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: ImageModelV4CallOptions): Promise<\n Awaited<ReturnType<ImageModelV4['doGenerate']>>\n > {\n const quiveraiOptions = await parseProviderOptions({\n provider: 'quiverai',\n providerOptions,\n schema: quiveraiImageModelOptionsSchema,\n });\n\n const operation: QuiverAIOperation =\n quiveraiOptions?.operation ?? 'generate';\n\n const warnings = collectWarnings({ size, aspectRatio, seed, mask });\n\n const body = buildRequestBody({\n modelId: this.modelId,\n n,\n prompt,\n files,\n mask,\n operation,\n options: quiveraiOptions ?? {},\n });\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const combinedHeaders = combineHeaders(this.config.headers?.(), headers);\n\n const { value: response, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}${getOperationPath(operation)}`,\n headers: combinedHeaders,\n body,\n failedResponseHandler: quiveraiFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n svgGenerationResponseSchema,\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const encoder = new TextEncoder();\n const images = response.data.map(image => encoder.encode(image.svg));\n\n return {\n images,\n warnings,\n providerMetadata: {\n quiverai: {\n ...(response.credits != null && { credits: response.credits }),\n images: response.data.map((image, index) => ({\n index,\n mimeType: image.mime_type,\n ...(image.loop_period_ms !== undefined && {\n loopPeriodMs: image.loop_period_ms,\n }),\n ...(image.opening_animation_ms !== undefined && {\n openingAnimationMs: image.opening_animation_ms,\n }),\n })),\n },\n },\n response: {\n timestamp: response.created\n ? new Date(response.created * 1000)\n : currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n ...(response.usage && {\n usage: {\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n totalTokens: response.usage.total_tokens,\n },\n }),\n };\n }\n}\n\nfunction getOperationPath(operation: QuiverAIOperation) {\n switch (operation) {\n case 'generate':\n return '/svgs/generations';\n case 'vectorize':\n return '/svgs/vectorizations';\n case 'animate':\n return '/svgs/animations';\n }\n}\n\nfunction getGenerateReferenceLimit(modelId: string) {\n // Only apply the lower limit to documented Arrow 1.x models. The API\n // enforces model-specific limits within its 16-reference request limit.\n return ['arrow-1', 'arrow-1.0', 'arrow-1.1'].includes(modelId) ? 4 : 16;\n}\n\nfunction toQuiverAIImageReference(image: ImageModelV4File) {\n if (image.type === 'url') {\n return { url: image.url };\n }\n return {\n base64:\n typeof image.data === 'string'\n ? image.data\n : convertUint8ArrayToBase64(image.data),\n };\n}\n\nconst maxAnimationSourceBase64Length = 1_066_668;\n\nfunction toQuiverAIAnimationSource(image: ImageModelV4File) {\n if (image.type === 'url') {\n let url: URL;\n try {\n url = new URL(image.url);\n } catch {\n throw new InvalidArgumentError({\n argument: 'files',\n message: 'QuiverAI animate requires a valid HTTP or HTTPS SVG URL.',\n });\n }\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new InvalidArgumentError({\n argument: 'files',\n message: 'QuiverAI animate requires an HTTP or HTTPS SVG URL.',\n });\n }\n\n return { url: image.url };\n }\n\n let base64: string;\n let bytes: Uint8Array;\n\n if (typeof image.data === 'string') {\n const dataUrlMatch =\n /^data:image\\/svg\\+xml(?:;[^,]*)?;base64,([\\s\\S]+)$/i.exec(image.data);\n const encodedData = dataUrlMatch?.[1] ?? image.data;\n\n try {\n bytes = convertBase64ToUint8Array(encodedData);\n } catch {\n throw new InvalidArgumentError({\n argument: 'files',\n message:\n 'QuiverAI animate requires the source SVG string to be valid base64 or an SVG data URL.',\n });\n }\n base64 = convertUint8ArrayToBase64(bytes);\n } else {\n bytes = image.data;\n base64 = convertUint8ArrayToBase64(bytes);\n }\n\n if (!isSvg(bytes)) {\n throw new InvalidArgumentError({\n argument: 'files',\n message: 'QuiverAI animate requires the input file to contain SVG data.',\n });\n }\n\n if (base64.length > maxAnimationSourceBase64Length) {\n throw new InvalidArgumentError({\n argument: 'files',\n message: `QuiverAI animate accepts at most ${maxAnimationSourceBase64Length} base64 characters for the source SVG.`,\n });\n }\n\n return { base64 };\n}\n\nfunction isSvg(data: Uint8Array): boolean {\n const head = new TextDecoder('utf-8', { fatal: false })\n .decode(data.subarray(0, 4096))\n .trimStart();\n\n return /^(?:(?:<\\?xml[\\s\\S]*?\\?>|<!--[\\s\\S]*?-->|<!DOCTYPE[\\s\\S]*?>)\\s*)*<svg(?:\\s|>)/i.test(\n head,\n );\n}\n\nfunction buildRequestBody({\n modelId,\n n,\n prompt,\n files,\n mask,\n operation,\n options,\n}: {\n modelId: string;\n n: number;\n prompt: string | undefined;\n files: ImageModelV4File[] | undefined;\n mask: ImageModelV4File | undefined;\n operation: QuiverAIOperation;\n options: QuiverAIImageModelOptions;\n}) {\n if (\n (modelId === 'arrow-2' || modelId === 'arrow-2-telos') &&\n options.maxOutputTokens != null &&\n options.maxOutputTokens > 65536\n ) {\n throw new InvalidArgumentError({\n argument: 'maxOutputTokens',\n message: `QuiverAI model \"${modelId}\" supports at most 65536 output tokens.`,\n });\n }\n\n const sharedOptions = {\n temperature: options.temperature,\n top_p: options.topP,\n presence_penalty: options.presencePenalty,\n max_output_tokens: options.maxOutputTokens,\n reasoning_effort: options.reasoningEffort,\n attributes: options.attributes,\n stream: false as const,\n };\n\n if (operation === 'generate') {\n if (prompt == null || prompt.trim().length === 0) {\n throw new InvalidArgumentError({\n argument: 'prompt',\n message:\n 'QuiverAI image generation requires a non-empty prompt for generateImage.',\n });\n }\n\n const references = files?.map(toQuiverAIImageReference);\n const maxReferences = getGenerateReferenceLimit(modelId);\n\n if (references != null && references.length > maxReferences) {\n throw new InvalidArgumentError({\n argument: 'files',\n message: `QuiverAI generate supports up to ${maxReferences} reference images for model \"${modelId}\".`,\n });\n }\n\n return {\n model: modelId,\n n,\n prompt,\n ...sharedOptions,\n instructions: options.instructions,\n references,\n };\n }\n\n if (operation === 'animate') {\n return buildAnimationRequestBody({\n modelId,\n n,\n prompt,\n files,\n mask,\n options,\n });\n }\n\n if (files == null || files.length === 0) {\n throw new InvalidArgumentError({\n argument: 'files',\n message:\n 'QuiverAI vectorize requires an input image. Pass an image in the generateImage prompt and set providerOptions.quiverai.operation to \"vectorize\".',\n });\n }\n\n if (files.length > 1) {\n throw new InvalidArgumentError({\n argument: 'files',\n message: 'QuiverAI vectorize accepts a single input image.',\n });\n }\n\n if (n !== 1) {\n throw new InvalidArgumentError({\n argument: 'n',\n message:\n 'QuiverAI vectorize returns one SVG per request. Set maxImagesPerCall to 1 in generateImage to vectorize multiple times.',\n });\n }\n\n return {\n model: modelId,\n image: toQuiverAIImageReference(files[0]),\n ...sharedOptions,\n auto_crop: options.autoCrop,\n target_size: options.targetSize,\n };\n}\n\nfunction buildAnimationRequestBody({\n modelId,\n n,\n prompt,\n files,\n mask,\n options,\n}: {\n modelId: string;\n n: number;\n prompt: string | undefined;\n files: ImageModelV4File[] | undefined;\n mask: ImageModelV4File | undefined;\n options: QuiverAIImageModelOptions;\n}) {\n if (modelId !== 'arrow-2' && modelId !== 'arrow-2-telos') {\n throw new InvalidArgumentError({\n argument: 'modelId',\n message:\n 'QuiverAI animate is supported by the \"arrow-2\" and \"arrow-2-telos\" models.',\n });\n }\n\n if (files == null || files.length === 0) {\n throw new InvalidArgumentError({\n argument: 'files',\n message:\n 'QuiverAI animate requires exactly one source SVG in prompt.images.',\n });\n }\n\n if (files.length !== 1) {\n throw new InvalidArgumentError({\n argument: 'files',\n message:\n 'QuiverAI animate accepts exactly one source SVG in prompt.images.',\n });\n }\n\n if (n !== 1) {\n throw new InvalidArgumentError({\n argument: 'n',\n message:\n 'QuiverAI animate returns one SVG per request. Set maxImagesPerCall to 1 in generateImage to animate multiple times.',\n });\n }\n\n if (mask != null) {\n throw new InvalidArgumentError({\n argument: 'mask',\n message: 'QuiverAI animate does not support masks.',\n });\n }\n\n if (prompt != null && prompt.trim().length === 0) {\n throw new InvalidArgumentError({\n argument: 'prompt',\n message:\n 'QuiverAI animate requires a non-empty prompt when an animation instruction is provided.',\n });\n }\n\n const unsupportedOptions = [\n ['instructions', options.instructions],\n ['topP', options.topP],\n ['presencePenalty', options.presencePenalty],\n ['attributes', options.attributes],\n ['autoCrop', options.autoCrop],\n ['targetSize', options.targetSize],\n ].filter((option): option is [string, NonNullable<unknown>] => {\n return option[1] !== undefined;\n });\n\n if (unsupportedOptions.length > 0) {\n throw new InvalidArgumentError({\n argument: `providerOptions.quiverai.${unsupportedOptions[0][0]}`,\n message: `QuiverAI animate does not support providerOptions.quiverai.${unsupportedOptions[0][0]}.`,\n });\n }\n\n return {\n model: modelId,\n svg_source: toQuiverAIAnimationSource(files[0]),\n prompt,\n temperature: options.temperature,\n max_output_tokens: options.maxOutputTokens,\n reasoning_effort: options.reasoningEffort,\n stream: false as const,\n };\n}\n\nfunction collectWarnings({\n size,\n aspectRatio,\n seed,\n mask,\n}: {\n size: `${number}x${number}` | undefined;\n aspectRatio: `${number}:${number}` | undefined;\n seed: number | undefined;\n mask: ImageModelV4File | undefined;\n}): SharedV4Warning[] {\n const warnings: SharedV4Warning[] = [];\n\n if (size != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'size',\n details:\n 'QuiverAI SVG generation does not support the `size` option. The setting was ignored.',\n });\n }\n\n if (aspectRatio != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'aspectRatio',\n details:\n 'QuiverAI SVG generation does not support the `aspectRatio` option. The setting was ignored.',\n });\n }\n\n if (seed != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'seed',\n details:\n 'QuiverAI SVG generation does not support the `seed` option. The setting was ignored.',\n });\n }\n\n if (mask != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'mask',\n details:\n 'QuiverAI SVG generation does not support masks. The mask was ignored.',\n });\n }\n\n return warnings;\n}\n\n// Limited schemas focused on what is needed for the implementation.\n// This approach limits breakages when the API changes and keeps the\n// response handler efficient.\nconst svgUsageSchema = z.object({\n total_tokens: z.number().int().nonnegative(),\n input_tokens: z.number().int().nonnegative(),\n output_tokens: z.number().int().nonnegative(),\n});\n\nconst svgDocumentSchema = z.object({\n svg: z.string().min(1),\n mime_type: z.literal('image/svg+xml'),\n loop_period_ms: z.number().int().nonnegative().nullish(),\n opening_animation_ms: z.number().int().nonnegative().nullish(),\n});\n\nconst svgGenerationResponseSchema = z.object({\n id: z.string().min(1),\n created: z.number().int().nonnegative(),\n data: z.array(svgDocumentSchema).min(1),\n usage: svgUsageSchema.nullish(),\n credits: z.number().int().nonnegative().nullish(),\n});\n\nconst quiveraiErrorSchema = z.object({\n status: z.number().int(),\n code: z.string().min(1),\n message: z.string().min(1),\n request_id: z.string().min(1),\n});\n\nexport const quiveraiFailedResponseHandler = createJsonErrorResponseHandler({\n errorSchema: quiveraiErrorSchema,\n errorToMessage: error => error.message,\n isRetryable: response => response.status === 429 || response.status >= 500,\n});\n","import {\n lazySchema,\n zodSchema,\n type InferSchema,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\n\n/**\n * Provider options schema for QuiverAI image generation.\n *\n * @see https://quiver.ai/\n */\nexport const quiveraiImageModelOptionsSchema = lazySchema(() =>\n zodSchema(\n z.object({\n /**\n * The operation to perform. Defaults to `generate`.\n *\n * - `generate`: Text-to-SVG generation. Requires `prompt`.\n * - `vectorize`: Convert an input raster image into an SVG. Requires a\n * single image in `prompt.images` / `files`.\n * - `animate`: Animate an input SVG. Requires a single SVG in\n * `prompt.images` / `files`; the text prompt is optional.\n */\n operation: z.enum(['generate', 'vectorize', 'animate']).optional(),\n\n /**\n * Extra style guidance for prompt-based generation.\n */\n instructions: z.string().min(1).optional(),\n\n /**\n * Reasoning effort applied to generation or vectorization.\n */\n reasoningEffort: z.enum(['low', 'medium', 'high', 'xhigh']).optional(),\n\n /**\n * SVG root attributes requested for generation or vectorization.\n */\n attributes: z\n .object({\n viewBox: z\n .object({\n minX: z.number(),\n minY: z.number(),\n width: z.number().positive(),\n height: z.number().positive(),\n })\n .optional(),\n })\n .optional(),\n\n /**\n * Sampling temperature (0-2).\n */\n temperature: z.number().min(0).max(2).optional(),\n\n /**\n * Nucleus sampling top-p (0-1).\n */\n topP: z.number().min(0).max(1).optional(),\n\n /**\n * Presence penalty (-2 to 2).\n */\n presencePenalty: z.number().min(-2).max(2).nullable().optional(),\n\n /**\n * Maximum number of output tokens (1 - 65536 for Arrow 2 models).\n * The legacy upper bound of 131072 is retained for other model IDs.\n */\n maxOutputTokens: z.number().int().min(1).max(131072).optional(),\n\n /**\n * Whether to auto-crop the input image before vectorization.\n * Only used when `operation` is `vectorize`.\n */\n autoCrop: z.boolean().optional(),\n\n /**\n * Target canvas size in pixels for vectorization (128 - 4096).\n * Only used when `operation` is `vectorize`.\n */\n targetSize: z.number().int().min(128).max(4096).optional(),\n }),\n ),\n);\n\nexport type QuiverAIImageModelOptions = InferSchema<\n typeof quiveraiImageModelOptionsSchema\n>;\n","// Version string of this package injected at build time.\ndeclare const __PACKAGE_VERSION__: string | undefined;\nexport const VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n"],"mappings":"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","names":["z","z"]}
|
package/docs/180-quiverai.mdx
CHANGED
|
@@ -5,7 +5,7 @@ description: Learn how to use QuiverAI models with the AI SDK.
|
|
|
5
5
|
|
|
6
6
|
# QuiverAI Provider
|
|
7
7
|
|
|
8
|
-
[QuiverAI](https://quiver.ai/) generates SVG documents directly from text prompts
|
|
8
|
+
[QuiverAI](https://quiver.ai/) generates SVG documents directly from text prompts, vectorizes raster images, and animates existing SVGs. The QuiverAI provider for the AI SDK exposes these operations through `generateImage`.
|
|
9
9
|
|
|
10
10
|
## Setup
|
|
11
11
|
|
|
@@ -119,9 +119,9 @@ await generateImage({
|
|
|
119
119
|
|
|
120
120
|
Supported options:
|
|
121
121
|
|
|
122
|
-
- **operation** _'generate' | 'vectorize'_
|
|
122
|
+
- **operation** _'generate' | 'vectorize' | 'animate'_
|
|
123
123
|
|
|
124
|
-
Choose between text-to-SVG generation (`generate`, default)
|
|
124
|
+
Choose between text-to-SVG generation (`generate`, default), image-to-SVG vectorization (`vectorize`), and SVG animation (`animate`).
|
|
125
125
|
|
|
126
126
|
- **instructions** _string_
|
|
127
127
|
|
|
@@ -203,8 +203,46 @@ fs.writeFileSync('logo.svg', image.uint8Array);
|
|
|
203
203
|
|
|
204
204
|
Vectorization returns one SVG per API request. To request multiple vectorizations with `n`, also set `maxImagesPerCall: 1` so `generateImage` splits them into separate calls.
|
|
205
205
|
|
|
206
|
+
### Animating an SVG
|
|
207
|
+
|
|
208
|
+
Arrow 2 and Arrow 2 Telos can animate an existing SVG. Set `operation` to `animate` and pass exactly one source SVG in `prompt.images`. The text instruction is optional; omit `text` to let QuiverAI choose an animation.
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
import { quiverai, type QuiverAIImageModelOptions } from '@ai-sdk/quiverai';
|
|
212
|
+
import { generateImage } from 'ai';
|
|
213
|
+
import fs from 'fs';
|
|
214
|
+
|
|
215
|
+
const { image, providerMetadata } = await generateImage({
|
|
216
|
+
model: quiverai.image('arrow-2'),
|
|
217
|
+
prompt: {
|
|
218
|
+
images: [fs.readFileSync('./logo.svg')],
|
|
219
|
+
text: 'Make the logo pulse gently.',
|
|
220
|
+
},
|
|
221
|
+
providerOptions: {
|
|
222
|
+
quiverai: {
|
|
223
|
+
operation: 'animate',
|
|
224
|
+
reasoningEffort: 'medium',
|
|
225
|
+
maxOutputTokens: 4096,
|
|
226
|
+
} satisfies QuiverAIImageModelOptions,
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
fs.writeFileSync('animated-logo.svg', image.uint8Array);
|
|
231
|
+
|
|
232
|
+
const timing = providerMetadata.quiverai?.images?.[0];
|
|
233
|
+
console.log(timing?.loopPeriodMs, timing?.openingAnimationMs);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
The animation source can be an HTTP or HTTPS URL, SVG bytes, raw base64, or an `image/svg+xml` base64 data URL. Local file inputs are inspected before the request and rejected when they do not contain SVG data. Remote URLs are validated for their scheme and fetched and validated by QuiverAI.
|
|
237
|
+
|
|
238
|
+
Animation returns an animated SVG as bytes in `image.uint8Array`. When QuiverAI returns timing information, the per-image metadata includes `loopPeriodMs` and `openingAnimationMs`; either timing value can be `null`.
|
|
239
|
+
|
|
240
|
+
Animation requests must use `arrow-2` or `arrow-2-telos`, contain exactly one source SVG, omit masks, and produce one result per provider request. To request multiple animations with `n`, set `maxImagesPerCall: 1` so `generateImage` splits them into separate calls. Animation supports `temperature`, `reasoningEffort`, and `maxOutputTokens`; generation-only and vectorization-only provider options are rejected.
|
|
241
|
+
|
|
242
|
+
Source SVGs, text instructions, and remote source URLs are sent to QuiverAI. Animated SVG is active document content. Sanitize it or render it in an isolated context before embedding output from an untrusted source inline in a page.
|
|
243
|
+
|
|
206
244
|
### Billing and Usage
|
|
207
245
|
|
|
208
246
|
Arrow 2 models return measured token counts in `result.usage`. Fixed-credit models may return compatibility token counts of zero; their credit charge is available in `result.providerMetadata?.quiverai?.credits` when supplied by the API.
|
|
209
247
|
|
|
210
|
-
Model availability and supported operations depend on your organization and API key permissions. Consult QuiverAI's [model catalog](https://docs.quiver.ai/developers/models) for current capabilities and billing. Editing
|
|
248
|
+
Model availability and supported operations depend on your organization and API key permissions. Consult QuiverAI's [model catalog](https://docs.quiver.ai/developers/models) for current capabilities and billing. Editing and the Responses API are not yet exposed by this provider.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/quiverai",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.44",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@ai-sdk/provider": "4.0.17",
|
|
33
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
33
|
+
"@ai-sdk/provider-utils": "5.0.44"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@ai-sdk/test-server": "2.0.1",
|
|
@@ -19,8 +19,10 @@ export const quiveraiImageModelOptionsSchema = lazySchema(() =>
|
|
|
19
19
|
* - `generate`: Text-to-SVG generation. Requires `prompt`.
|
|
20
20
|
* - `vectorize`: Convert an input raster image into an SVG. Requires a
|
|
21
21
|
* single image in `prompt.images` / `files`.
|
|
22
|
+
* - `animate`: Animate an input SVG. Requires a single SVG in
|
|
23
|
+
* `prompt.images` / `files`; the text prompt is optional.
|
|
22
24
|
*/
|
|
23
|
-
operation: z.enum(['generate', 'vectorize']).optional(),
|
|
25
|
+
operation: z.enum(['generate', 'vectorize', 'animate']).optional(),
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
* Extra style guidance for prompt-based generation.
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from '@ai-sdk/provider';
|
|
8
8
|
import {
|
|
9
9
|
combineHeaders,
|
|
10
|
+
convertBase64ToUint8Array,
|
|
10
11
|
convertUint8ArrayToBase64,
|
|
11
12
|
createJsonErrorResponseHandler,
|
|
12
13
|
createJsonResponseHandler,
|
|
@@ -94,6 +95,7 @@ export class QuiverAIImageModel implements ImageModelV4 {
|
|
|
94
95
|
n,
|
|
95
96
|
prompt,
|
|
96
97
|
files,
|
|
98
|
+
mask,
|
|
97
99
|
operation,
|
|
98
100
|
options: quiveraiOptions ?? {},
|
|
99
101
|
});
|
|
@@ -125,6 +127,12 @@ export class QuiverAIImageModel implements ImageModelV4 {
|
|
|
125
127
|
images: response.data.map((image, index) => ({
|
|
126
128
|
index,
|
|
127
129
|
mimeType: image.mime_type,
|
|
130
|
+
...(image.loop_period_ms !== undefined && {
|
|
131
|
+
loopPeriodMs: image.loop_period_ms,
|
|
132
|
+
}),
|
|
133
|
+
...(image.opening_animation_ms !== undefined && {
|
|
134
|
+
openingAnimationMs: image.opening_animation_ms,
|
|
135
|
+
}),
|
|
128
136
|
})),
|
|
129
137
|
},
|
|
130
138
|
},
|
|
@@ -147,9 +155,14 @@ export class QuiverAIImageModel implements ImageModelV4 {
|
|
|
147
155
|
}
|
|
148
156
|
|
|
149
157
|
function getOperationPath(operation: QuiverAIOperation) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
158
|
+
switch (operation) {
|
|
159
|
+
case 'generate':
|
|
160
|
+
return '/svgs/generations';
|
|
161
|
+
case 'vectorize':
|
|
162
|
+
return '/svgs/vectorizations';
|
|
163
|
+
case 'animate':
|
|
164
|
+
return '/svgs/animations';
|
|
165
|
+
}
|
|
153
166
|
}
|
|
154
167
|
|
|
155
168
|
function getGenerateReferenceLimit(modelId: string) {
|
|
@@ -170,11 +183,86 @@ function toQuiverAIImageReference(image: ImageModelV4File) {
|
|
|
170
183
|
};
|
|
171
184
|
}
|
|
172
185
|
|
|
186
|
+
const maxAnimationSourceBase64Length = 1_066_668;
|
|
187
|
+
|
|
188
|
+
function toQuiverAIAnimationSource(image: ImageModelV4File) {
|
|
189
|
+
if (image.type === 'url') {
|
|
190
|
+
let url: URL;
|
|
191
|
+
try {
|
|
192
|
+
url = new URL(image.url);
|
|
193
|
+
} catch {
|
|
194
|
+
throw new InvalidArgumentError({
|
|
195
|
+
argument: 'files',
|
|
196
|
+
message: 'QuiverAI animate requires a valid HTTP or HTTPS SVG URL.',
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
201
|
+
throw new InvalidArgumentError({
|
|
202
|
+
argument: 'files',
|
|
203
|
+
message: 'QuiverAI animate requires an HTTP or HTTPS SVG URL.',
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return { url: image.url };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let base64: string;
|
|
211
|
+
let bytes: Uint8Array;
|
|
212
|
+
|
|
213
|
+
if (typeof image.data === 'string') {
|
|
214
|
+
const dataUrlMatch =
|
|
215
|
+
/^data:image\/svg\+xml(?:;[^,]*)?;base64,([\s\S]+)$/i.exec(image.data);
|
|
216
|
+
const encodedData = dataUrlMatch?.[1] ?? image.data;
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
bytes = convertBase64ToUint8Array(encodedData);
|
|
220
|
+
} catch {
|
|
221
|
+
throw new InvalidArgumentError({
|
|
222
|
+
argument: 'files',
|
|
223
|
+
message:
|
|
224
|
+
'QuiverAI animate requires the source SVG string to be valid base64 or an SVG data URL.',
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
base64 = convertUint8ArrayToBase64(bytes);
|
|
228
|
+
} else {
|
|
229
|
+
bytes = image.data;
|
|
230
|
+
base64 = convertUint8ArrayToBase64(bytes);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (!isSvg(bytes)) {
|
|
234
|
+
throw new InvalidArgumentError({
|
|
235
|
+
argument: 'files',
|
|
236
|
+
message: 'QuiverAI animate requires the input file to contain SVG data.',
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (base64.length > maxAnimationSourceBase64Length) {
|
|
241
|
+
throw new InvalidArgumentError({
|
|
242
|
+
argument: 'files',
|
|
243
|
+
message: `QuiverAI animate accepts at most ${maxAnimationSourceBase64Length} base64 characters for the source SVG.`,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return { base64 };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function isSvg(data: Uint8Array): boolean {
|
|
251
|
+
const head = new TextDecoder('utf-8', { fatal: false })
|
|
252
|
+
.decode(data.subarray(0, 4096))
|
|
253
|
+
.trimStart();
|
|
254
|
+
|
|
255
|
+
return /^(?:(?:<\?xml[\s\S]*?\?>|<!--[\s\S]*?-->|<!DOCTYPE[\s\S]*?>)\s*)*<svg(?:\s|>)/i.test(
|
|
256
|
+
head,
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
173
260
|
function buildRequestBody({
|
|
174
261
|
modelId,
|
|
175
262
|
n,
|
|
176
263
|
prompt,
|
|
177
264
|
files,
|
|
265
|
+
mask,
|
|
178
266
|
operation,
|
|
179
267
|
options,
|
|
180
268
|
}: {
|
|
@@ -182,6 +270,7 @@ function buildRequestBody({
|
|
|
182
270
|
n: number;
|
|
183
271
|
prompt: string | undefined;
|
|
184
272
|
files: ImageModelV4File[] | undefined;
|
|
273
|
+
mask: ImageModelV4File | undefined;
|
|
185
274
|
operation: QuiverAIOperation;
|
|
186
275
|
options: QuiverAIImageModelOptions;
|
|
187
276
|
}) {
|
|
@@ -235,6 +324,17 @@ function buildRequestBody({
|
|
|
235
324
|
};
|
|
236
325
|
}
|
|
237
326
|
|
|
327
|
+
if (operation === 'animate') {
|
|
328
|
+
return buildAnimationRequestBody({
|
|
329
|
+
modelId,
|
|
330
|
+
n,
|
|
331
|
+
prompt,
|
|
332
|
+
files,
|
|
333
|
+
mask,
|
|
334
|
+
options,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
238
338
|
if (files == null || files.length === 0) {
|
|
239
339
|
throw new InvalidArgumentError({
|
|
240
340
|
argument: 'files',
|
|
@@ -267,6 +367,97 @@ function buildRequestBody({
|
|
|
267
367
|
};
|
|
268
368
|
}
|
|
269
369
|
|
|
370
|
+
function buildAnimationRequestBody({
|
|
371
|
+
modelId,
|
|
372
|
+
n,
|
|
373
|
+
prompt,
|
|
374
|
+
files,
|
|
375
|
+
mask,
|
|
376
|
+
options,
|
|
377
|
+
}: {
|
|
378
|
+
modelId: string;
|
|
379
|
+
n: number;
|
|
380
|
+
prompt: string | undefined;
|
|
381
|
+
files: ImageModelV4File[] | undefined;
|
|
382
|
+
mask: ImageModelV4File | undefined;
|
|
383
|
+
options: QuiverAIImageModelOptions;
|
|
384
|
+
}) {
|
|
385
|
+
if (modelId !== 'arrow-2' && modelId !== 'arrow-2-telos') {
|
|
386
|
+
throw new InvalidArgumentError({
|
|
387
|
+
argument: 'modelId',
|
|
388
|
+
message:
|
|
389
|
+
'QuiverAI animate is supported by the "arrow-2" and "arrow-2-telos" models.',
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (files == null || files.length === 0) {
|
|
394
|
+
throw new InvalidArgumentError({
|
|
395
|
+
argument: 'files',
|
|
396
|
+
message:
|
|
397
|
+
'QuiverAI animate requires exactly one source SVG in prompt.images.',
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (files.length !== 1) {
|
|
402
|
+
throw new InvalidArgumentError({
|
|
403
|
+
argument: 'files',
|
|
404
|
+
message:
|
|
405
|
+
'QuiverAI animate accepts exactly one source SVG in prompt.images.',
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (n !== 1) {
|
|
410
|
+
throw new InvalidArgumentError({
|
|
411
|
+
argument: 'n',
|
|
412
|
+
message:
|
|
413
|
+
'QuiverAI animate returns one SVG per request. Set maxImagesPerCall to 1 in generateImage to animate multiple times.',
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (mask != null) {
|
|
418
|
+
throw new InvalidArgumentError({
|
|
419
|
+
argument: 'mask',
|
|
420
|
+
message: 'QuiverAI animate does not support masks.',
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (prompt != null && prompt.trim().length === 0) {
|
|
425
|
+
throw new InvalidArgumentError({
|
|
426
|
+
argument: 'prompt',
|
|
427
|
+
message:
|
|
428
|
+
'QuiverAI animate requires a non-empty prompt when an animation instruction is provided.',
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const unsupportedOptions = [
|
|
433
|
+
['instructions', options.instructions],
|
|
434
|
+
['topP', options.topP],
|
|
435
|
+
['presencePenalty', options.presencePenalty],
|
|
436
|
+
['attributes', options.attributes],
|
|
437
|
+
['autoCrop', options.autoCrop],
|
|
438
|
+
['targetSize', options.targetSize],
|
|
439
|
+
].filter((option): option is [string, NonNullable<unknown>] => {
|
|
440
|
+
return option[1] !== undefined;
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
if (unsupportedOptions.length > 0) {
|
|
444
|
+
throw new InvalidArgumentError({
|
|
445
|
+
argument: `providerOptions.quiverai.${unsupportedOptions[0][0]}`,
|
|
446
|
+
message: `QuiverAI animate does not support providerOptions.quiverai.${unsupportedOptions[0][0]}.`,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return {
|
|
451
|
+
model: modelId,
|
|
452
|
+
svg_source: toQuiverAIAnimationSource(files[0]),
|
|
453
|
+
prompt,
|
|
454
|
+
temperature: options.temperature,
|
|
455
|
+
max_output_tokens: options.maxOutputTokens,
|
|
456
|
+
reasoning_effort: options.reasoningEffort,
|
|
457
|
+
stream: false as const,
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
270
461
|
function collectWarnings({
|
|
271
462
|
size,
|
|
272
463
|
aspectRatio,
|
|
@@ -331,6 +522,8 @@ const svgUsageSchema = z.object({
|
|
|
331
522
|
const svgDocumentSchema = z.object({
|
|
332
523
|
svg: z.string().min(1),
|
|
333
524
|
mime_type: z.literal('image/svg+xml'),
|
|
525
|
+
loop_period_ms: z.number().int().nonnegative().nullish(),
|
|
526
|
+
opening_animation_ms: z.number().int().nonnegative().nullish(),
|
|
334
527
|
});
|
|
335
528
|
|
|
336
529
|
const svgGenerationResponseSchema = z.object({
|
|
@@ -15,5 +15,6 @@ export type QuiverAIImageModelId =
|
|
|
15
15
|
* QuiverAI image operation:
|
|
16
16
|
* - `generate`: Text-to-SVG generation (default).
|
|
17
17
|
* - `vectorize`: Convert a raster image into an SVG.
|
|
18
|
+
* - `animate`: Animate a single source SVG.
|
|
18
19
|
*/
|
|
19
|
-
export type QuiverAIOperation = 'generate' | 'vectorize';
|
|
20
|
+
export type QuiverAIOperation = 'generate' | 'vectorize' | 'animate';
|