@modelnex/sdk 0.5.3 → 0.5.5
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 +83 -10
- package/dist/index.d.mts +4 -48
- package/dist/index.d.ts +4 -48
- package/dist/index.js +392 -460
- package/dist/index.mjs +221 -288
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -203,7 +203,6 @@ __export(index_exports, {
|
|
|
203
203
|
useExperiencePlayback: () => useExperiencePlayback,
|
|
204
204
|
useOnboardingPlayback: () => useOnboardingPlayback,
|
|
205
205
|
useRecordingMode: () => useRecordingMode,
|
|
206
|
-
useRegisterAction: () => useRegisterAction,
|
|
207
206
|
useRunCommand: () => useRunCommand,
|
|
208
207
|
useTagStore: () => useTagStore,
|
|
209
208
|
useTourPlayback: () => useTourPlayback,
|
|
@@ -213,7 +212,7 @@ __export(index_exports, {
|
|
|
213
212
|
useVoice: () => useVoice
|
|
214
213
|
});
|
|
215
214
|
module.exports = __toCommonJS(index_exports);
|
|
216
|
-
var
|
|
215
|
+
var import_react21 = __toESM(require("react"));
|
|
217
216
|
|
|
218
217
|
// src/context.ts
|
|
219
218
|
var import_react = require("react");
|
|
@@ -2297,56 +2296,31 @@ function useRunCommand(serverUrlOverride) {
|
|
|
2297
2296
|
);
|
|
2298
2297
|
}
|
|
2299
2298
|
|
|
2300
|
-
// src/hooks/useRegisterAction.ts
|
|
2301
|
-
var import_react10 = require("react");
|
|
2302
|
-
function useRegisterAction(action) {
|
|
2303
|
-
const ctx = (0, import_react10.useContext)(ModelNexContext);
|
|
2304
|
-
const registerAction = ctx?.registerAction;
|
|
2305
|
-
const unregisterAction = ctx?.unregisterAction;
|
|
2306
|
-
const actionRef = (0, import_react10.useRef)(action);
|
|
2307
|
-
actionRef.current = action;
|
|
2308
|
-
(0, import_react10.useEffect)(() => {
|
|
2309
|
-
if (!registerAction || !unregisterAction) return;
|
|
2310
|
-
const current = actionRef.current;
|
|
2311
|
-
const agentAction = {
|
|
2312
|
-
id: current.id,
|
|
2313
|
-
description: current.description,
|
|
2314
|
-
schema: current.schema,
|
|
2315
|
-
execute: current.execute
|
|
2316
|
-
};
|
|
2317
|
-
registerAction(agentAction);
|
|
2318
|
-
const id = current.id;
|
|
2319
|
-
return () => {
|
|
2320
|
-
unregisterAction(id);
|
|
2321
|
-
};
|
|
2322
|
-
}, [action.id, action.description, action.schema, action.execute, registerAction, unregisterAction]);
|
|
2323
|
-
}
|
|
2324
|
-
|
|
2325
2299
|
// src/ui-state.tsx
|
|
2326
|
-
var
|
|
2300
|
+
var import_react10 = require("react");
|
|
2327
2301
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2328
|
-
var UIStateContext = (0,
|
|
2302
|
+
var UIStateContext = (0, import_react10.createContext)(null);
|
|
2329
2303
|
function UIStateProvider({
|
|
2330
2304
|
children,
|
|
2331
2305
|
id = "agent-ui-state",
|
|
2332
2306
|
type = "ui",
|
|
2333
2307
|
initialState = {}
|
|
2334
2308
|
}) {
|
|
2335
|
-
const [state, setStateInternal] = (0,
|
|
2336
|
-
const setState = (0,
|
|
2309
|
+
const [state, setStateInternal] = (0, import_react10.useState)(initialState);
|
|
2310
|
+
const setState = (0, import_react10.useCallback)((update) => {
|
|
2337
2311
|
setStateInternal((prev) => ({ ...prev, ...update }));
|
|
2338
2312
|
}, []);
|
|
2339
|
-
const value = (0,
|
|
2313
|
+
const value = (0, import_react10.useMemo)(() => ({ state, setState }), [state, setState]);
|
|
2340
2314
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(UIStateContext.Provider, { value, children });
|
|
2341
2315
|
}
|
|
2342
2316
|
function useUIState() {
|
|
2343
|
-
const ctx = (0,
|
|
2317
|
+
const ctx = (0, import_react10.useContext)(UIStateContext);
|
|
2344
2318
|
if (!ctx) throw new Error("useUIState must be used within UIStateProvider");
|
|
2345
2319
|
return [ctx.state, ctx.setState];
|
|
2346
2320
|
}
|
|
2347
2321
|
|
|
2348
2322
|
// src/viewport.ts
|
|
2349
|
-
var
|
|
2323
|
+
var import_react11 = require("react");
|
|
2350
2324
|
var visibleIds = /* @__PURE__ */ new Set();
|
|
2351
2325
|
var listeners = /* @__PURE__ */ new Set();
|
|
2352
2326
|
function updateVisibility(id, visible) {
|
|
@@ -2355,9 +2329,9 @@ function updateVisibility(id, visible) {
|
|
|
2355
2329
|
listeners.forEach((fn) => fn());
|
|
2356
2330
|
}
|
|
2357
2331
|
function useViewportTrack(id) {
|
|
2358
|
-
const ref = (0,
|
|
2359
|
-
const [, setTick] = (0,
|
|
2360
|
-
(0,
|
|
2332
|
+
const ref = (0, import_react11.useRef)(null);
|
|
2333
|
+
const [, setTick] = (0, import_react11.useState)(0);
|
|
2334
|
+
(0, import_react11.useEffect)(() => {
|
|
2361
2335
|
const el = ref.current;
|
|
2362
2336
|
if (!el) return;
|
|
2363
2337
|
const obs = new IntersectionObserver(
|
|
@@ -2372,7 +2346,7 @@ function useViewportTrack(id) {
|
|
|
2372
2346
|
updateVisibility(id, false);
|
|
2373
2347
|
};
|
|
2374
2348
|
}, [id]);
|
|
2375
|
-
(0,
|
|
2349
|
+
(0, import_react11.useEffect)(() => {
|
|
2376
2350
|
const fn = () => setTick((t) => t + 1);
|
|
2377
2351
|
listeners.add(fn);
|
|
2378
2352
|
return () => {
|
|
@@ -2382,8 +2356,8 @@ function useViewportTrack(id) {
|
|
|
2382
2356
|
return ref;
|
|
2383
2357
|
}
|
|
2384
2358
|
function useVisibleIds() {
|
|
2385
|
-
const [ids, setIds] = (0,
|
|
2386
|
-
(0,
|
|
2359
|
+
const [ids, setIds] = (0, import_react11.useState)([]);
|
|
2360
|
+
(0, import_react11.useEffect)(() => {
|
|
2387
2361
|
const fn = () => setIds(Array.from(visibleIds));
|
|
2388
2362
|
fn();
|
|
2389
2363
|
listeners.add(fn);
|
|
@@ -2400,21 +2374,22 @@ function useAgentViewport(options = {}) {
|
|
|
2400
2374
|
}
|
|
2401
2375
|
|
|
2402
2376
|
// src/chat-bubble.tsx
|
|
2403
|
-
var
|
|
2377
|
+
var import_react18 = require("react");
|
|
2404
2378
|
var import_react_dom = require("react-dom");
|
|
2405
2379
|
|
|
2406
2380
|
// src/hooks/useExperiencePlaybackController.ts
|
|
2407
|
-
var
|
|
2381
|
+
var import_react13 = require("react");
|
|
2408
2382
|
|
|
2409
2383
|
// src/utils/draftPreview.ts
|
|
2410
2384
|
var ACTIVE_DRAFT_PREVIEW_STORAGE_KEY = "modelnex:active-draft-preview";
|
|
2411
2385
|
function getPreviewQueryParamName(experienceType) {
|
|
2412
|
-
return experienceType === "onboarding" ? "
|
|
2386
|
+
return experienceType === "onboarding" ? "modelnex_test_workflow" : "modelnex_test_tour";
|
|
2413
2387
|
}
|
|
2414
2388
|
function buildDraftPreviewUrl(currentUrl, draft) {
|
|
2415
2389
|
const url = new URL(currentUrl);
|
|
2416
2390
|
url.searchParams.delete("modelnex_test_tour");
|
|
2417
2391
|
url.searchParams.delete("modelnex_test_onboarding");
|
|
2392
|
+
url.searchParams.delete("modelnex_test_workflow");
|
|
2418
2393
|
url.searchParams.set(getPreviewQueryParamName(draft.experienceType), draft.id);
|
|
2419
2394
|
return url.toString();
|
|
2420
2395
|
}
|
|
@@ -2560,12 +2535,10 @@ function getStartPolicy(tour) {
|
|
|
2560
2535
|
function getNotificationType(tour) {
|
|
2561
2536
|
return tour.notificationType ?? "bubble_card";
|
|
2562
2537
|
}
|
|
2563
|
-
function isTourEligible(tour, userProfile
|
|
2538
|
+
function isTourEligible(tour, userProfile) {
|
|
2564
2539
|
switch (normalizeTrigger(tour.trigger)) {
|
|
2565
2540
|
case "first_visit":
|
|
2566
2541
|
return !!userProfile.isNewUser;
|
|
2567
|
-
case "feature_launch":
|
|
2568
|
-
return !!tour.featureKey && !!tourFacts?.features?.includes(tour.featureKey);
|
|
2569
2542
|
case "manual":
|
|
2570
2543
|
return false;
|
|
2571
2544
|
default:
|
|
@@ -2574,7 +2547,7 @@ function isTourEligible(tour, userProfile, tourFacts) {
|
|
|
2574
2547
|
}
|
|
2575
2548
|
|
|
2576
2549
|
// src/hooks/useTourPlayback.ts
|
|
2577
|
-
var
|
|
2550
|
+
var import_react12 = require("react");
|
|
2578
2551
|
|
|
2579
2552
|
// src/utils/retryLookup.ts
|
|
2580
2553
|
var defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -3079,7 +3052,6 @@ function useTourPlayback({
|
|
|
3079
3052
|
socketId,
|
|
3080
3053
|
websiteId,
|
|
3081
3054
|
userProfile,
|
|
3082
|
-
tourFacts,
|
|
3083
3055
|
voice,
|
|
3084
3056
|
appName = "this app",
|
|
3085
3057
|
extractedElements,
|
|
@@ -3091,46 +3063,46 @@ function useTourPlayback({
|
|
|
3091
3063
|
showCaptions = true,
|
|
3092
3064
|
enableAutoDiscovery = true
|
|
3093
3065
|
}) {
|
|
3094
|
-
const [isActive, setIsActive] = (0,
|
|
3095
|
-
const [currentStepIndex, setCurrentStepIndex] = (0,
|
|
3096
|
-
const [totalSteps, setTotalSteps] = (0,
|
|
3097
|
-
const [activeTour, setActiveTour] = (0,
|
|
3098
|
-
const [playbackState, setPlaybackState] = (0,
|
|
3099
|
-
const [isReviewMode, setIsReviewMode] = (0,
|
|
3100
|
-
const [previewRunId, setPreviewRunId] = (0,
|
|
3101
|
-
const [reviewSubmitting, setReviewSubmitting] = (0,
|
|
3102
|
-
const [reviewStatusMessage, setReviewStatusMessage] = (0,
|
|
3103
|
-
const [pendingTour, setPendingTour] = (0,
|
|
3104
|
-
const [serverState, setServerState] = (0,
|
|
3105
|
-
const ctx = (0,
|
|
3066
|
+
const [isActive, setIsActive] = (0, import_react12.useState)(false);
|
|
3067
|
+
const [currentStepIndex, setCurrentStepIndex] = (0, import_react12.useState)(0);
|
|
3068
|
+
const [totalSteps, setTotalSteps] = (0, import_react12.useState)(0);
|
|
3069
|
+
const [activeTour, setActiveTour] = (0, import_react12.useState)(null);
|
|
3070
|
+
const [playbackState, setPlaybackState] = (0, import_react12.useState)("idle");
|
|
3071
|
+
const [isReviewMode, setIsReviewMode] = (0, import_react12.useState)(false);
|
|
3072
|
+
const [previewRunId, setPreviewRunId] = (0, import_react12.useState)(null);
|
|
3073
|
+
const [reviewSubmitting, setReviewSubmitting] = (0, import_react12.useState)(false);
|
|
3074
|
+
const [reviewStatusMessage, setReviewStatusMessage] = (0, import_react12.useState)(null);
|
|
3075
|
+
const [pendingTour, setPendingTour] = (0, import_react12.useState)(null);
|
|
3076
|
+
const [serverState, setServerState] = (0, import_react12.useState)(null);
|
|
3077
|
+
const ctx = (0, import_react12.useContext)(ModelNexContext);
|
|
3106
3078
|
const devMode = ctx?.devMode;
|
|
3107
|
-
const tourRef = (0,
|
|
3108
|
-
const stepIndexRef = (0,
|
|
3109
|
-
const skipRequestedRef = (0,
|
|
3110
|
-
const advanceRequestedRef = (0,
|
|
3111
|
-
const textInputResolveRef = (0,
|
|
3112
|
-
const voiceInputResolveRef = (0,
|
|
3113
|
-
const askOrFillRef = (0,
|
|
3114
|
-
const pendingManualWaitCleanupRef = (0,
|
|
3115
|
-
const llmRespondingRef = (0,
|
|
3116
|
-
const interruptedForQuestionRef = (0,
|
|
3117
|
-
const pendingInputBufRef = (0,
|
|
3118
|
-
const activeExecutionTokenRef = (0,
|
|
3119
|
-
const commandInFlightRef = (0,
|
|
3120
|
-
const reviewModeRef = (0,
|
|
3121
|
-
const previewRunIdRef = (0,
|
|
3122
|
-
const toursApiBaseRef = (0,
|
|
3123
|
-
const pendingTourRef = (0,
|
|
3124
|
-
const pendingTourOptionsRef = (0,
|
|
3125
|
-
const showCaptionsRef = (0,
|
|
3126
|
-
const runIdRef = (0,
|
|
3127
|
-
const turnIdRef = (0,
|
|
3128
|
-
const socketRef = (0,
|
|
3129
|
-
const socketIdRef = (0,
|
|
3130
|
-
const commandUrlRef = (0,
|
|
3131
|
-
const onStepChangeRef = (0,
|
|
3132
|
-
const isActiveRef = (0,
|
|
3133
|
-
const activeCommandBatchIdRef = (0,
|
|
3079
|
+
const tourRef = (0, import_react12.useRef)(null);
|
|
3080
|
+
const stepIndexRef = (0, import_react12.useRef)(0);
|
|
3081
|
+
const skipRequestedRef = (0, import_react12.useRef)(false);
|
|
3082
|
+
const advanceRequestedRef = (0, import_react12.useRef)(false);
|
|
3083
|
+
const textInputResolveRef = (0, import_react12.useRef)(null);
|
|
3084
|
+
const voiceInputResolveRef = (0, import_react12.useRef)(null);
|
|
3085
|
+
const askOrFillRef = (0, import_react12.useRef)(null);
|
|
3086
|
+
const pendingManualWaitCleanupRef = (0, import_react12.useRef)(null);
|
|
3087
|
+
const llmRespondingRef = (0, import_react12.useRef)(false);
|
|
3088
|
+
const interruptedForQuestionRef = (0, import_react12.useRef)(false);
|
|
3089
|
+
const pendingInputBufRef = (0, import_react12.useRef)(null);
|
|
3090
|
+
const activeExecutionTokenRef = (0, import_react12.useRef)(0);
|
|
3091
|
+
const commandInFlightRef = (0, import_react12.useRef)(false);
|
|
3092
|
+
const reviewModeRef = (0, import_react12.useRef)(false);
|
|
3093
|
+
const previewRunIdRef = (0, import_react12.useRef)(null);
|
|
3094
|
+
const toursApiBaseRef = (0, import_react12.useRef)(toursApiBase);
|
|
3095
|
+
const pendingTourRef = (0, import_react12.useRef)(null);
|
|
3096
|
+
const pendingTourOptionsRef = (0, import_react12.useRef)(null);
|
|
3097
|
+
const showCaptionsRef = (0, import_react12.useRef)(showCaptions);
|
|
3098
|
+
const runIdRef = (0, import_react12.useRef)(null);
|
|
3099
|
+
const turnIdRef = (0, import_react12.useRef)(null);
|
|
3100
|
+
const socketRef = (0, import_react12.useRef)(null);
|
|
3101
|
+
const socketIdRef = (0, import_react12.useRef)(socketId);
|
|
3102
|
+
const commandUrlRef = (0, import_react12.useRef)(commandUrl);
|
|
3103
|
+
const onStepChangeRef = (0, import_react12.useRef)(onStepChange);
|
|
3104
|
+
const isActiveRef = (0, import_react12.useRef)(false);
|
|
3105
|
+
const activeCommandBatchIdRef = (0, import_react12.useRef)(null);
|
|
3134
3106
|
socketIdRef.current = socketId;
|
|
3135
3107
|
commandUrlRef.current = commandUrl;
|
|
3136
3108
|
onStepChangeRef.current = onStepChange;
|
|
@@ -3140,7 +3112,7 @@ function useTourPlayback({
|
|
|
3140
3112
|
toursApiBaseRef.current = toursApiBase;
|
|
3141
3113
|
pendingTourRef.current = pendingTour;
|
|
3142
3114
|
showCaptionsRef.current = showCaptions;
|
|
3143
|
-
(0,
|
|
3115
|
+
(0, import_react12.useEffect)(() => {
|
|
3144
3116
|
if (disabled) return;
|
|
3145
3117
|
if (typeof window === "undefined") return;
|
|
3146
3118
|
import("socket.io-client").then((ioModule) => {
|
|
@@ -3757,12 +3729,12 @@ function useTourPlayback({
|
|
|
3757
3729
|
turnIdRef.current = null;
|
|
3758
3730
|
};
|
|
3759
3731
|
}, [serverUrl, websiteId, userProfile, disabled, devMode, experienceType]);
|
|
3760
|
-
(0,
|
|
3732
|
+
(0, import_react12.useEffect)(() => {
|
|
3761
3733
|
if (!showCaptions || !isReviewMode) {
|
|
3762
3734
|
removeCaption();
|
|
3763
3735
|
}
|
|
3764
3736
|
}, [showCaptions, isReviewMode]);
|
|
3765
|
-
(0,
|
|
3737
|
+
(0, import_react12.useEffect)(() => {
|
|
3766
3738
|
if (!socketRef.current?.connected || !isActiveRef.current) return;
|
|
3767
3739
|
socketRef.current.emit("tour:client_state", {
|
|
3768
3740
|
runId: runIdRef.current,
|
|
@@ -3776,7 +3748,7 @@ function useTourPlayback({
|
|
|
3776
3748
|
awaitingVoiceResolve: Boolean(voiceInputResolveRef.current)
|
|
3777
3749
|
});
|
|
3778
3750
|
}, [isActive, playbackState, voice.isListening, voice.isSpeaking]);
|
|
3779
|
-
const syncAOM = (0,
|
|
3751
|
+
const syncAOM = (0, import_react12.useCallback)(async () => {
|
|
3780
3752
|
if (!socketRef.current?.connected || !isActiveRef.current) return;
|
|
3781
3753
|
const { generateMinifiedAOM: generateMinifiedAOM2 } = await Promise.resolve().then(() => (init_aom(), aom_exports));
|
|
3782
3754
|
const aom = generateMinifiedAOM2();
|
|
@@ -3786,7 +3758,7 @@ function useTourPlayback({
|
|
|
3786
3758
|
domSummary: captureDomSummary()
|
|
3787
3759
|
});
|
|
3788
3760
|
}, []);
|
|
3789
|
-
const interruptExecution = (0,
|
|
3761
|
+
const interruptExecution = (0, import_react12.useCallback)((transcript) => {
|
|
3790
3762
|
if (!socketRef.current?.connected || !isActiveRef.current) return false;
|
|
3791
3763
|
if (!commandInFlightRef.current && !voice.isSpeaking) return false;
|
|
3792
3764
|
interruptedForQuestionRef.current = true;
|
|
@@ -3813,7 +3785,7 @@ function useTourPlayback({
|
|
|
3813
3785
|
setPlaybackState("thinking");
|
|
3814
3786
|
return true;
|
|
3815
3787
|
}, [voice]);
|
|
3816
|
-
const stopTour = (0,
|
|
3788
|
+
const stopTour = (0, import_react12.useCallback)(() => {
|
|
3817
3789
|
skipRequestedRef.current = true;
|
|
3818
3790
|
isActiveRef.current = false;
|
|
3819
3791
|
activeExecutionTokenRef.current += 1;
|
|
@@ -3854,7 +3826,7 @@ function useTourPlayback({
|
|
|
3854
3826
|
pendingInputBufRef.current = null;
|
|
3855
3827
|
onTourEnd?.();
|
|
3856
3828
|
}, [voice, onTourEnd, serverUrl, websiteId]);
|
|
3857
|
-
const handleTourEnd = (0,
|
|
3829
|
+
const handleTourEnd = (0, import_react12.useCallback)(() => {
|
|
3858
3830
|
const endingTourId = tourRef.current?.id;
|
|
3859
3831
|
const endingPreviewRunId = previewRunIdRef.current;
|
|
3860
3832
|
const endingStepOrder = stepIndexRef.current;
|
|
@@ -3891,7 +3863,7 @@ function useTourPlayback({
|
|
|
3891
3863
|
}
|
|
3892
3864
|
onTourEnd?.();
|
|
3893
3865
|
}, [experienceType, userProfile, serverUrl, voice, onTourEnd, websiteId]);
|
|
3894
|
-
const runTour = (0,
|
|
3866
|
+
const runTour = (0, import_react12.useCallback)(async (tour, options) => {
|
|
3895
3867
|
setPendingTour(null);
|
|
3896
3868
|
pendingTourRef.current = null;
|
|
3897
3869
|
let retries = 0;
|
|
@@ -3933,13 +3905,13 @@ function useTourPlayback({
|
|
|
3933
3905
|
tourContext: tour
|
|
3934
3906
|
});
|
|
3935
3907
|
}, [serverUrl, websiteId]);
|
|
3936
|
-
(0,
|
|
3908
|
+
(0, import_react12.useEffect)(() => {
|
|
3937
3909
|
if (!enableAutoDiscovery) return;
|
|
3938
3910
|
if (disabled) return;
|
|
3939
3911
|
if (typeof window === "undefined") return;
|
|
3940
3912
|
const params = new URLSearchParams(window.location.search);
|
|
3941
|
-
const queryParam = experienceType === "onboarding" ? "
|
|
3942
|
-
const queryTourId = params.get(queryParam);
|
|
3913
|
+
const queryParam = experienceType === "onboarding" ? "modelnex_test_workflow" : "modelnex_test_tour";
|
|
3914
|
+
const queryTourId = experienceType === "onboarding" ? params.get("modelnex_test_workflow") || params.get("modelnex_test_onboarding") : params.get(queryParam);
|
|
3943
3915
|
const activeDraftPreview = readActiveDraftPreview();
|
|
3944
3916
|
const persistedTourId = activeDraftPreview?.experienceType === experienceType ? activeDraftPreview.id : null;
|
|
3945
3917
|
const tourId = queryTourId || persistedTourId;
|
|
@@ -3961,6 +3933,9 @@ function useTourPlayback({
|
|
|
3961
3933
|
if (queryTourId) {
|
|
3962
3934
|
const loc = new URL(window.location.href);
|
|
3963
3935
|
loc.searchParams.delete(queryParam);
|
|
3936
|
+
if (experienceType === "onboarding") {
|
|
3937
|
+
loc.searchParams.delete("modelnex_test_onboarding");
|
|
3938
|
+
}
|
|
3964
3939
|
window.history.replaceState({}, "", loc.toString());
|
|
3965
3940
|
}
|
|
3966
3941
|
const previewOptions = { reviewMode: true, reviewMetadata: { trigger: "query_param" } };
|
|
@@ -3979,13 +3954,13 @@ function useTourPlayback({
|
|
|
3979
3954
|
cancelled = true;
|
|
3980
3955
|
};
|
|
3981
3956
|
}, [serverUrl, toursApiBase, disabled, websiteId, experienceType, enableAutoDiscovery]);
|
|
3982
|
-
(0,
|
|
3957
|
+
(0, import_react12.useEffect)(() => {
|
|
3983
3958
|
if (!enableAutoDiscovery) return;
|
|
3984
3959
|
if (disabled) return;
|
|
3985
3960
|
if (!websiteId || !userProfile) return;
|
|
3986
3961
|
if (typeof window !== "undefined") {
|
|
3987
3962
|
const params = new URLSearchParams(window.location.search);
|
|
3988
|
-
if (params.has("modelnex_test_tour") || params.has("modelnex_test_onboarding") || readActiveDraftPreview()) return;
|
|
3963
|
+
if (params.has("modelnex_test_tour") || params.has("modelnex_test_workflow") || params.has("modelnex_test_onboarding") || readActiveDraftPreview()) return;
|
|
3989
3964
|
}
|
|
3990
3965
|
let cancelled = false;
|
|
3991
3966
|
const checkTours = async () => {
|
|
@@ -3993,7 +3968,7 @@ function useTourPlayback({
|
|
|
3993
3968
|
if (cancelled) return;
|
|
3994
3969
|
for (const tour of tours) {
|
|
3995
3970
|
if (cancelled) break;
|
|
3996
|
-
if (!isTourEligible(tour, userProfile
|
|
3971
|
+
if (!isTourEligible(tour, userProfile)) {
|
|
3997
3972
|
continue;
|
|
3998
3973
|
}
|
|
3999
3974
|
const startPolicy = getStartPolicy(tour);
|
|
@@ -4020,23 +3995,23 @@ function useTourPlayback({
|
|
|
4020
3995
|
cancelled = true;
|
|
4021
3996
|
clearTimeout(timer);
|
|
4022
3997
|
};
|
|
4023
|
-
}, [websiteId, serverUrl, toursApiBase, disabled, experienceType, userProfile,
|
|
4024
|
-
(0,
|
|
3998
|
+
}, [websiteId, serverUrl, toursApiBase, disabled, experienceType, userProfile, enableAutoDiscovery]);
|
|
3999
|
+
(0, import_react12.useEffect)(() => {
|
|
4025
4000
|
if (!disabled || !isActiveRef.current) return;
|
|
4026
4001
|
stopTour();
|
|
4027
4002
|
}, [disabled, stopTour]);
|
|
4028
|
-
const startTour = (0,
|
|
4003
|
+
const startTour = (0, import_react12.useCallback)((tour, options) => {
|
|
4029
4004
|
if (disabled) return;
|
|
4030
4005
|
void runTour(tour, options);
|
|
4031
4006
|
}, [disabled, runTour]);
|
|
4032
|
-
const acceptPendingTour = (0,
|
|
4007
|
+
const acceptPendingTour = (0, import_react12.useCallback)(() => {
|
|
4033
4008
|
const tour = pendingTourRef.current;
|
|
4034
4009
|
if (!tour || disabled) return;
|
|
4035
4010
|
const opts = pendingTourOptionsRef.current;
|
|
4036
4011
|
pendingTourOptionsRef.current = null;
|
|
4037
4012
|
void runTour(tour, opts ?? void 0);
|
|
4038
4013
|
}, [disabled, runTour]);
|
|
4039
|
-
const dismissPendingTour = (0,
|
|
4014
|
+
const dismissPendingTour = (0, import_react12.useCallback)(() => {
|
|
4040
4015
|
const tour = pendingTourRef.current;
|
|
4041
4016
|
setPendingTour(null);
|
|
4042
4017
|
pendingTourRef.current = null;
|
|
@@ -4044,7 +4019,7 @@ function useTourPlayback({
|
|
|
4044
4019
|
if (!tour || !userProfile?.userId) return;
|
|
4045
4020
|
void markTourDismissed(serverUrl, toursApiBaseRef.current, tour.id, userProfile.userId, experienceType, websiteId);
|
|
4046
4021
|
}, [experienceType, serverUrl, userProfile, websiteId]);
|
|
4047
|
-
const submitReviewFeedbackAction = (0,
|
|
4022
|
+
const submitReviewFeedbackAction = (0, import_react12.useCallback)(async (utterance, apply = false) => {
|
|
4048
4023
|
const trimmed = utterance.trim();
|
|
4049
4024
|
const currentTour = tourRef.current;
|
|
4050
4025
|
const currentPreviewRunId = previewRunIdRef.current;
|
|
@@ -4083,10 +4058,10 @@ function useTourPlayback({
|
|
|
4083
4058
|
setReviewSubmitting(false);
|
|
4084
4059
|
}
|
|
4085
4060
|
}, [playbackState, serverUrl, websiteId]);
|
|
4086
|
-
const advanceStep = (0,
|
|
4061
|
+
const advanceStep = (0, import_react12.useCallback)(() => {
|
|
4087
4062
|
advanceRequestedRef.current = true;
|
|
4088
4063
|
}, []);
|
|
4089
|
-
const skipTour = (0,
|
|
4064
|
+
const skipTour = (0, import_react12.useCallback)(() => {
|
|
4090
4065
|
skipRequestedRef.current = true;
|
|
4091
4066
|
voiceInputResolveRef.current?.("");
|
|
4092
4067
|
voiceInputResolveRef.current = null;
|
|
@@ -4096,19 +4071,19 @@ function useTourPlayback({
|
|
|
4096
4071
|
askOrFillRef.current = null;
|
|
4097
4072
|
stopTour();
|
|
4098
4073
|
}, [stopTour]);
|
|
4099
|
-
const pauseTour = (0,
|
|
4074
|
+
const pauseTour = (0, import_react12.useCallback)(() => {
|
|
4100
4075
|
if (socketRef.current?.connected && isActiveRef.current) {
|
|
4101
4076
|
socketRef.current.emit("tour:pause");
|
|
4102
4077
|
setPlaybackState("paused");
|
|
4103
4078
|
}
|
|
4104
4079
|
}, []);
|
|
4105
|
-
const resumeTour = (0,
|
|
4080
|
+
const resumeTour = (0, import_react12.useCallback)(() => {
|
|
4106
4081
|
if (socketRef.current?.connected && isActiveRef.current) {
|
|
4107
4082
|
socketRef.current.emit("tour:resume");
|
|
4108
4083
|
setPlaybackState("executing");
|
|
4109
4084
|
}
|
|
4110
4085
|
}, []);
|
|
4111
|
-
const repeatStep = (0,
|
|
4086
|
+
const repeatStep = (0, import_react12.useCallback)(() => {
|
|
4112
4087
|
const tour = tourRef.current;
|
|
4113
4088
|
const step = tour?.steps[stepIndexRef.current];
|
|
4114
4089
|
if (step) {
|
|
@@ -4116,7 +4091,7 @@ function useTourPlayback({
|
|
|
4116
4091
|
voice.speak(text, tour?.voice.ttsVoice);
|
|
4117
4092
|
}
|
|
4118
4093
|
}, [voice]);
|
|
4119
|
-
const handleVoiceInput = (0,
|
|
4094
|
+
const handleVoiceInput = (0, import_react12.useCallback)((transcript) => {
|
|
4120
4095
|
const text = transcript.trim();
|
|
4121
4096
|
console.log("[TourAgent] handleVoiceInput called with text:", text);
|
|
4122
4097
|
if (!text) return;
|
|
@@ -4138,7 +4113,7 @@ function useTourPlayback({
|
|
|
4138
4113
|
pendingInputBufRef.current = text;
|
|
4139
4114
|
}
|
|
4140
4115
|
}, [interruptExecution]);
|
|
4141
|
-
const handleTextInput = (0,
|
|
4116
|
+
const handleTextInput = (0, import_react12.useCallback)((text) => {
|
|
4142
4117
|
if (voiceInputResolveRef.current) {
|
|
4143
4118
|
const resolve = voiceInputResolveRef.current;
|
|
4144
4119
|
voiceInputResolveRef.current = null;
|
|
@@ -4151,7 +4126,7 @@ function useTourPlayback({
|
|
|
4151
4126
|
handleVoiceInput(text.trim());
|
|
4152
4127
|
}
|
|
4153
4128
|
}, [handleVoiceInput]);
|
|
4154
|
-
(0,
|
|
4129
|
+
(0, import_react12.useEffect)(() => {
|
|
4155
4130
|
return () => {
|
|
4156
4131
|
removeHighlight();
|
|
4157
4132
|
removeCaption();
|
|
@@ -4192,7 +4167,6 @@ function useExperiencePlaybackController({
|
|
|
4192
4167
|
socketId,
|
|
4193
4168
|
websiteId,
|
|
4194
4169
|
userProfile,
|
|
4195
|
-
tourFacts,
|
|
4196
4170
|
voice,
|
|
4197
4171
|
appName,
|
|
4198
4172
|
extractedElements,
|
|
@@ -4202,13 +4176,13 @@ function useExperiencePlaybackController({
|
|
|
4202
4176
|
showCaptions = true,
|
|
4203
4177
|
initialExperienceType = "tour"
|
|
4204
4178
|
}) {
|
|
4205
|
-
const [activeExperienceType, setActiveExperienceType] = (0,
|
|
4206
|
-
const [startingExperienceType, setStartingExperienceType] = (0,
|
|
4207
|
-
const [pendingPrompt, setPendingPrompt] = (0,
|
|
4208
|
-
const pendingPromptRef = (0,
|
|
4209
|
-
const queuedStartRef = (0,
|
|
4210
|
-
const bufferedVoiceInputsRef = (0,
|
|
4211
|
-
const previewDiscoveryInFlightRef = (0,
|
|
4179
|
+
const [activeExperienceType, setActiveExperienceType] = (0, import_react13.useState)(initialExperienceType);
|
|
4180
|
+
const [startingExperienceType, setStartingExperienceType] = (0, import_react13.useState)(null);
|
|
4181
|
+
const [pendingPrompt, setPendingPrompt] = (0, import_react13.useState)(null);
|
|
4182
|
+
const pendingPromptRef = (0, import_react13.useRef)(null);
|
|
4183
|
+
const queuedStartRef = (0, import_react13.useRef)(null);
|
|
4184
|
+
const bufferedVoiceInputsRef = (0, import_react13.useRef)([]);
|
|
4185
|
+
const previewDiscoveryInFlightRef = (0, import_react13.useRef)(false);
|
|
4212
4186
|
pendingPromptRef.current = pendingPrompt;
|
|
4213
4187
|
const playback = useTourPlayback({
|
|
4214
4188
|
serverUrl,
|
|
@@ -4217,7 +4191,6 @@ function useExperiencePlaybackController({
|
|
|
4217
4191
|
socketId,
|
|
4218
4192
|
websiteId,
|
|
4219
4193
|
userProfile,
|
|
4220
|
-
tourFacts,
|
|
4221
4194
|
voice,
|
|
4222
4195
|
appName,
|
|
4223
4196
|
extractedElements,
|
|
@@ -4228,7 +4201,7 @@ function useExperiencePlaybackController({
|
|
|
4228
4201
|
showCaptions,
|
|
4229
4202
|
enableAutoDiscovery: false
|
|
4230
4203
|
});
|
|
4231
|
-
const queueExperienceStart = (0,
|
|
4204
|
+
const queueExperienceStart = (0, import_react13.useCallback)((tour, experienceType, options) => {
|
|
4232
4205
|
setPendingPrompt(null);
|
|
4233
4206
|
pendingPromptRef.current = null;
|
|
4234
4207
|
setStartingExperienceType(experienceType);
|
|
@@ -4239,17 +4212,17 @@ function useExperiencePlaybackController({
|
|
|
4239
4212
|
}
|
|
4240
4213
|
playback.startTour(tour, options);
|
|
4241
4214
|
}, [activeExperienceType, playback]);
|
|
4242
|
-
const startExperience = (0,
|
|
4215
|
+
const startExperience = (0, import_react13.useCallback)((tour, experienceType, options) => {
|
|
4243
4216
|
const resolvedExperienceType = experienceType ?? tour.type ?? activeExperienceType;
|
|
4244
4217
|
queueExperienceStart(tour, resolvedExperienceType, options);
|
|
4245
4218
|
}, [activeExperienceType, queueExperienceStart]);
|
|
4246
|
-
const acceptPendingPrompt = (0,
|
|
4219
|
+
const acceptPendingPrompt = (0, import_react13.useCallback)((experienceType) => {
|
|
4247
4220
|
const prompt = pendingPromptRef.current;
|
|
4248
4221
|
if (!prompt) return;
|
|
4249
4222
|
if (experienceType && prompt.experienceType !== experienceType) return;
|
|
4250
4223
|
queueExperienceStart(prompt.tour, prompt.experienceType, prompt.options);
|
|
4251
4224
|
}, [queueExperienceStart]);
|
|
4252
|
-
const dismissPendingPrompt = (0,
|
|
4225
|
+
const dismissPendingPrompt = (0, import_react13.useCallback)((experienceType) => {
|
|
4253
4226
|
const prompt = pendingPromptRef.current;
|
|
4254
4227
|
if (!prompt) return;
|
|
4255
4228
|
if (experienceType && prompt.experienceType !== experienceType) return;
|
|
@@ -4265,7 +4238,7 @@ function useExperiencePlaybackController({
|
|
|
4265
4238
|
websiteId
|
|
4266
4239
|
);
|
|
4267
4240
|
}, [serverUrl, toursApiBase, userProfile, websiteId]);
|
|
4268
|
-
const handleVoiceInput = (0,
|
|
4241
|
+
const handleVoiceInput = (0, import_react13.useCallback)((transcript, experienceType) => {
|
|
4269
4242
|
const trimmed = transcript.trim();
|
|
4270
4243
|
if (!trimmed) return;
|
|
4271
4244
|
const targetExperienceType = experienceType ?? activeExperienceType;
|
|
@@ -4285,12 +4258,12 @@ function useExperiencePlaybackController({
|
|
|
4285
4258
|
}
|
|
4286
4259
|
playback.handleVoiceInput(trimmed);
|
|
4287
4260
|
}, [activeExperienceType, playback]);
|
|
4288
|
-
(0,
|
|
4261
|
+
(0, import_react13.useEffect)(() => {
|
|
4289
4262
|
if (playback.isActive && startingExperienceType !== null) {
|
|
4290
4263
|
setStartingExperienceType(null);
|
|
4291
4264
|
}
|
|
4292
4265
|
}, [playback.isActive, startingExperienceType]);
|
|
4293
|
-
(0,
|
|
4266
|
+
(0, import_react13.useEffect)(() => {
|
|
4294
4267
|
const queuedStart = queuedStartRef.current;
|
|
4295
4268
|
if (!queuedStart) return;
|
|
4296
4269
|
if (playback.isActive) return;
|
|
@@ -4298,23 +4271,23 @@ function useExperiencePlaybackController({
|
|
|
4298
4271
|
queuedStartRef.current = null;
|
|
4299
4272
|
playback.startTour(queuedStart.tour, queuedStart.options);
|
|
4300
4273
|
}, [activeExperienceType, playback]);
|
|
4301
|
-
(0,
|
|
4274
|
+
(0, import_react13.useEffect)(() => {
|
|
4302
4275
|
if (!playback.isActive) return;
|
|
4303
4276
|
const readyInputs = bufferedVoiceInputsRef.current.filter((item) => item.experienceType === activeExperienceType);
|
|
4304
4277
|
if (readyInputs.length === 0) return;
|
|
4305
4278
|
bufferedVoiceInputsRef.current = bufferedVoiceInputsRef.current.filter((item) => item.experienceType !== activeExperienceType);
|
|
4306
4279
|
readyInputs.forEach((item) => playback.handleVoiceInput(item.transcript));
|
|
4307
4280
|
}, [activeExperienceType, playback]);
|
|
4308
|
-
(0,
|
|
4281
|
+
(0, import_react13.useEffect)(() => {
|
|
4309
4282
|
if (disabled) return;
|
|
4310
4283
|
if (typeof window === "undefined") return;
|
|
4311
4284
|
if (previewDiscoveryInFlightRef.current) return;
|
|
4312
4285
|
const params = new URLSearchParams(window.location.search);
|
|
4313
4286
|
const activeDraftPreview = readActiveDraftPreview();
|
|
4314
4287
|
const previewRequests = [];
|
|
4315
|
-
const onboardingPreviewId = params.get("modelnex_test_onboarding");
|
|
4288
|
+
const onboardingPreviewId = params.get("modelnex_test_workflow") || params.get("modelnex_test_onboarding");
|
|
4316
4289
|
if (onboardingPreviewId) {
|
|
4317
|
-
previewRequests.push({ experienceType: "onboarding", queryParam: "
|
|
4290
|
+
previewRequests.push({ experienceType: "onboarding", queryParam: "modelnex_test_workflow", tourId: onboardingPreviewId });
|
|
4318
4291
|
}
|
|
4319
4292
|
const tourPreviewId = params.get("modelnex_test_tour");
|
|
4320
4293
|
if (tourPreviewId) {
|
|
@@ -4365,7 +4338,7 @@ function useExperiencePlaybackController({
|
|
|
4365
4338
|
previewDiscoveryInFlightRef.current = false;
|
|
4366
4339
|
};
|
|
4367
4340
|
}, [disabled, queueExperienceStart, serverUrl, toursApiBase, websiteId]);
|
|
4368
|
-
(0,
|
|
4341
|
+
(0, import_react13.useEffect)(() => {
|
|
4369
4342
|
if (disabled) return;
|
|
4370
4343
|
if (!websiteId || !userProfile) return;
|
|
4371
4344
|
if (playback.isActive || pendingPromptRef.current || previewDiscoveryInFlightRef.current) return;
|
|
@@ -4381,7 +4354,7 @@ function useExperiencePlaybackController({
|
|
|
4381
4354
|
for (const { experienceType, tours } of toursByExperience) {
|
|
4382
4355
|
for (const tour of tours) {
|
|
4383
4356
|
if (cancelled) return;
|
|
4384
|
-
if (!isTourEligible(tour, userProfile
|
|
4357
|
+
if (!isTourEligible(tour, userProfile)) continue;
|
|
4385
4358
|
const startPolicy = getStartPolicy(tour);
|
|
4386
4359
|
if (startPolicy === "manual_only") {
|
|
4387
4360
|
continue;
|
|
@@ -4408,7 +4381,7 @@ function useExperiencePlaybackController({
|
|
|
4408
4381
|
cancelled = true;
|
|
4409
4382
|
clearTimeout(timer);
|
|
4410
4383
|
};
|
|
4411
|
-
}, [disabled, playback.isActive, queueExperienceStart, serverUrl, toursApiBase,
|
|
4384
|
+
}, [disabled, playback.isActive, queueExperienceStart, serverUrl, toursApiBase, userProfile, websiteId]);
|
|
4412
4385
|
return {
|
|
4413
4386
|
activeExperienceType,
|
|
4414
4387
|
startingExperienceType,
|
|
@@ -4422,7 +4395,7 @@ function useExperiencePlaybackController({
|
|
|
4422
4395
|
}
|
|
4423
4396
|
|
|
4424
4397
|
// src/hooks/useVoice.ts
|
|
4425
|
-
var
|
|
4398
|
+
var import_react14 = require("react");
|
|
4426
4399
|
|
|
4427
4400
|
// src/utils/webrtc-aec.ts
|
|
4428
4401
|
function isWebRtcAecSupported() {
|
|
@@ -4791,36 +4764,36 @@ function isFatalSpeechError(error) {
|
|
|
4791
4764
|
return error === "not-allowed" || error === "service-not-allowed" || error === "audio-capture";
|
|
4792
4765
|
}
|
|
4793
4766
|
function useVoice(serverUrl) {
|
|
4794
|
-
const [isSpeaking, setIsSpeaking] = (0,
|
|
4795
|
-
const [isListening, setIsListening] = (0,
|
|
4796
|
-
const [isMuted, setIsMuted] = (0,
|
|
4797
|
-
const audioRef = (0,
|
|
4798
|
-
const audioBlobUrlRef = (0,
|
|
4799
|
-
const speakResolveRef = (0,
|
|
4800
|
-
const recognitionRef = (0,
|
|
4801
|
-
const isMutedRef = (0,
|
|
4802
|
-
const sttCallbacksRef = (0,
|
|
4803
|
-
const stripIndicesRef = (0,
|
|
4804
|
-
const accumulatedRef = (0,
|
|
4805
|
-
const interimDebounceRef = (0,
|
|
4806
|
-
const lastInterimRef = (0,
|
|
4807
|
-
const lastDeliveredRef = (0,
|
|
4808
|
-
const isSpeakingRef = (0,
|
|
4809
|
-
const speechEndTimeRef = (0,
|
|
4810
|
-
const recentTtsRef = (0,
|
|
4811
|
-
const prefetchedSpeechRef = (0,
|
|
4812
|
-
const nearEndTimeoutRef = (0,
|
|
4813
|
-
const queuePromiseRef = (0,
|
|
4814
|
-
const queueSeqRef = (0,
|
|
4815
|
-
const lastStopSeqRef = (0,
|
|
4816
|
-
const listeningSessionIdRef = (0,
|
|
4817
|
-
const listeningStartedAtRef = (0,
|
|
4818
|
-
const loopbackRef = (0,
|
|
4819
|
-
const aecActiveRef = (0,
|
|
4820
|
-
const mediaRecorderRef = (0,
|
|
4821
|
-
const micStreamRef = (0,
|
|
4822
|
-
const sttSocketRef = (0,
|
|
4823
|
-
const stopLiveSttTransport = (0,
|
|
4767
|
+
const [isSpeaking, setIsSpeaking] = (0, import_react14.useState)(false);
|
|
4768
|
+
const [isListening, setIsListening] = (0, import_react14.useState)(false);
|
|
4769
|
+
const [isMuted, setIsMuted] = (0, import_react14.useState)(false);
|
|
4770
|
+
const audioRef = (0, import_react14.useRef)(null);
|
|
4771
|
+
const audioBlobUrlRef = (0, import_react14.useRef)(null);
|
|
4772
|
+
const speakResolveRef = (0, import_react14.useRef)(null);
|
|
4773
|
+
const recognitionRef = (0, import_react14.useRef)(null);
|
|
4774
|
+
const isMutedRef = (0, import_react14.useRef)(false);
|
|
4775
|
+
const sttCallbacksRef = (0, import_react14.useRef)(null);
|
|
4776
|
+
const stripIndicesRef = (0, import_react14.useRef)({});
|
|
4777
|
+
const accumulatedRef = (0, import_react14.useRef)([]);
|
|
4778
|
+
const interimDebounceRef = (0, import_react14.useRef)(null);
|
|
4779
|
+
const lastInterimRef = (0, import_react14.useRef)("");
|
|
4780
|
+
const lastDeliveredRef = (0, import_react14.useRef)("");
|
|
4781
|
+
const isSpeakingRef = (0, import_react14.useRef)(false);
|
|
4782
|
+
const speechEndTimeRef = (0, import_react14.useRef)(0);
|
|
4783
|
+
const recentTtsRef = (0, import_react14.useRef)([]);
|
|
4784
|
+
const prefetchedSpeechRef = (0, import_react14.useRef)(/* @__PURE__ */ new Map());
|
|
4785
|
+
const nearEndTimeoutRef = (0, import_react14.useRef)(null);
|
|
4786
|
+
const queuePromiseRef = (0, import_react14.useRef)(Promise.resolve());
|
|
4787
|
+
const queueSeqRef = (0, import_react14.useRef)(0);
|
|
4788
|
+
const lastStopSeqRef = (0, import_react14.useRef)(0);
|
|
4789
|
+
const listeningSessionIdRef = (0, import_react14.useRef)(null);
|
|
4790
|
+
const listeningStartedAtRef = (0, import_react14.useRef)(0);
|
|
4791
|
+
const loopbackRef = (0, import_react14.useRef)(null);
|
|
4792
|
+
const aecActiveRef = (0, import_react14.useRef)(false);
|
|
4793
|
+
const mediaRecorderRef = (0, import_react14.useRef)(null);
|
|
4794
|
+
const micStreamRef = (0, import_react14.useRef)(null);
|
|
4795
|
+
const sttSocketRef = (0, import_react14.useRef)(null);
|
|
4796
|
+
const stopLiveSttTransport = (0, import_react14.useCallback)(() => {
|
|
4824
4797
|
const socket = sttSocketRef.current;
|
|
4825
4798
|
sttSocketRef.current = null;
|
|
4826
4799
|
if (socket) {
|
|
@@ -4849,16 +4822,16 @@ function useVoice(serverUrl) {
|
|
|
4849
4822
|
}
|
|
4850
4823
|
mediaRecorderRef.current = null;
|
|
4851
4824
|
}, []);
|
|
4852
|
-
(0,
|
|
4825
|
+
(0, import_react14.useEffect)(() => {
|
|
4853
4826
|
isMutedRef.current = isMuted;
|
|
4854
4827
|
}, [isMuted]);
|
|
4855
|
-
(0,
|
|
4828
|
+
(0, import_react14.useEffect)(() => {
|
|
4856
4829
|
isSpeakingRef.current = isSpeaking;
|
|
4857
4830
|
}, [isSpeaking]);
|
|
4858
4831
|
const webSpeechSupported = typeof window !== "undefined" && !!(window.SpeechRecognition || window.webkitSpeechRecognition);
|
|
4859
4832
|
const mediaCaptureSupported = typeof window !== "undefined" && typeof navigator !== "undefined" && !!navigator.mediaDevices?.getUserMedia && typeof MediaRecorder !== "undefined";
|
|
4860
4833
|
const sttSupported = typeof window !== "undefined" && (mediaCaptureSupported || webSpeechSupported);
|
|
4861
|
-
const stopSpeaking = (0,
|
|
4834
|
+
const stopSpeaking = (0, import_react14.useCallback)(() => {
|
|
4862
4835
|
emitVoiceDebug("tts_stop", {
|
|
4863
4836
|
queueSeq: queueSeqRef.current,
|
|
4864
4837
|
wasSpeaking: isSpeakingRef.current
|
|
@@ -4885,8 +4858,8 @@ function useVoice(serverUrl) {
|
|
|
4885
4858
|
speakResolveRef.current?.();
|
|
4886
4859
|
speakResolveRef.current = null;
|
|
4887
4860
|
}, []);
|
|
4888
|
-
const getSpeechCacheKey = (0,
|
|
4889
|
-
const loadAudioDurationMs = (0,
|
|
4861
|
+
const getSpeechCacheKey = (0, import_react14.useCallback)((text, voiceId) => `${voiceId}::${text}`, []);
|
|
4862
|
+
const loadAudioDurationMs = (0, import_react14.useCallback)(async (url, fallbackText) => {
|
|
4890
4863
|
try {
|
|
4891
4864
|
const probe = new Audio();
|
|
4892
4865
|
probe.preload = "metadata";
|
|
@@ -4908,7 +4881,7 @@ function useVoice(serverUrl) {
|
|
|
4908
4881
|
return estimateSpeechDurationMs(fallbackText);
|
|
4909
4882
|
}
|
|
4910
4883
|
}, []);
|
|
4911
|
-
const fetchSpeechClip = (0,
|
|
4884
|
+
const fetchSpeechClip = (0, import_react14.useCallback)(async (text, voiceId) => {
|
|
4912
4885
|
const baseUrl = serverUrl.replace(/\/$/, "");
|
|
4913
4886
|
const debugEnabled = isVoiceDebugEnabled();
|
|
4914
4887
|
const requestId = createVoiceDebugId("tts");
|
|
@@ -4970,7 +4943,7 @@ function useVoice(serverUrl) {
|
|
|
4970
4943
|
});
|
|
4971
4944
|
return { url, durationMs, requestId, buffered: true };
|
|
4972
4945
|
}, [loadAudioDurationMs, serverUrl]);
|
|
4973
|
-
const createStreamingSpeechClipForPlayback = (0,
|
|
4946
|
+
const createStreamingSpeechClipForPlayback = (0, import_react14.useCallback)((text, voiceId) => {
|
|
4974
4947
|
const requestId = createVoiceDebugId("tts");
|
|
4975
4948
|
const clip = createStreamingSpeechClip(serverUrl, text, voiceId, {
|
|
4976
4949
|
requestId,
|
|
@@ -4985,7 +4958,7 @@ function useVoice(serverUrl) {
|
|
|
4985
4958
|
});
|
|
4986
4959
|
return clip;
|
|
4987
4960
|
}, [serverUrl]);
|
|
4988
|
-
const prefetchSpeech = (0,
|
|
4961
|
+
const prefetchSpeech = (0, import_react14.useCallback)(async (text, voiceId = DEFAULT_VOICE_ID) => {
|
|
4989
4962
|
if (isMutedRef.current || !text.trim()) return;
|
|
4990
4963
|
const key = getSpeechCacheKey(text, voiceId);
|
|
4991
4964
|
if (!prefetchedSpeechRef.current.has(key)) {
|
|
@@ -4999,7 +4972,7 @@ function useVoice(serverUrl) {
|
|
|
4999
4972
|
}
|
|
5000
4973
|
await prefetchedSpeechRef.current.get(key);
|
|
5001
4974
|
}, [fetchSpeechClip, getSpeechCacheKey]);
|
|
5002
|
-
const playClipDirect = (0,
|
|
4975
|
+
const playClipDirect = (0, import_react14.useCallback)(async (clip, timeoutMs) => {
|
|
5003
4976
|
const { url } = clip;
|
|
5004
4977
|
const audio = new Audio();
|
|
5005
4978
|
audio.crossOrigin = "anonymous";
|
|
@@ -5095,7 +5068,7 @@ function useVoice(serverUrl) {
|
|
|
5095
5068
|
});
|
|
5096
5069
|
});
|
|
5097
5070
|
}, []);
|
|
5098
|
-
const speak = (0,
|
|
5071
|
+
const speak = (0, import_react14.useCallback)(async (text, voiceId = DEFAULT_VOICE_ID, options = {}) => {
|
|
5099
5072
|
if (isMutedRef.current) return;
|
|
5100
5073
|
const mySeq = ++queueSeqRef.current;
|
|
5101
5074
|
const interrupt = options.interrupt === true;
|
|
@@ -5187,7 +5160,7 @@ function useVoice(serverUrl) {
|
|
|
5187
5160
|
}
|
|
5188
5161
|
return taskPromise;
|
|
5189
5162
|
}, [createStreamingSpeechClipForPlayback, fetchSpeechClip, getSpeechCacheKey, playClipDirect, stopSpeaking]);
|
|
5190
|
-
const stopListening = (0,
|
|
5163
|
+
const stopListening = (0, import_react14.useCallback)(() => {
|
|
5191
5164
|
emitVoiceDebug("stt_stop_listening", {
|
|
5192
5165
|
listeningSessionId: listeningSessionIdRef.current,
|
|
5193
5166
|
listeningMs: listeningStartedAtRef.current ? Math.round(performance.now() - listeningStartedAtRef.current) : null
|
|
@@ -5219,7 +5192,7 @@ function useVoice(serverUrl) {
|
|
|
5219
5192
|
accumulatedRef.current = [];
|
|
5220
5193
|
setIsListening(false);
|
|
5221
5194
|
}, [stopLiveSttTransport]);
|
|
5222
|
-
const startListening = (0,
|
|
5195
|
+
const startListening = (0, import_react14.useCallback)((onResult, onInterruption, onError, options = {}) => {
|
|
5223
5196
|
console.log("[Voice] startListening called, options:", options);
|
|
5224
5197
|
stopListening();
|
|
5225
5198
|
listeningSessionIdRef.current = createVoiceDebugId("stt");
|
|
@@ -5502,7 +5475,7 @@ function useVoice(serverUrl) {
|
|
|
5502
5475
|
}
|
|
5503
5476
|
fallbackToWebSpeech();
|
|
5504
5477
|
}, [serverUrl, stopListening, stopSpeaking, stopLiveSttTransport]);
|
|
5505
|
-
const toggleMute = (0,
|
|
5478
|
+
const toggleMute = (0, import_react14.useCallback)(() => {
|
|
5506
5479
|
setIsMuted((prev) => {
|
|
5507
5480
|
const next = !prev;
|
|
5508
5481
|
if (next) {
|
|
@@ -5514,7 +5487,7 @@ function useVoice(serverUrl) {
|
|
|
5514
5487
|
return next;
|
|
5515
5488
|
});
|
|
5516
5489
|
}, []);
|
|
5517
|
-
(0,
|
|
5490
|
+
(0, import_react14.useEffect)(() => {
|
|
5518
5491
|
return () => {
|
|
5519
5492
|
stopSpeaking();
|
|
5520
5493
|
stopListening();
|
|
@@ -5543,18 +5516,18 @@ function useVoice(serverUrl) {
|
|
|
5543
5516
|
}
|
|
5544
5517
|
|
|
5545
5518
|
// src/hooks/useAudioLevel.ts
|
|
5546
|
-
var
|
|
5519
|
+
var import_react15 = require("react");
|
|
5547
5520
|
var BAR_COUNT = 9;
|
|
5548
5521
|
var SENSITIVITY = 2.8;
|
|
5549
5522
|
var FLOOR = 0.08;
|
|
5550
5523
|
function useAudioLevel(active) {
|
|
5551
|
-
const [levels, setLevels] = (0,
|
|
5552
|
-
const streamRef = (0,
|
|
5553
|
-
const ctxRef = (0,
|
|
5554
|
-
const analyserRef = (0,
|
|
5555
|
-
const rafRef = (0,
|
|
5556
|
-
const timeDataRef = (0,
|
|
5557
|
-
(0,
|
|
5524
|
+
const [levels, setLevels] = (0, import_react15.useState)(() => Array(BAR_COUNT).fill(FLOOR));
|
|
5525
|
+
const streamRef = (0, import_react15.useRef)(null);
|
|
5526
|
+
const ctxRef = (0, import_react15.useRef)(null);
|
|
5527
|
+
const analyserRef = (0, import_react15.useRef)(null);
|
|
5528
|
+
const rafRef = (0, import_react15.useRef)(0);
|
|
5529
|
+
const timeDataRef = (0, import_react15.useRef)(null);
|
|
5530
|
+
(0, import_react15.useEffect)(() => {
|
|
5558
5531
|
if (!active || typeof window === "undefined") {
|
|
5559
5532
|
setLevels(Array(BAR_COUNT).fill(FLOOR));
|
|
5560
5533
|
return;
|
|
@@ -5626,7 +5599,7 @@ function useAudioLevel(active) {
|
|
|
5626
5599
|
}
|
|
5627
5600
|
|
|
5628
5601
|
// src/hooks/useRecordingMode.ts
|
|
5629
|
-
var
|
|
5602
|
+
var import_react16 = require("react");
|
|
5630
5603
|
|
|
5631
5604
|
// src/utils/tourStepTypes.ts
|
|
5632
5605
|
function isAskDrivenInputStepType(stepType) {
|
|
@@ -5908,36 +5881,36 @@ function useRecordingMode({
|
|
|
5908
5881
|
onPreview,
|
|
5909
5882
|
experienceType = "tour"
|
|
5910
5883
|
}) {
|
|
5911
|
-
const [phase, setPhase] = (0,
|
|
5912
|
-
const [steps, setSteps] = (0,
|
|
5913
|
-
const [selectedElement, setSelectedElement] = (0,
|
|
5914
|
-
const [selectedStepType, setSelectedStepType] = (0,
|
|
5915
|
-
const [pendingNarration, setPendingNarration] = (0,
|
|
5916
|
-
const [polishedNarration, setPolishedNarration] = (0,
|
|
5917
|
-
const [captureEvents, setCaptureEvents] = (0,
|
|
5918
|
-
const [capturedTranscript, setCapturedTranscript] = (0,
|
|
5919
|
-
const [isVoiceCaptureActive, setIsVoiceCaptureActive] = (0,
|
|
5920
|
-
const stepsRef = (0,
|
|
5884
|
+
const [phase, setPhase] = (0, import_react16.useState)("idle");
|
|
5885
|
+
const [steps, setSteps] = (0, import_react16.useState)([]);
|
|
5886
|
+
const [selectedElement, setSelectedElement] = (0, import_react16.useState)(null);
|
|
5887
|
+
const [selectedStepType, setSelectedStepType] = (0, import_react16.useState)("ask_or_fill");
|
|
5888
|
+
const [pendingNarration, setPendingNarration] = (0, import_react16.useState)("");
|
|
5889
|
+
const [polishedNarration, setPolishedNarration] = (0, import_react16.useState)("");
|
|
5890
|
+
const [captureEvents, setCaptureEvents] = (0, import_react16.useState)([]);
|
|
5891
|
+
const [capturedTranscript, setCapturedTranscript] = (0, import_react16.useState)("");
|
|
5892
|
+
const [isVoiceCaptureActive, setIsVoiceCaptureActive] = (0, import_react16.useState)(false);
|
|
5893
|
+
const stepsRef = (0, import_react16.useRef)([]);
|
|
5921
5894
|
stepsRef.current = steps;
|
|
5922
|
-
const captureEventsRef = (0,
|
|
5923
|
-
const safeSpeak = (0,
|
|
5895
|
+
const captureEventsRef = (0, import_react16.useRef)([]);
|
|
5896
|
+
const safeSpeak = (0, import_react16.useCallback)((text) => {
|
|
5924
5897
|
void voice.speak(text).catch((err) => {
|
|
5925
5898
|
console.warn("[Recording] Voice playback unavailable:", err);
|
|
5926
5899
|
});
|
|
5927
5900
|
}, [voice]);
|
|
5928
5901
|
captureEventsRef.current = captureEvents;
|
|
5929
|
-
const pendingClicksRef = (0,
|
|
5930
|
-
const shouldKeepVoiceCaptureRef = (0,
|
|
5931
|
-
const resumeVoiceAfterNarrationRef = (0,
|
|
5932
|
-
const lastAutoNoteRef = (0,
|
|
5933
|
-
const lastHoverKeyRef = (0,
|
|
5934
|
-
const lastHoverAtRef = (0,
|
|
5935
|
-
const selectedStepTypeRef = (0,
|
|
5902
|
+
const pendingClicksRef = (0, import_react16.useRef)([]);
|
|
5903
|
+
const shouldKeepVoiceCaptureRef = (0, import_react16.useRef)(false);
|
|
5904
|
+
const resumeVoiceAfterNarrationRef = (0, import_react16.useRef)(false);
|
|
5905
|
+
const lastAutoNoteRef = (0, import_react16.useRef)("");
|
|
5906
|
+
const lastHoverKeyRef = (0, import_react16.useRef)("");
|
|
5907
|
+
const lastHoverAtRef = (0, import_react16.useRef)(0);
|
|
5908
|
+
const selectedStepTypeRef = (0, import_react16.useRef)("ask_or_fill");
|
|
5936
5909
|
selectedStepTypeRef.current = selectedStepType;
|
|
5937
5910
|
const isRecording = phase !== "idle";
|
|
5938
5911
|
const stepCount = steps.length;
|
|
5939
5912
|
const captureEventCount = captureEvents.length;
|
|
5940
|
-
const appendCaptureEvent = (0,
|
|
5913
|
+
const appendCaptureEvent = (0, import_react16.useCallback)((event) => {
|
|
5941
5914
|
setCaptureEvents((prev) => {
|
|
5942
5915
|
const nextEvent = {
|
|
5943
5916
|
id: event.id || newCaptureId(event.type),
|
|
@@ -5948,7 +5921,7 @@ function useRecordingMode({
|
|
|
5948
5921
|
return [...prev, nextEvent];
|
|
5949
5922
|
});
|
|
5950
5923
|
}, []);
|
|
5951
|
-
const updateCaptureEvent = (0,
|
|
5924
|
+
const updateCaptureEvent = (0, import_react16.useCallback)((id, metadataPatch) => {
|
|
5952
5925
|
setCaptureEvents((prev) => prev.map((event) => {
|
|
5953
5926
|
if (event.id === id) {
|
|
5954
5927
|
return {
|
|
@@ -5962,7 +5935,7 @@ function useRecordingMode({
|
|
|
5962
5935
|
return event;
|
|
5963
5936
|
}));
|
|
5964
5937
|
}, []);
|
|
5965
|
-
const appendVoiceNote = (0,
|
|
5938
|
+
const appendVoiceNote = (0, import_react16.useCallback)((transcript) => {
|
|
5966
5939
|
const text = transcript.trim();
|
|
5967
5940
|
if (!text) return;
|
|
5968
5941
|
if (lastAutoNoteRef.current === text) return;
|
|
@@ -6018,11 +5991,11 @@ function useRecordingMode({
|
|
|
6018
5991
|
}
|
|
6019
5992
|
});
|
|
6020
5993
|
}, [appendCaptureEvent]);
|
|
6021
|
-
const stopBackgroundVoiceCapture = (0,
|
|
5994
|
+
const stopBackgroundVoiceCapture = (0, import_react16.useCallback)(() => {
|
|
6022
5995
|
voice.stopListening();
|
|
6023
5996
|
setIsVoiceCaptureActive(false);
|
|
6024
5997
|
}, [voice]);
|
|
6025
|
-
const startBackgroundVoiceCapture = (0,
|
|
5998
|
+
const startBackgroundVoiceCapture = (0, import_react16.useCallback)(() => {
|
|
6026
5999
|
if (!shouldKeepVoiceCaptureRef.current) return;
|
|
6027
6000
|
if (!isRecording) return;
|
|
6028
6001
|
if (phase === "narrating" || phase === "reviewing") return;
|
|
@@ -6039,7 +6012,7 @@ function useRecordingMode({
|
|
|
6039
6012
|
);
|
|
6040
6013
|
setIsVoiceCaptureActive(true);
|
|
6041
6014
|
}, [appendVoiceNote, isRecording, phase, voice]);
|
|
6042
|
-
const startRecording = (0,
|
|
6015
|
+
const startRecording = (0, import_react16.useCallback)(() => {
|
|
6043
6016
|
setPhase("active");
|
|
6044
6017
|
setSteps([]);
|
|
6045
6018
|
pendingClicksRef.current = [];
|
|
@@ -6058,34 +6031,34 @@ function useRecordingMode({
|
|
|
6058
6031
|
lastHoverKeyRef.current = "";
|
|
6059
6032
|
lastHoverAtRef.current = 0;
|
|
6060
6033
|
}, []);
|
|
6061
|
-
const markStep = (0,
|
|
6034
|
+
const markStep = (0, import_react16.useCallback)(() => {
|
|
6062
6035
|
if (phase !== "active") return;
|
|
6063
6036
|
setPhase("selecting");
|
|
6064
6037
|
}, [phase]);
|
|
6065
|
-
const selectElement = (0,
|
|
6038
|
+
const selectElement = (0, import_react16.useCallback)((recorded) => {
|
|
6066
6039
|
setSelectedElement(recorded);
|
|
6067
6040
|
setPhase("configuring");
|
|
6068
6041
|
const isFormField = ["INPUT", "SELECT", "TEXTAREA"].includes(recorded.el.tagName);
|
|
6069
6042
|
setSelectedStepType(isFormField ? "ask_or_fill" : "narrate");
|
|
6070
6043
|
}, []);
|
|
6071
|
-
const selectPageLevel = (0,
|
|
6044
|
+
const selectPageLevel = (0, import_react16.useCallback)(() => {
|
|
6072
6045
|
setSelectedElement(null);
|
|
6073
6046
|
setSelectedStepType("narrate");
|
|
6074
6047
|
setPhase("configuring");
|
|
6075
6048
|
}, []);
|
|
6076
|
-
const cancelSelection = (0,
|
|
6049
|
+
const cancelSelection = (0, import_react16.useCallback)(() => {
|
|
6077
6050
|
setSelectedElement(null);
|
|
6078
6051
|
setPhase("active");
|
|
6079
6052
|
}, []);
|
|
6080
|
-
const setStepType = (0,
|
|
6053
|
+
const setStepType = (0, import_react16.useCallback)((type) => {
|
|
6081
6054
|
setSelectedStepType(type);
|
|
6082
6055
|
}, []);
|
|
6083
|
-
const runPolishAndReview = (0,
|
|
6056
|
+
const runPolishAndReview = (0, import_react16.useCallback)(async (transcript) => {
|
|
6084
6057
|
setPolishedNarration(transcript);
|
|
6085
6058
|
setPhase("reviewing");
|
|
6086
6059
|
}, []);
|
|
6087
|
-
const pendingNarrationRef = (0,
|
|
6088
|
-
const startNarration = (0,
|
|
6060
|
+
const pendingNarrationRef = (0, import_react16.useRef)("");
|
|
6061
|
+
const startNarration = (0, import_react16.useCallback)(() => {
|
|
6089
6062
|
resumeVoiceAfterNarrationRef.current = shouldKeepVoiceCaptureRef.current && isVoiceCaptureActive;
|
|
6090
6063
|
if (isVoiceCaptureActive) {
|
|
6091
6064
|
stopBackgroundVoiceCapture();
|
|
@@ -6107,7 +6080,7 @@ function useRecordingMode({
|
|
|
6107
6080
|
{ continuous: true }
|
|
6108
6081
|
);
|
|
6109
6082
|
}, [isVoiceCaptureActive, stopBackgroundVoiceCapture, voice]);
|
|
6110
|
-
const finishNarration = (0,
|
|
6083
|
+
const finishNarration = (0, import_react16.useCallback)(async () => {
|
|
6111
6084
|
if (phase !== "narrating") return;
|
|
6112
6085
|
voice.stopListening();
|
|
6113
6086
|
const text = pendingNarrationRef.current;
|
|
@@ -6122,13 +6095,13 @@ function useRecordingMode({
|
|
|
6122
6095
|
}
|
|
6123
6096
|
}
|
|
6124
6097
|
}, [phase, runPolishAndReview, startBackgroundVoiceCapture, voice]);
|
|
6125
|
-
const submitTextNarration = (0,
|
|
6098
|
+
const submitTextNarration = (0, import_react16.useCallback)(async (text) => {
|
|
6126
6099
|
if (phase !== "narrating" || !text.trim()) return;
|
|
6127
6100
|
voice.stopListening();
|
|
6128
6101
|
setPendingNarration(text);
|
|
6129
6102
|
await runPolishAndReview(text);
|
|
6130
6103
|
}, [phase, voice, runPolishAndReview]);
|
|
6131
|
-
const approveNarration = (0,
|
|
6104
|
+
const approveNarration = (0, import_react16.useCallback)(() => {
|
|
6132
6105
|
if (phase !== "reviewing") return;
|
|
6133
6106
|
const el = selectedElement;
|
|
6134
6107
|
const narration = polishedNarration || pendingNarration;
|
|
@@ -6214,17 +6187,17 @@ function useRecordingMode({
|
|
|
6214
6187
|
}, 0);
|
|
6215
6188
|
}
|
|
6216
6189
|
}, [appendCaptureEvent, phase, polishedNarration, pendingNarration, selectedElement, selectedStepType, startBackgroundVoiceCapture, voice]);
|
|
6217
|
-
const redoNarration = (0,
|
|
6190
|
+
const redoNarration = (0, import_react16.useCallback)(() => {
|
|
6218
6191
|
if (phase !== "reviewing") return;
|
|
6219
6192
|
setPendingNarration("");
|
|
6220
6193
|
setPolishedNarration("");
|
|
6221
6194
|
startNarration();
|
|
6222
6195
|
}, [phase, startNarration]);
|
|
6223
|
-
const editNarration = (0,
|
|
6196
|
+
const editNarration = (0, import_react16.useCallback)((text) => {
|
|
6224
6197
|
setPendingNarration(text);
|
|
6225
6198
|
setPolishedNarration(text);
|
|
6226
6199
|
}, []);
|
|
6227
|
-
const continueRecording = (0,
|
|
6200
|
+
const continueRecording = (0, import_react16.useCallback)(() => {
|
|
6228
6201
|
setPhase("active");
|
|
6229
6202
|
if (shouldKeepVoiceCaptureRef.current) {
|
|
6230
6203
|
window.setTimeout(() => {
|
|
@@ -6232,7 +6205,7 @@ function useRecordingMode({
|
|
|
6232
6205
|
}, 0);
|
|
6233
6206
|
}
|
|
6234
6207
|
}, [startBackgroundVoiceCapture]);
|
|
6235
|
-
const undoLastStep = (0,
|
|
6208
|
+
const undoLastStep = (0, import_react16.useCallback)(() => {
|
|
6236
6209
|
setSteps((prev) => {
|
|
6237
6210
|
const next = prev.slice(0, -1);
|
|
6238
6211
|
safeSpeak(
|
|
@@ -6242,7 +6215,7 @@ function useRecordingMode({
|
|
|
6242
6215
|
});
|
|
6243
6216
|
setPhase("active");
|
|
6244
6217
|
}, [voice]);
|
|
6245
|
-
const previewSteps = (0,
|
|
6218
|
+
const previewSteps = (0, import_react16.useCallback)(() => {
|
|
6246
6219
|
if (steps.length === 0) {
|
|
6247
6220
|
safeSpeak("No steps recorded yet.");
|
|
6248
6221
|
return;
|
|
@@ -6250,12 +6223,12 @@ function useRecordingMode({
|
|
|
6250
6223
|
onPreview?.(steps);
|
|
6251
6224
|
safeSpeak(`Previewing ${steps.length} step${steps.length !== 1 ? "s" : ""}.`);
|
|
6252
6225
|
}, [onPreview, safeSpeak, steps]);
|
|
6253
|
-
const prepareToStopRecording = (0,
|
|
6226
|
+
const prepareToStopRecording = (0, import_react16.useCallback)(() => {
|
|
6254
6227
|
shouldKeepVoiceCaptureRef.current = false;
|
|
6255
6228
|
resumeVoiceAfterNarrationRef.current = false;
|
|
6256
6229
|
stopBackgroundVoiceCapture();
|
|
6257
6230
|
}, [stopBackgroundVoiceCapture]);
|
|
6258
|
-
const cancelRecording = (0,
|
|
6231
|
+
const cancelRecording = (0, import_react16.useCallback)(() => {
|
|
6259
6232
|
shouldKeepVoiceCaptureRef.current = false;
|
|
6260
6233
|
stopBackgroundVoiceCapture();
|
|
6261
6234
|
setPhase("idle");
|
|
@@ -6268,7 +6241,7 @@ function useRecordingMode({
|
|
|
6268
6241
|
setPolishedNarration("");
|
|
6269
6242
|
safeSpeak("Recording cancelled.");
|
|
6270
6243
|
}, [safeSpeak, stopBackgroundVoiceCapture]);
|
|
6271
|
-
(0,
|
|
6244
|
+
(0, import_react16.useEffect)(() => {
|
|
6272
6245
|
if (!isRecording || typeof document === "undefined") return;
|
|
6273
6246
|
const handleMouseMove = (event) => {
|
|
6274
6247
|
const target = event.target;
|
|
@@ -6392,7 +6365,7 @@ function useRecordingMode({
|
|
|
6392
6365
|
window.clearInterval(routePoll);
|
|
6393
6366
|
};
|
|
6394
6367
|
}, [appendCaptureEvent, isRecording]);
|
|
6395
|
-
const stopRecording = (0,
|
|
6368
|
+
const stopRecording = (0, import_react16.useCallback)(async (tourName, targetUserTypes) => {
|
|
6396
6369
|
setPhase("finishing");
|
|
6397
6370
|
shouldKeepVoiceCaptureRef.current = false;
|
|
6398
6371
|
stopBackgroundVoiceCapture();
|
|
@@ -6447,17 +6420,17 @@ function useRecordingMode({
|
|
|
6447
6420
|
pendingClicksRef.current = [];
|
|
6448
6421
|
setPhase("idle");
|
|
6449
6422
|
const savedStepCount = Array.isArray(data?.tour?.steps) ? data.tour.steps.length : 0;
|
|
6450
|
-
const itemLabel = experienceType === "onboarding" ? "
|
|
6451
|
-
safeSpeak(`${itemLabel === "tour" ? "Tour" : "
|
|
6423
|
+
const itemLabel = experienceType === "onboarding" ? "workflow" : "tour";
|
|
6424
|
+
safeSpeak(`${itemLabel === "tour" ? "Tour" : "Workflow"} "${tourName}" saved as a draft with ${savedStepCount} generated steps. Review and preview it before publishing.`);
|
|
6452
6425
|
return data.id ?? null;
|
|
6453
6426
|
} catch (err) {
|
|
6454
6427
|
console.error("[Recording] Failed to save tour:", err);
|
|
6455
|
-
safeSpeak(`Failed to save the ${experienceType === "onboarding" ? "
|
|
6428
|
+
safeSpeak(`Failed to save the ${experienceType === "onboarding" ? "workflow" : "tour"}. Please try again.`);
|
|
6456
6429
|
setPhase("active");
|
|
6457
6430
|
return null;
|
|
6458
6431
|
}
|
|
6459
6432
|
}, [capturedTranscript, experienceType, safeSpeak, serverUrl, stopBackgroundVoiceCapture, steps, toursApiBase, websiteId]);
|
|
6460
|
-
const toggleVoiceCapture = (0,
|
|
6433
|
+
const toggleVoiceCapture = (0, import_react16.useCallback)(() => {
|
|
6461
6434
|
if (isVoiceCaptureActive || shouldKeepVoiceCaptureRef.current) {
|
|
6462
6435
|
shouldKeepVoiceCaptureRef.current = false;
|
|
6463
6436
|
stopBackgroundVoiceCapture();
|
|
@@ -6466,7 +6439,7 @@ function useRecordingMode({
|
|
|
6466
6439
|
shouldKeepVoiceCaptureRef.current = true;
|
|
6467
6440
|
startBackgroundVoiceCapture();
|
|
6468
6441
|
}, [isVoiceCaptureActive, startBackgroundVoiceCapture, stopBackgroundVoiceCapture]);
|
|
6469
|
-
(0,
|
|
6442
|
+
(0, import_react16.useEffect)(() => {
|
|
6470
6443
|
if (!isRecording) return;
|
|
6471
6444
|
if (phase === "active" && shouldKeepVoiceCaptureRef.current && !isVoiceCaptureActive) {
|
|
6472
6445
|
startBackgroundVoiceCapture();
|
|
@@ -6475,7 +6448,7 @@ function useRecordingMode({
|
|
|
6475
6448
|
stopBackgroundVoiceCapture();
|
|
6476
6449
|
}
|
|
6477
6450
|
}, [isRecording, isVoiceCaptureActive, phase, startBackgroundVoiceCapture, stopBackgroundVoiceCapture]);
|
|
6478
|
-
const handleVoiceCommand = (0,
|
|
6451
|
+
const handleVoiceCommand = (0, import_react16.useCallback)((transcript) => {
|
|
6479
6452
|
const lower = transcript.toLowerCase().trim();
|
|
6480
6453
|
if (!isRecording) return;
|
|
6481
6454
|
if (lower.includes("mark step") && phase === "active") {
|
|
@@ -6537,7 +6510,7 @@ function useRecordingMode({
|
|
|
6537
6510
|
}
|
|
6538
6511
|
|
|
6539
6512
|
// src/components/RecordingOverlay.tsx
|
|
6540
|
-
var
|
|
6513
|
+
var import_react17 = require("react");
|
|
6541
6514
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
6542
6515
|
function buildFingerprint(el) {
|
|
6543
6516
|
const tag = el.tagName.toLowerCase();
|
|
@@ -6825,8 +6798,8 @@ var STEP_TYPES_ADVANCED = [
|
|
|
6825
6798
|
];
|
|
6826
6799
|
function StepPopover({ element, stepIndex, onConfirm, onCancel }) {
|
|
6827
6800
|
const defaultType = element && ["INPUT", "SELECT", "TEXTAREA"].includes(element.el.tagName) ? "ask_or_fill" : "narrate";
|
|
6828
|
-
const [selected, setSelected] = (0,
|
|
6829
|
-
const [showAdvanced, setShowAdvanced] = (0,
|
|
6801
|
+
const [selected, setSelected] = (0, import_react17.useState)(defaultType);
|
|
6802
|
+
const [showAdvanced, setShowAdvanced] = (0, import_react17.useState)(false);
|
|
6830
6803
|
const hasTestId = !!element?.testId;
|
|
6831
6804
|
const allTypes = showAdvanced ? [...STEP_TYPES_PRIMARY, ...STEP_TYPES_ADVANCED] : STEP_TYPES_PRIMARY;
|
|
6832
6805
|
const popoverStyle = {
|
|
@@ -6970,8 +6943,8 @@ function StepPopover({ element, stepIndex, onConfirm, onCancel }) {
|
|
|
6970
6943
|
] });
|
|
6971
6944
|
}
|
|
6972
6945
|
function NarrationPanel({ stepIndex, stepCount, pendingNarration, isListening, onSubmitText, onCancel, onStopRecording }) {
|
|
6973
|
-
const [textInput, setTextInput] = (0,
|
|
6974
|
-
const [showTextInput, setShowTextInput] = (0,
|
|
6946
|
+
const [textInput, setTextInput] = (0, import_react17.useState)("");
|
|
6947
|
+
const [showTextInput, setShowTextInput] = (0, import_react17.useState)(false);
|
|
6975
6948
|
const audioLevels = useAudioLevel(isListening);
|
|
6976
6949
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
6977
6950
|
"div",
|
|
@@ -7138,8 +7111,8 @@ function NarrationPanel({ stepIndex, stepCount, pendingNarration, isListening, o
|
|
|
7138
7111
|
);
|
|
7139
7112
|
}
|
|
7140
7113
|
function ReviewPanel({ stepIndex, stepCount, polishedNarration, rawNarration, onApprove, onRedo, onEdit }) {
|
|
7141
|
-
const [editMode, setEditMode] = (0,
|
|
7142
|
-
const [editText, setEditText] = (0,
|
|
7114
|
+
const [editMode, setEditMode] = (0, import_react17.useState)(false);
|
|
7115
|
+
const [editText, setEditText] = (0, import_react17.useState)(polishedNarration || rawNarration);
|
|
7143
7116
|
const displayText = polishedNarration || rawNarration;
|
|
7144
7117
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
7145
7118
|
"div",
|
|
@@ -7434,17 +7407,17 @@ function RecordingOverlay({
|
|
|
7434
7407
|
onCancelRecording,
|
|
7435
7408
|
onStopRecording
|
|
7436
7409
|
}) {
|
|
7437
|
-
const [hoveredEl, setHoveredEl] = (0,
|
|
7438
|
-
const [pendingElement, setPendingElement] = (0,
|
|
7439
|
-
const [showPopover, setShowPopover] = (0,
|
|
7440
|
-
const [hudMinimized, setHudMinimized] = (0,
|
|
7441
|
-
const [voicePanelMinimized, setVoicePanelMinimized] = (0,
|
|
7410
|
+
const [hoveredEl, setHoveredEl] = (0, import_react17.useState)(null);
|
|
7411
|
+
const [pendingElement, setPendingElement] = (0, import_react17.useState)(null);
|
|
7412
|
+
const [showPopover, setShowPopover] = (0, import_react17.useState)(false);
|
|
7413
|
+
const [hudMinimized, setHudMinimized] = (0, import_react17.useState)(false);
|
|
7414
|
+
const [voicePanelMinimized, setVoicePanelMinimized] = (0, import_react17.useState)(false);
|
|
7442
7415
|
const isSelecting = phase === "selecting";
|
|
7443
|
-
const handleMouseMove = (0,
|
|
7416
|
+
const handleMouseMove = (0, import_react17.useCallback)((e) => {
|
|
7444
7417
|
const target = e.target.closest(INTERACTIVE_SELECTOR2);
|
|
7445
7418
|
setHoveredEl(target);
|
|
7446
7419
|
}, []);
|
|
7447
|
-
const handleClick = (0,
|
|
7420
|
+
const handleClick = (0, import_react17.useCallback)((e) => {
|
|
7448
7421
|
if (e.target.closest("[data-modelnex-internal]")) return;
|
|
7449
7422
|
const target = e.target.closest(INTERACTIVE_SELECTOR2);
|
|
7450
7423
|
if (target) {
|
|
@@ -7469,7 +7442,7 @@ function RecordingOverlay({
|
|
|
7469
7442
|
setShowPopover(true);
|
|
7470
7443
|
}
|
|
7471
7444
|
}, []);
|
|
7472
|
-
(0,
|
|
7445
|
+
(0, import_react17.useEffect)(() => {
|
|
7473
7446
|
if (!isSelecting) return;
|
|
7474
7447
|
document.addEventListener("mousemove", handleMouseMove, true);
|
|
7475
7448
|
document.addEventListener("click", handleClick, true);
|
|
@@ -7481,14 +7454,14 @@ function RecordingOverlay({
|
|
|
7481
7454
|
document.body.style.cursor = prev;
|
|
7482
7455
|
};
|
|
7483
7456
|
}, [isSelecting, handleMouseMove, handleClick]);
|
|
7484
|
-
(0,
|
|
7457
|
+
(0, import_react17.useEffect)(() => {
|
|
7485
7458
|
if (isSelecting) {
|
|
7486
7459
|
setShowPopover(false);
|
|
7487
7460
|
setPendingElement(null);
|
|
7488
7461
|
setHoveredEl(null);
|
|
7489
7462
|
}
|
|
7490
7463
|
}, [isSelecting]);
|
|
7491
|
-
const handlePopoverConfirm = (0,
|
|
7464
|
+
const handlePopoverConfirm = (0, import_react17.useCallback)((type) => {
|
|
7492
7465
|
setShowPopover(false);
|
|
7493
7466
|
if (pendingElement) {
|
|
7494
7467
|
onElementSelected(pendingElement);
|
|
@@ -7498,7 +7471,7 @@ function RecordingOverlay({
|
|
|
7498
7471
|
onStepTypeConfirmed(type);
|
|
7499
7472
|
onStartNarration();
|
|
7500
7473
|
}, [pendingElement, onElementSelected, onPageLevelStep, onStepTypeConfirmed, onStartNarration]);
|
|
7501
|
-
const handlePopoverCancel = (0,
|
|
7474
|
+
const handlePopoverCancel = (0, import_react17.useCallback)(() => {
|
|
7502
7475
|
setShowPopover(false);
|
|
7503
7476
|
setPendingElement(null);
|
|
7504
7477
|
}, []);
|
|
@@ -7996,8 +7969,8 @@ function shouldIgnoreTourGestureStart(target) {
|
|
|
7996
7969
|
return target instanceof HTMLElement && Boolean(target.closest('[data-modelnex-review-toggle="true"]'));
|
|
7997
7970
|
}
|
|
7998
7971
|
function useMediaQuery(query) {
|
|
7999
|
-
const [matches, setMatches] = (0,
|
|
8000
|
-
(0,
|
|
7972
|
+
const [matches, setMatches] = (0, import_react18.useState)(false);
|
|
7973
|
+
(0, import_react18.useEffect)(() => {
|
|
8001
7974
|
const media = window.matchMedia(query);
|
|
8002
7975
|
if (media.matches !== matches) setMatches(media.matches);
|
|
8003
7976
|
const listener = () => setMatches(media.matches);
|
|
@@ -8069,8 +8042,8 @@ var GLOBAL_STYLES = `
|
|
|
8069
8042
|
}
|
|
8070
8043
|
`;
|
|
8071
8044
|
function Tooltip({ children, title }) {
|
|
8072
|
-
const [show, setShow] = (0,
|
|
8073
|
-
const ref = (0,
|
|
8045
|
+
const [show, setShow] = (0, import_react18.useState)(false);
|
|
8046
|
+
const ref = (0, import_react18.useRef)(null);
|
|
8074
8047
|
const handleShow = () => setShow(true);
|
|
8075
8048
|
const handleHide = () => setShow(false);
|
|
8076
8049
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
@@ -8146,11 +8119,11 @@ var MinimizeIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { w
|
|
|
8146
8119
|
var StopIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) });
|
|
8147
8120
|
var ChevronDown = ({ open }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", style: { transform: open ? "rotate(180deg)" : "none", transition: "transform 0.2s" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "m6 9 6 6 6-6" }) });
|
|
8148
8121
|
function AgentTraces({ debug, command, defaultExpanded = true }) {
|
|
8149
|
-
const [expanded, setExpanded] = (0,
|
|
8150
|
-
const [expandedSteps, setExpandedSteps] = (0,
|
|
8122
|
+
const [expanded, setExpanded] = (0, import_react18.useState)(defaultExpanded);
|
|
8123
|
+
const [expandedSteps, setExpandedSteps] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
|
|
8151
8124
|
const traces = debug.traces ?? [];
|
|
8152
8125
|
const hasTraceContent = traces.length > 0 || debug.llmInput || (debug.llmOutput?.length ?? 0) > 0 || (debug.actions?.length ?? 0) > 0;
|
|
8153
|
-
(0,
|
|
8126
|
+
(0, import_react18.useEffect)(() => {
|
|
8154
8127
|
setExpandedSteps(new Set(traces.map((t) => t.step)));
|
|
8155
8128
|
}, [debug]);
|
|
8156
8129
|
const toggleStep = (step) => {
|
|
@@ -8337,11 +8310,6 @@ var RecordIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { wi
|
|
|
8337
8310
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "8" }),
|
|
8338
8311
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "3", fill: "currentColor" })
|
|
8339
8312
|
] });
|
|
8340
|
-
var MapIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
8341
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polygon", { points: "3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21" }),
|
|
8342
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "9", y1: "3", x2: "9", y2: "18" }),
|
|
8343
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "15", y1: "6", x2: "15", y2: "21" })
|
|
8344
|
-
] });
|
|
8345
8313
|
var BookOpenIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
8346
8314
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" }),
|
|
8347
8315
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" })
|
|
@@ -8350,27 +8318,27 @@ function ModelNexChatBubble({
|
|
|
8350
8318
|
placeholder = "Ask me to do something...",
|
|
8351
8319
|
defaultCommand = "List my documents",
|
|
8352
8320
|
className = "",
|
|
8353
|
-
onCommand,
|
|
8354
8321
|
welcomeMessage = "Hi! I can help you navigate and manage your documents. Try asking me to open a document, go to templates, or filter by status.",
|
|
8355
8322
|
agentName = "ModelNex AI",
|
|
8356
8323
|
appName = "this app",
|
|
8357
|
-
recordingExperienceType = "tour",
|
|
8358
8324
|
theme
|
|
8359
8325
|
}) {
|
|
8360
|
-
const
|
|
8361
|
-
const
|
|
8326
|
+
const onCommand = void 0;
|
|
8327
|
+
const recordingExperienceType = "tour";
|
|
8328
|
+
const noop = (0, import_react18.useCallback)(() => void 0, []);
|
|
8329
|
+
const noopAsync = (0, import_react18.useCallback)(async () => void 0, []);
|
|
8362
8330
|
const runCommand = useRunCommand();
|
|
8363
|
-
const ctx = (0,
|
|
8364
|
-
const [hydrated, setHydrated] = (0,
|
|
8365
|
-
const [expanded, setExpanded] = (0,
|
|
8366
|
-
const [input, setInput] = (0,
|
|
8331
|
+
const ctx = (0, import_react18.useContext)(ModelNexContext);
|
|
8332
|
+
const [hydrated, setHydrated] = (0, import_react18.useState)(false);
|
|
8333
|
+
const [expanded, setExpanded] = (0, import_react18.useState)(false);
|
|
8334
|
+
const [input, setInput] = (0, import_react18.useState)("");
|
|
8367
8335
|
const messages = ctx?.chatMessages ?? [];
|
|
8368
8336
|
const setMessages = ctx?.setChatMessages ?? (() => {
|
|
8369
8337
|
});
|
|
8370
|
-
const [loading, setLoading] = (0,
|
|
8371
|
-
const messagesEndRef = (0,
|
|
8372
|
-
const abortControllerRef = (0,
|
|
8373
|
-
const panelRef = (0,
|
|
8338
|
+
const [loading, setLoading] = (0, import_react18.useState)(false);
|
|
8339
|
+
const messagesEndRef = (0, import_react18.useRef)(null);
|
|
8340
|
+
const abortControllerRef = (0, import_react18.useRef)(null);
|
|
8341
|
+
const panelRef = (0, import_react18.useRef)(null);
|
|
8374
8342
|
const serverUrl = ctx?.serverUrl ?? "http://localhost:3002";
|
|
8375
8343
|
const voice = useVoice(serverUrl);
|
|
8376
8344
|
const audioLevels = useAudioLevel(voice.isListening);
|
|
@@ -8378,13 +8346,13 @@ function ModelNexChatBubble({
|
|
|
8378
8346
|
const setRecordingMode = ctx?.setRecordingMode ?? (() => {
|
|
8379
8347
|
});
|
|
8380
8348
|
const devMode = ctx?.devMode ?? false;
|
|
8381
|
-
const [recordingTourName, setRecordingTourName] = (0,
|
|
8382
|
-
const [recordingTargetTypes, setRecordingTargetTypes] = (0,
|
|
8383
|
-
const [showStopModal, setShowStopModal] = (0,
|
|
8384
|
-
const [savedDraft, setSavedDraft] = (0,
|
|
8385
|
-
const [reviewDraft, setReviewDraft] = (0,
|
|
8386
|
-
const [tourLiveTranscript, setTourLiveTranscript] = (0,
|
|
8387
|
-
const [activeRecordingExperienceType, setActiveRecordingExperienceType] = (0,
|
|
8349
|
+
const [recordingTourName, setRecordingTourName] = (0, import_react18.useState)("");
|
|
8350
|
+
const [recordingTargetTypes, setRecordingTargetTypes] = (0, import_react18.useState)("admin");
|
|
8351
|
+
const [showStopModal, setShowStopModal] = (0, import_react18.useState)(false);
|
|
8352
|
+
const [savedDraft, setSavedDraft] = (0, import_react18.useState)(null);
|
|
8353
|
+
const [reviewDraft, setReviewDraft] = (0, import_react18.useState)("");
|
|
8354
|
+
const [tourLiveTranscript, setTourLiveTranscript] = (0, import_react18.useState)("");
|
|
8355
|
+
const [activeRecordingExperienceType, setActiveRecordingExperienceType] = (0, import_react18.useState)(recordingExperienceType);
|
|
8388
8356
|
const recording = useRecordingMode({
|
|
8389
8357
|
serverUrl,
|
|
8390
8358
|
toursApiBase: ctx?.toursApiBase,
|
|
@@ -8401,7 +8369,6 @@ function ModelNexChatBubble({
|
|
|
8401
8369
|
socketId: ctx?.socketId,
|
|
8402
8370
|
websiteId: ctx?.websiteId,
|
|
8403
8371
|
userProfile: ctx?.userProfile,
|
|
8404
|
-
tourFacts: ctx?.tourFacts,
|
|
8405
8372
|
voice,
|
|
8406
8373
|
appName,
|
|
8407
8374
|
tagStore: ctx?.tagStore,
|
|
@@ -8418,7 +8385,7 @@ function ModelNexChatBubble({
|
|
|
8418
8385
|
const activePlayback = playbackController.playback;
|
|
8419
8386
|
const activeExperienceType = playbackController.activeExperienceType;
|
|
8420
8387
|
const startingExperienceType = playbackController.startingExperienceType;
|
|
8421
|
-
const createPlaybackView = (0,
|
|
8388
|
+
const createPlaybackView = (0, import_react18.useCallback)((experienceType) => {
|
|
8422
8389
|
const isActiveExperience = activePlayback.isActive && activeExperienceType === experienceType;
|
|
8423
8390
|
const pendingTour = playbackController.pendingPrompt?.experienceType === experienceType ? playbackController.pendingPrompt.tour : null;
|
|
8424
8391
|
return {
|
|
@@ -8446,11 +8413,11 @@ function ModelNexChatBubble({
|
|
|
8446
8413
|
submitReviewFeedback: isActiveExperience ? activePlayback.submitReviewFeedback : noopAsync
|
|
8447
8414
|
};
|
|
8448
8415
|
}, [activeExperienceType, activePlayback, noop, noopAsync, playbackController]);
|
|
8449
|
-
const tourPlayback = (0,
|
|
8450
|
-
const onboardingPlayback = (0,
|
|
8416
|
+
const tourPlayback = (0, import_react18.useMemo)(() => createPlaybackView("tour"), [createPlaybackView]);
|
|
8417
|
+
const onboardingPlayback = (0, import_react18.useMemo)(() => createPlaybackView("onboarding"), [createPlaybackView]);
|
|
8451
8418
|
const tourReviewToggle = getReviewModeToggleConfig(tourPlayback.playbackState);
|
|
8452
|
-
const lastAutoTaggedUrlRef = (0,
|
|
8453
|
-
const handleAutoTag = (0,
|
|
8419
|
+
const lastAutoTaggedUrlRef = (0, import_react18.useRef)(null);
|
|
8420
|
+
const handleAutoTag = (0, import_react18.useCallback)(async () => {
|
|
8454
8421
|
if (!ctx) return;
|
|
8455
8422
|
const { extractedElements, tagStore, commandUrl, serverUrl: serverUrl2, websiteId } = ctx;
|
|
8456
8423
|
if (extractedElements.length === 0) return;
|
|
@@ -8504,7 +8471,7 @@ function ModelNexChatBubble({
|
|
|
8504
8471
|
console.warn("[ModelNex] Auto-tag error:", err);
|
|
8505
8472
|
}
|
|
8506
8473
|
}, [ctx]);
|
|
8507
|
-
(0,
|
|
8474
|
+
(0, import_react18.useEffect)(() => {
|
|
8508
8475
|
if (devMode && ctx?.extractedElements.length) {
|
|
8509
8476
|
const timer = setTimeout(handleAutoTag, 1e3);
|
|
8510
8477
|
return () => clearTimeout(timer);
|
|
@@ -8512,7 +8479,7 @@ function ModelNexChatBubble({
|
|
|
8512
8479
|
}, [devMode, handleAutoTag, ctx?.extractedElements.length, window.location.pathname]);
|
|
8513
8480
|
const onboardingReviewToggle = getReviewModeToggleConfig(onboardingPlayback.playbackState);
|
|
8514
8481
|
const pendingNotificationType = (onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.notificationType ?? "bubble_card";
|
|
8515
|
-
(0,
|
|
8482
|
+
(0, import_react18.useEffect)(() => {
|
|
8516
8483
|
setHydrated(true);
|
|
8517
8484
|
try {
|
|
8518
8485
|
setExpanded(sessionStorage.getItem(BUBBLE_EXPANDED_STORAGE_KEY) === "true");
|
|
@@ -8520,27 +8487,27 @@ function ModelNexChatBubble({
|
|
|
8520
8487
|
setExpanded(false);
|
|
8521
8488
|
}
|
|
8522
8489
|
}, []);
|
|
8523
|
-
const sttActiveRef = (0,
|
|
8524
|
-
const [tourListenReady, setTourListenReady] = (0,
|
|
8525
|
-
const [tourSttError, setTourSttError] = (0,
|
|
8526
|
-
const previousTourActiveRef = (0,
|
|
8527
|
-
const tourListenReadyRef = (0,
|
|
8528
|
-
const tourSttErrorRef = (0,
|
|
8529
|
-
const updateTourListenReady = (0,
|
|
8490
|
+
const sttActiveRef = (0, import_react18.useRef)(false);
|
|
8491
|
+
const [tourListenReady, setTourListenReady] = (0, import_react18.useState)(false);
|
|
8492
|
+
const [tourSttError, setTourSttError] = (0, import_react18.useState)(null);
|
|
8493
|
+
const previousTourActiveRef = (0, import_react18.useRef)(false);
|
|
8494
|
+
const tourListenReadyRef = (0, import_react18.useRef)(false);
|
|
8495
|
+
const tourSttErrorRef = (0, import_react18.useRef)(null);
|
|
8496
|
+
const updateTourListenReady = (0, import_react18.useCallback)((next) => {
|
|
8530
8497
|
if (tourListenReadyRef.current === next) return;
|
|
8531
8498
|
tourListenReadyRef.current = next;
|
|
8532
8499
|
setTourListenReady(next);
|
|
8533
8500
|
}, []);
|
|
8534
|
-
const updateTourSttError = (0,
|
|
8501
|
+
const updateTourSttError = (0, import_react18.useCallback)((next) => {
|
|
8535
8502
|
if (tourSttErrorRef.current === next) return;
|
|
8536
8503
|
tourSttErrorRef.current = next;
|
|
8537
8504
|
setTourSttError(next);
|
|
8538
8505
|
}, []);
|
|
8539
|
-
const tourLiveTranscriptLines = (0,
|
|
8506
|
+
const tourLiveTranscriptLines = (0, import_react18.useMemo)(
|
|
8540
8507
|
() => buildTranscriptPreviewLines(tourLiveTranscript, { maxCharsPerLine: 36, maxLines: 2 }),
|
|
8541
8508
|
[tourLiveTranscript]
|
|
8542
8509
|
);
|
|
8543
|
-
(0,
|
|
8510
|
+
(0, import_react18.useEffect)(() => {
|
|
8544
8511
|
const shouldShowFloatingTranscript = (tourPlayback.isActive || onboardingPlayback.isActive) && tourListenReady && voice.isListening;
|
|
8545
8512
|
if (shouldShowFloatingTranscript) {
|
|
8546
8513
|
showFloatingLiveTranscript({
|
|
@@ -8562,10 +8529,10 @@ function ModelNexChatBubble({
|
|
|
8562
8529
|
tourPlayback.isActive,
|
|
8563
8530
|
voice.isListening
|
|
8564
8531
|
]);
|
|
8565
|
-
(0,
|
|
8532
|
+
(0, import_react18.useEffect)(() => () => {
|
|
8566
8533
|
hideFloatingLiveTranscript();
|
|
8567
8534
|
}, []);
|
|
8568
|
-
const setExpandedState = (0,
|
|
8535
|
+
const setExpandedState = (0, import_react18.useCallback)((next, opts) => {
|
|
8569
8536
|
setExpanded(next);
|
|
8570
8537
|
try {
|
|
8571
8538
|
sessionStorage.setItem(BUBBLE_EXPANDED_STORAGE_KEY, String(next));
|
|
@@ -8577,13 +8544,13 @@ function ModelNexChatBubble({
|
|
|
8577
8544
|
} catch {
|
|
8578
8545
|
}
|
|
8579
8546
|
}, [tourPlayback.isActive, onboardingPlayback.isActive]);
|
|
8580
|
-
(0,
|
|
8547
|
+
(0, import_react18.useEffect)(() => {
|
|
8581
8548
|
if ((onboardingPlayback.pendingTour || tourPlayback.pendingTour) && !recordingMode && pendingNotificationType === "bubble_card") {
|
|
8582
8549
|
setExpandedState(true);
|
|
8583
8550
|
}
|
|
8584
8551
|
}, [onboardingPlayback.pendingTour, tourPlayback.pendingTour, recordingMode, pendingNotificationType, setExpandedState]);
|
|
8585
|
-
const preferredListeningExperienceRef = (0,
|
|
8586
|
-
const playbackVoiceRoutingRef = (0,
|
|
8552
|
+
const preferredListeningExperienceRef = (0, import_react18.useRef)(null);
|
|
8553
|
+
const playbackVoiceRoutingRef = (0, import_react18.useRef)({
|
|
8587
8554
|
activeExperienceType,
|
|
8588
8555
|
isActive: activePlayback.isActive,
|
|
8589
8556
|
isReviewMode: activePlayback.isReviewMode,
|
|
@@ -8591,7 +8558,7 @@ function ModelNexChatBubble({
|
|
|
8591
8558
|
playbackState: activePlayback.playbackState,
|
|
8592
8559
|
handleVoiceInput: playbackController.handleVoiceInput
|
|
8593
8560
|
});
|
|
8594
|
-
(0,
|
|
8561
|
+
(0, import_react18.useEffect)(() => {
|
|
8595
8562
|
playbackVoiceRoutingRef.current = {
|
|
8596
8563
|
activeExperienceType,
|
|
8597
8564
|
isActive: activePlayback.isActive,
|
|
@@ -8608,7 +8575,7 @@ function ModelNexChatBubble({
|
|
|
8608
8575
|
playbackController.handleVoiceInput,
|
|
8609
8576
|
playbackController.pendingPrompt?.experienceType
|
|
8610
8577
|
]);
|
|
8611
|
-
const handleVoiceTourInput = (0,
|
|
8578
|
+
const handleVoiceTourInput = (0, import_react18.useCallback)(createSinglePlaybackTranscriptRouter(
|
|
8612
8579
|
() => ({
|
|
8613
8580
|
isReviewMode: playbackVoiceRoutingRef.current.isReviewMode,
|
|
8614
8581
|
playbackState: playbackVoiceRoutingRef.current.playbackState
|
|
@@ -8623,7 +8590,7 @@ function ModelNexChatBubble({
|
|
|
8623
8590
|
}
|
|
8624
8591
|
}
|
|
8625
8592
|
), []);
|
|
8626
|
-
const startTourListening = (0,
|
|
8593
|
+
const startTourListening = (0, import_react18.useCallback)((preferredExperience) => {
|
|
8627
8594
|
const listeningState = {
|
|
8628
8595
|
isTourActive: tourPlayback.isActive,
|
|
8629
8596
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
@@ -8679,7 +8646,7 @@ function ModelNexChatBubble({
|
|
|
8679
8646
|
updateTourListenReady,
|
|
8680
8647
|
updateTourSttError
|
|
8681
8648
|
]);
|
|
8682
|
-
(0,
|
|
8649
|
+
(0, import_react18.useEffect)(() => {
|
|
8683
8650
|
const isPlaybackActive = isTourListeningSessionActive({
|
|
8684
8651
|
isTourActive: tourPlayback.isActive,
|
|
8685
8652
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
@@ -8702,12 +8669,12 @@ function ModelNexChatBubble({
|
|
|
8702
8669
|
}
|
|
8703
8670
|
}
|
|
8704
8671
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, setExpandedState, startingExperienceType, updateTourSttError]);
|
|
8705
|
-
(0,
|
|
8672
|
+
(0, import_react18.useEffect)(() => {
|
|
8706
8673
|
if (!tourPlayback.isReviewMode && !onboardingPlayback.isReviewMode) {
|
|
8707
8674
|
setReviewDraft("");
|
|
8708
8675
|
}
|
|
8709
8676
|
}, [tourPlayback.isReviewMode, onboardingPlayback.isReviewMode]);
|
|
8710
|
-
(0,
|
|
8677
|
+
(0, import_react18.useEffect)(() => {
|
|
8711
8678
|
if (!isTourListeningSessionActive({
|
|
8712
8679
|
isTourActive: tourPlayback.isActive,
|
|
8713
8680
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
@@ -8716,12 +8683,12 @@ function ModelNexChatBubble({
|
|
|
8716
8683
|
preferredListeningExperienceRef.current = null;
|
|
8717
8684
|
}
|
|
8718
8685
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, startingExperienceType]);
|
|
8719
|
-
(0,
|
|
8686
|
+
(0, import_react18.useEffect)(() => {
|
|
8720
8687
|
if (recordingMode) {
|
|
8721
8688
|
setExpandedState(false);
|
|
8722
8689
|
}
|
|
8723
8690
|
}, [recordingMode, setExpandedState]);
|
|
8724
|
-
(0,
|
|
8691
|
+
(0, import_react18.useEffect)(() => {
|
|
8725
8692
|
const isPlaybackActive = isTourListeningSessionActive({
|
|
8726
8693
|
isTourActive: tourPlayback.isActive,
|
|
8727
8694
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
@@ -8735,7 +8702,7 @@ function ModelNexChatBubble({
|
|
|
8735
8702
|
}
|
|
8736
8703
|
updateTourListenReady(Boolean(voice.isListening && sttActiveRef.current));
|
|
8737
8704
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, voice.isListening, startingExperienceType, updateTourListenReady]);
|
|
8738
|
-
(0,
|
|
8705
|
+
(0, import_react18.useEffect)(() => {
|
|
8739
8706
|
const isPlaybackActive = isTourListeningSessionActive({
|
|
8740
8707
|
isTourActive: tourPlayback.isActive,
|
|
8741
8708
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
@@ -8750,7 +8717,7 @@ function ModelNexChatBubble({
|
|
|
8750
8717
|
voice.stopListening();
|
|
8751
8718
|
}
|
|
8752
8719
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, voice, startingExperienceType, updateTourListenReady, updateTourSttError]);
|
|
8753
|
-
(0,
|
|
8720
|
+
(0, import_react18.useEffect)(() => {
|
|
8754
8721
|
const isPlaybackActive = isTourListeningSessionActive({
|
|
8755
8722
|
isTourActive: tourPlayback.isActive,
|
|
8756
8723
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
@@ -8772,8 +8739,8 @@ function ModelNexChatBubble({
|
|
|
8772
8739
|
window.removeEventListener("keydown", enableTourListeningFromGesture, true);
|
|
8773
8740
|
};
|
|
8774
8741
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, tourListenReady, tourSttError, voice.sttSupported, startTourListening, startingExperienceType]);
|
|
8775
|
-
const [voiceInputMode, setVoiceInputMode] = (0,
|
|
8776
|
-
const toggleVoiceInput = (0,
|
|
8742
|
+
const [voiceInputMode, setVoiceInputMode] = (0, import_react18.useState)(false);
|
|
8743
|
+
const toggleVoiceInput = (0, import_react18.useCallback)(() => {
|
|
8777
8744
|
if (voiceInputMode) {
|
|
8778
8745
|
voice.stopListening();
|
|
8779
8746
|
setVoiceInputMode(false);
|
|
@@ -8796,7 +8763,7 @@ function ModelNexChatBubble({
|
|
|
8796
8763
|
);
|
|
8797
8764
|
}
|
|
8798
8765
|
}, [voiceInputMode, voice, recordingMode, recording]);
|
|
8799
|
-
(0,
|
|
8766
|
+
(0, import_react18.useEffect)(() => {
|
|
8800
8767
|
const panel = panelRef.current;
|
|
8801
8768
|
if (!panel) return;
|
|
8802
8769
|
const stopKeyPropagation = (e) => {
|
|
@@ -8811,7 +8778,7 @@ function ModelNexChatBubble({
|
|
|
8811
8778
|
panel.removeEventListener("keypress", stopKeyPropagation, true);
|
|
8812
8779
|
};
|
|
8813
8780
|
}, [expanded]);
|
|
8814
|
-
const onboardingRequiredCount = (0,
|
|
8781
|
+
const onboardingRequiredCount = (0, import_react18.useMemo)(
|
|
8815
8782
|
() => (onboardingPlayback.activeTour?.steps || []).filter((step) => step.onboarding?.required !== false).length,
|
|
8816
8783
|
[onboardingPlayback.activeTour]
|
|
8817
8784
|
);
|
|
@@ -8820,7 +8787,7 @@ function ModelNexChatBubble({
|
|
|
8820
8787
|
const tourCompletionRatio = tourPlayback.totalSteps > 0 ? Math.min(tourPlayback.currentStepIndex / tourPlayback.totalSteps, 1) : 0;
|
|
8821
8788
|
const tourCurrentStep = tourPlayback.activeTour?.steps?.[tourPlayback.currentStepIndex] || null;
|
|
8822
8789
|
const scrollToBottom = () => messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
8823
|
-
(0,
|
|
8790
|
+
(0, import_react18.useEffect)(() => {
|
|
8824
8791
|
if (messages.length > 0) scrollToBottom();
|
|
8825
8792
|
}, [messages, loading]);
|
|
8826
8793
|
const runAgent = async () => {
|
|
@@ -8877,7 +8844,7 @@ function ModelNexChatBubble({
|
|
|
8877
8844
|
const clearChat = () => {
|
|
8878
8845
|
setMessages([]);
|
|
8879
8846
|
};
|
|
8880
|
-
const startRecordingSession = (0,
|
|
8847
|
+
const startRecordingSession = (0, import_react18.useCallback)((experienceType) => {
|
|
8881
8848
|
abortControllerRef.current?.abort();
|
|
8882
8849
|
abortControllerRef.current = null;
|
|
8883
8850
|
setLoading(false);
|
|
@@ -8902,7 +8869,7 @@ function ModelNexChatBubble({
|
|
|
8902
8869
|
e.stopPropagation();
|
|
8903
8870
|
};
|
|
8904
8871
|
const isMobile = useMediaQuery("(max-width: 640px)");
|
|
8905
|
-
const themeStyles = (0,
|
|
8872
|
+
const themeStyles = (0, import_react18.useMemo)(() => {
|
|
8906
8873
|
if (!theme) return null;
|
|
8907
8874
|
const styles = {};
|
|
8908
8875
|
if (theme.accentColor) styles["--modelnex-accent"] = theme.accentColor;
|
|
@@ -9000,9 +8967,9 @@ function ModelNexChatBubble({
|
|
|
9000
8967
|
animation: "modelnex-slide-up 0.4s cubic-bezier(0.16, 1, 0.3, 1)"
|
|
9001
8968
|
},
|
|
9002
8969
|
children: [
|
|
9003
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "12px", fontWeight: 800, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--modelnex-accent, #4f46e5)", marginBottom: "12px" }, children: mc.title || (onboardingPlayback.pendingTour ? "
|
|
8970
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "12px", fontWeight: 800, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--modelnex-accent, #4f46e5)", marginBottom: "12px" }, children: mc.title || (onboardingPlayback.pendingTour ? "Workflow" : "Available Tour") }),
|
|
9004
8971
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "26px", lineHeight: 1.2, fontWeight: 700, color: mc.textColor || "var(--modelnex-fg, #09090b)", marginBottom: "12px" }, children: pt?.name }),
|
|
9005
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "15px", color: mc.textColor ? mc.textColor : "var(--modelnex-fg-muted, #52525b)", opacity: mc.textColor ? 0.8 : 1, lineHeight: 1.6, marginBottom: "24px" }, children: mc.description || (pt?.trigger === "first_visit" ? "Start a short guided tour to help you get started with the platform." : pt?.featureKey ? `We noticed you're exploring ${pt.featureKey}. Would you like a quick walkthrough?` : "A helpful walkthrough is available to guide you through this section.") }),
|
|
8972
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "15px", color: mc.textColor ? mc.textColor : "var(--modelnex-fg-muted, #52525b)", opacity: mc.textColor ? 0.8 : 1, lineHeight: 1.6, marginBottom: "24px" }, children: mc.description || (pt?.trigger === "first_visit" ? onboardingPlayback.pendingTour ? "Start a short workflow to help you get started with the platform." : "Start a short guided tour to help you get started with the platform." : pt?.featureKey ? `We noticed you're exploring ${pt.featureKey}. Would you like a quick walkthrough?` : "A helpful walkthrough is available to guide you through this section.") }),
|
|
9006
8973
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "12px", justifyContent: "flex-end" }, children: [
|
|
9007
8974
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
9008
8975
|
"button",
|
|
@@ -9076,7 +9043,7 @@ function ModelNexChatBubble({
|
|
|
9076
9043
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: "14px", fontWeight: 800, color: recordingMode ? "#dc2626" : "var(--modelnex-fg, #18181b)", display: "flex", alignItems: "center", gap: "6px" }, children: recordingMode ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
9077
9044
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { animation: "modelnex-bubble-pulse 1s infinite", color: "#dc2626" }, children: "\u25CF" }),
|
|
9078
9045
|
"REC"
|
|
9079
|
-
] }) : onboardingPlayback.isActive ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: "11px", textTransform: "uppercase", letterSpacing: "0.08em", color: PANEL_THEME.accent, fontWeight: 800 }, children: "
|
|
9046
|
+
] }) : onboardingPlayback.isActive ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: "11px", textTransform: "uppercase", letterSpacing: "0.08em", color: PANEL_THEME.accent, fontWeight: 800 }, children: "Workflow" }) : tourPlayback.isActive ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: "11px", textTransform: "uppercase", letterSpacing: "0.08em", color: TOUR_THEME.accent, fontWeight: 800 }, children: "Product Tour" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "6px" }, children: [
|
|
9080
9047
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BotIcon, {}),
|
|
9081
9048
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: agentName })
|
|
9082
9049
|
] }) }),
|
|
@@ -9104,62 +9071,33 @@ function ModelNexChatBubble({
|
|
|
9104
9071
|
children: voice.isMuted ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(VolumeMuteIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(VolumeIcon, {})
|
|
9105
9072
|
}
|
|
9106
9073
|
) }),
|
|
9107
|
-
devMode && /* @__PURE__ */ (0, import_jsx_runtime4.
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
{
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
) }),
|
|
9135
|
-
(!recordingMode || activeRecordingExperienceType === "onboarding") && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tooltip, { title: recordingMode ? "Stop & Save Onboarding" : "Record Onboarding", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
9136
|
-
"button",
|
|
9137
|
-
{
|
|
9138
|
-
onClick: () => {
|
|
9139
|
-
if (recordingMode) {
|
|
9140
|
-
recording.cancelSelection();
|
|
9141
|
-
setShowStopModal(true);
|
|
9142
|
-
} else {
|
|
9143
|
-
startRecordingSession("onboarding");
|
|
9144
|
-
}
|
|
9145
|
-
},
|
|
9146
|
-
style: {
|
|
9147
|
-
padding: "6px",
|
|
9148
|
-
borderRadius: "8px",
|
|
9149
|
-
border: "none",
|
|
9150
|
-
display: "flex",
|
|
9151
|
-
alignItems: "center",
|
|
9152
|
-
gap: "4px",
|
|
9153
|
-
background: recordingMode && activeRecordingExperienceType === "onboarding" ? "#fff" : "transparent",
|
|
9154
|
-
boxShadow: recordingMode && activeRecordingExperienceType === "onboarding" ? "0 1px 3px rgba(0,0,0,0.1)" : "none",
|
|
9155
|
-
cursor: "pointer",
|
|
9156
|
-
color: recordingMode && activeRecordingExperienceType === "onboarding" ? "#dc2626" : "#71717a"
|
|
9157
|
-
},
|
|
9158
|
-
"aria-label": recordingMode ? "Stop recording" : "Record onboarding",
|
|
9159
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BookOpenIcon, {})
|
|
9160
|
-
}
|
|
9161
|
-
) })
|
|
9162
|
-
] }),
|
|
9074
|
+
devMode && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", background: "var(--modelnex-bg-secondary, #f4f4f5)", borderRadius: "12px", padding: "2px", gap: "2px", marginRight: "4px" }, children: (!recordingMode || activeRecordingExperienceType === "onboarding") && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tooltip, { title: recordingMode ? "Stop & Save Workflow" : "Record Workflow", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
9075
|
+
"button",
|
|
9076
|
+
{
|
|
9077
|
+
onClick: () => {
|
|
9078
|
+
if (recordingMode) {
|
|
9079
|
+
recording.cancelSelection();
|
|
9080
|
+
setShowStopModal(true);
|
|
9081
|
+
} else {
|
|
9082
|
+
startRecordingSession("onboarding");
|
|
9083
|
+
}
|
|
9084
|
+
},
|
|
9085
|
+
style: {
|
|
9086
|
+
padding: "6px",
|
|
9087
|
+
borderRadius: "8px",
|
|
9088
|
+
border: "none",
|
|
9089
|
+
display: "flex",
|
|
9090
|
+
alignItems: "center",
|
|
9091
|
+
gap: "4px",
|
|
9092
|
+
background: recordingMode && activeRecordingExperienceType === "onboarding" ? "#fff" : "transparent",
|
|
9093
|
+
boxShadow: recordingMode && activeRecordingExperienceType === "onboarding" ? "0 1px 3px rgba(0,0,0,0.1)" : "none",
|
|
9094
|
+
cursor: "pointer",
|
|
9095
|
+
color: recordingMode && activeRecordingExperienceType === "onboarding" ? "#dc2626" : "#71717a"
|
|
9096
|
+
},
|
|
9097
|
+
"aria-label": recordingMode ? "Stop recording" : "Record workflow",
|
|
9098
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BookOpenIcon, {})
|
|
9099
|
+
}
|
|
9100
|
+
) }) }),
|
|
9163
9101
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tooltip, { title: "Minimize", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
9164
9102
|
"button",
|
|
9165
9103
|
{
|
|
@@ -9221,7 +9159,7 @@ function ModelNexChatBubble({
|
|
|
9221
9159
|
background: "linear-gradient(135deg, rgba(59,130,246,0.08) 0%, rgba(59,130,246,0.03) 100%)"
|
|
9222
9160
|
},
|
|
9223
9161
|
children: [
|
|
9224
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "13px", fontWeight: 600, color: "var(--modelnex-fg, #18181b)", marginBottom: "6px" }, children: onboardingPlayback.pendingTour ? "Suggested
|
|
9162
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "13px", fontWeight: 600, color: "var(--modelnex-fg, #18181b)", marginBottom: "6px" }, children: onboardingPlayback.pendingTour ? "Suggested workflow" : "Suggested tour" }),
|
|
9225
9163
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "14px", color: "var(--modelnex-fg, #27272a)", marginBottom: "6px" }, children: (onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.name }),
|
|
9226
9164
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "12px", color: "#52525b", lineHeight: 1.45, marginBottom: "12px" }, children: (onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.trigger === "first_visit" ? "Start a short walkthrough for this user now?" : (onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.featureKey ? `A walkthrough is available for ${(onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.featureKey}.` : "A walkthrough is available for this user." }),
|
|
9227
9165
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
@@ -9235,7 +9173,7 @@ function ModelNexChatBubble({
|
|
|
9235
9173
|
startTourListening(preferredExperience);
|
|
9236
9174
|
}, children: [
|
|
9237
9175
|
"Start ",
|
|
9238
|
-
onboardingPlayback.pendingTour ? "
|
|
9176
|
+
onboardingPlayback.pendingTour ? "workflow" : "tour"
|
|
9239
9177
|
] }),
|
|
9240
9178
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "btn btn-secondary btn-sm", onClick: onboardingPlayback.pendingTour ? onboardingPlayback.dismissPendingTour : tourPlayback.dismissPendingTour, children: "Not now" })
|
|
9241
9179
|
] })
|
|
@@ -9315,7 +9253,7 @@ function ModelNexChatBubble({
|
|
|
9315
9253
|
showStopModal && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { padding: "14px", borderBottom: "1px solid var(--modelnex-border, #e4e4e7)", background: "rgba(220,38,38,0.04)", flexShrink: 0 }, children: [
|
|
9316
9254
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontSize: "13px", fontWeight: 600, color: "#dc2626", marginBottom: "8px" }, children: [
|
|
9317
9255
|
"Save captured ",
|
|
9318
|
-
activeRecordingExperienceType === "onboarding" ? "
|
|
9256
|
+
activeRecordingExperienceType === "onboarding" ? "workflow" : "tour",
|
|
9319
9257
|
" (",
|
|
9320
9258
|
recording.captureEventCount > 0 ? recording.captureEventCount - 1 : 0,
|
|
9321
9259
|
" interactions, ",
|
|
@@ -9329,7 +9267,7 @@ function ModelNexChatBubble({
|
|
|
9329
9267
|
{
|
|
9330
9268
|
value: recordingTourName,
|
|
9331
9269
|
onChange: (e) => setRecordingTourName(e.target.value),
|
|
9332
|
-
placeholder: activeRecordingExperienceType === "onboarding" ? "
|
|
9270
|
+
placeholder: activeRecordingExperienceType === "onboarding" ? "Workflow name (e.g. New User Activation)" : "Tour name (e.g. Admin Setup Tour)",
|
|
9333
9271
|
disabled: Boolean(savedDraft) || isGeneratingDraft,
|
|
9334
9272
|
style: { width: "100%", padding: "7px 10px", borderRadius: "6px", border: "1px solid #e4e4e7", fontSize: "13px", marginBottom: "6px", boxSizing: "border-box" }
|
|
9335
9273
|
}
|
|
@@ -9427,7 +9365,7 @@ function ModelNexChatBubble({
|
|
|
9427
9365
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "13px", fontWeight: 600, color: "#16a34a", marginBottom: "6px" }, children: "Draft saved" }),
|
|
9428
9366
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontSize: "12px", color: "#52525b", marginBottom: "10px", lineHeight: 1.45 }, children: [
|
|
9429
9367
|
"Launch a live preview of the AI ",
|
|
9430
|
-
savedDraft.experienceType === "onboarding" ? "
|
|
9368
|
+
savedDraft.experienceType === "onboarding" ? "workflow" : "tour",
|
|
9431
9369
|
" now, or close this panel and review it later."
|
|
9432
9370
|
] }),
|
|
9433
9371
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "6px", flexWrap: "wrap" }, children: [
|
|
@@ -10119,7 +10057,7 @@ function ModelNexChatBubble({
|
|
|
10119
10057
|
}
|
|
10120
10058
|
|
|
10121
10059
|
// src/onboarding-panel.tsx
|
|
10122
|
-
var
|
|
10060
|
+
var import_react19 = require("react");
|
|
10123
10061
|
var import_react_dom2 = require("react-dom");
|
|
10124
10062
|
|
|
10125
10063
|
// src/hooks/useOnboardingPlayback.ts
|
|
@@ -10149,18 +10087,18 @@ function ModelNexOnboardingPanel({
|
|
|
10149
10087
|
appName = "this app",
|
|
10150
10088
|
title = "Getting Started"
|
|
10151
10089
|
}) {
|
|
10152
|
-
const ctx = (0,
|
|
10090
|
+
const ctx = (0, import_react19.useContext)(ModelNexContext);
|
|
10153
10091
|
const serverUrl = ctx?.serverUrl ?? "http://localhost:3002";
|
|
10154
10092
|
const voice = useVoice(serverUrl);
|
|
10155
10093
|
const audioLevels = useAudioLevel(voice.isListening);
|
|
10156
|
-
const [input, setInput] = (0,
|
|
10157
|
-
const [reviewDraft, setReviewDraft] = (0,
|
|
10158
|
-
const [open, setOpen] = (0,
|
|
10159
|
-
const [currentStepIndex, setCurrentStepIndex] = (0,
|
|
10160
|
-
const [liveTranscript, setLiveTranscript] = (0,
|
|
10161
|
-
const [voiceEnabled, setVoiceEnabled] = (0,
|
|
10162
|
-
const [sttError, setSttError] = (0,
|
|
10163
|
-
const voiceEnabledRef = (0,
|
|
10094
|
+
const [input, setInput] = (0, import_react19.useState)("");
|
|
10095
|
+
const [reviewDraft, setReviewDraft] = (0, import_react19.useState)("");
|
|
10096
|
+
const [open, setOpen] = (0, import_react19.useState)(true);
|
|
10097
|
+
const [currentStepIndex, setCurrentStepIndex] = (0, import_react19.useState)(0);
|
|
10098
|
+
const [liveTranscript, setLiveTranscript] = (0, import_react19.useState)("");
|
|
10099
|
+
const [voiceEnabled, setVoiceEnabled] = (0, import_react19.useState)(false);
|
|
10100
|
+
const [sttError, setSttError] = (0, import_react19.useState)(null);
|
|
10101
|
+
const voiceEnabledRef = (0, import_react19.useRef)(false);
|
|
10164
10102
|
const playback = useOnboardingPlayback({
|
|
10165
10103
|
serverUrl,
|
|
10166
10104
|
commandUrl: ctx?.commandUrl,
|
|
@@ -10180,25 +10118,25 @@ function ModelNexOnboardingPanel({
|
|
|
10180
10118
|
voiceEnabledRef.current = false;
|
|
10181
10119
|
}
|
|
10182
10120
|
});
|
|
10183
|
-
const playbackVoiceRoutingRef = (0,
|
|
10121
|
+
const playbackVoiceRoutingRef = (0, import_react19.useRef)({
|
|
10184
10122
|
isReviewMode: false,
|
|
10185
10123
|
playbackState: playback.playbackState,
|
|
10186
10124
|
handleVoiceInput: playback.handleVoiceInput
|
|
10187
10125
|
});
|
|
10188
10126
|
const reviewToggle = getReviewModeToggleConfig(playback.playbackState);
|
|
10189
|
-
(0,
|
|
10127
|
+
(0, import_react19.useEffect)(() => {
|
|
10190
10128
|
playbackVoiceRoutingRef.current = {
|
|
10191
10129
|
isReviewMode: playback.isReviewMode,
|
|
10192
10130
|
playbackState: playback.playbackState,
|
|
10193
10131
|
handleVoiceInput: playback.handleVoiceInput
|
|
10194
10132
|
};
|
|
10195
10133
|
}, [playback.isReviewMode, playback.playbackState, playback.handleVoiceInput]);
|
|
10196
|
-
(0,
|
|
10134
|
+
(0, import_react19.useEffect)(() => {
|
|
10197
10135
|
if (playback.isActive && !playback.isReviewMode) {
|
|
10198
10136
|
setOpen(true);
|
|
10199
10137
|
}
|
|
10200
10138
|
}, [playback.activeTour?.id, playback.isActive, playback.isReviewMode]);
|
|
10201
|
-
const startVoiceListening = (0,
|
|
10139
|
+
const startVoiceListening = (0, import_react19.useCallback)(() => {
|
|
10202
10140
|
if (voiceEnabledRef.current || !voice.sttSupported) return;
|
|
10203
10141
|
voiceEnabledRef.current = true;
|
|
10204
10142
|
setVoiceEnabled(true);
|
|
@@ -10245,7 +10183,7 @@ function ModelNexOnboardingPanel({
|
|
|
10245
10183
|
}
|
|
10246
10184
|
);
|
|
10247
10185
|
}, [playback.isActive, voice]);
|
|
10248
|
-
(0,
|
|
10186
|
+
(0, import_react19.useEffect)(() => {
|
|
10249
10187
|
if (!playback.isActive || voiceEnabledRef.current || !voice.sttSupported) return;
|
|
10250
10188
|
const startOnGesture = (event) => {
|
|
10251
10189
|
if (shouldIgnorePanelGestureStart(event.target)) {
|
|
@@ -10260,7 +10198,7 @@ function ModelNexOnboardingPanel({
|
|
|
10260
10198
|
window.removeEventListener("keydown", startOnGesture, true);
|
|
10261
10199
|
};
|
|
10262
10200
|
}, [playback.isActive, voice.sttSupported, startVoiceListening]);
|
|
10263
|
-
(0,
|
|
10201
|
+
(0, import_react19.useEffect)(() => {
|
|
10264
10202
|
if (!playback.isActive && voiceEnabledRef.current) {
|
|
10265
10203
|
voiceEnabledRef.current = false;
|
|
10266
10204
|
setVoiceEnabled(false);
|
|
@@ -10271,16 +10209,16 @@ function ModelNexOnboardingPanel({
|
|
|
10271
10209
|
}, [playback.isActive, voice]);
|
|
10272
10210
|
const pendingNotificationType = playback.pendingTour?.notificationType ?? "bubble_card";
|
|
10273
10211
|
const currentStep = playback.activeTour?.steps?.[currentStepIndex] || null;
|
|
10274
|
-
const requiredCount = (0,
|
|
10212
|
+
const requiredCount = (0, import_react19.useMemo)(
|
|
10275
10213
|
() => (playback.activeTour?.steps || []).filter((step) => step.onboarding?.required !== false).length,
|
|
10276
10214
|
[playback.activeTour]
|
|
10277
10215
|
);
|
|
10278
10216
|
const completionRatio = playback.totalSteps > 0 ? Math.min(currentStepIndex / playback.totalSteps, 1) : 0;
|
|
10279
|
-
const liveTranscriptLines = (0,
|
|
10217
|
+
const liveTranscriptLines = (0, import_react19.useMemo)(
|
|
10280
10218
|
() => buildTranscriptPreviewLines(liveTranscript, { maxCharsPerLine: 34, maxLines: 2 }),
|
|
10281
10219
|
[liveTranscript]
|
|
10282
10220
|
);
|
|
10283
|
-
(0,
|
|
10221
|
+
(0, import_react19.useEffect)(() => {
|
|
10284
10222
|
if (voiceEnabled && voice.isListening) {
|
|
10285
10223
|
showFloatingLiveTranscript({
|
|
10286
10224
|
levels: audioLevels,
|
|
@@ -10294,7 +10232,7 @@ function ModelNexOnboardingPanel({
|
|
|
10294
10232
|
}
|
|
10295
10233
|
hideFloatingLiveTranscript();
|
|
10296
10234
|
}, [audioLevels, liveTranscriptLines, voiceEnabled, voice.isListening]);
|
|
10297
|
-
(0,
|
|
10235
|
+
(0, import_react19.useEffect)(() => () => {
|
|
10298
10236
|
hideFloatingLiveTranscript();
|
|
10299
10237
|
}, []);
|
|
10300
10238
|
const actionButtonStyle = {
|
|
@@ -10329,7 +10267,7 @@ function ModelNexOnboardingPanel({
|
|
|
10329
10267
|
{
|
|
10330
10268
|
role: "dialog",
|
|
10331
10269
|
"aria-modal": "true",
|
|
10332
|
-
"aria-label": mc.title || "Start
|
|
10270
|
+
"aria-label": mc.title || "Start workflow",
|
|
10333
10271
|
style: {
|
|
10334
10272
|
width: "min(460px, 100%)",
|
|
10335
10273
|
borderRadius: "18px",
|
|
@@ -10340,9 +10278,9 @@ function ModelNexOnboardingPanel({
|
|
|
10340
10278
|
padding: "24px"
|
|
10341
10279
|
},
|
|
10342
10280
|
children: [
|
|
10343
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "12px", fontWeight: 700, letterSpacing: "0.04em", textTransform: "uppercase", color: PANEL_THEME2.accent, marginBottom: "10px" }, children: mc.title || "Suggested
|
|
10281
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "12px", fontWeight: 700, letterSpacing: "0.04em", textTransform: "uppercase", color: PANEL_THEME2.accent, marginBottom: "10px" }, children: mc.title || "Suggested workflow" }),
|
|
10344
10282
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "24px", lineHeight: 1.15, fontWeight: 650, marginBottom: "10px" }, children: playback.pendingTour.name }),
|
|
10345
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "14px", color: mc.textColor ? mc.textColor : "#52525b", opacity: mc.textColor ? 0.8 : 1, lineHeight: 1.5, marginBottom: "18px" }, children: mc.description || (playback.pendingTour.trigger === "first_visit" ? "Start
|
|
10283
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "14px", color: mc.textColor ? mc.textColor : "#52525b", opacity: mc.textColor ? 0.8 : 1, lineHeight: 1.5, marginBottom: "18px" }, children: mc.description || (playback.pendingTour.trigger === "first_visit" ? "Start this workflow for the user now?" : playback.pendingTour.featureKey ? `A workflow is available for ${playback.pendingTour.featureKey}.` : "A workflow is available for this user.") }),
|
|
10346
10284
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", gap: "10px", justifyContent: "flex-end" }, children: [
|
|
10347
10285
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
10348
10286
|
"button",
|
|
@@ -10376,7 +10314,7 @@ function ModelNexOnboardingPanel({
|
|
|
10376
10314
|
cursor: "pointer",
|
|
10377
10315
|
fontWeight: 700
|
|
10378
10316
|
},
|
|
10379
|
-
children: mc.buttonText || "Start
|
|
10317
|
+
children: mc.buttonText || "Start workflow"
|
|
10380
10318
|
}
|
|
10381
10319
|
)
|
|
10382
10320
|
] })
|
|
@@ -10409,11 +10347,11 @@ function ModelNexOnboardingPanel({
|
|
|
10409
10347
|
},
|
|
10410
10348
|
children: [
|
|
10411
10349
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { padding: "16px 18px", borderBottom: `1px solid ${PANEL_THEME2.border}`, background: PANEL_THEME2.hero }, children: [
|
|
10412
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "11px", textTransform: "uppercase", letterSpacing: "0.08em", color: PANEL_THEME2.accent, fontWeight: 700 }, children: "Suggested
|
|
10350
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "11px", textTransform: "uppercase", letterSpacing: "0.08em", color: PANEL_THEME2.accent, fontWeight: 700 }, children: "Suggested workflow" }),
|
|
10413
10351
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "18px", fontWeight: 700, marginTop: "4px" }, children: playback.pendingTour.name })
|
|
10414
10352
|
] }),
|
|
10415
10353
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { padding: "16px 18px" }, children: [
|
|
10416
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "14px", color: "#52525b", lineHeight: 1.5, marginBottom: "14px" }, children: playback.pendingTour.trigger === "first_visit" ? "Start
|
|
10354
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "14px", color: "#52525b", lineHeight: 1.5, marginBottom: "14px" }, children: playback.pendingTour.trigger === "first_visit" ? "Start this workflow for the user now?" : playback.pendingTour.featureKey ? `A workflow is available for ${playback.pendingTour.featureKey}.` : "A workflow is available for this user." }),
|
|
10417
10355
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
10418
10356
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
10419
10357
|
"button",
|
|
@@ -10423,7 +10361,7 @@ function ModelNexOnboardingPanel({
|
|
|
10423
10361
|
startVoiceListening();
|
|
10424
10362
|
},
|
|
10425
10363
|
style: { ...actionButtonStyle, flex: 1, padding: "11px 14px" },
|
|
10426
|
-
children: "Start
|
|
10364
|
+
children: "Start workflow"
|
|
10427
10365
|
}
|
|
10428
10366
|
),
|
|
10429
10367
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
@@ -10485,7 +10423,7 @@ function ModelNexOnboardingPanel({
|
|
|
10485
10423
|
fontSize: "18px"
|
|
10486
10424
|
}, children: "\u{1F3AF}" }),
|
|
10487
10425
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
10488
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "13px", fontWeight: 700, color: "#172033", marginBottom: "2px" }, children: "
|
|
10426
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "13px", fontWeight: 700, color: "#172033", marginBottom: "2px" }, children: "Workflow" }),
|
|
10489
10427
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "12px", color: "#6b7280" }, children: "Ready \u2014 onboarding will appear here when available." })
|
|
10490
10428
|
] })
|
|
10491
10429
|
]
|
|
@@ -10541,7 +10479,7 @@ function ModelNexOnboardingPanel({
|
|
|
10541
10479
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { padding: "16px 18px", borderBottom: `1px solid ${PANEL_THEME2.border}`, background: PANEL_THEME2.hero }, children: [
|
|
10542
10480
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", gap: "12px", alignItems: "center" }, children: [
|
|
10543
10481
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
10544
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "11px", textTransform: "uppercase", letterSpacing: "0.08em", color: PANEL_THEME2.accent, fontWeight: 700 }, children: "
|
|
10482
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "11px", textTransform: "uppercase", letterSpacing: "0.08em", color: PANEL_THEME2.accent, fontWeight: 700 }, children: "Workflow" }),
|
|
10545
10483
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "18px", fontWeight: 700 }, children: title })
|
|
10546
10484
|
] }),
|
|
10547
10485
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", gap: "6px", alignItems: "center" }, children: [
|
|
@@ -10808,9 +10746,9 @@ function ModelNexOnboardingPanel({
|
|
|
10808
10746
|
}
|
|
10809
10747
|
|
|
10810
10748
|
// src/hooks/useActionHighlight.ts
|
|
10811
|
-
var
|
|
10749
|
+
var import_react20 = require("react");
|
|
10812
10750
|
function useActionHighlight() {
|
|
10813
|
-
const context = (0,
|
|
10751
|
+
const context = (0, import_react20.useContext)(ModelNexContext);
|
|
10814
10752
|
if (!context) throw new Error("useActionHighlight must be used within ModelNexProvider");
|
|
10815
10753
|
return {
|
|
10816
10754
|
enabled: context.highlightActions,
|
|
@@ -10893,33 +10831,32 @@ function TourProgressPanel({ tour, currentStepIndex, onSkip, voiceOnly }) {
|
|
|
10893
10831
|
var DEFAULT_SERVER_URL2 = "https://api.modelnex.io";
|
|
10894
10832
|
var ModelNexProvider = ({
|
|
10895
10833
|
children,
|
|
10896
|
-
serverUrl = DEFAULT_SERVER_URL2,
|
|
10897
|
-
commandUrl,
|
|
10898
|
-
disableSocket,
|
|
10899
10834
|
websiteId,
|
|
10900
10835
|
userProfile,
|
|
10901
|
-
tourFacts,
|
|
10902
|
-
toursApiBase,
|
|
10903
10836
|
devMode
|
|
10904
10837
|
}) => {
|
|
10838
|
+
const serverUrl = DEFAULT_SERVER_URL2;
|
|
10839
|
+
const commandUrl = void 0;
|
|
10840
|
+
const disableSocket = false;
|
|
10841
|
+
const toursApiBase = void 0;
|
|
10905
10842
|
const renderedChildren = children;
|
|
10906
|
-
const [activeAgentActions, setActiveAgentActions] = (0,
|
|
10907
|
-
const [stagingFields, setStagingFields] = (0,
|
|
10908
|
-
const [executedFields, setExecutedFields] = (0,
|
|
10909
|
-
const [highlightActions, setHighlightActions] = (0,
|
|
10910
|
-
const [studioMode, setStudioMode] = (0,
|
|
10911
|
-
const [recordingMode, setRecordingMode] = (0,
|
|
10912
|
-
const [voiceMuted, setVoiceMuted] = (0,
|
|
10913
|
-
const [socketId, setSocketId] = (0,
|
|
10914
|
-
const [actions, setActions] = (0,
|
|
10915
|
-
const registerAction = (0,
|
|
10843
|
+
const [activeAgentActions, setActiveAgentActions] = (0, import_react21.useState)(/* @__PURE__ */ new Set());
|
|
10844
|
+
const [stagingFields, setStagingFields] = (0, import_react21.useState)(/* @__PURE__ */ new Set());
|
|
10845
|
+
const [executedFields, setExecutedFields] = (0, import_react21.useState)(/* @__PURE__ */ new Set());
|
|
10846
|
+
const [highlightActions, setHighlightActions] = (0, import_react21.useState)(false);
|
|
10847
|
+
const [studioMode, setStudioMode] = (0, import_react21.useState)(false);
|
|
10848
|
+
const [recordingMode, setRecordingMode] = (0, import_react21.useState)(false);
|
|
10849
|
+
const [voiceMuted, setVoiceMuted] = (0, import_react21.useState)(false);
|
|
10850
|
+
const [socketId, setSocketId] = (0, import_react21.useState)(null);
|
|
10851
|
+
const [actions, setActions] = (0, import_react21.useState)(/* @__PURE__ */ new Map());
|
|
10852
|
+
const registerAction = (0, import_react21.useCallback)((action) => {
|
|
10916
10853
|
setActions((prev) => {
|
|
10917
10854
|
const next = new Map(prev);
|
|
10918
10855
|
next.set(action.id, action);
|
|
10919
10856
|
return next;
|
|
10920
10857
|
});
|
|
10921
10858
|
}, []);
|
|
10922
|
-
const unregisterAction = (0,
|
|
10859
|
+
const unregisterAction = (0, import_react21.useCallback)((id) => {
|
|
10923
10860
|
setActions((prev) => {
|
|
10924
10861
|
const next = new Map(prev);
|
|
10925
10862
|
next.delete(id);
|
|
@@ -10930,8 +10867,8 @@ var ModelNexProvider = ({
|
|
|
10930
10867
|
const tagStore = useTagStore({ serverUrl, websiteId });
|
|
10931
10868
|
useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl, websiteId);
|
|
10932
10869
|
const CHAT_STORAGE_KEY = "modelnex-chat-messages";
|
|
10933
|
-
const [chatMessages, setChatMessagesRaw] = (0,
|
|
10934
|
-
(0,
|
|
10870
|
+
const [chatMessages, setChatMessagesRaw] = (0, import_react21.useState)([]);
|
|
10871
|
+
(0, import_react21.useEffect)(() => {
|
|
10935
10872
|
try {
|
|
10936
10873
|
const stored = sessionStorage.getItem(CHAT_STORAGE_KEY);
|
|
10937
10874
|
if (stored) {
|
|
@@ -10940,7 +10877,7 @@ var ModelNexProvider = ({
|
|
|
10940
10877
|
} catch {
|
|
10941
10878
|
}
|
|
10942
10879
|
}, []);
|
|
10943
|
-
const setChatMessages = (0,
|
|
10880
|
+
const setChatMessages = (0, import_react21.useCallback)((action) => {
|
|
10944
10881
|
setChatMessagesRaw((prev) => {
|
|
10945
10882
|
const next = typeof action === "function" ? action(prev) : action;
|
|
10946
10883
|
try {
|
|
@@ -10964,22 +10901,20 @@ var ModelNexProvider = ({
|
|
|
10964
10901
|
websiteId
|
|
10965
10902
|
});
|
|
10966
10903
|
useFieldHighlight(stagingFields, executedFields, setExecutedFields);
|
|
10967
|
-
(0,
|
|
10904
|
+
(0, import_react21.useEffect)(() => {
|
|
10968
10905
|
document.body.classList.toggle("modelnex-highlight-actions", highlightActions);
|
|
10969
10906
|
return () => {
|
|
10970
10907
|
document.body.classList.remove("modelnex-highlight-actions");
|
|
10971
10908
|
};
|
|
10972
10909
|
}, [highlightActions]);
|
|
10973
|
-
const [mounted, setMounted] = (0,
|
|
10974
|
-
(0,
|
|
10910
|
+
const [mounted, setMounted] = (0, import_react21.useState)(false);
|
|
10911
|
+
(0, import_react21.useEffect)(() => {
|
|
10975
10912
|
setMounted(true);
|
|
10976
10913
|
}, []);
|
|
10977
|
-
const value = (0,
|
|
10914
|
+
const value = (0, import_react21.useMemo)(
|
|
10978
10915
|
() => ({
|
|
10979
10916
|
serverUrl,
|
|
10980
10917
|
commandUrl: commandUrl ?? serverUrl,
|
|
10981
|
-
registerAction,
|
|
10982
|
-
unregisterAction,
|
|
10983
10918
|
activeAgentActions,
|
|
10984
10919
|
stagingFields,
|
|
10985
10920
|
highlightActions,
|
|
@@ -10994,23 +10929,21 @@ var ModelNexProvider = ({
|
|
|
10994
10929
|
setChatMessages,
|
|
10995
10930
|
websiteId,
|
|
10996
10931
|
userProfile,
|
|
10997
|
-
tourFacts,
|
|
10998
|
-
toursApiBase,
|
|
10999
10932
|
voiceMuted,
|
|
11000
10933
|
setVoiceMuted,
|
|
11001
10934
|
socketId,
|
|
11002
10935
|
devMode
|
|
11003
10936
|
}),
|
|
11004
|
-
[serverUrl, commandUrl, registerAction, unregisterAction, activeAgentActions, stagingFields, highlightActions, studioMode, recordingMode, extractedElements, tagStore, chatMessages, websiteId, userProfile,
|
|
10937
|
+
[serverUrl, commandUrl, registerAction, unregisterAction, activeAgentActions, stagingFields, highlightActions, studioMode, recordingMode, extractedElements, tagStore, chatMessages, websiteId, userProfile, voiceMuted, socketId, devMode]
|
|
11005
10938
|
);
|
|
11006
|
-
return
|
|
10939
|
+
return import_react21.default.createElement(
|
|
11007
10940
|
ModelNexContext.Provider,
|
|
11008
10941
|
{ value },
|
|
11009
10942
|
renderedChildren,
|
|
11010
|
-
mounted && studioMode &&
|
|
11011
|
-
mounted &&
|
|
10943
|
+
mounted && studioMode && import_react21.default.createElement(StudioOverlay, { elements: extractedElements, tagStore }),
|
|
10944
|
+
mounted && import_react21.default.createElement(AIActivityOverlay, { activeActions: activeAgentActions }),
|
|
11012
10945
|
// mounted && React.createElement(ReasoningBubble, null),
|
|
11013
|
-
mounted &&
|
|
10946
|
+
mounted && import_react21.default.createElement("style", null, HIGHLIGHT_STYLES)
|
|
11014
10947
|
);
|
|
11015
10948
|
};
|
|
11016
10949
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -11046,7 +10979,6 @@ var ModelNexProvider = ({
|
|
|
11046
10979
|
useExperiencePlayback,
|
|
11047
10980
|
useOnboardingPlayback,
|
|
11048
10981
|
useRecordingMode,
|
|
11049
|
-
useRegisterAction,
|
|
11050
10982
|
useRunCommand,
|
|
11051
10983
|
useTagStore,
|
|
11052
10984
|
useTourPlayback,
|