@chai-ui/core 0.6.0 → 0.7.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/README.md +10 -5
- package/dist/composer-view.d.ts +93 -0
- package/dist/composer-view.d.ts.map +1 -0
- package/dist/composer-view.js +142 -0
- package/dist/composer-view.js.map +1 -0
- package/dist/composer.d.ts +188 -0
- package/dist/composer.d.ts.map +1 -0
- package/dist/composer.js +326 -0
- package/dist/composer.js.map +1 -0
- package/dist/edit-card.d.ts +53 -0
- package/dist/edit-card.d.ts.map +1 -0
- package/dist/edit-card.js +119 -0
- package/dist/edit-card.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/media-actions.d.ts +19 -0
- package/dist/media-actions.d.ts.map +1 -0
- package/dist/media-actions.js +57 -0
- package/dist/media-actions.js.map +1 -0
- package/dist/media-analyzer.d.ts +101 -0
- package/dist/media-analyzer.d.ts.map +1 -0
- package/dist/media-analyzer.js +215 -0
- package/dist/media-analyzer.js.map +1 -0
- package/dist/reasoning.d.ts +59 -0
- package/dist/reasoning.d.ts.map +1 -0
- package/dist/reasoning.js +55 -0
- package/dist/reasoning.js.map +1 -0
- package/dist/region-edit.d.ts +2 -0
- package/dist/region-edit.d.ts.map +1 -1
- package/dist/region-edit.js +6 -0
- package/dist/region-edit.js.map +1 -1
- package/dist/result-format.d.ts +11 -0
- package/dist/result-format.d.ts.map +1 -0
- package/dist/result-format.js +30 -0
- package/dist/result-format.js.map +1 -0
- package/dist/unique-id.d.ts +3 -0
- package/dist/unique-id.d.ts.map +1 -0
- package/dist/unique-id.js +7 -0
- package/dist/unique-id.js.map +1 -0
- package/package.json +2 -1
- package/src/composer-view.ts +222 -0
- package/src/composer.ts +525 -0
- package/src/edit-card.ts +138 -0
- package/src/index.ts +7 -0
- package/src/media-actions.ts +55 -0
- package/src/media-analyzer.ts +293 -0
- package/src/reasoning.ts +90 -0
- package/src/region-edit.ts +8 -0
- package/src/result-format.ts +34 -0
- package/src/unique-id.ts +6 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Download and share for a piece of generated media, shared by the cards in
|
|
3
|
+
* every framework binding.
|
|
4
|
+
*
|
|
5
|
+
* A plain `<a download href={remoteUrl}>` only forces a download for a
|
|
6
|
+
* same-origin or `blob:`/`data:` URL; for a cross-origin CDN URL (what a
|
|
7
|
+
* generated result usually is) browsers ignore `download` and open it
|
|
8
|
+
* instead. Fetching it into a blob first works wherever the source allows
|
|
9
|
+
* cross-origin fetches. When it doesn't, opening the media is the fallback.
|
|
10
|
+
*/
|
|
11
|
+
export async function downloadMedia(src, filename) {
|
|
12
|
+
try {
|
|
13
|
+
const response = await fetch(src);
|
|
14
|
+
const blob = await response.blob();
|
|
15
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
16
|
+
const a = document.createElement("a");
|
|
17
|
+
a.href = blobUrl;
|
|
18
|
+
a.download = filename;
|
|
19
|
+
document.body.appendChild(a);
|
|
20
|
+
a.click();
|
|
21
|
+
a.remove();
|
|
22
|
+
URL.revokeObjectURL(blobUrl);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
window.open(src, "_blank", "noopener");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The native share sheet where there is one, otherwise the media's URL
|
|
30
|
+
* copied to the clipboard. Says which, so the button can confirm a copy.
|
|
31
|
+
*/
|
|
32
|
+
export async function shareMedia(src) {
|
|
33
|
+
if (navigator.share) {
|
|
34
|
+
try {
|
|
35
|
+
await navigator.share({ url: src });
|
|
36
|
+
return "shared";
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Dismissed, or not shareable: same as closing a native share sheet.
|
|
40
|
+
return "none";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
await navigator.clipboard.writeText(src);
|
|
45
|
+
return "copied";
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return "none";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** A file name for a download: the URL's own extension when it has one, otherwise a guess by kind. */
|
|
52
|
+
export function downloadFilename(id, kind, src) {
|
|
53
|
+
const match = /\.([a-zA-Z0-9]{2,5})(?:[?#]|$)/.exec(src);
|
|
54
|
+
const ext = match?.[1] ?? (kind === "video" ? "mp4" : kind === "audio" ? "mp3" : kind === "text" ? "txt" : "png");
|
|
55
|
+
return `${kind}-${id}.${ext}`;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=media-actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-actions.js","sourceRoot":"","sources":["../src/media-actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,QAAgB;IAC/D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC,CAAC,IAAI,GAAG,OAAO,CAAC;QACjB,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACtB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC,CAAC,KAAK,EAAE,CAAC;QACV,CAAC,CAAC,MAAM,EAAE,CAAC;QACX,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YACpC,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;YACrE,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IACD,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACzC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC;IAChB,CAAC;AACH,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,gBAAgB,CAAC,EAAU,EAAE,IAAY,EAAE,GAAW;IACpE,MAAM,KAAK,GAAG,gCAAgC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,MAAM,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAClH,OAAO,GAAG,IAAI,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { type GenerationEngine } from "./engine.js";
|
|
2
|
+
import { type MediaAnalysisPromptLength } from "./media-analysis-prompts.js";
|
|
3
|
+
import { type ModelRoutingInput, type ModelRoutingResult } from "./model-routing.js";
|
|
4
|
+
import { type Reasoning } from "./reasoning.js";
|
|
5
|
+
import type { DroppedMedia, MediaKind, ModelOption } from "./types.js";
|
|
6
|
+
export interface MediaAnalyzerAttachment extends DroppedMedia {
|
|
7
|
+
id: string;
|
|
8
|
+
}
|
|
9
|
+
export interface MediaAnalyzerSubmitPayload {
|
|
10
|
+
attachments: MediaAnalyzerAttachment[];
|
|
11
|
+
modelId: string | null;
|
|
12
|
+
/** When true, the analyzer routes among `models` at submit instead of using `modelId`. */
|
|
13
|
+
autoSelectModel: boolean;
|
|
14
|
+
/** The models offered for the attached media's kind. */
|
|
15
|
+
models: ModelOption[];
|
|
16
|
+
/** `null` until a person actually picks one — see `MediaAnalyzer`'s `promptLength` prop for why this doesn't default to "concise". */
|
|
17
|
+
promptLength: MediaAnalysisPromptLength | null;
|
|
18
|
+
}
|
|
19
|
+
export interface MediaAnalyzerOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Overrides the nearest `ChaiProvider`'s reasoning engine. With neither,
|
|
22
|
+
* a mock text engine answers, so a first render works with no key.
|
|
23
|
+
*/
|
|
24
|
+
engine?: GenerationEngine;
|
|
25
|
+
/** The model when the person hasn't picked one. Defaults to the provider's reasoning model for the media's kind. */
|
|
26
|
+
model?: string;
|
|
27
|
+
onResult?: (prompt: string) => void;
|
|
28
|
+
onError?: (message: string) => void;
|
|
29
|
+
/** Auto-select: fires with the routed model so the trigger shows it. Wire it to `MediaAnalyzer`'s `onModelChange` state. */
|
|
30
|
+
onModelChange?: (modelId: string) => void;
|
|
31
|
+
/** Replaces the routing instruction (`buildModelRoutingPrompt`). */
|
|
32
|
+
routingPrompt?: (input: ModelRoutingInput) => string;
|
|
33
|
+
/** Fires when auto-select fell back to the first listed model (no reasoning model, a failed call, or an unlisted reply). Analysis still runs. */
|
|
34
|
+
onRoutingFallback?: (result: Extract<ModelRoutingResult, {
|
|
35
|
+
status: "fallback";
|
|
36
|
+
}>) => void;
|
|
37
|
+
}
|
|
38
|
+
export interface MediaAnalyzerState {
|
|
39
|
+
analyzing: boolean;
|
|
40
|
+
error: string | null;
|
|
41
|
+
prompt: string | null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* `getOptions` is read on every call, so options can change between
|
|
45
|
+
* renders; `getProvided` is the nearest provider's reasoning, if any.
|
|
46
|
+
*/
|
|
47
|
+
export declare function createMediaAnalyzerStore(getOptions: () => MediaAnalyzerOptions, getProvided?: () => Reasoning | undefined): {
|
|
48
|
+
getState: () => MediaAnalyzerState;
|
|
49
|
+
subscribe(listener: () => void): () => undefined;
|
|
50
|
+
submit: (payload: MediaAnalyzerSubmitPayload) => void;
|
|
51
|
+
cancel: () => void;
|
|
52
|
+
reset: () => void;
|
|
53
|
+
};
|
|
54
|
+
export type MediaAnalyzerStore = ReturnType<typeof createMediaAnalyzerStore>;
|
|
55
|
+
export declare const MEDIA_KIND_LABEL: Record<MediaKind, string>;
|
|
56
|
+
/** Clarifies what "Terse"/"Concise"/"Detailed" mean in the "Prompt length" menu's rows. UI copy, not sent to any model. */
|
|
57
|
+
export declare const PROMPT_LENGTH_HINT: Record<MediaAnalysisPromptLength, string>;
|
|
58
|
+
/**
|
|
59
|
+
* How many attachments of each kind an analysis can hold at once. Image
|
|
60
|
+
* defaults to 5 (a sequence/series reads as one analysis); video and audio
|
|
61
|
+
* default to 1. Only one *kind* is ever active per analysis — these caps only
|
|
62
|
+
* bound how many of that one kind can pile up before the drop zone stops
|
|
63
|
+
* accepting more. `text` is output, never dropped: present only so this
|
|
64
|
+
* stays a total map.
|
|
65
|
+
*/
|
|
66
|
+
export declare const DEFAULT_MAX_ATTACHMENTS_BY_KIND: Record<MediaKind, number>;
|
|
67
|
+
/**
|
|
68
|
+
* Applies one newly-read file to the current attachment list. Only one media
|
|
69
|
+
* *kind* exists per analysis: a different kind replaces the whole list,
|
|
70
|
+
* never merges. Video and audio are single-slot (a same-kind drop replaces
|
|
71
|
+
* it); image fills up to `max`, then silently stops accepting more (the drop
|
|
72
|
+
* zone's "maximum added" look explains why).
|
|
73
|
+
*/
|
|
74
|
+
export declare function nextMediaAnalyzerAttachments(current: MediaAnalyzerAttachment[], incoming: DroppedMedia, maxByKind?: Record<MediaKind, number>): MediaAnalyzerAttachment[];
|
|
75
|
+
/** True once a same-kind drop would be rejected: only ever for image, since video and audio replace. */
|
|
76
|
+
export declare function isMediaAnalyzerAtCap(current: MediaAnalyzerAttachment[], maxByKind?: Record<MediaKind, number>): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Reads image, video and audio files as data URLs, all of them before
|
|
79
|
+
* returning, so a caller applies them in drop order in one go (applying
|
|
80
|
+
* each as its reader finishes would stack them on a stale list).
|
|
81
|
+
* `unsupported` names the files of another type, or that couldn't be read.
|
|
82
|
+
*/
|
|
83
|
+
export declare function readMediaFiles(files: Iterable<File>): Promise<{
|
|
84
|
+
media: DroppedMedia[];
|
|
85
|
+
unsupported: string[];
|
|
86
|
+
}>;
|
|
87
|
+
/** "Replaced 2 images with clip.wav.", or `null` when nothing was replaced. */
|
|
88
|
+
export declare function replacedNote(before: MediaAnalyzerAttachment[], after: MediaAnalyzerAttachment[]): string | null;
|
|
89
|
+
/**
|
|
90
|
+
* The "Select model" menu's sections: once a kind is attached, only its
|
|
91
|
+
* models (falling back to `models`); before that, all three kinds, each
|
|
92
|
+
* under its own header.
|
|
93
|
+
*/
|
|
94
|
+
export declare function mediaAnalyzerModelSections(kind: MediaKind | undefined, modelsByKind: Partial<Record<MediaKind, ModelOption[]>>, models: ModelOption[]): {
|
|
95
|
+
label: string;
|
|
96
|
+
options: {
|
|
97
|
+
id: string;
|
|
98
|
+
label: string;
|
|
99
|
+
}[];
|
|
100
|
+
}[];
|
|
101
|
+
//# sourceMappingURL=media-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-analyzer.d.ts","sourceRoot":"","sources":["../src/media-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Media Analyzer's behavior with no framework: sends the attached media
|
|
3
|
+
* and the instruction for its kind and prompt length
|
|
4
|
+
* (`MEDIA_ANALYSIS_PROMPTS`) to the reasoning engine, and keeps the
|
|
5
|
+
* generated prompt, which fills in as the text streams. A small store
|
|
6
|
+
* (`getState` + `subscribe`) that `useMediaAnalyzer` (React) and the Vue
|
|
7
|
+
* composable wrap.
|
|
8
|
+
*/
|
|
9
|
+
import { uniqueId } from "./unique-id.js";
|
|
10
|
+
import { warnNoReasoningOnce } from "./composer.js";
|
|
11
|
+
import { createMockEngine, isAbortError, normalizeGenerationError } from "./engine.js";
|
|
12
|
+
import { DEFAULT_MEDIA_ANALYSIS_PROMPT_LENGTH, MEDIA_ANALYSIS_PROMPTS, } from "./media-analysis-prompts.js";
|
|
13
|
+
import { routeModel } from "./model-routing.js";
|
|
14
|
+
import { reasoningModelFor } from "./reasoning.js";
|
|
15
|
+
const mockTextEngine = createMockEngine({ outputKind: "text" });
|
|
16
|
+
/**
|
|
17
|
+
* `getOptions` is read on every call, so options can change between
|
|
18
|
+
* renders; `getProvided` is the nearest provider's reasoning, if any.
|
|
19
|
+
*/
|
|
20
|
+
export function createMediaAnalyzerStore(getOptions, getProvided = () => undefined) {
|
|
21
|
+
let state = { analyzing: false, error: null, prompt: null };
|
|
22
|
+
const listeners = new Set();
|
|
23
|
+
const set = (next) => {
|
|
24
|
+
state = { ...state, ...next };
|
|
25
|
+
for (const l of listeners)
|
|
26
|
+
l();
|
|
27
|
+
};
|
|
28
|
+
// Each submit gets an id; a late reply from an earlier submit is dropped,
|
|
29
|
+
// and its call aborted.
|
|
30
|
+
let callId = 0;
|
|
31
|
+
let controller = null;
|
|
32
|
+
function submit(payload) {
|
|
33
|
+
const opts = getOptions();
|
|
34
|
+
const reasoning = getProvided();
|
|
35
|
+
const id = ++callId;
|
|
36
|
+
controller?.abort();
|
|
37
|
+
const { signal } = (controller = new AbortController());
|
|
38
|
+
set({ error: null, prompt: null });
|
|
39
|
+
const kind = payload.attachments[0]?.kind;
|
|
40
|
+
if (kind !== "image" && kind !== "video" && kind !== "audio") {
|
|
41
|
+
const message = "Attach an image, video, or audio file to analyze.";
|
|
42
|
+
set({ error: message });
|
|
43
|
+
opts.onError?.(message);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const engine = opts.engine ?? reasoning?.engine ?? mockTextEngine;
|
|
47
|
+
const defaultModel = opts.model ?? (reasoning ? reasoningModelFor(reasoning, payload.attachments) : undefined);
|
|
48
|
+
const instruction = MEDIA_ANALYSIS_PROMPTS[kind][payload.promptLength ?? DEFAULT_MEDIA_ANALYSIS_PROMPT_LENGTH];
|
|
49
|
+
const current = () => id === callId;
|
|
50
|
+
const autoSelect = payload.autoSelectModel && payload.models.length > 0;
|
|
51
|
+
const analyze = (modelId) => engine
|
|
52
|
+
.generate({
|
|
53
|
+
modelId,
|
|
54
|
+
prompt: instruction,
|
|
55
|
+
attachments: payload.attachments,
|
|
56
|
+
onText: (text) => current() && set({ prompt: text }),
|
|
57
|
+
signal,
|
|
58
|
+
})
|
|
59
|
+
.then(({ src }) => {
|
|
60
|
+
if (!current())
|
|
61
|
+
return;
|
|
62
|
+
set({ prompt: src });
|
|
63
|
+
getOptions().onResult?.(src);
|
|
64
|
+
}, (err) => {
|
|
65
|
+
if (!current() || isAbortError(err))
|
|
66
|
+
return;
|
|
67
|
+
const { message } = normalizeGenerationError(err);
|
|
68
|
+
set({ error: message });
|
|
69
|
+
getOptions().onError?.(message);
|
|
70
|
+
})
|
|
71
|
+
.finally(() => current() && set({ analyzing: false }));
|
|
72
|
+
set({ analyzing: true });
|
|
73
|
+
if (!autoSelect) {
|
|
74
|
+
void analyze(payload.modelId ?? defaultModel);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// Auto-select: the reasoning model looks at the media and picks the
|
|
78
|
+
// analysis model first. A routing problem falls back, never blocks.
|
|
79
|
+
void routeModel({
|
|
80
|
+
prompt: "",
|
|
81
|
+
outputKind: "text",
|
|
82
|
+
attachmentKinds: payload.attachments.map((a) => a.kind),
|
|
83
|
+
attachments: payload.attachments,
|
|
84
|
+
models: payload.models,
|
|
85
|
+
engine: opts.engine ?? reasoning?.engine,
|
|
86
|
+
model: defaultModel,
|
|
87
|
+
routingPrompt: opts.routingPrompt,
|
|
88
|
+
signal,
|
|
89
|
+
}).then((routed) => {
|
|
90
|
+
if (!current() || signal.aborted)
|
|
91
|
+
return;
|
|
92
|
+
const latest = getOptions();
|
|
93
|
+
if (routed.status === "fallback") {
|
|
94
|
+
if (routed.reason === "no-reasoning")
|
|
95
|
+
warnNoReasoningOnce("analysis runs on the first listed model");
|
|
96
|
+
latest.onRoutingFallback?.(routed);
|
|
97
|
+
}
|
|
98
|
+
latest.onModelChange?.(routed.modelId);
|
|
99
|
+
return analyze(routed.modelId);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/** Stops the analysis in flight (cancelling at the provider where it can), keeping any text that already streamed in. */
|
|
103
|
+
function cancel() {
|
|
104
|
+
callId += 1;
|
|
105
|
+
controller?.abort();
|
|
106
|
+
controller = null;
|
|
107
|
+
set({ analyzing: false });
|
|
108
|
+
}
|
|
109
|
+
/** Stops anything in flight and clears the prompt and error, e.g. when the person changes their media. */
|
|
110
|
+
function reset() {
|
|
111
|
+
cancel();
|
|
112
|
+
set({ error: null, prompt: null });
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
getState: () => state,
|
|
116
|
+
subscribe(listener) {
|
|
117
|
+
listeners.add(listener);
|
|
118
|
+
return () => void listeners.delete(listener);
|
|
119
|
+
},
|
|
120
|
+
submit,
|
|
121
|
+
cancel,
|
|
122
|
+
reset,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// --- Attachments and menus: what the MediaAnalyzer component shows, the same in every framework binding.
|
|
126
|
+
const ACCEPTED_KINDS = ["image", "video", "audio"];
|
|
127
|
+
export const MEDIA_KIND_LABEL = { image: "Image", video: "Video", audio: "Audio", text: "Text" };
|
|
128
|
+
/** Clarifies what "Terse"/"Concise"/"Detailed" mean in the "Prompt length" menu's rows. UI copy, not sent to any model. */
|
|
129
|
+
export const PROMPT_LENGTH_HINT = {
|
|
130
|
+
terse: "short",
|
|
131
|
+
concise: "moderate",
|
|
132
|
+
detailed: "long",
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* How many attachments of each kind an analysis can hold at once. Image
|
|
136
|
+
* defaults to 5 (a sequence/series reads as one analysis); video and audio
|
|
137
|
+
* default to 1. Only one *kind* is ever active per analysis — these caps only
|
|
138
|
+
* bound how many of that one kind can pile up before the drop zone stops
|
|
139
|
+
* accepting more. `text` is output, never dropped: present only so this
|
|
140
|
+
* stays a total map.
|
|
141
|
+
*/
|
|
142
|
+
export const DEFAULT_MAX_ATTACHMENTS_BY_KIND = { image: 5, video: 1, audio: 1, text: 0 };
|
|
143
|
+
/**
|
|
144
|
+
* Applies one newly-read file to the current attachment list. Only one media
|
|
145
|
+
* *kind* exists per analysis: a different kind replaces the whole list,
|
|
146
|
+
* never merges. Video and audio are single-slot (a same-kind drop replaces
|
|
147
|
+
* it); image fills up to `max`, then silently stops accepting more (the drop
|
|
148
|
+
* zone's "maximum added" look explains why).
|
|
149
|
+
*/
|
|
150
|
+
export function nextMediaAnalyzerAttachments(current, incoming, maxByKind = DEFAULT_MAX_ATTACHMENTS_BY_KIND) {
|
|
151
|
+
const existingKind = current[0]?.kind;
|
|
152
|
+
const withId = { ...incoming, id: uniqueId() };
|
|
153
|
+
if (!existingKind || existingKind !== incoming.kind)
|
|
154
|
+
return [withId];
|
|
155
|
+
if (incoming.kind === "image") {
|
|
156
|
+
if (current.length >= (maxByKind.image ?? DEFAULT_MAX_ATTACHMENTS_BY_KIND.image))
|
|
157
|
+
return current;
|
|
158
|
+
return [...current, withId];
|
|
159
|
+
}
|
|
160
|
+
return [withId];
|
|
161
|
+
}
|
|
162
|
+
/** True once a same-kind drop would be rejected: only ever for image, since video and audio replace. */
|
|
163
|
+
export function isMediaAnalyzerAtCap(current, maxByKind = DEFAULT_MAX_ATTACHMENTS_BY_KIND) {
|
|
164
|
+
if (current[0]?.kind !== "image")
|
|
165
|
+
return false;
|
|
166
|
+
return current.length >= (maxByKind.image ?? DEFAULT_MAX_ATTACHMENTS_BY_KIND.image);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Reads image, video and audio files as data URLs, all of them before
|
|
170
|
+
* returning, so a caller applies them in drop order in one go (applying
|
|
171
|
+
* each as its reader finishes would stack them on a stale list).
|
|
172
|
+
* `unsupported` names the files of another type, or that couldn't be read.
|
|
173
|
+
*/
|
|
174
|
+
export async function readMediaFiles(files) {
|
|
175
|
+
const unsupported = [];
|
|
176
|
+
const read = await Promise.all([...files].map((file) => {
|
|
177
|
+
const kind = ACCEPTED_KINDS.find((k) => k === file.type.split("/")[0]);
|
|
178
|
+
if (!kind) {
|
|
179
|
+
unsupported.push(file.name);
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
return new Promise((resolve) => {
|
|
183
|
+
const reader = new FileReader();
|
|
184
|
+
reader.onload = () => resolve({ src: String(reader.result), kind, name: file.name, size: file.size });
|
|
185
|
+
reader.onerror = () => {
|
|
186
|
+
unsupported.push(file.name);
|
|
187
|
+
resolve(null);
|
|
188
|
+
};
|
|
189
|
+
reader.readAsDataURL(file);
|
|
190
|
+
});
|
|
191
|
+
}));
|
|
192
|
+
return { media: read.filter((m) => m !== null), unsupported };
|
|
193
|
+
}
|
|
194
|
+
/** "Replaced 2 images with clip.wav.", or `null` when nothing was replaced. */
|
|
195
|
+
export function replacedNote(before, after) {
|
|
196
|
+
const removed = before.filter((a) => !after.some((n) => n.id === a.id));
|
|
197
|
+
const added = after.filter((n) => !before.some((a) => a.id === n.id));
|
|
198
|
+
if (removed.length === 0 || added.length === 0)
|
|
199
|
+
return null;
|
|
200
|
+
const name = (a) => a.name ?? MEDIA_KIND_LABEL[a.kind].toLowerCase();
|
|
201
|
+
const describe = (list) => list.length === 1 ? name(list[0]) : `${list.length} ${MEDIA_KIND_LABEL[list[0].kind].toLowerCase()}s`;
|
|
202
|
+
return `Replaced ${describe(removed)} with ${describe(added)}.`;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* The "Select model" menu's sections: once a kind is attached, only its
|
|
206
|
+
* models (falling back to `models`); before that, all three kinds, each
|
|
207
|
+
* under its own header.
|
|
208
|
+
*/
|
|
209
|
+
export function mediaAnalyzerModelSections(kind, modelsByKind, models) {
|
|
210
|
+
const options = (list = []) => list.map((m) => ({ id: m.id, label: m.label }));
|
|
211
|
+
return kind
|
|
212
|
+
? [{ label: MEDIA_KIND_LABEL[kind], options: options(modelsByKind[kind] ?? models) }]
|
|
213
|
+
: ["image", "video", "audio"].map((k) => ({ label: MEDIA_KIND_LABEL[k], options: options(modelsByKind[k]) }));
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=media-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-analyzer.js","sourceRoot":"","sources":["../src/media-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { GenerationEngine } from "./engine.js";
|
|
2
|
+
import type { DroppedMedia, MediaKind } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* The suggested reasoning model for text and images: prompt enhancement,
|
|
5
|
+
* auto-select routing and image analysis. A default, not a requirement —
|
|
6
|
+
* pass any model id `reasoningEngine` can run.
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_REASONING_MODEL = "anthropic/claude-opus-5";
|
|
9
|
+
/**
|
|
10
|
+
* Suggested per-kind overrides for media Claude can't read. Gemini takes
|
|
11
|
+
* video and audio directly. For a cheaper option, swap in
|
|
12
|
+
* `"qwen/qwen3.8-omni-flash"`, which takes both too.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DEFAULT_REASONING_MODEL_BY_KIND: Partial<Record<MediaKind, string>>;
|
|
15
|
+
/** The reasoning engine and models every CHAI component shares. */
|
|
16
|
+
export interface Reasoning {
|
|
17
|
+
engine: GenerationEngine;
|
|
18
|
+
/** The model for text and any attachment kind without its own entry in `modelByKind`. */
|
|
19
|
+
model: string;
|
|
20
|
+
modelByKind: Partial<Record<MediaKind, string>>;
|
|
21
|
+
}
|
|
22
|
+
/** What a `ChaiProvider` takes, in any framework. */
|
|
23
|
+
export interface ReasoningConfig {
|
|
24
|
+
/** Text, image and routing model. Defaults to `DEFAULT_REASONING_MODEL`. */
|
|
25
|
+
reasoningModel?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Per-attachment-kind models, merged over `DEFAULT_REASONING_MODEL_BY_KIND`
|
|
28
|
+
* one kind at a time, e.g. `{ video: "qwen/qwen3.8-omni-flash" }` keeps
|
|
29
|
+
* the default for audio. Map a kind to `reasoningModel`'s value to use
|
|
30
|
+
* one model for everything.
|
|
31
|
+
*/
|
|
32
|
+
reasoningModelByKind?: Partial<Record<MediaKind, string>>;
|
|
33
|
+
/**
|
|
34
|
+
* The engine the reasoning models run on. Defaults to OpenRouter,
|
|
35
|
+
* independent of the generation engine: Fal's own LLM access is an
|
|
36
|
+
* OpenRouter proxy, so defaulting to it would double-proxy.
|
|
37
|
+
*/
|
|
38
|
+
reasoningEngine?: GenerationEngine;
|
|
39
|
+
}
|
|
40
|
+
/** A provider's `Reasoning`, from its config and the engine it holds (`config.reasoningEngine`, else one OpenRouter engine it created once). */
|
|
41
|
+
export declare function createReasoning(config: ReasoningConfig, engine: GenerationEngine): Reasoning;
|
|
42
|
+
/** The reasoning engine a provider uses: the one passed, else OpenRouter's. */
|
|
43
|
+
export declare function reasoningEngineFor(config: ReasoningConfig): GenerationEngine;
|
|
44
|
+
/**
|
|
45
|
+
* A hook's or composable's own pair wins, but only as a pair: half of one
|
|
46
|
+
* never mixes with half of the provider's (e.g. a hook engine with the
|
|
47
|
+
* provider's model). Half a pair means no reasoning.
|
|
48
|
+
*/
|
|
49
|
+
export declare function pickReasoning(own: {
|
|
50
|
+
reasoningEngine?: GenerationEngine;
|
|
51
|
+
reasoningModel?: string;
|
|
52
|
+
}, provided: Reasoning | undefined): Reasoning | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* The reasoning model for a call with these attachments: the first
|
|
55
|
+
* attachment whose kind has its own model wins (a clip plus a still goes
|
|
56
|
+
* to the model that can read the clip), else `reasoning.model`.
|
|
57
|
+
*/
|
|
58
|
+
export declare function reasoningModelFor(reasoning: Reasoning, attachments?: DroppedMedia[]): string;
|
|
59
|
+
//# sourceMappingURL=reasoning.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoning.d.ts","sourceRoot":"","sources":["../src/reasoning.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE1D;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AAEjE;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAG9E,CAAC;AAEF,mEAAmE;AACnE,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,gBAAgB,CAAC;IACzB,yFAAyF;IACzF,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;CACjD;AAED,qDAAqD;AACrD,MAAM,WAAW,eAAe;IAC9B,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D;;;;OAIG;IACH,eAAe,CAAC,EAAE,gBAAgB,CAAC;CACpC;AAED,gJAAgJ;AAChJ,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAQ5F;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,gBAAgB,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE;IAAE,eAAe,CAAC,EAAE,gBAAgB,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,EACpE,QAAQ,EAAE,SAAS,GAAG,SAAS,GAC9B,SAAS,GAAG,SAAS,CAIvB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,GAAE,YAAY,EAAO,GAAG,MAAM,CAMhG"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createOpenRouterEngine } from "./engines/openrouter.js";
|
|
2
|
+
/**
|
|
3
|
+
* The suggested reasoning model for text and images: prompt enhancement,
|
|
4
|
+
* auto-select routing and image analysis. A default, not a requirement —
|
|
5
|
+
* pass any model id `reasoningEngine` can run.
|
|
6
|
+
*/
|
|
7
|
+
export const DEFAULT_REASONING_MODEL = "anthropic/claude-opus-5";
|
|
8
|
+
/**
|
|
9
|
+
* Suggested per-kind overrides for media Claude can't read. Gemini takes
|
|
10
|
+
* video and audio directly. For a cheaper option, swap in
|
|
11
|
+
* `"qwen/qwen3.8-omni-flash"`, which takes both too.
|
|
12
|
+
*/
|
|
13
|
+
export const DEFAULT_REASONING_MODEL_BY_KIND = {
|
|
14
|
+
video: "google/gemini-3.8-flash",
|
|
15
|
+
audio: "google/gemini-3.8-flash",
|
|
16
|
+
};
|
|
17
|
+
/** A provider's `Reasoning`, from its config and the engine it holds (`config.reasoningEngine`, else one OpenRouter engine it created once). */
|
|
18
|
+
export function createReasoning(config, engine) {
|
|
19
|
+
const byKind = config.reasoningModelByKind ?? {};
|
|
20
|
+
const overrides = Object.fromEntries(Object.entries(byKind).filter(([, v]) => v !== undefined));
|
|
21
|
+
return {
|
|
22
|
+
engine,
|
|
23
|
+
model: config.reasoningModel ?? DEFAULT_REASONING_MODEL,
|
|
24
|
+
modelByKind: { ...DEFAULT_REASONING_MODEL_BY_KIND, ...overrides },
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** The reasoning engine a provider uses: the one passed, else OpenRouter's. */
|
|
28
|
+
export function reasoningEngineFor(config) {
|
|
29
|
+
return config.reasoningEngine ?? createOpenRouterEngine();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A hook's or composable's own pair wins, but only as a pair: half of one
|
|
33
|
+
* never mixes with half of the provider's (e.g. a hook engine with the
|
|
34
|
+
* provider's model). Half a pair means no reasoning.
|
|
35
|
+
*/
|
|
36
|
+
export function pickReasoning(own, provided) {
|
|
37
|
+
const { reasoningEngine, reasoningModel } = own;
|
|
38
|
+
if (!reasoningEngine && !reasoningModel)
|
|
39
|
+
return provided;
|
|
40
|
+
return reasoningEngine && reasoningModel ? { engine: reasoningEngine, model: reasoningModel, modelByKind: {} } : undefined;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The reasoning model for a call with these attachments: the first
|
|
44
|
+
* attachment whose kind has its own model wins (a clip plus a still goes
|
|
45
|
+
* to the model that can read the clip), else `reasoning.model`.
|
|
46
|
+
*/
|
|
47
|
+
export function reasoningModelFor(reasoning, attachments = []) {
|
|
48
|
+
for (const { kind } of attachments) {
|
|
49
|
+
const model = reasoning.modelByKind[kind];
|
|
50
|
+
if (model)
|
|
51
|
+
return model;
|
|
52
|
+
}
|
|
53
|
+
return reasoning.model;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=reasoning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoning.js","sourceRoot":"","sources":["../src/reasoning.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAIjE;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAEjE;;;;GAIG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAuC;IACjF,KAAK,EAAE,yBAAyB;IAChC,KAAK,EAAE,yBAAyB;CACjC,CAAC;AA6BF,gJAAgJ;AAChJ,MAAM,UAAU,eAAe,CAAC,MAAuB,EAAE,MAAwB;IAC/E,MAAM,MAAM,GAAG,MAAM,CAAC,oBAAoB,IAAI,EAAE,CAAC;IACjD,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC;IAChG,OAAO;QACL,MAAM;QACN,KAAK,EAAE,MAAM,CAAC,cAAc,IAAI,uBAAuB;QACvD,WAAW,EAAE,EAAE,GAAG,+BAA+B,EAAE,GAAG,SAAS,EAAE;KAClE,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,kBAAkB,CAAC,MAAuB;IACxD,OAAO,MAAM,CAAC,eAAe,IAAI,sBAAsB,EAAE,CAAC;AAC5D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAoE,EACpE,QAA+B;IAE/B,MAAM,EAAE,eAAe,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC;IAChD,IAAI,CAAC,eAAe,IAAI,CAAC,cAAc;QAAE,OAAO,QAAQ,CAAC;IACzD,OAAO,eAAe,IAAI,cAAc,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7H,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAoB,EAAE,cAA8B,EAAE;IACtF,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,WAAW,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IACD,OAAO,SAAS,CAAC,KAAK,CAAC;AACzB,CAAC"}
|
package/dist/region-edit.d.ts
CHANGED
|
@@ -47,4 +47,6 @@ export declare function buildRegionEditPrompt({ prompt, regions, format, }: {
|
|
|
47
47
|
regions: EditRegion[];
|
|
48
48
|
format?: RegionFormat;
|
|
49
49
|
}): string;
|
|
50
|
+
/** The color token for a region number. Numbers past the last color start over at the first. */
|
|
51
|
+
export declare function regionColor(number: number): string;
|
|
50
52
|
//# sourceMappingURL=region-edit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"region-edit.d.ts","sourceRoot":"","sources":["../src/region-edit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,iHAAiH;AACjH,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,gEAAgE;AAChE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,kHAAkH;IAClH,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,EAS5C,CAAC;AAmBF;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,OAAO,EACP,MAAe,GAChB,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,MAAM,CA8BT"}
|
|
1
|
+
{"version":3,"file":"region-edit.d.ts","sourceRoot":"","sources":["../src/region-edit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,iHAAiH;AACjH,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,gEAAgE;AAChE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,kHAAkH;IAClH,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,EAS5C,CAAC;AAmBF;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,OAAO,EACP,MAAe,GAChB,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,MAAM,CA8BT;AAKD,gGAAgG;AAChG,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElD"}
|
package/dist/region-edit.js
CHANGED
|
@@ -75,4 +75,10 @@ export function buildRegionEditPrompt({ prompt, regions, format = "text", }) {
|
|
|
75
75
|
.filter(Boolean)
|
|
76
76
|
.join(" ");
|
|
77
77
|
}
|
|
78
|
+
/** How many region colors the tokens define (`--chai-color-semantic-region-1` to `-6`). */
|
|
79
|
+
const REGION_COLOR_COUNT = 6;
|
|
80
|
+
/** The color token for a region number. Numbers past the last color start over at the first. */
|
|
81
|
+
export function regionColor(number) {
|
|
82
|
+
return `var(--chai-color-semantic-region-${((Math.max(1, number) - 1) % REGION_COLOR_COUNT) + 1})`;
|
|
83
|
+
}
|
|
78
84
|
//# sourceMappingURL=region-edit.js.map
|
package/dist/region-edit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"region-edit.js","sourceRoot":"","sources":["../src/region-edit.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"region-edit.js","sourceRoot":"","sources":["../src/region-edit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** How `ResultCard` shows a result's details, the same in every framework binding. */
|
|
2
|
+
import { type Result } from "./run.js";
|
|
3
|
+
import type { ModelOption } from "./types.js";
|
|
4
|
+
export declare function formatDuration(ms: number | undefined): string | undefined;
|
|
5
|
+
export declare function formatCost(usd: number | undefined): string | undefined;
|
|
6
|
+
export declare function formatTokens(total: number | undefined): string | undefined;
|
|
7
|
+
/** A real, exactly-reduced ratio (e.g. 1024×768 → "4:3", 1920×1080 → "16:9") from the media's own measured dimensions — not a guess at the nearest "named" ratio, so an unusual crop just shows its own honest (if less familiar) reduced fraction instead of a misleading rounded one. */
|
|
8
|
+
export declare function formatAspectRatio(width: number, height: number): string | undefined;
|
|
9
|
+
/** The model's label from `models`, falling back to its raw id; "Choosing model…" while auto-select is still picking. */
|
|
10
|
+
export declare function resultModelLabel(result: Result, models?: ModelOption[]): string;
|
|
11
|
+
//# sourceMappingURL=result-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-format.d.ts","sourceRoot":"","sources":["../src/result-format.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,OAAO,EAAoB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAEzE;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAEtE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAE1E;AAMD,2RAA2R;AAC3R,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMnF;AAED,yHAAyH;AACzH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,GAAG,MAAM,CAG/E"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** How `ResultCard` shows a result's details, the same in every framework binding. */
|
|
2
|
+
import { ROUTING_MODEL_ID } from "./run.js";
|
|
3
|
+
export function formatDuration(ms) {
|
|
4
|
+
return ms == null ? undefined : `${(ms / 1000).toFixed(2)}s`;
|
|
5
|
+
}
|
|
6
|
+
export function formatCost(usd) {
|
|
7
|
+
return usd == null ? undefined : `$${usd.toFixed(2)}`;
|
|
8
|
+
}
|
|
9
|
+
export function formatTokens(total) {
|
|
10
|
+
return total == null ? undefined : `${total.toLocaleString()} tokens`;
|
|
11
|
+
}
|
|
12
|
+
function gcd(a, b) {
|
|
13
|
+
return b === 0 ? a : gcd(b, a % b);
|
|
14
|
+
}
|
|
15
|
+
/** A real, exactly-reduced ratio (e.g. 1024×768 → "4:3", 1920×1080 → "16:9") from the media's own measured dimensions — not a guess at the nearest "named" ratio, so an unusual crop just shows its own honest (if less familiar) reduced fraction instead of a misleading rounded one. */
|
|
16
|
+
export function formatAspectRatio(width, height) {
|
|
17
|
+
if (!width || !height)
|
|
18
|
+
return undefined;
|
|
19
|
+
const w = Math.round(width);
|
|
20
|
+
const h = Math.round(height);
|
|
21
|
+
const divisor = gcd(w, h);
|
|
22
|
+
return `${w / divisor}:${h / divisor}`;
|
|
23
|
+
}
|
|
24
|
+
/** The model's label from `models`, falling back to its raw id; "Choosing model…" while auto-select is still picking. */
|
|
25
|
+
export function resultModelLabel(result, models) {
|
|
26
|
+
if (result.modelId === ROUTING_MODEL_ID)
|
|
27
|
+
return "Choosing model…";
|
|
28
|
+
return models?.find((m) => m.id === result.modelId)?.label ?? result.modelId;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=result-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-format.js","sourceRoot":"","sources":["../src/result-format.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,OAAO,EAAE,gBAAgB,EAAe,MAAM,UAAU,CAAC;AAGzD,MAAM,UAAU,cAAc,CAAC,EAAsB;IACnD,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAuB;IAChD,OAAO,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAyB;IACpD,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,cAAc,EAAE,SAAS,CAAC;AACxE,CAAC;AAED,SAAS,GAAG,CAAC,CAAS,EAAE,CAAS;IAC/B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,2RAA2R;AAC3R,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,MAAc;IAC7D,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1B,OAAO,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG,OAAO,EAAE,CAAC;AACzC,CAAC;AAED,yHAAyH;AACzH,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,MAAsB;IACrE,IAAI,MAAM,CAAC,OAAO,KAAK,gBAAgB;QAAE,OAAO,iBAAiB,CAAC;IAClE,OAAO,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unique-id.d.ts","sourceRoot":"","sources":["../src/unique-id.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,wBAAgB,QAAQ,IAAI,MAAM,CAIjC"}
|