@ai-sdk/quiverai 2.0.44 → 2.0.45
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 +10 -0
- package/dist/index.d.ts +25 -2
- package/dist/index.js +554 -29
- package/dist/index.js.map +1 -1
- package/docs/180-quiverai.mdx +87 -13
- package/package.json +3 -2
- package/src/index.ts +5 -0
- package/src/prepare-quiverai-image-reference.ts +161 -0
- package/src/quiverai-image-model-options.ts +39 -1
- package/src/quiverai-image-model.ts +488 -0
- package/src/quiverai-image-settings.ts +2 -1
package/dist/index.js
CHANGED
|
@@ -11,12 +11,12 @@ import {
|
|
|
11
11
|
|
|
12
12
|
// src/quiverai-image-model.ts
|
|
13
13
|
import {
|
|
14
|
-
InvalidArgumentError
|
|
14
|
+
InvalidArgumentError as InvalidArgumentError2
|
|
15
15
|
} from "@ai-sdk/provider";
|
|
16
16
|
import {
|
|
17
17
|
combineHeaders,
|
|
18
|
-
convertBase64ToUint8Array,
|
|
19
|
-
convertUint8ArrayToBase64,
|
|
18
|
+
convertBase64ToUint8Array as convertBase64ToUint8Array2,
|
|
19
|
+
convertUint8ArrayToBase64 as convertUint8ArrayToBase642,
|
|
20
20
|
createJsonErrorResponseHandler,
|
|
21
21
|
createJsonResponseHandler,
|
|
22
22
|
parseProviderOptions,
|
|
@@ -44,8 +44,10 @@ var quiveraiImageModelOptionsSchema = lazySchema(
|
|
|
44
44
|
* single image in `prompt.images` / `files`.
|
|
45
45
|
* - `animate`: Animate an input SVG. Requires a single SVG in
|
|
46
46
|
* `prompt.images` / `files`; the text prompt is optional.
|
|
47
|
+
* - `edit`: Edit a single SVG from `prompt.images` using `prompt.text`
|
|
48
|
+
* as the required instruction.
|
|
47
49
|
*/
|
|
48
|
-
operation: z.enum(["generate", "vectorize", "animate"]).optional(),
|
|
50
|
+
operation: z.enum(["generate", "vectorize", "animate", "edit"]).optional(),
|
|
49
51
|
/**
|
|
50
52
|
* Extra style guidance for prompt-based generation.
|
|
51
53
|
*/
|
|
@@ -54,6 +56,20 @@ var quiveraiImageModelOptionsSchema = lazySchema(
|
|
|
54
56
|
* Reasoning effort applied to generation or vectorization.
|
|
55
57
|
*/
|
|
56
58
|
reasoningEffort: z.enum(["low", "medium", "high", "xhigh"]).optional(),
|
|
59
|
+
/**
|
|
60
|
+
* Optional reference images for SVG editing. Use
|
|
61
|
+
* `prepareQuiverAIImageReference` to convert binary inputs.
|
|
62
|
+
*/
|
|
63
|
+
referenceImages: z.array(
|
|
64
|
+
z.union([
|
|
65
|
+
z.object({ url: z.string().min(1) }).strict(),
|
|
66
|
+
z.object({ base64: z.string().min(1).max(16777216) }).strict()
|
|
67
|
+
])
|
|
68
|
+
).max(4).optional(),
|
|
69
|
+
/**
|
|
70
|
+
* Maximum number of edit review and redo steps (0-5).
|
|
71
|
+
*/
|
|
72
|
+
maxReviewSteps: z.number().int().min(0).max(5).optional(),
|
|
57
73
|
/**
|
|
58
74
|
* SVG root attributes requested for generation or vectorization.
|
|
59
75
|
*/
|
|
@@ -82,6 +98,14 @@ var quiveraiImageModelOptionsSchema = lazySchema(
|
|
|
82
98
|
* The legacy upper bound of 131072 is retained for other model IDs.
|
|
83
99
|
*/
|
|
84
100
|
maxOutputTokens: z.number().int().min(1).max(131072).optional(),
|
|
101
|
+
/**
|
|
102
|
+
* Provider orchestrator token budget for SVG editing (1-65536).
|
|
103
|
+
*/
|
|
104
|
+
orchestratorMaxOutputTokens: z.number().int().min(1).max(65536).optional(),
|
|
105
|
+
/**
|
|
106
|
+
* Provider shallow edit token budget for SVG editing (1-65536).
|
|
107
|
+
*/
|
|
108
|
+
shallowMaxOutputTokens: z.number().int().min(1).max(65536).optional(),
|
|
85
109
|
/**
|
|
86
110
|
* Whether to auto-crop the input image before vectorization.
|
|
87
111
|
* Only used when `operation` is `vectorize`.
|
|
@@ -96,6 +120,113 @@ var quiveraiImageModelOptionsSchema = lazySchema(
|
|
|
96
120
|
)
|
|
97
121
|
);
|
|
98
122
|
|
|
123
|
+
// src/prepare-quiverai-image-reference.ts
|
|
124
|
+
import { InvalidArgumentError } from "@ai-sdk/provider";
|
|
125
|
+
import {
|
|
126
|
+
convertBase64ToUint8Array,
|
|
127
|
+
convertUint8ArrayToBase64,
|
|
128
|
+
detectMediaType
|
|
129
|
+
} from "@ai-sdk/provider-utils";
|
|
130
|
+
var MAX_REFERENCE_BASE64_LENGTH = 16777216;
|
|
131
|
+
var MAX_REFERENCE_BYTES = 12582912;
|
|
132
|
+
var supportedReferenceMediaTypes = /* @__PURE__ */ new Set([
|
|
133
|
+
"image/gif",
|
|
134
|
+
"image/jpeg",
|
|
135
|
+
"image/png",
|
|
136
|
+
"image/svg+xml",
|
|
137
|
+
"image/webp"
|
|
138
|
+
]);
|
|
139
|
+
function prepareQuiverAIImageReference(input) {
|
|
140
|
+
if (input instanceof URL) {
|
|
141
|
+
return { url: validateQuiverAIImageUrl(input.toString()) };
|
|
142
|
+
}
|
|
143
|
+
if (typeof input === "string") {
|
|
144
|
+
if (/^[a-z][a-z\d+.-]*:\/\//i.test(input)) {
|
|
145
|
+
return { url: validateQuiverAIImageUrl(input) };
|
|
146
|
+
}
|
|
147
|
+
if (input.startsWith("data:")) {
|
|
148
|
+
const match = /^data:([^;,]+);base64,(.+)$/s.exec(input);
|
|
149
|
+
if (match == null || !supportedReferenceMediaTypes.has(match[1])) {
|
|
150
|
+
throw new InvalidArgumentError({
|
|
151
|
+
argument: "input",
|
|
152
|
+
message: "QuiverAI reference image data URLs must use base64 encoding and a supported image media type."
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
validateQuiverAIReferenceBase64(match[2], "input");
|
|
156
|
+
return { base64: match[2] };
|
|
157
|
+
}
|
|
158
|
+
validateQuiverAIReferenceBase64(input, "input");
|
|
159
|
+
return { base64: input };
|
|
160
|
+
}
|
|
161
|
+
const data = input instanceof ArrayBuffer ? new Uint8Array(input) : new Uint8Array(input);
|
|
162
|
+
validateQuiverAIReferenceBytes(data, "input");
|
|
163
|
+
return { base64: convertUint8ArrayToBase64(data) };
|
|
164
|
+
}
|
|
165
|
+
function validateQuiverAIImageUrl(url) {
|
|
166
|
+
let parsed;
|
|
167
|
+
try {
|
|
168
|
+
parsed = new URL(url);
|
|
169
|
+
} catch (e) {
|
|
170
|
+
throw new InvalidArgumentError({
|
|
171
|
+
argument: "url",
|
|
172
|
+
message: "QuiverAI image URLs must be valid HTTP or HTTPS URLs."
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
176
|
+
throw new InvalidArgumentError({
|
|
177
|
+
argument: "url",
|
|
178
|
+
message: "QuiverAI image URLs must use HTTP or HTTPS."
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return parsed.toString();
|
|
182
|
+
}
|
|
183
|
+
function validateQuiverAIReferenceBase64(base64, argument) {
|
|
184
|
+
if (base64.length === 0 || base64.length > MAX_REFERENCE_BASE64_LENGTH) {
|
|
185
|
+
throw new InvalidArgumentError({
|
|
186
|
+
argument,
|
|
187
|
+
message: `QuiverAI reference images must contain 1-${MAX_REFERENCE_BASE64_LENGTH} base64 characters.`
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
let data;
|
|
191
|
+
try {
|
|
192
|
+
data = convertBase64ToUint8Array(base64);
|
|
193
|
+
} catch (cause) {
|
|
194
|
+
throw new InvalidArgumentError({
|
|
195
|
+
argument,
|
|
196
|
+
message: "QuiverAI reference image data must be valid base64.",
|
|
197
|
+
cause
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
validateQuiverAIReferenceBytes(data, argument);
|
|
201
|
+
}
|
|
202
|
+
function validateQuiverAIReferenceBytes(data, argument) {
|
|
203
|
+
if (data.length === 0 || data.length > MAX_REFERENCE_BYTES) {
|
|
204
|
+
throw new InvalidArgumentError({
|
|
205
|
+
argument,
|
|
206
|
+
message: `QuiverAI reference images must decode to 1-${MAX_REFERENCE_BYTES} bytes.`
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
const mediaType = isSvg(data) ? "image/svg+xml" : detectMediaType({ data, topLevelType: "image" });
|
|
210
|
+
if (mediaType == null || !supportedReferenceMediaTypes.has(mediaType)) {
|
|
211
|
+
throw new InvalidArgumentError({
|
|
212
|
+
argument,
|
|
213
|
+
message: "QuiverAI reference images must be PNG, JPEG, WebP, GIF, or SVG data."
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function isSvg(data) {
|
|
218
|
+
let text;
|
|
219
|
+
try {
|
|
220
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(data);
|
|
221
|
+
} catch (e) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
const normalized = text.replace(/^\uFEFF/, "").trim();
|
|
225
|
+
return /^(?:<\?xml[\s\S]*?\?>\s*)?(?:<!--[\s\S]*?-->\s*)?(?:<!DOCTYPE[\s\S]*?>\s*)?<svg[\s>]/i.test(
|
|
226
|
+
normalized
|
|
227
|
+
) && (/<\/svg>\s*$/i.test(normalized) || /<svg(?:\s[^>]*)?\/>\s*$/is.test(normalized));
|
|
228
|
+
}
|
|
229
|
+
|
|
99
230
|
// src/quiverai-image-model.ts
|
|
100
231
|
var QuiverAIImageModel = class _QuiverAIImageModel {
|
|
101
232
|
constructor(modelId, config) {
|
|
@@ -199,6 +330,8 @@ function getOperationPath(operation) {
|
|
|
199
330
|
return "/svgs/generations";
|
|
200
331
|
case "vectorize":
|
|
201
332
|
return "/svgs/vectorizations";
|
|
333
|
+
case "edit":
|
|
334
|
+
return "/svgs/edits";
|
|
202
335
|
case "animate":
|
|
203
336
|
return "/svgs/animations";
|
|
204
337
|
}
|
|
@@ -211,7 +344,7 @@ function toQuiverAIImageReference(image) {
|
|
|
211
344
|
return { url: image.url };
|
|
212
345
|
}
|
|
213
346
|
return {
|
|
214
|
-
base64: typeof image.data === "string" ? image.data :
|
|
347
|
+
base64: typeof image.data === "string" ? image.data : convertUint8ArrayToBase642(image.data)
|
|
215
348
|
};
|
|
216
349
|
}
|
|
217
350
|
var maxAnimationSourceBase64Length = 1066668;
|
|
@@ -222,13 +355,13 @@ function toQuiverAIAnimationSource(image) {
|
|
|
222
355
|
try {
|
|
223
356
|
url = new URL(image.url);
|
|
224
357
|
} catch (e) {
|
|
225
|
-
throw new
|
|
358
|
+
throw new InvalidArgumentError2({
|
|
226
359
|
argument: "files",
|
|
227
360
|
message: "QuiverAI animate requires a valid HTTP or HTTPS SVG URL."
|
|
228
361
|
});
|
|
229
362
|
}
|
|
230
363
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
231
|
-
throw new
|
|
364
|
+
throw new InvalidArgumentError2({
|
|
232
365
|
argument: "files",
|
|
233
366
|
message: "QuiverAI animate requires an HTTP or HTTPS SVG URL."
|
|
234
367
|
});
|
|
@@ -241,33 +374,33 @@ function toQuiverAIAnimationSource(image) {
|
|
|
241
374
|
const dataUrlMatch = /^data:image\/svg\+xml(?:;[^,]*)?;base64,([\s\S]+)$/i.exec(image.data);
|
|
242
375
|
const encodedData = (_a = dataUrlMatch == null ? void 0 : dataUrlMatch[1]) != null ? _a : image.data;
|
|
243
376
|
try {
|
|
244
|
-
bytes =
|
|
377
|
+
bytes = convertBase64ToUint8Array2(encodedData);
|
|
245
378
|
} catch (e) {
|
|
246
|
-
throw new
|
|
379
|
+
throw new InvalidArgumentError2({
|
|
247
380
|
argument: "files",
|
|
248
381
|
message: "QuiverAI animate requires the source SVG string to be valid base64 or an SVG data URL."
|
|
249
382
|
});
|
|
250
383
|
}
|
|
251
|
-
base64 =
|
|
384
|
+
base64 = convertUint8ArrayToBase642(bytes);
|
|
252
385
|
} else {
|
|
253
386
|
bytes = image.data;
|
|
254
|
-
base64 =
|
|
387
|
+
base64 = convertUint8ArrayToBase642(bytes);
|
|
255
388
|
}
|
|
256
|
-
if (!
|
|
257
|
-
throw new
|
|
389
|
+
if (!isSvg2(bytes)) {
|
|
390
|
+
throw new InvalidArgumentError2({
|
|
258
391
|
argument: "files",
|
|
259
392
|
message: "QuiverAI animate requires the input file to contain SVG data."
|
|
260
393
|
});
|
|
261
394
|
}
|
|
262
395
|
if (base64.length > maxAnimationSourceBase64Length) {
|
|
263
|
-
throw new
|
|
396
|
+
throw new InvalidArgumentError2({
|
|
264
397
|
argument: "files",
|
|
265
398
|
message: `QuiverAI animate accepts at most ${maxAnimationSourceBase64Length} base64 characters for the source SVG.`
|
|
266
399
|
});
|
|
267
400
|
}
|
|
268
401
|
return { base64 };
|
|
269
402
|
}
|
|
270
|
-
function
|
|
403
|
+
function isSvg2(data) {
|
|
271
404
|
const head = new TextDecoder("utf-8", { fatal: false }).decode(data.subarray(0, 4096)).trimStart();
|
|
272
405
|
return /^(?:(?:<\?xml[\s\S]*?\?>|<!--[\s\S]*?-->|<!DOCTYPE[\s\S]*?>)\s*)*<svg(?:\s|>)/i.test(
|
|
273
406
|
head
|
|
@@ -283,7 +416,7 @@ function buildRequestBody({
|
|
|
283
416
|
options
|
|
284
417
|
}) {
|
|
285
418
|
if ((modelId === "arrow-2" || modelId === "arrow-2-telos") && options.maxOutputTokens != null && options.maxOutputTokens > 65536) {
|
|
286
|
-
throw new
|
|
419
|
+
throw new InvalidArgumentError2({
|
|
287
420
|
argument: "maxOutputTokens",
|
|
288
421
|
message: `QuiverAI model "${modelId}" supports at most 65536 output tokens.`
|
|
289
422
|
});
|
|
@@ -297,9 +430,12 @@ function buildRequestBody({
|
|
|
297
430
|
attributes: options.attributes,
|
|
298
431
|
stream: false
|
|
299
432
|
};
|
|
433
|
+
if (operation !== "edit") {
|
|
434
|
+
rejectEditOnlyOptions(operation, options);
|
|
435
|
+
}
|
|
300
436
|
if (operation === "generate") {
|
|
301
437
|
if (prompt == null || prompt.trim().length === 0) {
|
|
302
|
-
throw new
|
|
438
|
+
throw new InvalidArgumentError2({
|
|
303
439
|
argument: "prompt",
|
|
304
440
|
message: "QuiverAI image generation requires a non-empty prompt for generateImage."
|
|
305
441
|
});
|
|
@@ -307,7 +443,7 @@ function buildRequestBody({
|
|
|
307
443
|
const references = files == null ? void 0 : files.map(toQuiverAIImageReference);
|
|
308
444
|
const maxReferences = getGenerateReferenceLimit(modelId);
|
|
309
445
|
if (references != null && references.length > maxReferences) {
|
|
310
|
-
throw new
|
|
446
|
+
throw new InvalidArgumentError2({
|
|
311
447
|
argument: "files",
|
|
312
448
|
message: `QuiverAI generate supports up to ${maxReferences} reference images for model "${modelId}".`
|
|
313
449
|
});
|
|
@@ -321,6 +457,16 @@ function buildRequestBody({
|
|
|
321
457
|
references
|
|
322
458
|
};
|
|
323
459
|
}
|
|
460
|
+
if (operation === "edit") {
|
|
461
|
+
return buildEditRequestBody({
|
|
462
|
+
modelId,
|
|
463
|
+
n,
|
|
464
|
+
prompt,
|
|
465
|
+
files,
|
|
466
|
+
mask,
|
|
467
|
+
options
|
|
468
|
+
});
|
|
469
|
+
}
|
|
324
470
|
if (operation === "animate") {
|
|
325
471
|
return buildAnimationRequestBody({
|
|
326
472
|
modelId,
|
|
@@ -332,19 +478,19 @@ function buildRequestBody({
|
|
|
332
478
|
});
|
|
333
479
|
}
|
|
334
480
|
if (files == null || files.length === 0) {
|
|
335
|
-
throw new
|
|
481
|
+
throw new InvalidArgumentError2({
|
|
336
482
|
argument: "files",
|
|
337
483
|
message: 'QuiverAI vectorize requires an input image. Pass an image in the generateImage prompt and set providerOptions.quiverai.operation to "vectorize".'
|
|
338
484
|
});
|
|
339
485
|
}
|
|
340
486
|
if (files.length > 1) {
|
|
341
|
-
throw new
|
|
487
|
+
throw new InvalidArgumentError2({
|
|
342
488
|
argument: "files",
|
|
343
489
|
message: "QuiverAI vectorize accepts a single input image."
|
|
344
490
|
});
|
|
345
491
|
}
|
|
346
492
|
if (n !== 1) {
|
|
347
|
-
throw new
|
|
493
|
+
throw new InvalidArgumentError2({
|
|
348
494
|
argument: "n",
|
|
349
495
|
message: "QuiverAI vectorize returns one SVG per request. Set maxImagesPerCall to 1 in generateImage to vectorize multiple times."
|
|
350
496
|
});
|
|
@@ -366,37 +512,37 @@ function buildAnimationRequestBody({
|
|
|
366
512
|
options
|
|
367
513
|
}) {
|
|
368
514
|
if (modelId !== "arrow-2" && modelId !== "arrow-2-telos") {
|
|
369
|
-
throw new
|
|
515
|
+
throw new InvalidArgumentError2({
|
|
370
516
|
argument: "modelId",
|
|
371
517
|
message: 'QuiverAI animate is supported by the "arrow-2" and "arrow-2-telos" models.'
|
|
372
518
|
});
|
|
373
519
|
}
|
|
374
520
|
if (files == null || files.length === 0) {
|
|
375
|
-
throw new
|
|
521
|
+
throw new InvalidArgumentError2({
|
|
376
522
|
argument: "files",
|
|
377
523
|
message: "QuiverAI animate requires exactly one source SVG in prompt.images."
|
|
378
524
|
});
|
|
379
525
|
}
|
|
380
526
|
if (files.length !== 1) {
|
|
381
|
-
throw new
|
|
527
|
+
throw new InvalidArgumentError2({
|
|
382
528
|
argument: "files",
|
|
383
529
|
message: "QuiverAI animate accepts exactly one source SVG in prompt.images."
|
|
384
530
|
});
|
|
385
531
|
}
|
|
386
532
|
if (n !== 1) {
|
|
387
|
-
throw new
|
|
533
|
+
throw new InvalidArgumentError2({
|
|
388
534
|
argument: "n",
|
|
389
535
|
message: "QuiverAI animate returns one SVG per request. Set maxImagesPerCall to 1 in generateImage to animate multiple times."
|
|
390
536
|
});
|
|
391
537
|
}
|
|
392
538
|
if (mask != null) {
|
|
393
|
-
throw new
|
|
539
|
+
throw new InvalidArgumentError2({
|
|
394
540
|
argument: "mask",
|
|
395
541
|
message: "QuiverAI animate does not support masks."
|
|
396
542
|
});
|
|
397
543
|
}
|
|
398
544
|
if (prompt != null && prompt.trim().length === 0) {
|
|
399
|
-
throw new
|
|
545
|
+
throw new InvalidArgumentError2({
|
|
400
546
|
argument: "prompt",
|
|
401
547
|
message: "QuiverAI animate requires a non-empty prompt when an animation instruction is provided."
|
|
402
548
|
});
|
|
@@ -412,7 +558,7 @@ function buildAnimationRequestBody({
|
|
|
412
558
|
return option[1] !== void 0;
|
|
413
559
|
});
|
|
414
560
|
if (unsupportedOptions.length > 0) {
|
|
415
|
-
throw new
|
|
561
|
+
throw new InvalidArgumentError2({
|
|
416
562
|
argument: `providerOptions.quiverai.${unsupportedOptions[0][0]}`,
|
|
417
563
|
message: `QuiverAI animate does not support providerOptions.quiverai.${unsupportedOptions[0][0]}.`
|
|
418
564
|
});
|
|
@@ -427,6 +573,384 @@ function buildAnimationRequestBody({
|
|
|
427
573
|
stream: false
|
|
428
574
|
};
|
|
429
575
|
}
|
|
576
|
+
var editModelIds = /* @__PURE__ */ new Set(["arrow-2", "arrow-2-telos"]);
|
|
577
|
+
var MAX_EDIT_SVG_BYTES = 2e5;
|
|
578
|
+
function buildEditRequestBody({
|
|
579
|
+
modelId,
|
|
580
|
+
n,
|
|
581
|
+
prompt,
|
|
582
|
+
files,
|
|
583
|
+
mask,
|
|
584
|
+
options
|
|
585
|
+
}) {
|
|
586
|
+
var _a;
|
|
587
|
+
if (!editModelIds.has(modelId)) {
|
|
588
|
+
throw new InvalidArgumentError2({
|
|
589
|
+
argument: "modelId",
|
|
590
|
+
message: 'QuiverAI SVG editing is supported by the "arrow-2" and "arrow-2-telos" models.'
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
if (prompt == null || prompt.trim().length === 0) {
|
|
594
|
+
throw new InvalidArgumentError2({
|
|
595
|
+
argument: "prompt",
|
|
596
|
+
message: "QuiverAI SVG editing requires a non-empty instruction in generateImage prompt.text."
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
if (prompt.length > 4e3) {
|
|
600
|
+
throw new InvalidArgumentError2({
|
|
601
|
+
argument: "prompt",
|
|
602
|
+
message: "QuiverAI SVG editing instructions must contain at most 4000 characters."
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
if (files == null || files.length === 0) {
|
|
606
|
+
throw new InvalidArgumentError2({
|
|
607
|
+
argument: "files",
|
|
608
|
+
message: "QuiverAI SVG editing requires one source SVG in generateImage prompt.images."
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
if (files.length !== 1) {
|
|
612
|
+
throw new InvalidArgumentError2({
|
|
613
|
+
argument: "files",
|
|
614
|
+
message: "QuiverAI SVG editing accepts exactly one source SVG."
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
if (n !== 1) {
|
|
618
|
+
throw new InvalidArgumentError2({
|
|
619
|
+
argument: "n",
|
|
620
|
+
message: "QuiverAI SVG editing returns exactly one SVG per request. Set maxImagesPerCall to 1 in generateImage to edit multiple times."
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
if (mask != null) {
|
|
624
|
+
throw new InvalidArgumentError2({
|
|
625
|
+
argument: "mask",
|
|
626
|
+
message: "QuiverAI SVG editing does not support masks."
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
const unsupportedOptions = [
|
|
630
|
+
["instructions", options.instructions],
|
|
631
|
+
["attributes", options.attributes],
|
|
632
|
+
["topP", options.topP],
|
|
633
|
+
["presencePenalty", options.presencePenalty],
|
|
634
|
+
["autoCrop", options.autoCrop],
|
|
635
|
+
["targetSize", options.targetSize]
|
|
636
|
+
].flatMap(([name, value]) => value == null ? [] : [name]);
|
|
637
|
+
if (unsupportedOptions.length > 0) {
|
|
638
|
+
throw new InvalidArgumentError2({
|
|
639
|
+
argument: "providerOptions",
|
|
640
|
+
message: `QuiverAI SVG editing does not support these provider options: ${unsupportedOptions.join(
|
|
641
|
+
", "
|
|
642
|
+
)}.`
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
const referenceImages = (_a = options.referenceImages) == null ? void 0 : _a.map((reference, index) => {
|
|
646
|
+
if ("url" in reference) {
|
|
647
|
+
return {
|
|
648
|
+
url: validateQuiverAIImageUrl(reference.url)
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
validateQuiverAIReferenceBase64(
|
|
652
|
+
reference.base64,
|
|
653
|
+
`providerOptions.quiverai.referenceImages[${index}]`
|
|
654
|
+
);
|
|
655
|
+
return { base64: reference.base64 };
|
|
656
|
+
});
|
|
657
|
+
const settings = {
|
|
658
|
+
max_output_tokens: options.maxOutputTokens,
|
|
659
|
+
orchestrator_max_output_tokens: options.orchestratorMaxOutputTokens,
|
|
660
|
+
shallow_max_output_tokens: options.shallowMaxOutputTokens,
|
|
661
|
+
temperature: options.temperature
|
|
662
|
+
};
|
|
663
|
+
const hasSettings = Object.values(settings).some((value) => value != null);
|
|
664
|
+
return {
|
|
665
|
+
model: modelId,
|
|
666
|
+
prompt,
|
|
667
|
+
...toQuiverAIEditSource(files[0]),
|
|
668
|
+
reference_images: referenceImages,
|
|
669
|
+
max_review_steps: options.maxReviewSteps,
|
|
670
|
+
reasoning_effort: options.reasoningEffort,
|
|
671
|
+
...hasSettings && { settings },
|
|
672
|
+
stream: false
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
function rejectEditOnlyOptions(operation, options) {
|
|
676
|
+
const editOnlyOptions = [
|
|
677
|
+
["referenceImages", options.referenceImages],
|
|
678
|
+
["maxReviewSteps", options.maxReviewSteps],
|
|
679
|
+
["orchestratorMaxOutputTokens", options.orchestratorMaxOutputTokens],
|
|
680
|
+
["shallowMaxOutputTokens", options.shallowMaxOutputTokens]
|
|
681
|
+
].flatMap(([name, value]) => value == null ? [] : [name]);
|
|
682
|
+
if (editOnlyOptions.length > 0) {
|
|
683
|
+
throw new InvalidArgumentError2({
|
|
684
|
+
argument: "providerOptions",
|
|
685
|
+
message: `QuiverAI ${operation} does not support these edit-only provider options: ${editOnlyOptions.join(
|
|
686
|
+
", "
|
|
687
|
+
)}.`
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
function toQuiverAIEditSource(file) {
|
|
692
|
+
if (file.type === "url") {
|
|
693
|
+
return {
|
|
694
|
+
svg_source: {
|
|
695
|
+
url: validateQuiverAIImageUrl(file.url)
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
let data;
|
|
700
|
+
try {
|
|
701
|
+
data = typeof file.data === "string" ? convertBase64ToUint8Array2(file.data) : file.data;
|
|
702
|
+
} catch (cause) {
|
|
703
|
+
throw new InvalidArgumentError2({
|
|
704
|
+
argument: "files",
|
|
705
|
+
message: "QuiverAI SVG source data must be valid base64 or binary data.",
|
|
706
|
+
cause
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
if (data.length === 0 || data.length > MAX_EDIT_SVG_BYTES) {
|
|
710
|
+
throw new InvalidArgumentError2({
|
|
711
|
+
argument: "files",
|
|
712
|
+
message: `QuiverAI SVG source data must contain 1-${MAX_EDIT_SVG_BYTES} bytes.`
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
let svg;
|
|
716
|
+
try {
|
|
717
|
+
svg = new TextDecoder("utf-8", { fatal: true }).decode(data);
|
|
718
|
+
} catch (cause) {
|
|
719
|
+
throw new InvalidArgumentError2({
|
|
720
|
+
argument: "files",
|
|
721
|
+
message: "QuiverAI SVG source data must be valid UTF-8.",
|
|
722
|
+
cause
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
if (svg.length > MAX_EDIT_SVG_BYTES || !isSvgMarkup(svg)) {
|
|
726
|
+
throw new InvalidArgumentError2({
|
|
727
|
+
argument: "files",
|
|
728
|
+
message: "QuiverAI SVG source data must contain a complete SVG document."
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
return {
|
|
732
|
+
svg_source: {
|
|
733
|
+
base64: convertUint8ArrayToBase642(data)
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
function isSvgMarkup(svg) {
|
|
738
|
+
var _a;
|
|
739
|
+
const document = svg.replace(/^\uFEFF/, "");
|
|
740
|
+
const elements = [];
|
|
741
|
+
let position = 0;
|
|
742
|
+
let rootSeen = false;
|
|
743
|
+
let rootClosed = false;
|
|
744
|
+
let doctypeSeen = false;
|
|
745
|
+
while (position < document.length) {
|
|
746
|
+
if (document[position] !== "<") {
|
|
747
|
+
const nextTag = document.indexOf("<", position);
|
|
748
|
+
const end = nextTag === -1 ? document.length : nextTag;
|
|
749
|
+
const text = document.slice(position, end);
|
|
750
|
+
if (elements.length === 0 && text.trim().length > 0 || text.includes("]]>") || !hasValidXmlReferences(text)) {
|
|
751
|
+
return false;
|
|
752
|
+
}
|
|
753
|
+
position = end;
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
if (document.startsWith("<!--", position)) {
|
|
757
|
+
const commentEnd = document.indexOf("-->", position + 4);
|
|
758
|
+
if (commentEnd === -1 || document.slice(position + 4, commentEnd).includes("--")) {
|
|
759
|
+
return false;
|
|
760
|
+
}
|
|
761
|
+
position = commentEnd + 3;
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
if (document.startsWith("<?", position)) {
|
|
765
|
+
const instructionEnd = document.indexOf("?>", position + 2);
|
|
766
|
+
if (instructionEnd === -1) {
|
|
767
|
+
return false;
|
|
768
|
+
}
|
|
769
|
+
position = instructionEnd + 2;
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
if (document.startsWith("<![CDATA[", position)) {
|
|
773
|
+
if (elements.length === 0) {
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
const cdataEnd = document.indexOf("]]>", position + 9);
|
|
777
|
+
if (cdataEnd === -1) {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
position = cdataEnd + 3;
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
if (document.slice(position, position + 9).toUpperCase() === "<!DOCTYPE") {
|
|
784
|
+
if (rootSeen || doctypeSeen || elements.length > 0 || !/[\t\n\r ]/.test((_a = document[position + 9]) != null ? _a : "")) {
|
|
785
|
+
return false;
|
|
786
|
+
}
|
|
787
|
+
const doctypeName = readXmlName(
|
|
788
|
+
document,
|
|
789
|
+
skipXmlWhitespace(document, position + 9)
|
|
790
|
+
);
|
|
791
|
+
if ((doctypeName == null ? void 0 : doctypeName.name.toLowerCase()) !== "svg") {
|
|
792
|
+
return false;
|
|
793
|
+
}
|
|
794
|
+
const doctypeEnd = findDoctypeEnd(document, doctypeName.end);
|
|
795
|
+
if (doctypeEnd === -1) {
|
|
796
|
+
return false;
|
|
797
|
+
}
|
|
798
|
+
doctypeSeen = true;
|
|
799
|
+
position = doctypeEnd;
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
802
|
+
if (document.startsWith("<!", position)) {
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
if (document.startsWith("</", position)) {
|
|
806
|
+
const closingTag = readXmlName(document, position + 2);
|
|
807
|
+
if (closingTag == null) {
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
let tagEnd = skipXmlWhitespace(document, closingTag.end);
|
|
811
|
+
if (document[tagEnd] !== ">") {
|
|
812
|
+
return false;
|
|
813
|
+
}
|
|
814
|
+
const expectedTag = elements.pop();
|
|
815
|
+
if (expectedTag !== closingTag.name) {
|
|
816
|
+
return false;
|
|
817
|
+
}
|
|
818
|
+
tagEnd += 1;
|
|
819
|
+
if (elements.length === 0) {
|
|
820
|
+
rootClosed = true;
|
|
821
|
+
}
|
|
822
|
+
position = tagEnd;
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
825
|
+
if (rootClosed) {
|
|
826
|
+
return false;
|
|
827
|
+
}
|
|
828
|
+
const openingTag = readXmlName(document, position + 1);
|
|
829
|
+
if (openingTag == null) {
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
832
|
+
if (!rootSeen) {
|
|
833
|
+
if (openingTag.name.toLowerCase() !== "svg") {
|
|
834
|
+
return false;
|
|
835
|
+
}
|
|
836
|
+
rootSeen = true;
|
|
837
|
+
}
|
|
838
|
+
const attributes = /* @__PURE__ */ new Set();
|
|
839
|
+
let tagPosition = openingTag.end;
|
|
840
|
+
while (tagPosition < document.length) {
|
|
841
|
+
const beforeWhitespace = tagPosition;
|
|
842
|
+
tagPosition = skipXmlWhitespace(document, tagPosition);
|
|
843
|
+
if (document.startsWith("/>", tagPosition)) {
|
|
844
|
+
tagPosition += 2;
|
|
845
|
+
if (elements.length === 0) {
|
|
846
|
+
rootClosed = true;
|
|
847
|
+
}
|
|
848
|
+
position = tagPosition;
|
|
849
|
+
break;
|
|
850
|
+
}
|
|
851
|
+
if (document[tagPosition] === ">") {
|
|
852
|
+
elements.push(openingTag.name);
|
|
853
|
+
position = tagPosition + 1;
|
|
854
|
+
break;
|
|
855
|
+
}
|
|
856
|
+
if (tagPosition === beforeWhitespace) {
|
|
857
|
+
return false;
|
|
858
|
+
}
|
|
859
|
+
const attribute = readXmlName(document, tagPosition);
|
|
860
|
+
if (attribute == null || attributes.has(attribute.name)) {
|
|
861
|
+
return false;
|
|
862
|
+
}
|
|
863
|
+
attributes.add(attribute.name);
|
|
864
|
+
tagPosition = skipXmlWhitespace(document, attribute.end);
|
|
865
|
+
if (document[tagPosition] !== "=") {
|
|
866
|
+
return false;
|
|
867
|
+
}
|
|
868
|
+
tagPosition = skipXmlWhitespace(document, tagPosition + 1);
|
|
869
|
+
const quote = document[tagPosition];
|
|
870
|
+
if (quote !== '"' && quote !== "'") {
|
|
871
|
+
return false;
|
|
872
|
+
}
|
|
873
|
+
const valueEnd = document.indexOf(quote, tagPosition + 1);
|
|
874
|
+
if (valueEnd === -1 || document.slice(tagPosition + 1, valueEnd).includes("<") || !hasValidXmlReferences(document.slice(tagPosition + 1, valueEnd))) {
|
|
875
|
+
return false;
|
|
876
|
+
}
|
|
877
|
+
tagPosition = valueEnd + 1;
|
|
878
|
+
}
|
|
879
|
+
if (tagPosition >= document.length && position !== document.length) {
|
|
880
|
+
return false;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
return rootSeen && rootClosed && elements.length === 0;
|
|
884
|
+
}
|
|
885
|
+
function isXmlNameStart(character) {
|
|
886
|
+
return character != null && /[A-Z_a-z:\u0080-\uFFFF]/.test(character);
|
|
887
|
+
}
|
|
888
|
+
function isXmlNameCharacter(character) {
|
|
889
|
+
return character != null && /[-.0-9A-Z_a-z:\u00B7\u0080-\uFFFF]/.test(character);
|
|
890
|
+
}
|
|
891
|
+
function readXmlName(value, position) {
|
|
892
|
+
if (!isXmlNameStart(value[position])) {
|
|
893
|
+
return void 0;
|
|
894
|
+
}
|
|
895
|
+
const start = position;
|
|
896
|
+
position += 1;
|
|
897
|
+
while (isXmlNameCharacter(value[position])) {
|
|
898
|
+
position += 1;
|
|
899
|
+
}
|
|
900
|
+
return {
|
|
901
|
+
name: value.slice(start, position),
|
|
902
|
+
end: position
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
function skipXmlWhitespace(value, position) {
|
|
906
|
+
var _a;
|
|
907
|
+
while (/[\t\n\r ]/.test((_a = value[position]) != null ? _a : "")) {
|
|
908
|
+
position += 1;
|
|
909
|
+
}
|
|
910
|
+
return position;
|
|
911
|
+
}
|
|
912
|
+
function hasValidXmlReferences(value) {
|
|
913
|
+
let position = value.indexOf("&");
|
|
914
|
+
while (position !== -1) {
|
|
915
|
+
const end = value.indexOf(";", position + 1);
|
|
916
|
+
if (end === -1) {
|
|
917
|
+
return false;
|
|
918
|
+
}
|
|
919
|
+
const reference = value.slice(position + 1, end);
|
|
920
|
+
if (!/^#\d+$/.test(reference) && !/^#x[\dA-Fa-f]+$/.test(reference) && !/^[A-Z_a-z:\u0080-\uFFFF][-.0-9A-Z_a-z:\u00B7\u0080-\uFFFF]*$/.test(
|
|
921
|
+
reference
|
|
922
|
+
)) {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
position = value.indexOf("&", end + 1);
|
|
926
|
+
}
|
|
927
|
+
return true;
|
|
928
|
+
}
|
|
929
|
+
function findDoctypeEnd(value, position) {
|
|
930
|
+
let subsetDepth = 0;
|
|
931
|
+
let quote;
|
|
932
|
+
while (position < value.length) {
|
|
933
|
+
const character = value[position];
|
|
934
|
+
if (quote != null) {
|
|
935
|
+
if (character === quote) {
|
|
936
|
+
quote = void 0;
|
|
937
|
+
}
|
|
938
|
+
} else if (character === '"' || character === "'") {
|
|
939
|
+
quote = character;
|
|
940
|
+
} else if (character === "[") {
|
|
941
|
+
subsetDepth += 1;
|
|
942
|
+
} else if (character === "]") {
|
|
943
|
+
if (subsetDepth === 0) {
|
|
944
|
+
return -1;
|
|
945
|
+
}
|
|
946
|
+
subsetDepth -= 1;
|
|
947
|
+
} else if (character === ">" && subsetDepth === 0) {
|
|
948
|
+
return position + 1;
|
|
949
|
+
}
|
|
950
|
+
position += 1;
|
|
951
|
+
}
|
|
952
|
+
return -1;
|
|
953
|
+
}
|
|
430
954
|
function collectWarnings({
|
|
431
955
|
size,
|
|
432
956
|
aspectRatio,
|
|
@@ -495,7 +1019,7 @@ var quiveraiFailedResponseHandler = createJsonErrorResponseHandler({
|
|
|
495
1019
|
});
|
|
496
1020
|
|
|
497
1021
|
// src/version.ts
|
|
498
|
-
var VERSION = true ? "2.0.
|
|
1022
|
+
var VERSION = true ? "2.0.45" : "0.0.0-test";
|
|
499
1023
|
|
|
500
1024
|
// src/quiverai-provider.ts
|
|
501
1025
|
var defaultBaseURL = "https://api.quiver.ai/v1";
|
|
@@ -548,6 +1072,7 @@ var quiverai = createQuiverAI();
|
|
|
548
1072
|
export {
|
|
549
1073
|
VERSION,
|
|
550
1074
|
createQuiverAI,
|
|
1075
|
+
prepareQuiverAIImageReference,
|
|
551
1076
|
quiverai
|
|
552
1077
|
};
|
|
553
1078
|
//# sourceMappingURL=index.js.map
|