@decartai/sdk 0.1.22 → 0.2.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/files/client.d.ts +6 -0
- package/dist/files/client.js +9 -2
- package/dist/files/types.d.ts +6 -0
- package/dist/package.js +1 -1
- package/dist/process/types.d.ts +1 -1
- package/dist/realtime/config-realtime.js +21 -6
- package/dist/realtime/media-channel.js +37 -2
- package/dist/realtime/methods.js +4 -1
- package/dist/realtime/observability/connection-quality.js +2 -1
- package/dist/shared/model.d.ts +3 -58
- package/dist/shared/model.js +1 -81
- package/dist/utils/media.js +16 -0
- package/package.json +1 -1
package/dist/files/client.d.ts
CHANGED
|
@@ -27,6 +27,12 @@ type FilesClient = {
|
|
|
27
27
|
*/
|
|
28
28
|
upload: (file: FileUploadInput, options?: UploadFileOptions) => Promise<FileReference>;
|
|
29
29
|
get: (fileId: string) => Promise<FileReference>;
|
|
30
|
+
/**
|
|
31
|
+
* Look up an upload by the MD5 of its bytes when you no longer have the id.
|
|
32
|
+
* Resolves the newest non-expired match; rejects with `FILES_GET_ERROR` on
|
|
33
|
+
* 404, exactly like `get` does for an unknown id.
|
|
34
|
+
*/
|
|
35
|
+
getByMd5: (md5: string) => Promise<FileReference>;
|
|
30
36
|
delete: (fileId: string) => Promise<void>;
|
|
31
37
|
};
|
|
32
38
|
//#endregion
|
package/dist/files/client.js
CHANGED
|
@@ -4,6 +4,7 @@ import { z } from "zod";
|
|
|
4
4
|
//#region src/files/client.ts
|
|
5
5
|
const MAX_TTL_SECONDS = 720 * 60 * 60;
|
|
6
6
|
const ttlSecondsSchema = z.union([z.number().int().min(60).max(MAX_TTL_SECONDS), z.literal("persistent")]);
|
|
7
|
+
const MD5_HEX = /^[0-9a-f]{32}$/i;
|
|
7
8
|
const createFilesClient = (opts) => {
|
|
8
9
|
const { baseUrl, apiKey, integration } = opts;
|
|
9
10
|
const upload = async (file, options) => {
|
|
@@ -28,8 +29,8 @@ const createFilesClient = (opts) => {
|
|
|
28
29
|
}
|
|
29
30
|
return response.json();
|
|
30
31
|
};
|
|
31
|
-
const
|
|
32
|
-
const response = await fetch(`${baseUrl}
|
|
32
|
+
const fetchReference = async (path) => {
|
|
33
|
+
const response = await fetch(`${baseUrl}${path}`, {
|
|
33
34
|
method: "GET",
|
|
34
35
|
headers: buildAuthHeaders({
|
|
35
36
|
apiKey,
|
|
@@ -42,6 +43,11 @@ const createFilesClient = (opts) => {
|
|
|
42
43
|
}
|
|
43
44
|
return response.json();
|
|
44
45
|
};
|
|
46
|
+
const get = (fileId) => fetchReference(`/v1/files/${encodeURIComponent(fileId)}`);
|
|
47
|
+
const getByMd5 = async (md5) => {
|
|
48
|
+
if (!MD5_HEX.test(md5)) throw createInvalidInputError("md5 must be 32 hex characters");
|
|
49
|
+
return fetchReference(`/v1/files/by-md5/${md5.toLowerCase()}`);
|
|
50
|
+
};
|
|
45
51
|
const deleteFile = async (fileId) => {
|
|
46
52
|
const response = await fetch(`${baseUrl}/v1/files/${encodeURIComponent(fileId)}`, {
|
|
47
53
|
method: "DELETE",
|
|
@@ -58,6 +64,7 @@ const createFilesClient = (opts) => {
|
|
|
58
64
|
return {
|
|
59
65
|
upload,
|
|
60
66
|
get,
|
|
67
|
+
getByMd5,
|
|
61
68
|
delete: deleteFile
|
|
62
69
|
};
|
|
63
70
|
};
|
package/dist/files/types.d.ts
CHANGED
|
@@ -14,6 +14,12 @@ interface FileReference {
|
|
|
14
14
|
filename: string | null;
|
|
15
15
|
mime_type: string;
|
|
16
16
|
size_bytes: number;
|
|
17
|
+
/**
|
|
18
|
+
* Lowercase hex MD5 of the uploaded bytes; pass it to `client.files.getByMd5(...)`
|
|
19
|
+
* to find this file again without its id. `null` on files uploaded before
|
|
20
|
+
* hashes were recorded.
|
|
21
|
+
*/
|
|
22
|
+
md5: string | null;
|
|
17
23
|
created_at: string;
|
|
18
24
|
expires_at: string | null;
|
|
19
25
|
}
|
package/dist/package.js
CHANGED
package/dist/process/types.d.ts
CHANGED
|
@@ -143,7 +143,7 @@ interface PromptInput {
|
|
|
143
143
|
* This allows different models to have field-specific documentation while maintaining type safety.
|
|
144
144
|
* Specific models are checked first, then falls back to category-based selection.
|
|
145
145
|
*/
|
|
146
|
-
type ModelSpecificInputs<T extends ModelDefinition> = T["name"] extends "lucy-pro-i2i" | "lucy-image-2" ? ImageEditingInputs : T["name"] extends "lucy-restyle-v2v" | "lucy-restyle-2" ? VideoRestyleInputs : T["name"] extends "lucy-2.1" | "lucy-2.5" | "lucy-vton-
|
|
146
|
+
type ModelSpecificInputs<T extends ModelDefinition> = T["name"] extends "lucy-pro-i2i" | "lucy-image-2" ? ImageEditingInputs : T["name"] extends "lucy-restyle-v2v" | "lucy-restyle-2" ? VideoRestyleInputs : T["name"] extends "lucy-2.1" | "lucy-2.5" | "lucy-vton-3.5" | "lucy-vton-latest" ? VideoEdit2Inputs : T["name"] extends "lucy-pro-v2v" | "lucy-clip" ? VideoEditInputs : T["name"] extends ImageModels ? ImageGenerationInputs : T["name"] extends VideoModels ? VideoModelInputs : PromptInput;
|
|
147
147
|
interface ProcessInputs {
|
|
148
148
|
/**
|
|
149
149
|
* Random seed for reproducible results.
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
//#region src/realtime/config-realtime.ts
|
|
2
|
+
/** Publish bitrate floor for the primary video layer (bps). */
|
|
3
|
+
const MIN_VIDEO_BITRATE_BPS = 11e5;
|
|
4
|
+
/** Publish bitrate cap for the primary video layer (bps). */
|
|
5
|
+
const MAX_VIDEO_BITRATE_BPS = 35e5;
|
|
6
|
+
/** Combined max bitrate of livekit-client's default lower simulcast layers (bps); pinned by a unit test. */
|
|
7
|
+
const SIMULCAST_LOWER_LAYERS_BPS = 61e4;
|
|
8
|
+
/** Fraction of the bandwidth estimate available to the video encoders. */
|
|
9
|
+
const BWE_VIDEO_SHARE = .8;
|
|
10
|
+
/** Bandwidth estimate (kbps) needed for the primary layer to reach `primaryBps`. */
|
|
11
|
+
function estimateKbpsFor(primaryBps) {
|
|
12
|
+
return Math.round((primaryBps + SIMULCAST_LOWER_LAYERS_BPS) / BWE_VIDEO_SHARE / 1e3);
|
|
13
|
+
}
|
|
2
14
|
const REALTIME_CONFIG = {
|
|
3
15
|
signaling: {
|
|
4
16
|
connectTimeoutMs: 6e4,
|
|
@@ -34,8 +46,12 @@ const REALTIME_CONFIG = {
|
|
|
34
46
|
dynacast: false
|
|
35
47
|
},
|
|
36
48
|
defaultVideoCodec: "h264",
|
|
37
|
-
defaultMaxVideoBitrateBps:
|
|
49
|
+
defaultMaxVideoBitrateBps: MAX_VIDEO_BITRATE_BPS,
|
|
38
50
|
vp9MaxVideoBitrateBps: 3e6,
|
|
51
|
+
/** Seeds the publisher's bandwidth estimate (a start bitrate, not a minimum). */
|
|
52
|
+
minVideoBitrateBps: MIN_VIDEO_BITRATE_BPS,
|
|
53
|
+
simulcastLowerLayersBitrateBps: SIMULCAST_LOWER_LAYERS_BPS,
|
|
54
|
+
bweVideoShare: BWE_VIDEO_SHARE,
|
|
39
55
|
defaultPublishFps: 30
|
|
40
56
|
},
|
|
41
57
|
observability: {
|
|
@@ -109,12 +125,11 @@ const REALTIME_CONFIG = {
|
|
|
109
125
|
fair: .01,
|
|
110
126
|
poor: .05
|
|
111
127
|
},
|
|
112
|
-
/**
|
|
128
|
+
/** Available upstream bandwidth bands (kbps). Chromium-only. */
|
|
113
129
|
upstream: {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
requiredUpstreamKbps: 3500
|
|
130
|
+
goodKbps: estimateKbpsFor(MAX_VIDEO_BITRATE_BPS),
|
|
131
|
+
fairKbps: estimateKbpsFor(MIN_VIDEO_BITRATE_BPS),
|
|
132
|
+
poorKbps: estimateKbpsFor(MIN_VIDEO_BITRATE_BPS / 2)
|
|
118
133
|
},
|
|
119
134
|
/** Rendered (inbound) frames-per-second. */
|
|
120
135
|
stall: {
|
|
@@ -3,13 +3,32 @@ import { REALTIME_CONFIG } from "./config-realtime.js";
|
|
|
3
3
|
import { loadLiveKitClient } from "./livekit.js";
|
|
4
4
|
import mitt from "mitt";
|
|
5
5
|
//#region src/realtime/media-channel.ts
|
|
6
|
+
const START_BITRATE_PARAM = "x-google-start-bitrate";
|
|
7
|
+
/** Add `x-google-start-bitrate=<kbps>` to every video codec's fmtp line; libwebrtc reads it from the remote description. */
|
|
8
|
+
function withVideoStartBitrate(sdp, kbps) {
|
|
9
|
+
const param = `${START_BITRATE_PARAM}=${kbps}`;
|
|
10
|
+
return sdp.split(/(?=^m=)/m).map((section) => {
|
|
11
|
+
if (!section.startsWith("m=video")) return section;
|
|
12
|
+
const withFmtp = new Set(Array.from(section.matchAll(/^a=fmtp:(\d+) /gm), (m) => m[1]));
|
|
13
|
+
return section.replace(/^a=fmtp:\d+ [^\r\n]*/gm, (line) => line.includes(START_BITRATE_PARAM) ? line : `${line};${param}`).replace(/^a=rtpmap:(\d+) (?!rtx|red|ulpfec|flexfec)[^\r\n]*(\r?\n)/gim, (line, pt, eol) => withFmtp.has(pt) ? line : `${line}a=fmtp:${pt} ${param}${eol}`);
|
|
14
|
+
}).join("");
|
|
15
|
+
}
|
|
16
|
+
function usesSimulcast(videoCodec) {
|
|
17
|
+
return (videoCodec ?? REALTIME_CONFIG.livekit.defaultVideoCodec) !== "vp9";
|
|
18
|
+
}
|
|
19
|
+
/** Bandwidth-estimator seed (kbps) for the publisher. */
|
|
20
|
+
function getVideoStartBitrateKbps(videoCodec) {
|
|
21
|
+
const { minVideoBitrateBps, simulcastLowerLayersBitrateBps, bweVideoShare } = REALTIME_CONFIG.livekit;
|
|
22
|
+
const lowerLayers = usesSimulcast(videoCodec) ? simulcastLowerLayersBitrateBps : 0;
|
|
23
|
+
return Math.round((minVideoBitrateBps + lowerLayers) / bweVideoShare / 1e3);
|
|
24
|
+
}
|
|
6
25
|
function getDefaultVideoPublishOptions(source, videoCodec, frameMetadata = false) {
|
|
7
26
|
const resolvedCodec = videoCodec ?? REALTIME_CONFIG.livekit.defaultVideoCodec;
|
|
8
27
|
const maxBitrate = resolvedCodec === "vp9" ? REALTIME_CONFIG.livekit.vp9MaxVideoBitrateBps : REALTIME_CONFIG.livekit.defaultMaxVideoBitrateBps;
|
|
9
28
|
return {
|
|
10
29
|
source,
|
|
11
30
|
videoCodec: resolvedCodec,
|
|
12
|
-
simulcast: resolvedCodec
|
|
31
|
+
simulcast: usesSimulcast(resolvedCodec),
|
|
13
32
|
videoEncoding: {
|
|
14
33
|
maxBitrate,
|
|
15
34
|
maxFramerate: REALTIME_CONFIG.livekit.defaultPublishFps
|
|
@@ -82,6 +101,7 @@ var LiveKitMediaChannel = class {
|
|
|
82
101
|
this.config.observability?.startPhase("webrtc-handshake");
|
|
83
102
|
await room.connect(opts.url, opts.token);
|
|
84
103
|
this.config.observability?.endPhase("webrtc-handshake", { success: true });
|
|
104
|
+
this.seedStartBitrate(room);
|
|
85
105
|
this.config.observability?.setLiveKitRoom(room);
|
|
86
106
|
}
|
|
87
107
|
async publishLocalTracks() {
|
|
@@ -106,6 +126,21 @@ var LiveKitMediaChannel = class {
|
|
|
106
126
|
this.config.observability?.setLiveKitRoom(null);
|
|
107
127
|
if (room) room.disconnect().catch(() => {});
|
|
108
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* livekit-client has no start-bitrate option for H264/VP8, so seed the estimator through the
|
|
131
|
+
* SFU answer. Installed once per room: if livekit-client itself performs a full reconnect it
|
|
132
|
+
* creates a new publisher transport, and the rest of that session ramps from the default.
|
|
133
|
+
*/
|
|
134
|
+
seedStartBitrate(room) {
|
|
135
|
+
const publisher = room.engine?.pcManager?.publisher;
|
|
136
|
+
const original = publisher?.setRemoteDescription;
|
|
137
|
+
if (!publisher || typeof original !== "function") return;
|
|
138
|
+
const kbps = getVideoStartBitrateKbps(this.config.videoCodec);
|
|
139
|
+
publisher.setRemoteDescription = (sd, offerId) => original.call(publisher, sd.type === "answer" && sd.sdp ? {
|
|
140
|
+
type: sd.type,
|
|
141
|
+
sdp: withVideoStartBitrate(sd.sdp, kbps)
|
|
142
|
+
} : sd, offerId);
|
|
143
|
+
}
|
|
109
144
|
async publishTracks(stream) {
|
|
110
145
|
if (!this.room) return;
|
|
111
146
|
for (const track of stream.getTracks()) if (track.kind === "video") {
|
|
@@ -116,4 +151,4 @@ var LiveKitMediaChannel = class {
|
|
|
116
151
|
};
|
|
117
152
|
const createLiveKitMediaChannel = (config) => new LiveKitMediaChannel(config);
|
|
118
153
|
//#endregion
|
|
119
|
-
export { LiveKitMediaChannel, createLiveKitMediaChannel, getDefaultVideoPublishOptions };
|
|
154
|
+
export { LiveKitMediaChannel, createLiveKitMediaChannel, getDefaultVideoPublishOptions, getVideoStartBitrateKbps, withVideoStartBitrate };
|
package/dist/realtime/methods.js
CHANGED
|
@@ -7,7 +7,10 @@ const setInputSchema = z.object({
|
|
|
7
7
|
prompt: z.string().min(1).optional(),
|
|
8
8
|
enhance: z.boolean().optional().default(true),
|
|
9
9
|
/**
|
|
10
|
-
* - `Blob`/`File`/data:/
|
|
10
|
+
* - `Blob`/`File`/data:/base64 string: bytes traverse the wire as base64.
|
|
11
|
+
* - `http(s):` URL: fetched, then sent as base64. Browser-oriented — the fetch
|
|
12
|
+
* relies on the same-origin policy. Server-side, pass bytes rather than a
|
|
13
|
+
* caller-supplied URL (fetching an arbitrary URL from a server is an SSRF risk).
|
|
11
14
|
* - `"file_..."` id (from `client.files.upload(...).id`): sent as a server-side reference.
|
|
12
15
|
*/
|
|
13
16
|
image: z.union([
|
|
@@ -47,7 +47,8 @@ function scoreMetrics(signals, thresholds, options = {}) {
|
|
|
47
47
|
const loss = scoreLowerBetter(signals.fractionLost, thresholds.loss.good, thresholds.loss.fair, thresholds.loss.poor);
|
|
48
48
|
let bandwidth = "good";
|
|
49
49
|
if (!options.skipBitrate) {
|
|
50
|
-
|
|
50
|
+
const { goodKbps, fairKbps, poorKbps } = thresholds.upstream;
|
|
51
|
+
bandwidth = scoreHigherBetter(signals.availableOutgoingKbps, goodKbps, fairKbps, poorKbps);
|
|
51
52
|
if (signals.qualityLimitationReason === "bandwidth") bandwidth = worst(bandwidth, "fair");
|
|
52
53
|
}
|
|
53
54
|
let stall = scoreHigherBetter(signals.fps, thresholds.stall.goodFps, thresholds.stall.fairFps, thresholds.stall.poorFps);
|
package/dist/shared/model.d.ts
CHANGED
|
@@ -5,8 +5,6 @@ import { z } from "zod";
|
|
|
5
5
|
declare const canonicalModelSchema: z.ZodEnum<{
|
|
6
6
|
"lucy-2.1": "lucy-2.1";
|
|
7
7
|
"lucy-2.5": "lucy-2.5";
|
|
8
|
-
"lucy-vton-2": "lucy-vton-2";
|
|
9
|
-
"lucy-vton-3": "lucy-vton-3";
|
|
10
8
|
"lucy-vton-3.5": "lucy-vton-3.5";
|
|
11
9
|
"lucy-restyle-2": "lucy-restyle-2";
|
|
12
10
|
"lucy-clip": "lucy-clip";
|
|
@@ -18,17 +16,16 @@ type CanonicalModel = z.infer<typeof canonicalModelSchema>;
|
|
|
18
16
|
* Old names still work but will log a deprecation warning.
|
|
19
17
|
*/
|
|
20
18
|
declare const modelAliases: {
|
|
21
|
-
readonly "lucy-2.1-vton-2": "lucy-vton-2";
|
|
22
19
|
readonly "lucy-pro-v2v": "lucy-clip";
|
|
23
20
|
readonly "lucy-restyle-v2v": "lucy-restyle-2";
|
|
24
21
|
readonly "lucy-pro-i2i": "lucy-image-2";
|
|
25
22
|
};
|
|
26
23
|
/** @internal Test-only helper to reset deprecation warning tracking */
|
|
27
24
|
|
|
28
|
-
declare const realtimeModels: z.ZodUnion<readonly [z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-
|
|
29
|
-
declare const videoModels: z.ZodUnion<readonly [z.ZodLiteral<"lucy-clip">, z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-
|
|
25
|
+
declare const realtimeModels: z.ZodUnion<readonly [z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-3.5">, z.ZodLiteral<"lucy-restyle-2">, z.ZodLiteral<"lucy-latest">, z.ZodLiteral<"lucy-vton-latest">, z.ZodLiteral<"lucy-restyle-latest">]>;
|
|
26
|
+
declare const videoModels: z.ZodUnion<readonly [z.ZodLiteral<"lucy-clip">, z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-3.5">, z.ZodLiteral<"lucy-restyle-2">, z.ZodLiteral<"lucy-latest">, z.ZodLiteral<"lucy-vton-latest">, z.ZodLiteral<"lucy-restyle-latest">, z.ZodLiteral<"lucy-clip-latest">, z.ZodLiteral<"lucy-pro-v2v">, z.ZodLiteral<"lucy-restyle-v2v">]>;
|
|
30
27
|
declare const imageModels: z.ZodUnion<readonly [z.ZodLiteral<"lucy-image-2">, z.ZodLiteral<"lucy-image-latest">, z.ZodLiteral<"lucy-pro-i2i">]>;
|
|
31
|
-
declare const modelSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-
|
|
28
|
+
declare const modelSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-3.5">, z.ZodLiteral<"lucy-restyle-2">, z.ZodLiteral<"lucy-latest">, z.ZodLiteral<"lucy-vton-latest">, z.ZodLiteral<"lucy-restyle-latest">]>, z.ZodUnion<readonly [z.ZodLiteral<"lucy-clip">, z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-3.5">, z.ZodLiteral<"lucy-restyle-2">, z.ZodLiteral<"lucy-latest">, z.ZodLiteral<"lucy-vton-latest">, z.ZodLiteral<"lucy-restyle-latest">, z.ZodLiteral<"lucy-clip-latest">, z.ZodLiteral<"lucy-pro-v2v">, z.ZodLiteral<"lucy-restyle-v2v">]>, z.ZodUnion<readonly [z.ZodLiteral<"lucy-image-2">, z.ZodLiteral<"lucy-image-latest">, z.ZodLiteral<"lucy-pro-i2i">]>]>;
|
|
32
29
|
type Model = z.infer<typeof modelSchema>;
|
|
33
30
|
type RealTimeModels = z.infer<typeof realtimeModels>;
|
|
34
31
|
type VideoModels = z.infer<typeof videoModels>;
|
|
@@ -134,38 +131,6 @@ declare const modelInputSchemas: {
|
|
|
134
131
|
resolution: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"720p">>>;
|
|
135
132
|
enhance_prompt: z.ZodOptional<z.ZodBoolean>;
|
|
136
133
|
}, z.core.$strip>;
|
|
137
|
-
readonly "lucy-vton-2": z.ZodObject<{
|
|
138
|
-
prompt: z.ZodString;
|
|
139
|
-
reference_image: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<File, unknown, z.core.$ZodTypeInternals<File, unknown>>, z.ZodType<Blob, unknown, z.core.$ZodTypeInternals<Blob, unknown>>, z.ZodType<ReadableStream<any>, unknown, z.core.$ZodTypeInternals<ReadableStream<any>, unknown>>, z.ZodType<URL, unknown, z.core.$ZodTypeInternals<URL, unknown>>, z.ZodURL, z.ZodObject<{
|
|
140
|
-
uri: z.ZodString;
|
|
141
|
-
type: z.ZodString;
|
|
142
|
-
name: z.ZodString;
|
|
143
|
-
}, z.core.$strip>]>>;
|
|
144
|
-
data: z.ZodUnion<readonly [z.ZodType<File, unknown, z.core.$ZodTypeInternals<File, unknown>>, z.ZodType<Blob, unknown, z.core.$ZodTypeInternals<Blob, unknown>>, z.ZodType<ReadableStream<any>, unknown, z.core.$ZodTypeInternals<ReadableStream<any>, unknown>>, z.ZodType<URL, unknown, z.core.$ZodTypeInternals<URL, unknown>>, z.ZodURL, z.ZodObject<{
|
|
145
|
-
uri: z.ZodString;
|
|
146
|
-
type: z.ZodString;
|
|
147
|
-
name: z.ZodString;
|
|
148
|
-
}, z.core.$strip>]>;
|
|
149
|
-
seed: z.ZodOptional<z.ZodNumber>;
|
|
150
|
-
resolution: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"720p">>>;
|
|
151
|
-
enhance_prompt: z.ZodOptional<z.ZodBoolean>;
|
|
152
|
-
}, z.core.$strip>;
|
|
153
|
-
readonly "lucy-vton-3": z.ZodObject<{
|
|
154
|
-
prompt: z.ZodString;
|
|
155
|
-
reference_image: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<File, unknown, z.core.$ZodTypeInternals<File, unknown>>, z.ZodType<Blob, unknown, z.core.$ZodTypeInternals<Blob, unknown>>, z.ZodType<ReadableStream<any>, unknown, z.core.$ZodTypeInternals<ReadableStream<any>, unknown>>, z.ZodType<URL, unknown, z.core.$ZodTypeInternals<URL, unknown>>, z.ZodURL, z.ZodObject<{
|
|
156
|
-
uri: z.ZodString;
|
|
157
|
-
type: z.ZodString;
|
|
158
|
-
name: z.ZodString;
|
|
159
|
-
}, z.core.$strip>]>>;
|
|
160
|
-
data: z.ZodUnion<readonly [z.ZodType<File, unknown, z.core.$ZodTypeInternals<File, unknown>>, z.ZodType<Blob, unknown, z.core.$ZodTypeInternals<Blob, unknown>>, z.ZodType<ReadableStream<any>, unknown, z.core.$ZodTypeInternals<ReadableStream<any>, unknown>>, z.ZodType<URL, unknown, z.core.$ZodTypeInternals<URL, unknown>>, z.ZodURL, z.ZodObject<{
|
|
161
|
-
uri: z.ZodString;
|
|
162
|
-
type: z.ZodString;
|
|
163
|
-
name: z.ZodString;
|
|
164
|
-
}, z.core.$strip>]>;
|
|
165
|
-
seed: z.ZodOptional<z.ZodNumber>;
|
|
166
|
-
resolution: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"720p">>>;
|
|
167
|
-
enhance_prompt: z.ZodOptional<z.ZodBoolean>;
|
|
168
|
-
}, z.core.$strip>;
|
|
169
134
|
readonly "lucy-vton-3.5": z.ZodObject<{
|
|
170
135
|
prompt: z.ZodString;
|
|
171
136
|
reference_image: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<File, unknown, z.core.$ZodTypeInternals<File, unknown>>, z.ZodType<Blob, unknown, z.core.$ZodTypeInternals<Blob, unknown>>, z.ZodType<ReadableStream<any>, unknown, z.core.$ZodTypeInternals<ReadableStream<any>, unknown>>, z.ZodType<URL, unknown, z.core.$ZodTypeInternals<URL, unknown>>, z.ZodURL, z.ZodObject<{
|
|
@@ -265,22 +230,6 @@ declare const modelInputSchemas: {
|
|
|
265
230
|
}>>>;
|
|
266
231
|
enhance_prompt: z.ZodOptional<z.ZodBoolean>;
|
|
267
232
|
}, z.core.$strip>;
|
|
268
|
-
readonly "lucy-2.1-vton-2": z.ZodObject<{
|
|
269
|
-
prompt: z.ZodString;
|
|
270
|
-
reference_image: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<File, unknown, z.core.$ZodTypeInternals<File, unknown>>, z.ZodType<Blob, unknown, z.core.$ZodTypeInternals<Blob, unknown>>, z.ZodType<ReadableStream<any>, unknown, z.core.$ZodTypeInternals<ReadableStream<any>, unknown>>, z.ZodType<URL, unknown, z.core.$ZodTypeInternals<URL, unknown>>, z.ZodURL, z.ZodObject<{
|
|
271
|
-
uri: z.ZodString;
|
|
272
|
-
type: z.ZodString;
|
|
273
|
-
name: z.ZodString;
|
|
274
|
-
}, z.core.$strip>]>>;
|
|
275
|
-
data: z.ZodUnion<readonly [z.ZodType<File, unknown, z.core.$ZodTypeInternals<File, unknown>>, z.ZodType<Blob, unknown, z.core.$ZodTypeInternals<Blob, unknown>>, z.ZodType<ReadableStream<any>, unknown, z.core.$ZodTypeInternals<ReadableStream<any>, unknown>>, z.ZodType<URL, unknown, z.core.$ZodTypeInternals<URL, unknown>>, z.ZodURL, z.ZodObject<{
|
|
276
|
-
uri: z.ZodString;
|
|
277
|
-
type: z.ZodString;
|
|
278
|
-
name: z.ZodString;
|
|
279
|
-
}, z.core.$strip>]>;
|
|
280
|
-
seed: z.ZodOptional<z.ZodNumber>;
|
|
281
|
-
resolution: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"720p">>>;
|
|
282
|
-
enhance_prompt: z.ZodOptional<z.ZodBoolean>;
|
|
283
|
-
}, z.core.$strip>;
|
|
284
233
|
readonly "lucy-pro-v2v": z.ZodObject<{
|
|
285
234
|
prompt: z.ZodString;
|
|
286
235
|
data: z.ZodUnion<readonly [z.ZodType<File, unknown, z.core.$ZodTypeInternals<File, unknown>>, z.ZodType<Blob, unknown, z.core.$ZodTypeInternals<Blob, unknown>>, z.ZodType<ReadableStream<any>, unknown, z.core.$ZodTypeInternals<ReadableStream<any>, unknown>>, z.ZodType<URL, unknown, z.core.$ZodTypeInternals<URL, unknown>>, z.ZodURL, z.ZodObject<{
|
|
@@ -396,8 +345,6 @@ declare const models: {
|
|
|
396
345
|
* Available options:
|
|
397
346
|
* - `"lucy-2.1"` - Lucy 2.1 realtime video editing
|
|
398
347
|
* - `"lucy-2.5"` - Lucy 2.5 realtime video editing
|
|
399
|
-
* - `"lucy-vton-2"` - Lucy virtual try-on 2
|
|
400
|
-
* - `"lucy-vton-3"` - Lucy virtual try-on 3
|
|
401
348
|
* - `"lucy-vton-3.5"` - Lucy virtual try-on 3.5 (latest)
|
|
402
349
|
* - `"lucy-restyle-2"` - Realtime video restyling
|
|
403
350
|
*/
|
|
@@ -409,8 +356,6 @@ declare const models: {
|
|
|
409
356
|
* - `"lucy-clip"` - Video-to-video editing
|
|
410
357
|
* - `"lucy-2.1"` - Long-form video editing (Lucy 2.1)
|
|
411
358
|
* - `"lucy-2.5"` - Long-form video editing (Lucy 2.5)
|
|
412
|
-
* - `"lucy-vton-2"` - Virtual try-on 2 video editing
|
|
413
|
-
* - `"lucy-vton-3"` - Virtual try-on 3 video editing
|
|
414
359
|
* - `"lucy-vton-3.5"` - Virtual try-on 3.5 video editing (latest)
|
|
415
360
|
* - `"lucy-restyle-2"` - Video restyling
|
|
416
361
|
*/
|
package/dist/shared/model.js
CHANGED
|
@@ -5,8 +5,6 @@ import { z } from "zod";
|
|
|
5
5
|
const CANONICAL_MODEL_NAMES = [
|
|
6
6
|
"lucy-2.1",
|
|
7
7
|
"lucy-2.5",
|
|
8
|
-
"lucy-vton-2",
|
|
9
|
-
"lucy-vton-3",
|
|
10
8
|
"lucy-vton-3.5",
|
|
11
9
|
"lucy-restyle-2",
|
|
12
10
|
"lucy-clip",
|
|
@@ -15,8 +13,6 @@ const CANONICAL_MODEL_NAMES = [
|
|
|
15
13
|
const CANONICAL_REALTIME_MODEL_NAMES = [
|
|
16
14
|
"lucy-2.1",
|
|
17
15
|
"lucy-2.5",
|
|
18
|
-
"lucy-vton-2",
|
|
19
|
-
"lucy-vton-3",
|
|
20
16
|
"lucy-vton-3.5",
|
|
21
17
|
"lucy-restyle-2"
|
|
22
18
|
];
|
|
@@ -24,8 +20,6 @@ const CANONICAL_VIDEO_MODEL_NAMES = [
|
|
|
24
20
|
"lucy-clip",
|
|
25
21
|
"lucy-2.1",
|
|
26
22
|
"lucy-2.5",
|
|
27
|
-
"lucy-vton-2",
|
|
28
|
-
"lucy-vton-3",
|
|
29
23
|
"lucy-vton-3.5",
|
|
30
24
|
"lucy-restyle-2"
|
|
31
25
|
];
|
|
@@ -39,7 +33,6 @@ const canonicalModelSchema = z.enum(CANONICAL_MODEL_NAMES);
|
|
|
39
33
|
* Old names still work but will log a deprecation warning.
|
|
40
34
|
*/
|
|
41
35
|
const modelAliases = {
|
|
42
|
-
"lucy-2.1-vton-2": "lucy-vton-2",
|
|
43
36
|
"lucy-pro-v2v": "lucy-clip",
|
|
44
37
|
"lucy-restyle-v2v": "lucy-restyle-2",
|
|
45
38
|
"lucy-pro-i2i": "lucy-image-2"
|
|
@@ -55,28 +48,22 @@ function warnDeprecated(model) {
|
|
|
55
48
|
const realtimeModels = z.union([
|
|
56
49
|
z.literal("lucy-2.1"),
|
|
57
50
|
z.literal("lucy-2.5"),
|
|
58
|
-
z.literal("lucy-vton-2"),
|
|
59
|
-
z.literal("lucy-vton-3"),
|
|
60
51
|
z.literal("lucy-vton-3.5"),
|
|
61
52
|
z.literal("lucy-restyle-2"),
|
|
62
53
|
z.literal("lucy-latest"),
|
|
63
54
|
z.literal("lucy-vton-latest"),
|
|
64
|
-
z.literal("lucy-restyle-latest")
|
|
65
|
-
z.literal("lucy-2.1-vton-2")
|
|
55
|
+
z.literal("lucy-restyle-latest")
|
|
66
56
|
]);
|
|
67
57
|
const videoModels = z.union([
|
|
68
58
|
z.literal("lucy-clip"),
|
|
69
59
|
z.literal("lucy-2.1"),
|
|
70
60
|
z.literal("lucy-2.5"),
|
|
71
|
-
z.literal("lucy-vton-2"),
|
|
72
|
-
z.literal("lucy-vton-3"),
|
|
73
61
|
z.literal("lucy-vton-3.5"),
|
|
74
62
|
z.literal("lucy-restyle-2"),
|
|
75
63
|
z.literal("lucy-latest"),
|
|
76
64
|
z.literal("lucy-vton-latest"),
|
|
77
65
|
z.literal("lucy-restyle-latest"),
|
|
78
66
|
z.literal("lucy-clip-latest"),
|
|
79
|
-
z.literal("lucy-2.1-vton-2"),
|
|
80
67
|
z.literal("lucy-pro-v2v"),
|
|
81
68
|
z.literal("lucy-restyle-v2v")
|
|
82
69
|
]);
|
|
@@ -188,15 +175,12 @@ const modelInputSchemas = {
|
|
|
188
175
|
"lucy-restyle-2": restyleSchema,
|
|
189
176
|
"lucy-2.1": videoEdit2Schema,
|
|
190
177
|
"lucy-2.5": videoEdit2Schema,
|
|
191
|
-
"lucy-vton-2": videoEdit2Schema,
|
|
192
|
-
"lucy-vton-3": videoEdit2Schema,
|
|
193
178
|
"lucy-vton-3.5": videoEdit2Schema,
|
|
194
179
|
"lucy-latest": videoEdit2Schema,
|
|
195
180
|
"lucy-vton-latest": videoEdit2Schema,
|
|
196
181
|
"lucy-restyle-latest": restyleSchema,
|
|
197
182
|
"lucy-clip-latest": videoEditSchema,
|
|
198
183
|
"lucy-image-latest": imageEditSchema,
|
|
199
|
-
"lucy-2.1-vton-2": videoEdit2Schema,
|
|
200
184
|
"lucy-pro-v2v": videoEditSchema,
|
|
201
185
|
"lucy-pro-i2i": imageEditSchema,
|
|
202
186
|
"lucy-restyle-v2v": restyleSchema
|
|
@@ -243,28 +227,6 @@ const _models = {
|
|
|
243
227
|
height: 720,
|
|
244
228
|
inputSchema: z.object({})
|
|
245
229
|
},
|
|
246
|
-
"lucy-vton-2": {
|
|
247
|
-
urlPath: "/v1/stream",
|
|
248
|
-
name: "lucy-vton-2",
|
|
249
|
-
fps: {
|
|
250
|
-
ideal: 30,
|
|
251
|
-
max: 30
|
|
252
|
-
},
|
|
253
|
-
width: 1088,
|
|
254
|
-
height: 624,
|
|
255
|
-
inputSchema: z.object({})
|
|
256
|
-
},
|
|
257
|
-
"lucy-vton-3": {
|
|
258
|
-
urlPath: "/v1/stream",
|
|
259
|
-
name: "lucy-vton-3",
|
|
260
|
-
fps: {
|
|
261
|
-
ideal: 30,
|
|
262
|
-
max: 30
|
|
263
|
-
},
|
|
264
|
-
width: 1088,
|
|
265
|
-
height: 624,
|
|
266
|
-
inputSchema: z.object({})
|
|
267
|
-
},
|
|
268
230
|
"lucy-vton-3.5": {
|
|
269
231
|
urlPath: "/v1/stream",
|
|
270
232
|
name: "lucy-vton-3.5",
|
|
@@ -319,17 +281,6 @@ const _models = {
|
|
|
319
281
|
width: 1280,
|
|
320
282
|
height: 704,
|
|
321
283
|
inputSchema: z.object({})
|
|
322
|
-
},
|
|
323
|
-
"lucy-2.1-vton-2": {
|
|
324
|
-
urlPath: "/v1/stream",
|
|
325
|
-
name: "lucy-2.1-vton-2",
|
|
326
|
-
fps: {
|
|
327
|
-
ideal: 30,
|
|
328
|
-
max: 30
|
|
329
|
-
},
|
|
330
|
-
width: 1088,
|
|
331
|
-
height: 624,
|
|
332
|
-
inputSchema: z.object({})
|
|
333
284
|
}
|
|
334
285
|
},
|
|
335
286
|
image: {
|
|
@@ -389,24 +340,6 @@ const _models = {
|
|
|
389
340
|
height: 720,
|
|
390
341
|
inputSchema: modelInputSchemas["lucy-2.5"]
|
|
391
342
|
},
|
|
392
|
-
"lucy-vton-2": {
|
|
393
|
-
urlPath: "/v1/generate/lucy-vton-2",
|
|
394
|
-
queueUrlPath: "/v1/jobs/lucy-vton-2",
|
|
395
|
-
name: "lucy-vton-2",
|
|
396
|
-
fps: 20,
|
|
397
|
-
width: 1088,
|
|
398
|
-
height: 624,
|
|
399
|
-
inputSchema: modelInputSchemas["lucy-vton-2"]
|
|
400
|
-
},
|
|
401
|
-
"lucy-vton-3": {
|
|
402
|
-
urlPath: "/v1/generate/lucy-vton-3",
|
|
403
|
-
queueUrlPath: "/v1/jobs/lucy-vton-3",
|
|
404
|
-
name: "lucy-vton-3",
|
|
405
|
-
fps: 20,
|
|
406
|
-
width: 1088,
|
|
407
|
-
height: 624,
|
|
408
|
-
inputSchema: modelInputSchemas["lucy-vton-3"]
|
|
409
|
-
},
|
|
410
343
|
"lucy-vton-3.5": {
|
|
411
344
|
urlPath: "/v1/generate/lucy-vton-3.5",
|
|
412
345
|
queueUrlPath: "/v1/jobs/lucy-vton-3.5",
|
|
@@ -461,15 +394,6 @@ const _models = {
|
|
|
461
394
|
height: 704,
|
|
462
395
|
inputSchema: modelInputSchemas["lucy-clip-latest"]
|
|
463
396
|
},
|
|
464
|
-
"lucy-2.1-vton-2": {
|
|
465
|
-
urlPath: "/v1/generate/lucy-2.1-vton-2",
|
|
466
|
-
queueUrlPath: "/v1/jobs/lucy-2.1-vton-2",
|
|
467
|
-
name: "lucy-2.1-vton-2",
|
|
468
|
-
fps: 20,
|
|
469
|
-
width: 1088,
|
|
470
|
-
height: 624,
|
|
471
|
-
inputSchema: modelInputSchemas["lucy-2.1-vton-2"]
|
|
472
|
-
},
|
|
473
397
|
"lucy-pro-v2v": {
|
|
474
398
|
urlPath: "/v1/generate/lucy-pro-v2v",
|
|
475
399
|
queueUrlPath: "/v1/jobs/lucy-pro-v2v",
|
|
@@ -520,8 +444,6 @@ const models = {
|
|
|
520
444
|
* Available options:
|
|
521
445
|
* - `"lucy-2.1"` - Lucy 2.1 realtime video editing
|
|
522
446
|
* - `"lucy-2.5"` - Lucy 2.5 realtime video editing
|
|
523
|
-
* - `"lucy-vton-2"` - Lucy virtual try-on 2
|
|
524
|
-
* - `"lucy-vton-3"` - Lucy virtual try-on 3
|
|
525
447
|
* - `"lucy-vton-3.5"` - Lucy virtual try-on 3.5 (latest)
|
|
526
448
|
* - `"lucy-restyle-2"` - Realtime video restyling
|
|
527
449
|
*/
|
|
@@ -538,8 +460,6 @@ const models = {
|
|
|
538
460
|
* - `"lucy-clip"` - Video-to-video editing
|
|
539
461
|
* - `"lucy-2.1"` - Long-form video editing (Lucy 2.1)
|
|
540
462
|
* - `"lucy-2.5"` - Long-form video editing (Lucy 2.5)
|
|
541
|
-
* - `"lucy-vton-2"` - Virtual try-on 2 video editing
|
|
542
|
-
* - `"lucy-vton-3"` - Virtual try-on 3 video editing
|
|
543
463
|
* - `"lucy-vton-3.5"` - Virtual try-on 3.5 video editing (latest)
|
|
544
464
|
* - `"lucy-restyle-2"` - Video restyling
|
|
545
465
|
*/
|
package/dist/utils/media.js
CHANGED
|
@@ -19,6 +19,21 @@ async function blobToBase64(blob) {
|
|
|
19
19
|
reader.readAsDataURL(blob);
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Normalizes an image input to a raw base64 string (no `data:` prefix).
|
|
24
|
+
*
|
|
25
|
+
* String inputs are interpreted by URL scheme:
|
|
26
|
+
* - `data:` URL — decoded locally.
|
|
27
|
+
* - `http:`/`https:` URL — fetched, then encoded. This is a browser-oriented
|
|
28
|
+
* convenience that leans on the browser's same-origin policy to bound what
|
|
29
|
+
* the fetch can read. Do NOT rely on it server-side (Node/SSR/edge) with a
|
|
30
|
+
* caller-supplied URL: fetching an arbitrary URL from a server is an SSRF
|
|
31
|
+
* vector, and this helper can't distinguish an internal host from an external
|
|
32
|
+
* one. Server-side callers should pass binary (`Blob`/`File`) instead.
|
|
33
|
+
* - any other string that parses as a URL (e.g. `file:`, `blob:`, `ftp:`) — a
|
|
34
|
+
* clear error, rather than being forwarded to the API as if it were base64.
|
|
35
|
+
* - a string that isn't a URL — assumed to already be raw base64.
|
|
36
|
+
*/
|
|
22
37
|
async function imageToBase64(image) {
|
|
23
38
|
if (typeof image === "string") {
|
|
24
39
|
let url = null;
|
|
@@ -35,6 +50,7 @@ async function imageToBase64(image) {
|
|
|
35
50
|
if (!response.ok) throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`);
|
|
36
51
|
return blobToBase64(await response.blob());
|
|
37
52
|
}
|
|
53
|
+
if (url) throw new Error(`Unsupported image URL scheme: ${url.protocol}`);
|
|
38
54
|
return image;
|
|
39
55
|
}
|
|
40
56
|
return blobToBase64(image);
|