@chai-ui/core 0.11.4 → 0.13.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/composer-view.d.ts.map +1 -1
- package/dist/composer-view.js +4 -2
- package/dist/composer-view.js.map +1 -1
- package/dist/composer.d.ts +22 -1
- package/dist/composer.d.ts.map +1 -1
- package/dist/composer.js +64 -13
- package/dist/composer.js.map +1 -1
- package/dist/engines/fal.d.ts.map +1 -1
- package/dist/engines/fal.js +15 -6
- package/dist/engines/fal.js.map +1 -1
- package/dist/evaluation-judge.d.ts +33 -0
- package/dist/evaluation-judge.d.ts.map +1 -0
- package/dist/evaluation-judge.js +37 -0
- package/dist/evaluation-judge.js.map +1 -0
- package/dist/image-fit.d.ts +16 -0
- package/dist/image-fit.d.ts.map +1 -0
- package/dist/image-fit.js +54 -0
- package/dist/image-fit.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/run.d.ts +2 -0
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +4 -0
- package/dist/run.js.map +1 -1
- package/dist/suggested-models.d.ts +9 -2
- package/dist/suggested-models.d.ts.map +1 -1
- package/dist/suggested-models.js +42 -13
- package/dist/suggested-models.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/composer-view.ts +4 -2
- package/src/composer.ts +97 -20
- package/src/engines/fal.ts +15 -6
- package/src/evaluation-judge.ts +60 -0
- package/src/image-fit.ts +61 -0
- package/src/index.ts +2 -0
- package/src/run.ts +5 -0
- package/src/suggested-models.ts +43 -13
- package/src/types.ts +7 -0
package/src/image-fit.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fitting a video's start image to the picked aspect ratio, so the ratio
|
|
3
|
+
* wins even on image-to-video models that take the image's own shape.
|
|
4
|
+
*/
|
|
5
|
+
import type { DroppedMedia } from "./types.js";
|
|
6
|
+
|
|
7
|
+
/** How a start image meets the picked ratio: cropped around its center, or padded with black bars. */
|
|
8
|
+
export type StartImageFit = "crop" | "pad";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The image redrawn at `ratio` (e.g. "16:9"), as a JPEG data URL. Returns
|
|
12
|
+
* `src` unchanged when it already has that shape, the ratio isn't "w:h",
|
|
13
|
+
* or there's no canvas to draw on (a server, or a test DOM).
|
|
14
|
+
*/
|
|
15
|
+
export async function fitImageToRatio(src: string, ratio: string, fit: StartImageFit): Promise<string> {
|
|
16
|
+
const [w, h] = ratio.split(":").map(Number);
|
|
17
|
+
if (!w || !h || typeof document === "undefined") return src;
|
|
18
|
+
const canvas = document.createElement("canvas");
|
|
19
|
+
const ctx = canvas.getContext("2d");
|
|
20
|
+
if (!ctx) return src;
|
|
21
|
+
const img = await loadImage(src).catch(() => null);
|
|
22
|
+
if (!img) return src;
|
|
23
|
+
const iw = img.naturalWidth;
|
|
24
|
+
const ih = img.naturalHeight;
|
|
25
|
+
const target = w / h;
|
|
26
|
+
if (!iw || !ih || Math.abs(iw / ih - target) < 0.01) return src;
|
|
27
|
+
// Crop keeps the image's short side and cuts the long one; pad keeps
|
|
28
|
+
// the whole image and grows the short side.
|
|
29
|
+
const wider = iw / ih > target;
|
|
30
|
+
const keepHeight = fit === "crop" ? wider : !wider;
|
|
31
|
+
canvas.width = keepHeight ? Math.round(ih * target) : iw;
|
|
32
|
+
canvas.height = keepHeight ? ih : Math.round(iw / target);
|
|
33
|
+
if (fit === "pad") {
|
|
34
|
+
ctx.fillStyle = "black";
|
|
35
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
36
|
+
}
|
|
37
|
+
ctx.drawImage(img, (canvas.width - iw) / 2, (canvas.height - ih) / 2);
|
|
38
|
+
try {
|
|
39
|
+
return canvas.toDataURL("image/jpeg", 0.92);
|
|
40
|
+
} catch {
|
|
41
|
+
// A cross-origin image without CORS can't be read back: send it as is.
|
|
42
|
+
return src;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The attachments with each image fitted to `ratio`; other media unchanged. */
|
|
47
|
+
export function fitImagesToRatio(attachments: DroppedMedia[], ratio: string, fit: StartImageFit): Promise<DroppedMedia[]> {
|
|
48
|
+
return Promise.all(
|
|
49
|
+
attachments.map(async (a) => (a.kind === "image" ? { ...a, src: await fitImageToRatio(a.src, ratio, fit) } : a))
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function loadImage(src: string): Promise<HTMLImageElement> {
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
const img = new Image();
|
|
56
|
+
img.crossOrigin = "anonymous";
|
|
57
|
+
img.onload = () => resolve(img);
|
|
58
|
+
img.onerror = reject;
|
|
59
|
+
img.src = src;
|
|
60
|
+
});
|
|
61
|
+
}
|
package/src/index.ts
CHANGED
package/src/run.ts
CHANGED
|
@@ -112,6 +112,11 @@ export function resolveResult(
|
|
|
112
112
|
}));
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
/** The result with `evaluations` added after any it already has (e.g. the judge's after the backend's). */
|
|
116
|
+
export function addEvaluations(run: Run, resultId: string, evaluations: Evaluation[]): Run {
|
|
117
|
+
return updateResult(run, resultId, (r) => ({ ...r, evaluations: [...(r.evaluations ?? []), ...evaluations] }));
|
|
118
|
+
}
|
|
119
|
+
|
|
115
120
|
export function failResult(run: Run, resultId: string, error: Result["error"]): Run {
|
|
116
121
|
return updateResult(run, resultId, (r) => ({
|
|
117
122
|
...r,
|
package/src/suggested-models.ts
CHANGED
|
@@ -19,31 +19,48 @@ import { DEFAULT_MAX_REGIONS } from "./region-edit.js";
|
|
|
19
19
|
|
|
20
20
|
const NANO_BANANA_RATIOS = ["21:9", "16:9", "3:2", "4:3", "5:4", "1:1", "4:5", "3:4", "2:3", "9:16"];
|
|
21
21
|
const FLUX_3_RATIOS = ["21:9", "2:1", "16:9", "3:2", "7:5", "4:3", "5:4", "1:1", "4:5", "3:4", "5:7", "2:3", "9:16", "1:2"];
|
|
22
|
-
|
|
22
|
+
const NANO_BANANA_2_RATIOS = [...NANO_BANANA_RATIOS, "4:1", "1:4", "8:1", "1:8"];
|
|
23
|
+
/** The ratios a named `image_size` covers (Flux 3 Klein, GPT Image 2). */
|
|
23
24
|
const IMAGE_SIZE_RATIOS = ["1:1", "4:3", "16:9", "3:4", "9:16"];
|
|
24
25
|
|
|
25
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Create image. Each model's `withImages` endpoint takes attached images
|
|
28
|
+
* (as references) and still the picked aspect ratio.
|
|
29
|
+
*/
|
|
26
30
|
export const SUGGESTED_IMAGE_MODELS: ModelOption[] = [
|
|
27
|
-
{ id: "fal-ai/nano-banana-pro", label: "Nano Banana Pro", provider: "Google", speed: "standard", aspectRatios: NANO_BANANA_RATIOS, falInput: { aspectRatio: "aspect_ratio" } },
|
|
31
|
+
{ id: "fal-ai/nano-banana-pro", label: "Nano Banana Pro", provider: "Google", speed: "standard", aspectRatios: NANO_BANANA_RATIOS, falInput: { aspectRatio: "aspect_ratio" }, withImages: "fal-ai/nano-banana-pro/edit" },
|
|
28
32
|
{
|
|
29
33
|
id: "fal-ai/nano-banana-2",
|
|
30
34
|
label: "Nano Banana 2",
|
|
31
35
|
provider: "Google",
|
|
32
36
|
speed: "fast",
|
|
33
|
-
aspectRatios:
|
|
37
|
+
aspectRatios: NANO_BANANA_2_RATIOS,
|
|
34
38
|
falInput: { aspectRatio: "aspect_ratio" },
|
|
39
|
+
withImages: "fal-ai/nano-banana-2/edit",
|
|
40
|
+
},
|
|
41
|
+
{ id: "blackforestlabs/flux-3/text-to-image", label: "Flux 3 Image", provider: "Black Forest Labs", speed: "standard", aspectRatios: FLUX_3_RATIOS, falInput: { aspectRatio: "aspect_ratio" }, withImages: "blackforestlabs/flux-3/edit-image" },
|
|
42
|
+
{ id: "openai/gpt-image-2", label: "GPT Image 2", provider: "OpenAI", speed: "slow", aspectRatios: IMAGE_SIZE_RATIOS, falInput: { aspectRatio: "image_size" }, withImages: "openai/gpt-image-2/edit" },
|
|
43
|
+
{
|
|
44
|
+
id: "blackforestlabs/flux-3/klein/text-to-image",
|
|
45
|
+
label: "Flux 3 Klein",
|
|
46
|
+
provider: "Black Forest Labs",
|
|
47
|
+
speed: "fast",
|
|
48
|
+
aspectRatios: IMAGE_SIZE_RATIOS,
|
|
49
|
+
falInput: { aspectRatio: "image_size" },
|
|
50
|
+
withImages: "blackforestlabs/flux-3/klein/edit-image",
|
|
35
51
|
},
|
|
36
|
-
{ id: "blackforestlabs/flux-3/text-to-image", label: "Flux 3 Image", provider: "Black Forest Labs", speed: "standard", aspectRatios: FLUX_3_RATIOS, falInput: { aspectRatio: "aspect_ratio" } },
|
|
37
|
-
{ id: "openai/gpt-image-2", label: "GPT Image 2", provider: "OpenAI", speed: "slow", aspectRatios: IMAGE_SIZE_RATIOS, falInput: { aspectRatio: "image_size" } },
|
|
38
|
-
{ id: "fal-ai/flux/schnell", label: "FLUX.1 schnell", provider: "Black Forest Labs", speed: "fast", aspectRatios: IMAGE_SIZE_RATIOS, falInput: { aspectRatio: "image_size" } },
|
|
39
52
|
];
|
|
40
53
|
|
|
41
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Create video. With an image attached, each runs as its `withImages`
|
|
56
|
+
* image-to-video endpoint, the image as the first frame; the image is
|
|
57
|
+
* fitted to the picked ratio first (`startImageFit`).
|
|
58
|
+
*/
|
|
42
59
|
export const SUGGESTED_TEXT_TO_VIDEO_MODELS: ModelOption[] = [
|
|
43
|
-
{ id: "minimax/h3-max/text-to-video", label: "MiniMax H3 Max", provider: "MiniMax", speed: "slow", aspectRatios: ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"], falInput: { aspectRatio: "aspect_ratio" } },
|
|
44
|
-
{ id: "bytedance/seedance-2.5/text-to-video", label: "Seedance 2.5", provider: "ByteDance", speed: "slow", aspectRatios: ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"], falInput: { aspectRatio: "aspect_ratio" } },
|
|
45
|
-
{ id: "fal-ai/kling-video/v3/pro/text-to-video", label: "Kling v3 Pro", provider: "Kling", speed: "slow", aspectRatios: ["16:9", "9:16", "1:1"], falInput: { aspectRatio: "aspect_ratio" } },
|
|
46
|
-
{ id: "fal-ai/veo3.1/fast", label: "Veo 3.1 Fast", provider: "Google", speed: "standard", aspectRatios: ["16:9", "9:16"], falInput: { aspectRatio: "aspect_ratio" } },
|
|
60
|
+
{ id: "minimax/h3-max/text-to-video", label: "MiniMax H3 Max", provider: "MiniMax", speed: "slow", aspectRatios: ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"], falInput: { aspectRatio: "aspect_ratio" }, withImages: "minimax/h3-max/image-to-video" },
|
|
61
|
+
{ id: "bytedance/seedance-2.5/text-to-video", label: "Seedance 2.5", provider: "ByteDance", speed: "slow", aspectRatios: ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"], falInput: { aspectRatio: "aspect_ratio" }, withImages: "bytedance/seedance-2.5/image-to-video" },
|
|
62
|
+
{ id: "fal-ai/kling-video/v3/pro/text-to-video", label: "Kling v3 Pro", provider: "Kling", speed: "slow", aspectRatios: ["16:9", "9:16", "1:1"], falInput: { aspectRatio: "aspect_ratio" }, withImages: "fal-ai/kling-video/v3/pro/image-to-video" },
|
|
63
|
+
{ id: "fal-ai/veo3.1/fast", label: "Veo 3.1 Fast", provider: "Google", speed: "standard", aspectRatios: ["16:9", "9:16"], falInput: { aspectRatio: "aspect_ratio" }, withImages: "fal-ai/veo3.1/fast/image-to-video" },
|
|
47
64
|
];
|
|
48
65
|
|
|
49
66
|
/**
|
|
@@ -122,7 +139,20 @@ export function suggestedModels(useCase: GenerationUseCase | undefined): ModelOp
|
|
|
122
139
|
}
|
|
123
140
|
}
|
|
124
141
|
|
|
142
|
+
/** `withImages` endpoints in no menu of their own. */
|
|
143
|
+
const IMAGE_INPUT_ONLY: ModelOption[] = [
|
|
144
|
+
{ id: "fal-ai/nano-banana-2/edit", label: "Nano Banana 2", provider: "Google", speed: "fast", aspectRatios: NANO_BANANA_2_RATIOS, falInput: { aspectRatio: "aspect_ratio", image: "image_urls" } },
|
|
145
|
+
{
|
|
146
|
+
id: "blackforestlabs/flux-3/klein/edit-image",
|
|
147
|
+
label: "Flux 3 Klein",
|
|
148
|
+
provider: "Black Forest Labs",
|
|
149
|
+
speed: "fast",
|
|
150
|
+
aspectRatios: IMAGE_SIZE_RATIOS,
|
|
151
|
+
falInput: { aspectRatio: "image_size", image: "image_urls" },
|
|
152
|
+
},
|
|
153
|
+
];
|
|
154
|
+
|
|
125
155
|
/** Every suggested Fal model, by id: how the Fal engine knows each one's inputs. */
|
|
126
156
|
export const SUGGESTED_FAL_MODELS: ReadonlyMap<string, ModelOption> = new Map(
|
|
127
|
-
[...SUGGESTED_IMAGE_MODELS, ...SUGGESTED_TEXT_TO_VIDEO_MODELS, ...SUGGESTED_IMAGE_TO_VIDEO_MODELS, ...SUGGESTED_EDIT_MODELS].map((m) => [m.id, m])
|
|
157
|
+
[...SUGGESTED_IMAGE_MODELS, ...SUGGESTED_TEXT_TO_VIDEO_MODELS, ...SUGGESTED_IMAGE_TO_VIDEO_MODELS, ...SUGGESTED_EDIT_MODELS, ...IMAGE_INPUT_ONLY].map((m) => [m.id, m])
|
|
128
158
|
);
|
package/src/types.ts
CHANGED
|
@@ -112,6 +112,13 @@ export interface ModelOption {
|
|
|
112
112
|
* without it the Fal engine guesses from the id.
|
|
113
113
|
*/
|
|
114
114
|
falInput?: FalInputFormat;
|
|
115
|
+
/**
|
|
116
|
+
* The Fal model to call instead when images are attached, for a model
|
|
117
|
+
* whose own endpoint takes a prompt only: e.g. Nano Banana Pro's edit
|
|
118
|
+
* endpoint, or a video model's image-to-video one. The Fal engine reads
|
|
119
|
+
* that model's inputs from the suggested lists or `FalEngineOptions.models`.
|
|
120
|
+
*/
|
|
121
|
+
withImages?: string;
|
|
115
122
|
/**
|
|
116
123
|
* The output aspect ratios the model takes, e.g. `["1:1", "16:9", "9:16"]`.
|
|
117
124
|
* Composer's Aspect ratio menu offers only ratios the selected models
|