pixelkiln 0.57.0 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +268 -12
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +268 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +417 -63
- package/dist/index.d.ts +417 -63
- package/dist/index.js +268 -12
- package/dist/index.js.map +1 -1
- package/docs/ENDPOINTS.md +15 -4
- package/docs/MANIFEST.md +7 -2
- package/docs/REVISIONS.md +84 -8
- package/package.json +1 -1
- package/schema/manifest.schema.json +33 -1
- package/skills/pixelkiln/references/pixellab-roadmap.md +21 -14
- package/skills/pixelkiln/references/pixellab.md +17 -10
- package/skills/pixelkiln/references/revisions.md +17 -3
package/dist/cli.js
CHANGED
|
@@ -712,7 +712,12 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
|
|
|
712
712
|
numColors: spec.revision.numColors,
|
|
713
713
|
paletteImageSha256: spec.revision.paletteImageSha256,
|
|
714
714
|
dithering: spec.revision.dithering,
|
|
715
|
-
ditheringStrength: spec.revision.ditheringStrength
|
|
715
|
+
ditheringStrength: spec.revision.ditheringStrength,
|
|
716
|
+
frames: spec.revision.frames,
|
|
717
|
+
fps: spec.revision.fps,
|
|
718
|
+
lastFrameSha256: spec.revision.lastFrameSha256,
|
|
719
|
+
direction: spec.revision.direction,
|
|
720
|
+
enhancePrompt: spec.revision.enhancePrompt
|
|
716
721
|
} : void 0
|
|
717
722
|
})
|
|
718
723
|
);
|
|
@@ -732,7 +737,15 @@ import { z } from "zod";
|
|
|
732
737
|
var MediaTypeSchema = z.enum(["image/png", "image/gif"]);
|
|
733
738
|
var GeneratorSchema = z.enum(["1dir", "map", "pixflux", "tiles", "animation", "frames", "character", "terrain", "imagePro", "isometricTile", "objectPro"]);
|
|
734
739
|
var GridConfidenceSchema = z.enum(["low", "medium", "high"]);
|
|
735
|
-
var RevisionModeSchema = z.enum([
|
|
740
|
+
var RevisionModeSchema = z.enum([
|
|
741
|
+
"image-to-image",
|
|
742
|
+
"inpaint",
|
|
743
|
+
"outpaint",
|
|
744
|
+
"reduce-colors",
|
|
745
|
+
"correct-pixelart",
|
|
746
|
+
"animate",
|
|
747
|
+
"animate-pixminimax"
|
|
748
|
+
]);
|
|
736
749
|
function tileVariationCount(descriptions) {
|
|
737
750
|
return Math.max(1, descriptions) * 4;
|
|
738
751
|
}
|
|
@@ -943,7 +956,21 @@ var RevisionSchema = z.object({
|
|
|
943
956
|
/** `reduce-colors` only: ordered dithering matrix size. */
|
|
944
957
|
dithering: RevisionDitheringSchema.optional(),
|
|
945
958
|
/** `reduce-colors` only: dithering intensity; ignored when `dithering` is "none" or unset. */
|
|
946
|
-
ditheringStrength: z.number().min(0).max(10).optional()
|
|
959
|
+
ditheringStrength: z.number().min(0).max(10).optional(),
|
|
960
|
+
/**
|
|
961
|
+
* `animate`/`animate-pixminimax` only: frames to generate, even, 4 to 40
|
|
962
|
+
* (the provider-specific ceiling — 16 for `animate` — is enforced at
|
|
963
|
+
* the provider layer, since it differs by mode).
|
|
964
|
+
*/
|
|
965
|
+
frames: z.number().int().min(4).max(40).optional(),
|
|
966
|
+
/** `animate`/`animate-pixminimax` only: playback rate recorded with the frames; PixelLab does not store one. */
|
|
967
|
+
fps: z.number().int().min(1).max(60).optional(),
|
|
968
|
+
/** `animate`/`animate-pixminimax` only: manifest-relative image pinning where the motion ends (interpolation instead of open-ended animation). */
|
|
969
|
+
lastFrame: z.string().min(1).optional(),
|
|
970
|
+
/** `animate-pixminimax` only: facing direction, used only alongside `enhancePrompt` to hold the sprite's facing. */
|
|
971
|
+
direction: CharacterDirectionSchema.optional(),
|
|
972
|
+
/** `animate`/`animate-pixminimax` only: let PixelLab expand the action into a fuller motion description first. */
|
|
973
|
+
enhancePrompt: z.boolean().optional()
|
|
947
974
|
}).strict().superRefine((revision, context) => {
|
|
948
975
|
if (revision.mode === "inpaint" && !revision.mask) {
|
|
949
976
|
context.addIssue({
|
|
@@ -982,6 +1009,32 @@ var RevisionSchema = z.object({
|
|
|
982
1009
|
path: ["strength"]
|
|
983
1010
|
});
|
|
984
1011
|
}
|
|
1012
|
+
if (revision.strength !== void 0 && (revision.mode === "animate" || revision.mode === "animate-pixminimax")) {
|
|
1013
|
+
context.addIssue({
|
|
1014
|
+
code: z.ZodIssueCode.custom,
|
|
1015
|
+
message: `${revision.mode} revisions do not take a strength; use enhancePrompt`,
|
|
1016
|
+
path: ["strength"]
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
for (const field of ["frames", "fps", "lastFrame", "enhancePrompt"]) {
|
|
1020
|
+
if (revision[field] !== void 0 && revision.mode !== "animate" && revision.mode !== "animate-pixminimax") {
|
|
1021
|
+
context.addIssue({
|
|
1022
|
+
code: z.ZodIssueCode.custom,
|
|
1023
|
+
message: `${field} applies to animate/animate-pixminimax revisions only`,
|
|
1024
|
+
path: [field]
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
if (revision.direction !== void 0 && revision.mode !== "animate-pixminimax") {
|
|
1029
|
+
context.addIssue({
|
|
1030
|
+
code: z.ZodIssueCode.custom,
|
|
1031
|
+
message: "direction applies to animate-pixminimax revisions only",
|
|
1032
|
+
path: ["direction"]
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
if (revision.frames !== void 0 && revision.frames % 2 !== 0) {
|
|
1036
|
+
context.addIssue({ code: z.ZodIssueCode.custom, message: "frames must be even", path: ["frames"] });
|
|
1037
|
+
}
|
|
985
1038
|
});
|
|
986
1039
|
var StyleObjectSchema = z.object({
|
|
987
1040
|
/** Generation backend for this style. Omit to inherit the manifest default. */
|
|
@@ -1592,7 +1645,12 @@ var LockEntrySchema = z.object({
|
|
|
1592
1645
|
numColors: z.number().int().min(2).max(256).optional(),
|
|
1593
1646
|
paletteImageSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
|
|
1594
1647
|
dithering: RevisionDitheringSchema.optional(),
|
|
1595
|
-
ditheringStrength: z.number().min(0).max(10).optional()
|
|
1648
|
+
ditheringStrength: z.number().min(0).max(10).optional(),
|
|
1649
|
+
frames: z.number().int().min(4).max(40).optional(),
|
|
1650
|
+
fps: z.number().int().min(1).max(60).optional(),
|
|
1651
|
+
lastFrameSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
|
|
1652
|
+
direction: CharacterDirectionSchema.optional(),
|
|
1653
|
+
enhancePrompt: z.boolean().optional()
|
|
1596
1654
|
}).strict().nullable().default(null),
|
|
1597
1655
|
/** For a mirror: the asset it flips and a hash over that asset's output hashes when this was made. */
|
|
1598
1656
|
mirror: z.object({
|
|
@@ -4667,8 +4725,16 @@ var ComfyUIProvider = class _ComfyUIProvider {
|
|
|
4667
4725
|
supports(generator) {
|
|
4668
4726
|
return generator === "map" || generator === "frames";
|
|
4669
4727
|
}
|
|
4670
|
-
|
|
4671
|
-
|
|
4728
|
+
/**
|
|
4729
|
+
* Everything else resolves generically to whatever the user's own
|
|
4730
|
+
* workflow does with `bindings.sourceImage`. `animate`/`animate-pixminimax`
|
|
4731
|
+
* are the one exception: they produce an ordered frame set, and this
|
|
4732
|
+
* adapter's revision path always writes a single output image (see
|
|
4733
|
+
* `submit`/`fetch` below) — a real structural gap, not a missing binding,
|
|
4734
|
+
* so it is rejected here rather than only failing once `validate` runs.
|
|
4735
|
+
*/
|
|
4736
|
+
supportsRevision(mode2) {
|
|
4737
|
+
return mode2 !== "animate" && mode2 !== "animate-pixminimax";
|
|
4672
4738
|
}
|
|
4673
4739
|
estimate(spec) {
|
|
4674
4740
|
return {
|
|
@@ -6196,6 +6262,50 @@ var PixelLabClient = class {
|
|
|
6196
6262
|
);
|
|
6197
6263
|
return { png: Buffer.from(res.images[0].base64, "base64"), usage: res.usage };
|
|
6198
6264
|
}
|
|
6265
|
+
/**
|
|
6266
|
+
* `/animate-with-text-v3`: animate a loose image from a text description,
|
|
6267
|
+
* no PixelLab character/object resource required — unlike `animateCharacter`
|
|
6268
|
+
* / `animateObject`, `firstFrame` is whatever bytes the caller has on hand.
|
|
6269
|
+
* A plain background job, like every other PixelLab async submission;
|
|
6270
|
+
* unlike `inpaintV3`/`editImagesV2`, its completed shape has not been
|
|
6271
|
+
* exercised against a live account (request/response fields here come from
|
|
6272
|
+
* the live OpenAPI document, not an observed call — `pollAnimateRevision`
|
|
6273
|
+
* in pixellab.ts checks several plausible field names for the frame list
|
|
6274
|
+
* defensively, the same as `pollRevision` already does for image edits).
|
|
6275
|
+
*/
|
|
6276
|
+
async animateWithTextV3(args) {
|
|
6277
|
+
const body = { first_frame: args.firstFrame, action: args.action };
|
|
6278
|
+
if (args.lastFrame) body.last_frame = args.lastFrame;
|
|
6279
|
+
if (args.frameCount != null) body.frame_count = args.frameCount;
|
|
6280
|
+
if (args.seed != null) body.seed = args.seed;
|
|
6281
|
+
if (args.noBackground != null) body.no_background = args.noBackground;
|
|
6282
|
+
if (args.enhancePrompt != null) body.enhance_prompt = args.enhancePrompt;
|
|
6283
|
+
return validateResponse(
|
|
6284
|
+
RevisionJobSubmitSchema,
|
|
6285
|
+
await this.request("/animate-with-text-v3", { method: "POST", body: JSON.stringify(body) }),
|
|
6286
|
+
"animate-with-text-v3"
|
|
6287
|
+
);
|
|
6288
|
+
}
|
|
6289
|
+
/**
|
|
6290
|
+
* `/animate-pixminimax`, beta (tier 1 subscription or higher): PixMiniMax's
|
|
6291
|
+
* richer take on the same idea — `direction` and `enhancePrompt` steer
|
|
6292
|
+
* facing for aimed motions. Same unverified-completed-shape caveat as
|
|
6293
|
+
* `animateWithTextV3` above.
|
|
6294
|
+
*/
|
|
6295
|
+
async animatePixminimax(args) {
|
|
6296
|
+
const body = { first_frame: args.firstFrame, description: args.description };
|
|
6297
|
+
if (args.lastFrame) body.last_frame = args.lastFrame;
|
|
6298
|
+
if (args.frameCount != null) body.frame_count = args.frameCount;
|
|
6299
|
+
if (args.seed != null) body.seed = args.seed;
|
|
6300
|
+
if (args.noBackground != null) body.no_background = args.noBackground;
|
|
6301
|
+
if (args.enhancePrompt != null) body.enhance_prompt = args.enhancePrompt;
|
|
6302
|
+
if (args.direction) body.direction = args.direction;
|
|
6303
|
+
return validateResponse(
|
|
6304
|
+
RevisionJobSubmitSchema,
|
|
6305
|
+
await this.request("/animate-pixminimax", { method: "POST", body: JSON.stringify(body) }),
|
|
6306
|
+
"animate-pixminimax"
|
|
6307
|
+
);
|
|
6308
|
+
}
|
|
6199
6309
|
async getBackgroundJob(jobId) {
|
|
6200
6310
|
const raw = await this.request(`/background-jobs/${encodeURIComponent(jobId)}`);
|
|
6201
6311
|
return validateResponse(BackgroundJobSchema, raw, "background-jobs/{id}");
|
|
@@ -6378,12 +6488,15 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6378
6488
|
* no mask) both exist on PixelLab, and so do `reduce-colors`
|
|
6379
6489
|
* (`/reduce-colors`) and `correct-pixelart` (`/correct-pixelart`) — PixelLab's
|
|
6380
6490
|
* "Cleanup" tier, a mechanical post-process on the source's own pixels
|
|
6381
|
-
* rather than a described edit
|
|
6382
|
-
*
|
|
6383
|
-
*
|
|
6491
|
+
* rather than a described edit — and `animate`/`animate-pixminimax`
|
|
6492
|
+
* (`/animate-with-text-v3`, `/animate-pixminimax`), which animate any loose
|
|
6493
|
+
* image from a text description with no character/object resource
|
|
6494
|
+
* required. `outpaint` does not: there is no canvas-expansion endpoint in
|
|
6495
|
+
* the API, matching docs/REVISIONS.md's note that no provider ships a
|
|
6496
|
+
* tested outpaint path yet.
|
|
6384
6497
|
*/
|
|
6385
6498
|
supportsRevision(mode2) {
|
|
6386
|
-
return mode2 === "inpaint" || mode2 === "image-to-image" || mode2 === "reduce-colors" || mode2 === "correct-pixelart";
|
|
6499
|
+
return mode2 === "inpaint" || mode2 === "image-to-image" || mode2 === "reduce-colors" || mode2 === "correct-pixelart" || mode2 === "animate" || mode2 === "animate-pixminimax";
|
|
6387
6500
|
}
|
|
6388
6501
|
/** PixelLab's own constraints: submissions must be >2s apart, and
|
|
6389
6502
|
* background jobs in flight are capped by subscription tier (Tier 1=8,
|
|
@@ -6408,6 +6521,13 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6408
6521
|
if (spec.revision?.mode === "reduce-colors" || spec.revision?.mode === "correct-pixelart") {
|
|
6409
6522
|
return { unit: "generations", amount: 0.1, candidates: 1 };
|
|
6410
6523
|
}
|
|
6524
|
+
if (spec.revision?.mode === "animate" || spec.revision?.mode === "animate-pixminimax") {
|
|
6525
|
+
const width = spec.revision.sourceWidth ?? spec.width;
|
|
6526
|
+
const height = spec.revision.sourceHeight ?? spec.height;
|
|
6527
|
+
const frames = spec.revision.frames ?? 8;
|
|
6528
|
+
const base = Math.max(1, Math.ceil(width * height * frames / 65536));
|
|
6529
|
+
return { unit: "generations", amount: spec.revision.enhancePrompt ? base + 0.05 : base, candidates: 1 };
|
|
6530
|
+
}
|
|
6411
6531
|
if (spec.revision) {
|
|
6412
6532
|
const width = spec.revision.sourceWidth ?? spec.width;
|
|
6413
6533
|
const height = spec.revision.sourceHeight ?? spec.height;
|
|
@@ -6449,6 +6569,20 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6449
6569
|
throw new Error(`PixelLab correct-pixelart source is ${width}x${height}; the API takes at most 1024 pixels per side`);
|
|
6450
6570
|
}
|
|
6451
6571
|
}
|
|
6572
|
+
if (spec.revision?.mode === "animate" || spec.revision?.mode === "animate-pixminimax") {
|
|
6573
|
+
const { sourceWidth: width, sourceHeight: height, mode: mode2, frames, lastFrameWidth, lastFrameHeight } = spec.revision;
|
|
6574
|
+
if (width != null && height != null && (width > 256 || height > 256)) {
|
|
6575
|
+
throw new Error(`PixelLab ${mode2} source is ${width}x${height}; the API takes at most 256 pixels per side`);
|
|
6576
|
+
}
|
|
6577
|
+
if (mode2 === "animate" && frames != null && frames > 16) {
|
|
6578
|
+
throw new Error(`PixelLab animate takes 4 to 16 frames; ${frames} is too many (use animate-pixminimax for up to 40)`);
|
|
6579
|
+
}
|
|
6580
|
+
if (lastFrameWidth != null && lastFrameHeight != null && width != null && height != null && (lastFrameWidth !== width || lastFrameHeight !== height)) {
|
|
6581
|
+
throw new Error(
|
|
6582
|
+
`PixelLab ${mode2} lastFrame is ${lastFrameWidth}x${lastFrameHeight}; source is ${width}x${height} \u2014 they must match`
|
|
6583
|
+
);
|
|
6584
|
+
}
|
|
6585
|
+
}
|
|
6452
6586
|
if (spec.generator === "1dir" && (spec.width < 32 || spec.width > 256)) {
|
|
6453
6587
|
throw new Error("PixelLab 1dir dimensions must be between 32 and 256 pixels");
|
|
6454
6588
|
}
|
|
@@ -7270,6 +7404,42 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
7270
7404
|
writeFileSync(path12.join(_PixelLabProvider.cacheDir(), `${jobId}.png`), res2.png);
|
|
7271
7405
|
return { jobId, metadata: { revisionUsage: res2.usage } };
|
|
7272
7406
|
}
|
|
7407
|
+
if (revision.mode === "animate" || revision.mode === "animate-pixminimax") {
|
|
7408
|
+
let lastFrame;
|
|
7409
|
+
if (revision.lastFrameFile) {
|
|
7410
|
+
if (!revision.lastFrameSha256 || !revision.lastFrameFormat) {
|
|
7411
|
+
throw new Error(`${spec.styleId}/${spec.assetId}: revision last frame is not ready`);
|
|
7412
|
+
}
|
|
7413
|
+
const lastFrameBytes = readFileSync2(revision.lastFrameFile);
|
|
7414
|
+
if (sha256(lastFrameBytes) !== revision.lastFrameSha256) {
|
|
7415
|
+
throw new Error(`${spec.styleId}/${spec.assetId}: revision last frame changed after the manifest was resolved`);
|
|
7416
|
+
}
|
|
7417
|
+
lastFrame = { base64: lastFrameBytes.toString("base64"), format: revision.lastFrameFormat };
|
|
7418
|
+
}
|
|
7419
|
+
if (revision.mode === "animate") {
|
|
7420
|
+
const res3 = await this.client.animateWithTextV3({
|
|
7421
|
+
firstFrame: image,
|
|
7422
|
+
lastFrame,
|
|
7423
|
+
action: spec.prompt,
|
|
7424
|
+
frameCount: revision.frames,
|
|
7425
|
+
seed: spec.seed,
|
|
7426
|
+
noBackground: spec.noBackground,
|
|
7427
|
+
enhancePrompt: revision.enhancePrompt
|
|
7428
|
+
});
|
|
7429
|
+
return { jobId: res3.background_job_id };
|
|
7430
|
+
}
|
|
7431
|
+
const res2 = await this.client.animatePixminimax({
|
|
7432
|
+
firstFrame: image,
|
|
7433
|
+
lastFrame,
|
|
7434
|
+
description: spec.prompt,
|
|
7435
|
+
frameCount: revision.frames,
|
|
7436
|
+
seed: spec.seed,
|
|
7437
|
+
noBackground: spec.noBackground,
|
|
7438
|
+
enhancePrompt: revision.enhancePrompt,
|
|
7439
|
+
direction: revision.direction
|
|
7440
|
+
});
|
|
7441
|
+
return { jobId: res2.background_job_id };
|
|
7442
|
+
}
|
|
7273
7443
|
if (revision.strength != null) {
|
|
7274
7444
|
throw new Error(
|
|
7275
7445
|
`${spec.styleId}/${spec.assetId}: PixelLab image-to-image revisions take no strength; edit-images-v2 always applies the full instruction`
|
|
@@ -7305,6 +7475,9 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
7305
7475
|
if (revisionMode === "reduce-colors" || revisionMode === "correct-pixelart") {
|
|
7306
7476
|
return this.pollCachedRevision(jobId, context);
|
|
7307
7477
|
}
|
|
7478
|
+
if (revisionMode === "animate" || revisionMode === "animate-pixminimax") {
|
|
7479
|
+
return this.pollAnimateRevision(jobId, context);
|
|
7480
|
+
}
|
|
7308
7481
|
if (context?.spec?.revision) return this.pollRevision(jobId);
|
|
7309
7482
|
if (generator === "pixflux") {
|
|
7310
7483
|
const file = path12.join(_PixelLabProvider.cacheDir(), `${jobId}.png`);
|
|
@@ -7361,6 +7534,71 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
7361
7534
|
const usage = context?.metadata?.revisionUsage;
|
|
7362
7535
|
return { status: "ready", objectId: jobId, sourceUrl, sources: [{ url: sourceUrl }], billed: billedFromUsage(usage) };
|
|
7363
7536
|
}
|
|
7537
|
+
/**
|
|
7538
|
+
* `animate`/`animate-pixminimax` revisions: a plain background job, like
|
|
7539
|
+
* `pollRevision` above, but completing with an ORDERED FRAME LIST instead
|
|
7540
|
+
* of a single image — the same `review-set` shape `pollCharacterAnimation`
|
|
7541
|
+
* returns, minus any character/object resource to look the result up on
|
|
7542
|
+
* (there is none; this operates on a loose image). Unlike every other
|
|
7543
|
+
* PixelLab call this adapter makes, the completed shape for
|
|
7544
|
+
* `/animate-with-text-v3`/`/animate-pixminimax` has never been exercised
|
|
7545
|
+
* against a live account — the checks below are an informed guess (hosted
|
|
7546
|
+
* URLs under a plausible key name, the same `storage_urls.frames` shape
|
|
7547
|
+
* character animations use, or inline base64 per frame, decoded to a local
|
|
7548
|
+
* cache file the same way `pollRevision`'s single-image case already is)
|
|
7549
|
+
* rather than an observed shape, and fail loudly, naming the keys actually
|
|
7550
|
+
* received, for whatever the real shape turns out to be.
|
|
7551
|
+
*/
|
|
7552
|
+
async pollAnimateRevision(jobId, context) {
|
|
7553
|
+
const job = await this.client.getBackgroundJob(jobId);
|
|
7554
|
+
if (job.status === "failed") return { status: "failed", error: "animation job failed upstream" };
|
|
7555
|
+
if (job.status !== "completed") return { status: "processing" };
|
|
7556
|
+
const billed = billedFromUsage(job.usage);
|
|
7557
|
+
const done = job.last_response ?? {};
|
|
7558
|
+
const fps = context?.spec?.revision?.fps ?? 8;
|
|
7559
|
+
const review = (frameUrls) => ({
|
|
7560
|
+
status: "review-set",
|
|
7561
|
+
objectId: jobId,
|
|
7562
|
+
frameUrls,
|
|
7563
|
+
sources: frameUrls.map((url, index) => ({ url, role: `frame-${String(index).padStart(2, "0")}` })),
|
|
7564
|
+
fps,
|
|
7565
|
+
metadata: { frameSet: { fps, count: frameUrls.length } },
|
|
7566
|
+
billed
|
|
7567
|
+
});
|
|
7568
|
+
for (const key of ["frame_urls", "frames", "images"]) {
|
|
7569
|
+
const list = done[key];
|
|
7570
|
+
if (!Array.isArray(list) || !list.length) continue;
|
|
7571
|
+
const urls = [];
|
|
7572
|
+
for (const [index, item] of list.entries()) {
|
|
7573
|
+
if (typeof item === "string" && item) {
|
|
7574
|
+
urls.push(item);
|
|
7575
|
+
continue;
|
|
7576
|
+
}
|
|
7577
|
+
const url = item?.url;
|
|
7578
|
+
if (typeof url === "string" && url) {
|
|
7579
|
+
urls.push(url);
|
|
7580
|
+
continue;
|
|
7581
|
+
}
|
|
7582
|
+
const base64 = extractBase64(item);
|
|
7583
|
+
if (base64) {
|
|
7584
|
+
const file = path12.join(_PixelLabProvider.cacheDir(), `${jobId}-${index}.png`);
|
|
7585
|
+
writeFileSync(file, Buffer.from(base64, "base64"));
|
|
7586
|
+
urls.push(`file://${file}`);
|
|
7587
|
+
continue;
|
|
7588
|
+
}
|
|
7589
|
+
break;
|
|
7590
|
+
}
|
|
7591
|
+
if (urls.length === list.length) return review(urls);
|
|
7592
|
+
}
|
|
7593
|
+
const storageFrames = done.storage_urls?.frames;
|
|
7594
|
+
if (Array.isArray(storageFrames) && storageFrames.length && storageFrames.every((f) => typeof f === "string")) {
|
|
7595
|
+
return review(storageFrames);
|
|
7596
|
+
}
|
|
7597
|
+
return {
|
|
7598
|
+
status: "failed",
|
|
7599
|
+
error: `Invalid PixelLab response for animate job ${jobId}: completed with no recognized frame list (got: ${Object.keys(done).join(", ") || "no keys"}); update pollAnimateRevision in src/providers/pixellab.ts with the real shape`
|
|
7600
|
+
};
|
|
7601
|
+
}
|
|
7364
7602
|
/**
|
|
7365
7603
|
* `/inpaint-v3` and `/edit-images-v2` both hand back a plain background
|
|
7366
7604
|
* job with no resource of its own, polled generically at
|
|
@@ -9217,6 +9455,8 @@ async function resolveSpecs(loaded, filter) {
|
|
|
9217
9455
|
}
|
|
9218
9456
|
const paletteImageFile = asset.revision.paletteImage ? path13.resolve(root, asset.revision.paletteImage) : void 0;
|
|
9219
9457
|
const paletteImage = paletteImageFile ? await optionalRevisionImage(paletteImageFile, "revision palette image", "png") : null;
|
|
9458
|
+
const lastFrameFile = asset.revision.lastFrame ? path13.resolve(root, asset.revision.lastFrame) : void 0;
|
|
9459
|
+
const lastFrame = lastFrameFile ? await optionalRevisionImage(lastFrameFile, "revision last frame") : null;
|
|
9220
9460
|
resolved.revision = {
|
|
9221
9461
|
mode: asset.revision.mode,
|
|
9222
9462
|
sourceAssetId: asset.revision.from,
|
|
@@ -9243,7 +9483,18 @@ async function resolveSpecs(loaded, filter) {
|
|
|
9243
9483
|
paletteImageFormat: paletteImage?.format ?? null
|
|
9244
9484
|
} : {},
|
|
9245
9485
|
...asset.revision.dithering ? { dithering: asset.revision.dithering } : {},
|
|
9246
|
-
...asset.revision.ditheringStrength == null ? {} : { ditheringStrength: asset.revision.ditheringStrength }
|
|
9486
|
+
...asset.revision.ditheringStrength == null ? {} : { ditheringStrength: asset.revision.ditheringStrength },
|
|
9487
|
+
...asset.revision.frames == null ? {} : { frames: asset.revision.frames },
|
|
9488
|
+
...asset.revision.fps == null ? {} : { fps: asset.revision.fps },
|
|
9489
|
+
...lastFrameFile ? {
|
|
9490
|
+
lastFrameFile,
|
|
9491
|
+
lastFrameSha256: lastFrame?.hash ?? null,
|
|
9492
|
+
lastFrameWidth: lastFrame?.width ?? null,
|
|
9493
|
+
lastFrameHeight: lastFrame?.height ?? null,
|
|
9494
|
+
lastFrameFormat: lastFrame?.format ?? null
|
|
9495
|
+
} : {},
|
|
9496
|
+
...asset.revision.direction ? { direction: asset.revision.direction } : {},
|
|
9497
|
+
...asset.revision.enhancePrompt == null ? {} : { enhancePrompt: asset.revision.enhancePrompt }
|
|
9247
9498
|
};
|
|
9248
9499
|
}
|
|
9249
9500
|
resolved.specHash = specHash(
|
|
@@ -13603,7 +13854,12 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
|
|
|
13603
13854
|
...spec.revision.numColors == null ? {} : { numColors: spec.revision.numColors },
|
|
13604
13855
|
...spec.revision.paletteImageSha256 ? { paletteImageSha256: spec.revision.paletteImageSha256 } : {},
|
|
13605
13856
|
...spec.revision.dithering ? { dithering: spec.revision.dithering } : {},
|
|
13606
|
-
...spec.revision.ditheringStrength == null ? {} : { ditheringStrength: spec.revision.ditheringStrength }
|
|
13857
|
+
...spec.revision.ditheringStrength == null ? {} : { ditheringStrength: spec.revision.ditheringStrength },
|
|
13858
|
+
...spec.revision.frames == null ? {} : { frames: spec.revision.frames },
|
|
13859
|
+
...spec.revision.fps == null ? {} : { fps: spec.revision.fps },
|
|
13860
|
+
...spec.revision.lastFrameSha256 ? { lastFrameSha256: spec.revision.lastFrameSha256 } : {},
|
|
13861
|
+
...spec.revision.direction ? { direction: spec.revision.direction } : {},
|
|
13862
|
+
...spec.revision.enhancePrompt == null ? {} : { enhancePrompt: spec.revision.enhancePrompt }
|
|
13607
13863
|
} : null,
|
|
13608
13864
|
status: "pending",
|
|
13609
13865
|
jobId: previousJobId ?? null,
|