@vanillaskyai/video 0.10.2 → 0.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/PUBLIC-API.md +43 -31
- package/README.md +18 -9
- package/dist/check-runtime.js +2 -2
- package/dist/{chunk-KHLO5OHT.js → chunk-G5TYLTL5.js} +1 -1
- package/dist/{chunk-77VY4O7A.js → chunk-O6FBIB4L.js} +58 -10
- package/dist/{chunk-TVIU23OM.js → chunk-OOBT4X46.js} +13 -3
- package/dist/{chunk-5C6HZNHY.js → chunk-QZAZT44G.js} +3 -2
- package/dist/{chunk-6KZGF63O.js → chunk-WZFLEPLM.js} +58 -35
- package/dist/{chunk-VQH3JTQC.js → chunk-Z2ZI5G7O.js} +1 -1
- package/dist/{cinema-media-APDJS7SC.js → cinema-media-3SIGVVCY.js} +4 -4
- package/dist/{comparison-ZVE2DE7U.js → comparison-VDGRWPB5.js} +4 -4
- package/dist/{editorial-timeline-YIXXVJUV.js → editorial-timeline-QJU4JJWB.js} +4 -4
- package/dist/{key-figure-I2C37FWV.js → key-figure-YUAQW6OE.js} +4 -4
- package/dist/{mobile-message-JSGBU6EX.js → mobile-message-ZMMTUDUQ.js} +4 -4
- package/dist/{quote-XH54G3FS.js → quote-BB6UJT6L.js} +4 -4
- package/dist/react.d.ts +3 -1
- package/dist/react.js +94 -84
- package/dist/{scene-video-backdrop-PCTARAAJ.js → scene-video-backdrop-4EZVVQY7.js} +2 -2
- package/dist/server.d.ts +15 -3
- package/dist/server.js +416 -275
- package/dist/{types-CdBmNTGD.d.ts → types-BqB8zC9u.d.ts} +1 -1
- package/docs/agent-integration.md +5 -4
- package/docs/concepts.md +2 -2
- package/docs/development.md +23 -0
- package/docs/getting-started.md +7 -5
- package/docs/media-and-audio.md +37 -18
- package/docs/performance.md +21 -10
- package/docs/production.md +11 -10
- package/docs/prompt-and-input.md +24 -15
- package/docs/provider-integration.md +11 -13
- package/docs/reference/protocol.md +7 -1
- package/docs/reference/provider-adapters.md +7 -4
- package/docs/testing.md +7 -2
- package/package.json +5 -2
- package/registry/items/backgrounds.json +2 -2
- package/registry/items/cinemaMedia.json +1 -1
- package/registry/items/comparison.json +1 -1
- package/registry/items/editorialTimeline.json +1 -1
- package/registry/items/keyFigure.json +1 -1
- package/registry/items/mobileMessage.json +1 -1
- package/registry/items/quote.json +1 -1
- package/starters/video-chat/README.md +25 -26
- package/starters/video-chat/package.json +1 -1
- package/starters/video-chat/providers/video.ts +10 -6
- package/starters/video-chat/server.ts +1 -1
- package/starters/video-chat/stock.ts +59 -31
- package/styles/video-chat.css +6 -61
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EditorialSurface
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-G5TYLTL5.js";
|
|
4
|
+
import "./chunk-QZAZT44G.js";
|
|
5
|
+
import "./chunk-O6FBIB4L.js";
|
|
6
6
|
import {
|
|
7
7
|
editorialLabel,
|
|
8
8
|
fade
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
hasSceneMedia
|
|
12
12
|
} from "./chunk-224QNWRA.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-OOBT4X46.js";
|
|
14
14
|
|
|
15
15
|
// src/visual-system/scene-templates/comparison.tsx
|
|
16
16
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EditorialSurface
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-G5TYLTL5.js";
|
|
4
|
+
import "./chunk-QZAZT44G.js";
|
|
5
|
+
import "./chunk-O6FBIB4L.js";
|
|
6
6
|
import {
|
|
7
7
|
fade
|
|
8
8
|
} from "./chunk-4YM2M62S.js";
|
|
9
9
|
import "./chunk-224QNWRA.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-OOBT4X46.js";
|
|
11
11
|
|
|
12
12
|
// src/visual-system/scene-templates/editorial-timeline.tsx
|
|
13
13
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EditorialSurface
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-G5TYLTL5.js";
|
|
4
|
+
import "./chunk-QZAZT44G.js";
|
|
5
|
+
import "./chunk-O6FBIB4L.js";
|
|
6
6
|
import {
|
|
7
7
|
editorialLabel,
|
|
8
8
|
fade
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
hasSceneMedia
|
|
12
12
|
} from "./chunk-224QNWRA.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-OOBT4X46.js";
|
|
14
14
|
|
|
15
15
|
// src/visual-system/scene-templates/key-figure.tsx
|
|
16
16
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MediaScene
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-Z2ZI5G7O.js";
|
|
4
|
+
import "./chunk-QZAZT44G.js";
|
|
5
5
|
import {
|
|
6
6
|
spring
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-O6FBIB4L.js";
|
|
8
8
|
import {
|
|
9
9
|
editorialFont
|
|
10
10
|
} from "./chunk-4YM2M62S.js";
|
|
11
11
|
import "./chunk-224QNWRA.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-OOBT4X46.js";
|
|
13
13
|
|
|
14
14
|
// src/visual-system/scene-templates/mobile-message.tsx
|
|
15
15
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EditorialSurface
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-G5TYLTL5.js";
|
|
4
|
+
import "./chunk-QZAZT44G.js";
|
|
5
|
+
import "./chunk-O6FBIB4L.js";
|
|
6
6
|
import {
|
|
7
7
|
fade
|
|
8
8
|
} from "./chunk-4YM2M62S.js";
|
|
9
9
|
import {
|
|
10
10
|
hasSceneMedia
|
|
11
11
|
} from "./chunk-224QNWRA.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-OOBT4X46.js";
|
|
13
13
|
|
|
14
14
|
// src/visual-system/scene-templates/quote.tsx
|
|
15
15
|
import { jsx, jsxs } from "react/jsx-runtime";
|
package/dist/react.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { CSSProperties, ReactElement, ReactNode } from 'react';
|
|
|
3
3
|
import { b as VideoEvent } from './events-B4YCc4vc.js';
|
|
4
4
|
import { b as VideoOrientation, e as VideoScene, c as Video, i as VideoStyleOptions } from './types-DdZw4GRQ.js';
|
|
5
5
|
import { T as TemplateRegistry } from './kit-DrRpdn0p.js';
|
|
6
|
-
import { V as VideoChatMode, a as VideoChatAskOptions, b as VideoChatMedia, c as VideoChatSuggestion, d as VideoChatCapabilities, e as VideoChatWelcome } from './types-
|
|
6
|
+
import { V as VideoChatMode, a as VideoChatAskOptions, b as VideoChatMedia, c as VideoChatSuggestion, d as VideoChatCapabilities, e as VideoChatWelcome } from './types-BqB8zC9u.js';
|
|
7
7
|
import './catalog-types-WTbLP6Jh.js';
|
|
8
8
|
|
|
9
9
|
type VideoPlaybackMode = "manual" | "muted-autoplay" | "autoplay-with-sound" | "autoplay-after-interaction";
|
|
@@ -185,6 +185,8 @@ interface VideoChatTurn {
|
|
|
185
185
|
orientation: VideoOrientation;
|
|
186
186
|
/** Generated footage keeps the orientation it was created in. */
|
|
187
187
|
fixedOrientation: boolean;
|
|
188
|
+
/** Footage source selected for this answer; omitted in older saved turns. */
|
|
189
|
+
mode?: VideoChatMode;
|
|
188
190
|
video?: Video;
|
|
189
191
|
suggestions: readonly VideoChatSuggestion[];
|
|
190
192
|
}
|
package/dist/react.js
CHANGED
|
@@ -40,9 +40,9 @@ import {
|
|
|
40
40
|
VideoFrame,
|
|
41
41
|
getDimensions,
|
|
42
42
|
sceneReadinessKey
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-WZFLEPLM.js";
|
|
44
44
|
import "./chunk-224QNWRA.js";
|
|
45
|
-
import "./chunk-
|
|
45
|
+
import "./chunk-OOBT4X46.js";
|
|
46
46
|
import {
|
|
47
47
|
getVideoDuration,
|
|
48
48
|
resolveVideoTimeline
|
|
@@ -94,13 +94,13 @@ import { createElement } from "react";
|
|
|
94
94
|
|
|
95
95
|
// src/visual-system/catalog/builtin-loaders.generated.ts
|
|
96
96
|
var GENERATED_BUILTIN_TEMPLATE_LOADERS = {
|
|
97
|
-
"cinemaMedia": () => import("./cinema-media-
|
|
97
|
+
"cinemaMedia": () => import("./cinema-media-3SIGVVCY.js").then((module) => ({ default: module.MediaSceneTemplate })),
|
|
98
98
|
"chapterTitle": () => import("./chapter-title-YRLIQY3V.js").then((module) => ({ default: module.TitleSceneTemplate })),
|
|
99
|
-
"editorialTimeline": () => import("./editorial-timeline-
|
|
100
|
-
"mobileMessage": () => import("./mobile-message-
|
|
101
|
-
"comparison": () => import("./comparison-
|
|
102
|
-
"quote": () => import("./quote-
|
|
103
|
-
"keyFigure": () => import("./key-figure-
|
|
99
|
+
"editorialTimeline": () => import("./editorial-timeline-QJU4JJWB.js").then((module) => ({ default: module.TimelineSceneTemplate })),
|
|
100
|
+
"mobileMessage": () => import("./mobile-message-ZMMTUDUQ.js").then((module) => ({ default: module.NotificationSceneTemplate })),
|
|
101
|
+
"comparison": () => import("./comparison-VDGRWPB5.js").then((module) => ({ default: module.ComparisonSceneTemplate })),
|
|
102
|
+
"quote": () => import("./quote-BB6UJT6L.js").then((module) => ({ default: module.QuoteSceneTemplate })),
|
|
103
|
+
"keyFigure": () => import("./key-figure-YUAQW6OE.js").then((module) => ({ default: module.KeyFigureSceneTemplate }))
|
|
104
104
|
};
|
|
105
105
|
|
|
106
106
|
// src/visual-system/catalog/builtin-player.generated.ts
|
|
@@ -754,6 +754,14 @@ function VideoPlayerRuntime({
|
|
|
754
754
|
}
|
|
755
755
|
}, []);
|
|
756
756
|
const playbackEndedRef = useRef(false);
|
|
757
|
+
let mediaPlaying = isPlaying;
|
|
758
|
+
if (sceneIndexRef.current >= 0) {
|
|
759
|
+
try {
|
|
760
|
+
mediaPlaying = isPlaying && narrationReady?.() !== false;
|
|
761
|
+
} catch {
|
|
762
|
+
mediaPlaying = false;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
757
765
|
stateRef.current = state;
|
|
758
766
|
timeRef.current = currentTime;
|
|
759
767
|
callbacksRef.current = { onComplete, onPlaybackEnd, onError, onSceneChange, narrationReady, narrationTime, onFramePresented, onMediaFramePresented, onStallChange, onStateChange };
|
|
@@ -1131,7 +1139,8 @@ function VideoPlayerRuntime({
|
|
|
1131
1139
|
time: showStartPoster ? posterTime : currentTime,
|
|
1132
1140
|
width: dimensions.width,
|
|
1133
1141
|
height: dimensions.height,
|
|
1134
|
-
playing:
|
|
1142
|
+
playing: mediaPlaying,
|
|
1143
|
+
preparingNarration: isPlaying && !mediaPlaying,
|
|
1135
1144
|
mediaAudioMuted: !nativeMediaAudio || isMuted,
|
|
1136
1145
|
mediaAudioVolume: nativeMediaVolume,
|
|
1137
1146
|
style: {
|
|
@@ -1243,7 +1252,7 @@ var VideoError = class extends Error {
|
|
|
1243
1252
|
function recoverSceneMedia(scene) {
|
|
1244
1253
|
if (scene.templateId === "cinemaMedia") {
|
|
1245
1254
|
const title = scene.variables.fallbackText;
|
|
1246
|
-
if (typeof title !== "string" || !title.trim() || [...title].length > 65) return
|
|
1255
|
+
if (typeof title !== "string" || !title.trim() || [...title].length > 65) return { ...scene, variables: { mediaType: "video", mediaUrl: "" } };
|
|
1247
1256
|
return { ...scene, templateId: "chapterTitle", variables: { title: title.trim() } };
|
|
1248
1257
|
}
|
|
1249
1258
|
if (!["comparison", "editorialTimeline", "quote", "keyFigure"].includes(scene.templateId)) return void 0;
|
|
@@ -1397,7 +1406,11 @@ function useNarration(options) {
|
|
|
1397
1406
|
if (!optionsRef.current.voice.getCurrentTime) return void 0;
|
|
1398
1407
|
const time = currentRef.current ? optionsRef.current.voice.getCurrentTime() : void 0;
|
|
1399
1408
|
if (currentRef.current && readyRef.current && time === void 0) return void 0;
|
|
1400
|
-
if (time !== void 0 && Number.isFinite(time))
|
|
1409
|
+
if (time !== void 0 && Number.isFinite(time)) {
|
|
1410
|
+
const end = group?.totalSeconds ?? scene.timing.fixedDuration ?? Infinity;
|
|
1411
|
+
const limit = currentRef.current ? Math.max(0, end - 0.01) : end;
|
|
1412
|
+
clockRef.current = Math.min(limit, Math.max(group?.offsetSeconds ?? 0, time));
|
|
1413
|
+
}
|
|
1401
1414
|
return clockRef.current;
|
|
1402
1415
|
}, []);
|
|
1403
1416
|
const isReady = useCallback(() => optionsRef.current.enabled === false || readyRef.current || clockRef.current !== void 0 && clockRef.current >= (groupRef.current?.offsetSeconds ?? 0) + 0.04, []);
|
|
@@ -2082,7 +2095,7 @@ function errorFrom(cause) {
|
|
|
2082
2095
|
return new VideoError("Video chat could not produce a playable response", { code: "video_chat_failed", recoverable: false });
|
|
2083
2096
|
}
|
|
2084
2097
|
async function responseError(response) {
|
|
2085
|
-
return new VideoError(response.status === 429 ? "
|
|
2098
|
+
return new VideoError(response.status === 429 ? "Too many requests right now. Please try again shortly." : "Video chat could not produce a playable response", {
|
|
2086
2099
|
code: "http_error",
|
|
2087
2100
|
status: response.status,
|
|
2088
2101
|
recoverable: false
|
|
@@ -2275,7 +2288,7 @@ function useVideoChatSession(options = {}) {
|
|
|
2275
2288
|
throw new VideoError("timeoutMs must be positive", { code: "invalid_option" });
|
|
2276
2289
|
}
|
|
2277
2290
|
const timeout = setTimeout(() => controller.abort(new DOMException("Video chat timed out", "TimeoutError")), timeoutMs);
|
|
2278
|
-
const mode = "cinematic";
|
|
2291
|
+
const mode = currentOptions.mode ?? "cinematic";
|
|
2279
2292
|
const orientation = currentOptions.orientation ?? "landscape";
|
|
2280
2293
|
const id = (currentOptions.createTurnId ?? defaultTurnId)();
|
|
2281
2294
|
const conversation = conversationFor(stateRef.current.turns);
|
|
@@ -2287,6 +2300,7 @@ function useVideoChatSession(options = {}) {
|
|
|
2287
2300
|
completed: false,
|
|
2288
2301
|
orientation,
|
|
2289
2302
|
fixedOrientation: true,
|
|
2303
|
+
mode,
|
|
2290
2304
|
suggestions: [],
|
|
2291
2305
|
...openingMedia ? { openingMedia } : {}
|
|
2292
2306
|
};
|
|
@@ -2355,26 +2369,30 @@ function useVideoChatSession(options = {}) {
|
|
|
2355
2369
|
}
|
|
2356
2370
|
};
|
|
2357
2371
|
flushRef.current = flush;
|
|
2358
|
-
const
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2372
|
+
const speechLoads = /* @__PURE__ */ new Map();
|
|
2373
|
+
const speechLanes = [Promise.resolve(), Promise.resolve()];
|
|
2374
|
+
let nextSpeechLane = 0;
|
|
2375
|
+
let customVoiceFailed = false;
|
|
2376
|
+
const prepareSpeech = (text, signal) => {
|
|
2377
|
+
const cached = speechLoads.get(text);
|
|
2378
|
+
if (cached) return cached;
|
|
2379
|
+
const lane = nextSpeechLane++ % speechLanes.length;
|
|
2380
|
+
const prepared = speechLanes[lane].then(async () => {
|
|
2381
|
+
signal.throwIfAborted();
|
|
2382
|
+
try {
|
|
2383
|
+
if (customVoiceFailed) throw new Error("Voice preparation did not respond");
|
|
2384
|
+
return currentOptions.voice ? await withDeadline((child) => voiceRef.current.prepare(text, { signal: child }), 3e3, signal) : await voiceRef.current.prepare(text, { signal });
|
|
2385
|
+
} catch (cause) {
|
|
2386
|
+
if (currentOptions.voice && !signal.aborted && isCurrent()) {
|
|
2387
|
+
unavailableVoiceLines.current.add(text);
|
|
2388
|
+
if (cause instanceof DOMException && cause.name === "TimeoutError") customVoiceFailed = true;
|
|
2389
|
+
}
|
|
2390
|
+
throw cause;
|
|
2391
|
+
}
|
|
2392
|
+
});
|
|
2393
|
+
speechLoads.set(text, prepared);
|
|
2394
|
+
speechLanes[lane] = prepared.catch(() => void 0);
|
|
2395
|
+
return prepared;
|
|
2378
2396
|
};
|
|
2379
2397
|
const speakOpening = async (text) => {
|
|
2380
2398
|
try {
|
|
@@ -2427,12 +2445,16 @@ function useVideoChatSession(options = {}) {
|
|
|
2427
2445
|
if (event.type === "response.warning" || event.type === "response.error" && !event.data.terminal) {
|
|
2428
2446
|
warn(event.type === "response.warning" && event.data.warning.message === MEDIA_RECOVERY_NOTICE ? MEDIA_RECOVERY_NOTICE : "Some parts were simplified so the response could continue.");
|
|
2429
2447
|
}
|
|
2448
|
+
if (event.type === "data.video-chat-preparation") {
|
|
2449
|
+
const data = event.data;
|
|
2450
|
+
if (data && typeof data.sceneId === "string" && data.sceneId.length <= 200 && typeof data.narration === "string" && data.narration.trim() && data.narration.length <= 2e3 && speechLoads.size < 32) {
|
|
2451
|
+
void prepareSpeech(data.narration.trim(), controller.signal).catch(() => void 0);
|
|
2452
|
+
}
|
|
2453
|
+
continue;
|
|
2454
|
+
}
|
|
2430
2455
|
if (event.type === "data.video-chat-opening") {
|
|
2431
2456
|
const payload = event.data && typeof event.data === "object" && !Array.isArray(event.data) ? event.data : {};
|
|
2432
2457
|
const line = typeof payload.line === "string" ? payload.line.trim().slice(0, 300) : "";
|
|
2433
|
-
const keyword = typeof payload.keyword === "string" ? payload.keyword.trim().slice(0, 80) : "";
|
|
2434
|
-
const fallbackKeyword = typeof payload.fallbackKeyword === "string" ? payload.fallbackKeyword.trim().slice(0, 80) : void 0;
|
|
2435
|
-
if (!openingMedia && keyword) void resolveOpeningMedia(keyword, fallbackKeyword);
|
|
2436
2458
|
if (!openingRequested && line) {
|
|
2437
2459
|
spokenHook = line;
|
|
2438
2460
|
lines.push(line);
|
|
@@ -3315,6 +3337,13 @@ function Logo() {
|
|
|
3315
3337
|
return /* @__PURE__ */ jsx7("img", { className: "brand-logo", src: new URL("./assets/vanillasky-logo.svg", import.meta.url).href, alt: "VanillaSky", width: 144, height: 36 });
|
|
3316
3338
|
}
|
|
3317
3339
|
|
|
3340
|
+
// src/video-chat/modes.ts
|
|
3341
|
+
var visualModes = [
|
|
3342
|
+
{ id: "cinematic", label: "AI video", note: "Generated footage shaped by your prompt" },
|
|
3343
|
+
{ id: "pexels", label: "Pexels", note: "Stock footage with lower generation costs" }
|
|
3344
|
+
];
|
|
3345
|
+
var defaultMode = visualModes[0];
|
|
3346
|
+
|
|
3318
3347
|
// src/video-chat/video-chat.tsx
|
|
3319
3348
|
import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
3320
3349
|
var DESKTOP_WIDTH = 900;
|
|
@@ -3330,28 +3359,13 @@ function useViewportOrientation() {
|
|
|
3330
3359
|
}, []);
|
|
3331
3360
|
return portrait ? "portrait" : "landscape";
|
|
3332
3361
|
}
|
|
3333
|
-
var STEPS = [
|
|
3334
|
-
"Rolling camera\u2026",
|
|
3335
|
-
"Framing the shots\u2026",
|
|
3336
|
-
"Filming your response\u2026",
|
|
3337
|
-
"Still filming\u2026"
|
|
3338
|
-
];
|
|
3339
|
-
function useFilmingStep(active, key) {
|
|
3340
|
-
const [step, setStep] = useState7(0);
|
|
3341
|
-
useEffect9(() => {
|
|
3342
|
-
if (!active) return;
|
|
3343
|
-
setStep(0);
|
|
3344
|
-
const stepper = window.setInterval(() => setStep((current) => current + 1), 3e3);
|
|
3345
|
-
return () => window.clearInterval(stepper);
|
|
3346
|
-
}, [active, key]);
|
|
3347
|
-
return STEPS[Math.min(step, STEPS.length - 1)];
|
|
3348
|
-
}
|
|
3349
3362
|
function Waveform({ active, listening }) {
|
|
3350
3363
|
return /* @__PURE__ */ jsx8("span", { className: `waveform${active ? " on" : ""}${listening ? " hearing" : ""}`, "aria-hidden": "true", children: [0, 1, 2, 3, 4].map((bar) => /* @__PURE__ */ jsx8("span", { style: { animationDelay: `${bar * 140}ms`, animationDuration: `${900 + bar * 130}ms` } }, bar)) });
|
|
3351
3364
|
}
|
|
3352
3365
|
function VideoChat({ options = {}, className, welcomeTitle, showRecoveryNotice = false }) {
|
|
3353
3366
|
const [dismissedNoticeTurn, setDismissedNoticeTurn] = useState7();
|
|
3354
3367
|
const [draft, setDraft] = useState7("");
|
|
3368
|
+
const [selectedMode, setSelectedMode] = useState7();
|
|
3355
3369
|
const [savedSessions, setSavedSessions] = useState7([]);
|
|
3356
3370
|
const [historyOpen, setHistoryOpen] = useState7(false);
|
|
3357
3371
|
const [settingsOpen, setSettingsOpen] = useState7(false);
|
|
@@ -3368,7 +3382,7 @@ function VideoChat({ options = {}, className, welcomeTitle, showRecoveryNotice =
|
|
|
3368
3382
|
const { chat, restoreSession } = useVideoChatSession({
|
|
3369
3383
|
...options,
|
|
3370
3384
|
orientation: sessionOrientation,
|
|
3371
|
-
|
|
3385
|
+
mode: selectedMode ?? options.mode
|
|
3372
3386
|
});
|
|
3373
3387
|
const instanceId = useId();
|
|
3374
3388
|
const historyId = `${instanceId}-history`;
|
|
@@ -3405,7 +3419,6 @@ function VideoChat({ options = {}, className, welcomeTitle, showRecoveryNotice =
|
|
|
3405
3419
|
resumeAfterInput.current = false;
|
|
3406
3420
|
inputRef.current?.blur();
|
|
3407
3421
|
void chat.ask(prompt, typeof value === "string" ? void 0 : {
|
|
3408
|
-
openingMedia: value.media,
|
|
3409
3422
|
opening: value.opening
|
|
3410
3423
|
});
|
|
3411
3424
|
}, [chat, listen]);
|
|
@@ -3428,16 +3441,10 @@ function VideoChat({ options = {}, className, welcomeTitle, showRecoveryNotice =
|
|
|
3428
3441
|
resumeAfterInput.current = false;
|
|
3429
3442
|
inputRef.current?.blur();
|
|
3430
3443
|
}, [chat, listen]);
|
|
3431
|
-
const current = chat.currentTurn;
|
|
3432
3444
|
const shown = chat.shownTurn;
|
|
3433
3445
|
const showing = chat.playerProps != null;
|
|
3434
|
-
const
|
|
3435
|
-
const
|
|
3436
|
-
const openingMediaFailed = openingAsset?.key === openingAssetKey && openingAsset.state === "failed";
|
|
3437
|
-
const openingMediaReady = openingAsset?.key === openingAssetKey && openingAsset.state === "ready";
|
|
3438
|
-
const openingChapter = !showing && Boolean(shown?.opening) && (!shown?.openingMedia || openingMediaFailed || !openingMediaReady);
|
|
3439
|
-
const waitingForPicture = chat.turns.length > 0 && !showing && (chat.status === "composing" || chat.status === "playing" || chat.status === "paused");
|
|
3440
|
-
const filmingStep = useFilmingStep(waitingForPicture, current?.id);
|
|
3446
|
+
const openingChapter = !showing && Boolean(shown?.prompt);
|
|
3447
|
+
const openingTitle = shown?.opening ?? shown?.prompt ?? "";
|
|
3441
3448
|
const status = chat.turns.length === 0 ? "idle" : chat.status === "composing" ? "drawing" : chat.status === "playing" ? "narrating" : chat.status === "error" || chat.status === "cancelled" ? "ended" : chat.status;
|
|
3442
3449
|
const shownOrientation = shown?.orientation ?? sessionOrientation;
|
|
3443
3450
|
const stageOrientation = shown?.fixedOrientation ? shownOrientation : sessionOrientation;
|
|
@@ -3497,7 +3504,10 @@ function VideoChat({ options = {}, className, welcomeTitle, showRecoveryNotice =
|
|
|
3497
3504
|
onKeyDownCapture: controls.reveal,
|
|
3498
3505
|
children: [
|
|
3499
3506
|
/* @__PURE__ */ jsxs6("header", { className: "chrome", ...controlEvents, children: [
|
|
3500
|
-
/* @__PURE__ */
|
|
3507
|
+
/* @__PURE__ */ jsxs6("div", { className: "session-brand", children: [
|
|
3508
|
+
/* @__PURE__ */ jsx8(Logo, {}),
|
|
3509
|
+
(shown?.mode ?? selectedMode ?? options.mode) === "pexels" && /* @__PURE__ */ jsx8("a", { className: "media-credit", href: "https://www.pexels.com", target: "_blank", rel: "noopener noreferrer", children: "Videos by Pexels" })
|
|
3510
|
+
] }),
|
|
3501
3511
|
/* @__PURE__ */ jsxs6("div", { className: "group", children: [
|
|
3502
3512
|
/* @__PURE__ */ jsxs6(
|
|
3503
3513
|
"button",
|
|
@@ -3552,27 +3562,8 @@ function VideoChat({ options = {}, className, welcomeTitle, showRecoveryNotice =
|
|
|
3552
3562
|
/* @__PURE__ */ jsxs6("div", { className: "stage-area", children: [
|
|
3553
3563
|
/* @__PURE__ */ jsxs6("div", { className: "stage", style: { background: "#000" }, children: [
|
|
3554
3564
|
!showing && /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
3555
|
-
/* @__PURE__ */ jsx8(
|
|
3556
|
-
|
|
3557
|
-
shown?.openingMedia && !openingMediaFailed && /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
3558
|
-
/* @__PURE__ */ jsx8(
|
|
3559
|
-
Frame,
|
|
3560
|
-
{
|
|
3561
|
-
media: shown.openingMedia,
|
|
3562
|
-
poster: true,
|
|
3563
|
-
revealWhenReady: true,
|
|
3564
|
-
onReady: () => setOpeningAsset({ key: openingAssetKey, state: "ready" }),
|
|
3565
|
-
onError: () => setOpeningAsset({ key: openingAssetKey, state: "failed" })
|
|
3566
|
-
},
|
|
3567
|
-
openingAssetKey
|
|
3568
|
-
),
|
|
3569
|
-
openingMediaReady && /* @__PURE__ */ jsx8("div", { className: "opening-wash", "aria-hidden": "true" })
|
|
3570
|
-
] }),
|
|
3571
|
-
chat.turns.length === 0 && /* @__PURE__ */ jsx8(Welcome, { data: chat.welcome, onAsk: ask, title: welcomeTitle }),
|
|
3572
|
-
shown?.prompt && !shown.opening && /* @__PURE__ */ jsxs6("div", { className: "asked", children: [
|
|
3573
|
-
/* @__PURE__ */ jsx8("p", { className: "asked-prompt", children: shown.prompt }),
|
|
3574
|
-
waitingForPicture && /* @__PURE__ */ jsx8("p", { className: "asked-step", "aria-live": "polite", children: filmingStep })
|
|
3575
|
-
] })
|
|
3565
|
+
openingChapter && /* @__PURE__ */ jsx8(OpeningChapter, { title: openingTitle.length > 120 ? `${openingTitle.slice(0, 117).trimEnd()}\u2026` : openingTitle }, shown.id),
|
|
3566
|
+
chat.turns.length === 0 && /* @__PURE__ */ jsx8(Welcome, { data: chat.welcome, onAsk: ask, title: welcomeTitle })
|
|
3576
3567
|
] }),
|
|
3577
3568
|
chat.playerProps && /* @__PURE__ */ jsx8("div", { className: "player-fit", style: { width: stageOrientation === "portrait" ? "min(100cqw, 56.25cqh)" : "min(100cqw, 177.7778cqh)" }, children: /* @__PURE__ */ jsx8(
|
|
3578
3569
|
VideoPlayer,
|
|
@@ -3671,6 +3662,25 @@ function VideoChat({ options = {}, className, welcomeTitle, showRecoveryNotice =
|
|
|
3671
3662
|
/* @__PURE__ */ jsx8("h2", { children: "Settings" }),
|
|
3672
3663
|
/* @__PURE__ */ jsx8("button", { type: "button", className: "round", "aria-label": "Close settings", onClick: closeSettings, children: /* @__PURE__ */ jsx8(Close, {}) })
|
|
3673
3664
|
] }),
|
|
3665
|
+
/* @__PURE__ */ jsxs6("fieldset", { className: "playback-options", children: [
|
|
3666
|
+
/* @__PURE__ */ jsx8("legend", { children: "Video source" }),
|
|
3667
|
+
visualModes.filter((mode) => chat.availableModes.includes(mode.id)).map((mode) => /* @__PURE__ */ jsxs6("label", { className: "switch-row", children: [
|
|
3668
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
3669
|
+
/* @__PURE__ */ jsx8("strong", { children: mode.label }),
|
|
3670
|
+
/* @__PURE__ */ jsx8("small", { children: mode.note })
|
|
3671
|
+
] }),
|
|
3672
|
+
/* @__PURE__ */ jsx8(
|
|
3673
|
+
"input",
|
|
3674
|
+
{
|
|
3675
|
+
type: "radio",
|
|
3676
|
+
name: `${instanceId}-source`,
|
|
3677
|
+
value: mode.id,
|
|
3678
|
+
checked: (selectedMode ?? options.mode ?? "cinematic") === mode.id,
|
|
3679
|
+
onChange: () => setSelectedMode(mode.id)
|
|
3680
|
+
}
|
|
3681
|
+
)
|
|
3682
|
+
] }, mode.id))
|
|
3683
|
+
] }),
|
|
3674
3684
|
/* @__PURE__ */ jsxs6("fieldset", { className: "playback-options", children: [
|
|
3675
3685
|
/* @__PURE__ */ jsx8("legend", { children: "Watching" }),
|
|
3676
3686
|
/* @__PURE__ */ jsxs6("label", { className: "switch-row", children: [
|
package/dist/server.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { k as VideoGenerationContext, l as VideoPlanner, m as VideoRequest, a as
|
|
|
2
2
|
import { a as VideoFinishReason, V as VideoWarning, b as VideoEvent } from './events-B4YCc4vc.js';
|
|
3
3
|
export { c as VideoWarningCategory } from './events-B4YCc4vc.js';
|
|
4
4
|
import { S as SceneTemplateMetadata } from './catalog-types-WTbLP6Jh.js';
|
|
5
|
-
import { f as VideoChatWelcomeOptions } from './types-
|
|
6
|
-
export { d as VideoChatCapabilities, g as VideoChatConversationTurn,
|
|
5
|
+
import { V as VideoChatMode, f as VideoChatWelcomeOptions } from './types-BqB8zC9u.js';
|
|
6
|
+
export { d as VideoChatCapabilities, g as VideoChatConversationTurn, h as VideoChatWelcomePrompt } from './types-BqB8zC9u.js';
|
|
7
7
|
|
|
8
8
|
interface VideoProviderUsage {
|
|
9
9
|
inputTokens?: number;
|
|
@@ -236,6 +236,18 @@ interface VideoChatHandlerOptions extends Pick<VideoHandlerOptions, "templates"
|
|
|
236
236
|
maxGeneratedVideos?: number;
|
|
237
237
|
/** Generated media deadline in milliseconds, 1–120000. Defaults to 15000. Host providers must honor cancellation. */
|
|
238
238
|
generateVideoTimeoutMs?: number;
|
|
239
|
+
/** Provider-supported clip duration in seconds, 2–20. Defaults to 5; does not change provider billing configuration. */
|
|
240
|
+
generatedClipDurationSec?: number;
|
|
241
|
+
/** Safe host-only phase timings; never includes prompts, narration, media URLs or provider error text. */
|
|
242
|
+
onDiagnostic?: (event: {
|
|
243
|
+
requestId: string;
|
|
244
|
+
mode: VideoChatMode;
|
|
245
|
+
phase: "request-accepted" | "opening-authored" | "shot-authored" | "media-start" | "media-end" | "media-skipped";
|
|
246
|
+
elapsedMs: number;
|
|
247
|
+
sceneId?: string;
|
|
248
|
+
durationMs?: number;
|
|
249
|
+
reason?: "ready" | "empty" | "provider-error" | "timeout" | "cancelled" | "allowance" | "deadline" | "not-configured";
|
|
250
|
+
}) => unknown;
|
|
239
251
|
/** Trusted application guidance appended to the general-purpose response brief. */
|
|
240
252
|
instructions?: string;
|
|
241
253
|
/** Application-owned prompts and visual searches shown before the first turn. */
|
|
@@ -254,4 +266,4 @@ type VideoChatHandler = (request: Request) => Promise<Response>;
|
|
|
254
266
|
*/
|
|
255
267
|
declare function createVideoChatHandler(options: VideoChatHandlerOptions): VideoChatHandler;
|
|
256
268
|
|
|
257
|
-
export { SceneTemplateMetadata as ServerTemplateMetadata, type ServerTemplateRegistry, type VideoChatHandlerOptions, VideoChatWelcomeOptions, VideoFinishReason, type VideoGenerationSummary, type VideoProviderUsage, VideoWarning, createServerTemplateRegistry, createVideoChatHandler };
|
|
269
|
+
export { SceneTemplateMetadata as ServerTemplateMetadata, type ServerTemplateRegistry, type VideoChatHandlerOptions, VideoChatMode, VideoChatWelcomeOptions, VideoFinishReason, type VideoGenerationSummary, type VideoProviderUsage, VideoWarning, createServerTemplateRegistry, createVideoChatHandler };
|