@foisit/react-wrapper 2.4.4 → 2.4.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 +63 -5
- package/index.js +88 -3
- package/index.mjs +407 -191
- package/lib/services/AssistantService.d.ts +10 -0
- package/package.json +9 -2
package/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as k } from "react/jsx-runtime";
|
|
2
|
-
import { createContext as F, useState as
|
|
3
|
-
const
|
|
4
|
-
function
|
|
5
|
-
return /* @__PURE__ */ k("div", { className:
|
|
2
|
+
import { createContext as F, useState as I, useEffect as $, useContext as N } from "react";
|
|
3
|
+
const O = {};
|
|
4
|
+
function Q() {
|
|
5
|
+
return /* @__PURE__ */ k("div", { className: O.container, children: /* @__PURE__ */ k("h1", { children: "Welcome to ReactWrapper!" }) });
|
|
6
6
|
}
|
|
7
|
-
class
|
|
7
|
+
class T {
|
|
8
8
|
constructor(t) {
|
|
9
9
|
this.endpoint = t || "https://foisit-ninja.netlify.app/.netlify/functions/intent";
|
|
10
10
|
}
|
|
@@ -12,11 +12,11 @@ class M {
|
|
|
12
12
|
try {
|
|
13
13
|
const s = {
|
|
14
14
|
userInput: t,
|
|
15
|
-
commands: e.map((
|
|
16
|
-
id:
|
|
17
|
-
command:
|
|
18
|
-
description:
|
|
19
|
-
parameters:
|
|
15
|
+
commands: e.map((o) => ({
|
|
16
|
+
id: o.id,
|
|
17
|
+
command: o.command,
|
|
18
|
+
description: o.description,
|
|
19
|
+
parameters: o.parameters
|
|
20
20
|
// Send param schemas to AI
|
|
21
21
|
})),
|
|
22
22
|
context: i
|
|
@@ -35,13 +35,13 @@ class M {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
class
|
|
38
|
+
class z {
|
|
39
39
|
constructor(t = !0) {
|
|
40
40
|
if (this.commands = /* @__PURE__ */ new Map(), this.openAIService = null, this.context = null, this.pendingConfirmation = null, this.enableSmartIntent = !0, this.selectOptionsCache = /* @__PURE__ */ new Map(), typeof t == "boolean") {
|
|
41
|
-
this.enableSmartIntent = t, this.enableSmartIntent && (this.openAIService = new
|
|
41
|
+
this.enableSmartIntent = t, this.enableSmartIntent && (this.openAIService = new T());
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
|
-
this.enableSmartIntent = t.enableSmartIntent ?? !0, this.enableSmartIntent && (this.openAIService = new
|
|
44
|
+
this.enableSmartIntent = t.enableSmartIntent ?? !0, this.enableSmartIntent && (this.openAIService = new T(t.intentEndpoint));
|
|
45
45
|
}
|
|
46
46
|
/** Add a new command (string or object) */
|
|
47
47
|
addCommand(t, e) {
|
|
@@ -66,14 +66,14 @@ class B {
|
|
|
66
66
|
async executeCommand(t) {
|
|
67
67
|
if (typeof t == "object" && t !== null) {
|
|
68
68
|
if (this.isStructured(t)) {
|
|
69
|
-
const c = String(t.commandId), f = t.params ?? {},
|
|
70
|
-
if (!
|
|
71
|
-
const p = this.sanitizeParamsForCommand(
|
|
72
|
-
return m.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(
|
|
73
|
-
message: `Please provide the required details for "${
|
|
69
|
+
const c = String(t.commandId), f = t.params ?? {}, r = this.getCommandById(c);
|
|
70
|
+
if (!r) return { message: "That command is not available.", type: "error" };
|
|
71
|
+
const p = this.sanitizeParamsForCommand(r, f), m = (r.parameters ?? []).filter((C) => C.required).filter((C) => p[C.name] == null || p[C.name] === "");
|
|
72
|
+
return m.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(r), params: p }, {
|
|
73
|
+
message: `Please provide the required details for "${r.command}".`,
|
|
74
74
|
type: "form",
|
|
75
75
|
fields: m
|
|
76
|
-
}) :
|
|
76
|
+
}) : r.critical ? (this.pendingConfirmation = { commandId: this.getCommandIdentifier(r), params: p }, this.buildConfirmResponse(r)) : this.safeRunAction(r, p);
|
|
77
77
|
}
|
|
78
78
|
if (!this.context)
|
|
79
79
|
return { message: "Session expired or invalid context.", type: "error" };
|
|
@@ -82,26 +82,26 @@ class B {
|
|
|
82
82
|
return this.context = null, { message: "Session expired or invalid context.", type: "error" };
|
|
83
83
|
if (Array.isArray(t))
|
|
84
84
|
return { message: "Invalid form payload.", type: "error" };
|
|
85
|
-
const
|
|
85
|
+
const a = {
|
|
86
86
|
...this.context.params,
|
|
87
87
|
...t
|
|
88
88
|
};
|
|
89
89
|
if (n.critical)
|
|
90
90
|
return this.context = null, this.pendingConfirmation = {
|
|
91
91
|
commandId: this.getCommandIdentifier(n),
|
|
92
|
-
params:
|
|
92
|
+
params: a
|
|
93
93
|
}, this.buildConfirmResponse(n);
|
|
94
|
-
const
|
|
95
|
-
return this.context = null, this.normalizeResponse(
|
|
94
|
+
const o = await this.safeRunAction(n, a);
|
|
95
|
+
return this.context = null, this.normalizeResponse(o);
|
|
96
96
|
}
|
|
97
97
|
const e = t.trim().toLowerCase();
|
|
98
98
|
if (this.pendingConfirmation) {
|
|
99
99
|
const n = e;
|
|
100
100
|
if (["yes", "y", "confirm", "ok", "okay"].includes(n)) {
|
|
101
|
-
const { commandId:
|
|
101
|
+
const { commandId: a, params: o } = this.pendingConfirmation;
|
|
102
102
|
this.pendingConfirmation = null;
|
|
103
|
-
const c = this.getCommandById(
|
|
104
|
-
return c ? this.safeRunAction(c,
|
|
103
|
+
const c = this.getCommandById(a);
|
|
104
|
+
return c ? this.safeRunAction(c, o) : { message: "That action is no longer available.", type: "error" };
|
|
105
105
|
}
|
|
106
106
|
return ["no", "n", "cancel", "stop"].includes(n) ? (this.pendingConfirmation = null, { message: "Cancelled.", type: "success" }) : {
|
|
107
107
|
message: "Please confirm: Yes or No.",
|
|
@@ -114,22 +114,25 @@ class B {
|
|
|
114
114
|
}
|
|
115
115
|
const i = this.commands.get(e);
|
|
116
116
|
if (i) {
|
|
117
|
-
const n = i
|
|
118
|
-
|
|
117
|
+
const n = i;
|
|
118
|
+
if (n.macro)
|
|
119
|
+
return this.safeRunAction(n, {});
|
|
120
|
+
const a = (n.parameters ?? []).filter((o) => o.required);
|
|
121
|
+
return a.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(n), params: {} }, {
|
|
119
122
|
message: `Please provide the required details for "${n.command}".`,
|
|
120
123
|
type: "form",
|
|
121
|
-
fields:
|
|
124
|
+
fields: a
|
|
122
125
|
}) : n.critical ? (this.pendingConfirmation = { commandId: this.getCommandIdentifier(n), params: {} }, this.buildConfirmResponse(n)) : this.safeRunAction(n, {});
|
|
123
126
|
}
|
|
124
127
|
const s = await this.tryDeterministicMatch(e);
|
|
125
128
|
if (s) return s;
|
|
126
129
|
if (this.enableSmartIntent && this.openAIService) {
|
|
127
|
-
const n = await this.getCommandsForAI(),
|
|
130
|
+
const n = await this.getCommandsForAI(), a = await this.openAIService.determineIntent(
|
|
128
131
|
e,
|
|
129
132
|
n,
|
|
130
133
|
this.context
|
|
131
134
|
);
|
|
132
|
-
return this.handleAIResult(
|
|
135
|
+
return this.handleAIResult(a);
|
|
133
136
|
}
|
|
134
137
|
return this.enableSmartIntent ? this.listAllCommands() : { message: "I'm not sure what you mean.", type: "error" };
|
|
135
138
|
}
|
|
@@ -138,10 +141,12 @@ class B {
|
|
|
138
141
|
const e = this.getCommandById(t.match);
|
|
139
142
|
if (!e)
|
|
140
143
|
return { message: "I'm not sure what you mean.", type: "error" };
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
if (e.macro)
|
|
145
|
+
return this.safeRunAction(e, {});
|
|
146
|
+
const i = t.params ?? {}, s = this.sanitizeParamsForCommand(e, i), n = e.allowAiParamExtraction === !1 ? {} : s, o = (e.parameters ?? []).filter((f) => f.required).filter((f) => n[f.name] == null || n[f.name] === "");
|
|
147
|
+
if (t.incomplete || o.length > 0) {
|
|
148
|
+
if (this.context = { commandId: this.getCommandIdentifier(e), params: n }, !(e.collectRequiredViaForm !== !1) && this.shouldAskSingleQuestion(o)) {
|
|
149
|
+
const p = o.map((g) => g.name).join(" and ");
|
|
145
150
|
return {
|
|
146
151
|
message: t.message || `Please provide ${p}.`,
|
|
147
152
|
type: "question"
|
|
@@ -150,7 +155,7 @@ class B {
|
|
|
150
155
|
return {
|
|
151
156
|
message: t.message || `Please fill in the missing details for "${e.command}".`,
|
|
152
157
|
type: "form",
|
|
153
|
-
fields:
|
|
158
|
+
fields: o
|
|
154
159
|
};
|
|
155
160
|
}
|
|
156
161
|
if (e.critical)
|
|
@@ -180,52 +185,52 @@ class B {
|
|
|
180
185
|
delete i[s.name];
|
|
181
186
|
continue;
|
|
182
187
|
}
|
|
183
|
-
const
|
|
184
|
-
if (!
|
|
188
|
+
const a = n.trim();
|
|
189
|
+
if (!a) {
|
|
185
190
|
delete i[s.name];
|
|
186
191
|
continue;
|
|
187
192
|
}
|
|
188
|
-
i[s.name] =
|
|
193
|
+
i[s.name] = a;
|
|
189
194
|
}
|
|
190
195
|
if (s.type === "number") {
|
|
191
|
-
const
|
|
192
|
-
if (Number.isNaN(
|
|
196
|
+
const a = typeof n == "number" ? n : Number(n == null ? void 0 : n.toString().trim());
|
|
197
|
+
if (Number.isNaN(a)) {
|
|
193
198
|
delete i[s.name];
|
|
194
199
|
continue;
|
|
195
200
|
}
|
|
196
|
-
if (typeof s.min == "number" &&
|
|
201
|
+
if (typeof s.min == "number" && a < s.min) {
|
|
197
202
|
delete i[s.name];
|
|
198
203
|
continue;
|
|
199
204
|
}
|
|
200
|
-
if (typeof s.max == "number" &&
|
|
205
|
+
if (typeof s.max == "number" && a > s.max) {
|
|
201
206
|
delete i[s.name];
|
|
202
207
|
continue;
|
|
203
208
|
}
|
|
204
|
-
i[s.name] =
|
|
209
|
+
i[s.name] = a;
|
|
205
210
|
}
|
|
206
211
|
if (s.type === "date") {
|
|
207
|
-
const
|
|
208
|
-
if (typeof
|
|
209
|
-
const
|
|
210
|
-
this.isIsoDateString(
|
|
212
|
+
const a = i[s.name];
|
|
213
|
+
if (typeof a == "string") {
|
|
214
|
+
const o = a.trim();
|
|
215
|
+
this.isIsoDateString(o) ? i[s.name] = o : delete i[s.name];
|
|
211
216
|
} else
|
|
212
217
|
delete i[s.name];
|
|
213
218
|
}
|
|
214
219
|
if (s.type === "select") {
|
|
215
|
-
const
|
|
216
|
-
if (!
|
|
220
|
+
const a = typeof n == "string" ? n : n == null ? void 0 : n.toString();
|
|
221
|
+
if (!a) {
|
|
217
222
|
delete i[s.name];
|
|
218
223
|
continue;
|
|
219
224
|
}
|
|
220
|
-
if (Array.isArray(s.options) && s.options.length > 0 && !s.options.some((c) => String(c.value) === String(
|
|
225
|
+
if (Array.isArray(s.options) && s.options.length > 0 && !s.options.some((c) => String(c.value) === String(a))) {
|
|
221
226
|
delete i[s.name];
|
|
222
227
|
continue;
|
|
223
228
|
}
|
|
224
|
-
i[s.name] =
|
|
229
|
+
i[s.name] = a;
|
|
225
230
|
}
|
|
226
231
|
if (s.type === "file") {
|
|
227
|
-
const
|
|
228
|
-
(s.delivery ?? "file") === "base64" ? !c && !
|
|
232
|
+
const a = i[s.name], o = a && typeof a == "object" && typeof a.name == "string" && typeof a.size == "number", c = typeof a == "string" && /^data:[^;]+;base64,/.test(a);
|
|
233
|
+
(s.delivery ?? "file") === "base64" ? !c && !o && delete i[s.name] : o || delete i[s.name];
|
|
229
234
|
}
|
|
230
235
|
}
|
|
231
236
|
return i;
|
|
@@ -252,35 +257,35 @@ class B {
|
|
|
252
257
|
}
|
|
253
258
|
async tryDeterministicMatch(t) {
|
|
254
259
|
const e = [];
|
|
255
|
-
for (const
|
|
260
|
+
for (const o of this.commands.values()) {
|
|
256
261
|
let c = 0;
|
|
257
|
-
const f =
|
|
262
|
+
const f = o.command.toLowerCase();
|
|
258
263
|
t.includes(f) && (c += 5);
|
|
259
|
-
const
|
|
260
|
-
for (const p of
|
|
264
|
+
const r = o.keywords ?? [];
|
|
265
|
+
for (const p of r) {
|
|
261
266
|
const g = p.toLowerCase().trim();
|
|
262
267
|
g && (t === g ? c += 4 : t.includes(g) && (c += 3));
|
|
263
268
|
}
|
|
264
|
-
c > 0 && e.push({ cmd:
|
|
269
|
+
c > 0 && e.push({ cmd: o, score: c });
|
|
265
270
|
}
|
|
266
271
|
if (e.length === 0) return null;
|
|
267
|
-
e.sort((
|
|
268
|
-
const i = e[0].score, s = e.filter((
|
|
272
|
+
e.sort((o, c) => c.score - o.score);
|
|
273
|
+
const i = e[0].score, s = e.filter((o) => o.score === i).slice(0, 3);
|
|
269
274
|
if (s.length > 1)
|
|
270
275
|
return {
|
|
271
276
|
message: "I think you mean one of these. Which one should I run?",
|
|
272
277
|
type: "ambiguous",
|
|
273
|
-
options: s.map((
|
|
274
|
-
label:
|
|
275
|
-
value:
|
|
276
|
-
commandId:
|
|
278
|
+
options: s.map((o) => ({
|
|
279
|
+
label: o.cmd.command,
|
|
280
|
+
value: o.cmd.command,
|
|
281
|
+
commandId: o.cmd.id
|
|
277
282
|
}))
|
|
278
283
|
};
|
|
279
|
-
const n = s[0].cmd,
|
|
280
|
-
return
|
|
284
|
+
const n = s[0].cmd, a = (n.parameters ?? []).filter((o) => o.required);
|
|
285
|
+
return a.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(n), params: {} }, {
|
|
281
286
|
message: `Please provide the required details for "${n.command}".`,
|
|
282
287
|
type: "form",
|
|
283
|
-
fields:
|
|
288
|
+
fields: a
|
|
284
289
|
}) : n.critical ? (this.pendingConfirmation = { commandId: this.getCommandIdentifier(n), params: {} }, this.buildConfirmResponse(n)) : this.safeRunAction(n, {});
|
|
285
290
|
}
|
|
286
291
|
async safeRunAction(t, e) {
|
|
@@ -301,14 +306,14 @@ class B {
|
|
|
301
306
|
e.parameters && await Promise.all(
|
|
302
307
|
e.parameters.map(async (i) => {
|
|
303
308
|
if (i.type !== "select" || !i.getOptions || i.options && i.options.length) return;
|
|
304
|
-
const s = `${e.id ?? e.command}:${i.name}`, n = this.selectOptionsCache.get(s),
|
|
305
|
-
if (n &&
|
|
309
|
+
const s = `${e.id ?? e.command}:${i.name}`, n = this.selectOptionsCache.get(s), a = Date.now();
|
|
310
|
+
if (n && a - n.ts < 6e4) {
|
|
306
311
|
i.options = n.options;
|
|
307
312
|
return;
|
|
308
313
|
}
|
|
309
314
|
try {
|
|
310
|
-
const
|
|
311
|
-
this.selectOptionsCache.set(s, { options:
|
|
315
|
+
const o = await i.getOptions();
|
|
316
|
+
this.selectOptionsCache.set(s, { options: o, ts: a }), i.options = o;
|
|
312
317
|
} catch {
|
|
313
318
|
}
|
|
314
319
|
})
|
|
@@ -345,7 +350,7 @@ class B {
|
|
|
345
350
|
return Array.from(this.commands.keys());
|
|
346
351
|
}
|
|
347
352
|
}
|
|
348
|
-
class
|
|
353
|
+
class P {
|
|
349
354
|
constructor() {
|
|
350
355
|
this.synth = typeof window < "u" ? window.speechSynthesis : null;
|
|
351
356
|
}
|
|
@@ -367,7 +372,7 @@ class H {
|
|
|
367
372
|
this.synth && this.synth.cancel();
|
|
368
373
|
}
|
|
369
374
|
}
|
|
370
|
-
class
|
|
375
|
+
class W {
|
|
371
376
|
constructor() {
|
|
372
377
|
this.fallbackMessage = "Sorry, I didn’t understand that.";
|
|
373
378
|
}
|
|
@@ -375,18 +380,18 @@ class z {
|
|
|
375
380
|
this.fallbackMessage = t;
|
|
376
381
|
}
|
|
377
382
|
handleFallback(t) {
|
|
378
|
-
t && console.log(`Fallback triggered for: "${t}"`), console.log(this.fallbackMessage), new
|
|
383
|
+
t && console.log(`Fallback triggered for: "${t}"`), console.log(this.fallbackMessage), new P().speak(this.fallbackMessage);
|
|
379
384
|
}
|
|
380
385
|
getFallbackMessage() {
|
|
381
386
|
return this.fallbackMessage;
|
|
382
387
|
}
|
|
383
388
|
}
|
|
384
|
-
const
|
|
389
|
+
const H = () => {
|
|
385
390
|
if (typeof window > "u") return null;
|
|
386
391
|
const d = window;
|
|
387
392
|
return d.SpeechRecognition ?? d.webkitSpeechRecognition ?? null;
|
|
388
393
|
};
|
|
389
|
-
class
|
|
394
|
+
class B {
|
|
390
395
|
constructor(t = "en-US", e = {}) {
|
|
391
396
|
this.recognition = null, this.isListening = !1, this.engineActive = !1, this.intentionallyStopped = !1, this.restartAllowed = !0, this.lastStart = 0, this.backoffMs = 250, this.destroyed = !1, this.resultCallback = null, this.ttsSpeaking = !1, this.debugEnabled = !0, this.restartTimer = null, this.prewarmed = !1, this.hadResultThisSession = !1, this.onTTSStart = () => {
|
|
392
397
|
var s;
|
|
@@ -399,7 +404,7 @@ class O {
|
|
|
399
404
|
}, this.onTTSEnd = () => {
|
|
400
405
|
this.ttsSpeaking = !1, this.isListening && this.restartAllowed ? this.safeRestart() : this.emitStatus(this.isListening ? "listening" : "idle");
|
|
401
406
|
};
|
|
402
|
-
const i =
|
|
407
|
+
const i = H();
|
|
403
408
|
if (i) {
|
|
404
409
|
this.recognition = new i(), this.recognition.lang = t, this.recognition.interimResults = e.interimResults ?? !0, this.recognition.continuous = e.continuous ?? !0, this.recognition.onresult = (n) => this.handleResult(n, e), this.recognition.onend = () => this.handleEnd(), this.recognition.onstart = () => {
|
|
405
410
|
this.log("recognition onstart"), this.engineActive = !0, this.hadResultThisSession = !1, this.restartTimer && (clearTimeout(this.restartTimer), this.restartTimer = null), this.backoffMs = 250, this.isListening && !this.ttsSpeaking && this.emitStatus("listening");
|
|
@@ -431,7 +436,7 @@ class O {
|
|
|
431
436
|
}
|
|
432
437
|
/** Check if SpeechRecognition is available */
|
|
433
438
|
isSupported() {
|
|
434
|
-
return
|
|
439
|
+
return H() !== null;
|
|
435
440
|
}
|
|
436
441
|
/** Allow consumers (wrappers) to observe status changes */
|
|
437
442
|
onStatusChange(t) {
|
|
@@ -469,11 +474,11 @@ class O {
|
|
|
469
474
|
var s, n;
|
|
470
475
|
if (!this.resultCallback) return;
|
|
471
476
|
const i = e.confidenceThreshold ?? 0.6;
|
|
472
|
-
for (let
|
|
473
|
-
const
|
|
474
|
-
if (f && !(!
|
|
477
|
+
for (let a = t.resultIndex; a < t.results.length; a++) {
|
|
478
|
+
const o = t.results[a], c = o && o[0], f = ((n = (s = c == null ? void 0 : c.transcript) == null ? void 0 : s.trim) == null ? void 0 : n.call(s)) || "", r = (c == null ? void 0 : c.confidence) ?? 0;
|
|
479
|
+
if (f && !(!o.isFinal && e.interimResults === !1) && !(o.isFinal && r < i))
|
|
475
480
|
try {
|
|
476
|
-
this.hadResultThisSession = !0, this.resultCallback(f, !!
|
|
481
|
+
this.hadResultThisSession = !0, this.resultCallback(f, !!o.isFinal);
|
|
477
482
|
} catch {
|
|
478
483
|
this.error("VoiceProcessor: result callback error");
|
|
479
484
|
}
|
|
@@ -552,27 +557,29 @@ class O {
|
|
|
552
557
|
}
|
|
553
558
|
}
|
|
554
559
|
}
|
|
555
|
-
class
|
|
560
|
+
class R {
|
|
556
561
|
constructor() {
|
|
557
|
-
this.lastTap = 0;
|
|
562
|
+
this.lastTap = 0, this.tapCount = 0;
|
|
558
563
|
}
|
|
559
564
|
/**
|
|
560
|
-
* Sets up
|
|
561
|
-
* @param
|
|
565
|
+
* Sets up triple-click and triple-tap listeners
|
|
566
|
+
* @param onTripleClickOrTap Callback to execute when a triple-click or triple-tap is detected
|
|
562
567
|
*/
|
|
563
|
-
|
|
564
|
-
this.destroy(), this.
|
|
565
|
-
|
|
566
|
-
|
|
568
|
+
setupTripleTapListener(t) {
|
|
569
|
+
this.destroy(), this.clickListener = () => {
|
|
570
|
+
this.tapCount++, this.tapCount === 1 ? this.tapTimeout = window.setTimeout(() => {
|
|
571
|
+
this.tapCount = 0;
|
|
572
|
+
}, 500) : this.tapCount === 3 && (clearTimeout(this.tapTimeout), this.tapCount = 0, t());
|
|
573
|
+
}, document.addEventListener("click", this.clickListener), this.touchEndListener = () => {
|
|
567
574
|
const e = (/* @__PURE__ */ new Date()).getTime(), i = e - this.lastTap;
|
|
568
|
-
i <
|
|
575
|
+
i < 500 && i > 0 ? (this.tapCount++, this.tapCount === 3 && (this.tapCount = 0, t())) : this.tapCount = 1, this.lastTap = e;
|
|
569
576
|
}, document.addEventListener("touchend", this.touchEndListener);
|
|
570
577
|
}
|
|
571
578
|
destroy() {
|
|
572
|
-
this.dblClickListener && document.removeEventListener("dblclick", this.dblClickListener), this.touchEndListener && document.removeEventListener("touchend", this.touchEndListener), this.dblClickListener = void 0, this.touchEndListener = void 0;
|
|
579
|
+
this.dblClickListener && document.removeEventListener("dblclick", this.dblClickListener), this.touchEndListener && document.removeEventListener("touchend", this.touchEndListener), this.clickListener && document.removeEventListener("click", this.clickListener), this.tapTimeout && clearTimeout(this.tapTimeout), this.dblClickListener = void 0, this.touchEndListener = void 0, this.clickListener = void 0, this.tapTimeout = void 0, this.tapCount = 0;
|
|
573
580
|
}
|
|
574
581
|
}
|
|
575
|
-
function
|
|
582
|
+
function j() {
|
|
576
583
|
if (document.querySelector("#assistant-styles")) {
|
|
577
584
|
console.log("Styles already injected");
|
|
578
585
|
return;
|
|
@@ -613,20 +620,20 @@ function D() {
|
|
|
613
620
|
}
|
|
614
621
|
`, document.head.appendChild(t), console.log("Gradient styles injected");
|
|
615
622
|
}
|
|
616
|
-
function
|
|
623
|
+
function U() {
|
|
617
624
|
if (document.querySelector("#gradient-indicator"))
|
|
618
625
|
return;
|
|
619
626
|
const d = document.createElement("div");
|
|
620
|
-
d.id = "gradient-indicator",
|
|
627
|
+
d.id = "gradient-indicator", j(), d.classList.add("gradient-indicator"), document.body.appendChild(d), console.log("Gradient indicator added to the DOM");
|
|
621
628
|
}
|
|
622
|
-
function
|
|
629
|
+
function D() {
|
|
623
630
|
const d = document.querySelector("#gradient-indicator");
|
|
624
631
|
d && (d.remove(), console.log("Gradient indicator removed from the DOM"));
|
|
625
632
|
}
|
|
626
633
|
function V() {
|
|
627
634
|
return typeof window < "u" && typeof document < "u";
|
|
628
635
|
}
|
|
629
|
-
class
|
|
636
|
+
class _ {
|
|
630
637
|
constructor() {
|
|
631
638
|
this.state = "idle", this.subscribers = [];
|
|
632
639
|
}
|
|
@@ -634,7 +641,7 @@ class G {
|
|
|
634
641
|
return this.state;
|
|
635
642
|
}
|
|
636
643
|
setState(t) {
|
|
637
|
-
this.state = t, this.notifySubscribers(), console.log("State updated:", t), t === "listening" ?
|
|
644
|
+
this.state = t, this.notifySubscribers(), console.log("State updated:", t), t === "listening" ? U() : D();
|
|
638
645
|
}
|
|
639
646
|
// eslint-disable-next-line no-unused-vars
|
|
640
647
|
subscribe(t) {
|
|
@@ -644,9 +651,66 @@ class G {
|
|
|
644
651
|
this.subscribers.forEach((t) => t(this.state));
|
|
645
652
|
}
|
|
646
653
|
}
|
|
647
|
-
class
|
|
654
|
+
class G {
|
|
648
655
|
constructor(t) {
|
|
649
|
-
this.container = null, this.chatWindow = null, this.messagesContainer = null, this.input = null, this.isOpen = !1, this.loadingEl = null, this.
|
|
656
|
+
this.container = null, this.chatWindow = null, this.messagesContainer = null, this.input = null, this.isOpen = !1, this.loadingEl = null, this.commandHandlers = /* @__PURE__ */ new Map(), this.active = V(), this.handleClickOutside = (e) => {
|
|
657
|
+
const i = e.target;
|
|
658
|
+
this.chatWindow && this.chatWindow.contains(i) || i.closest(".foisit-floating-btn") || this.toggle();
|
|
659
|
+
}, this.config = t, this.active && this.init();
|
|
660
|
+
}
|
|
661
|
+
/** Register a command handler that can be invoked programmatically via `runCommand` */
|
|
662
|
+
registerCommandHandler(t, e) {
|
|
663
|
+
!t || typeof e != "function" || this.commandHandlers.set(t, e);
|
|
664
|
+
}
|
|
665
|
+
/** Check whether a programmatic handler is registered locally */
|
|
666
|
+
hasCommandHandler(t) {
|
|
667
|
+
return this.commandHandlers.has(t);
|
|
668
|
+
}
|
|
669
|
+
/** Set an external executor (used to run commands registered via CommandHandler) */
|
|
670
|
+
setExternalCommandExecutor(t) {
|
|
671
|
+
this.externalCommandExecutor = t;
|
|
672
|
+
}
|
|
673
|
+
/** Unregister a previously registered command handler */
|
|
674
|
+
unregisterCommandHandler(t) {
|
|
675
|
+
t && this.commandHandlers.delete(t);
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Run a registered command by id. Options:
|
|
679
|
+
* - `params`: passed to the handler
|
|
680
|
+
* - `openOverlay`: if true, open the overlay before running
|
|
681
|
+
* - `showInvocation`: if true, show the invocation as a user message
|
|
682
|
+
*/
|
|
683
|
+
async runCommand(t) {
|
|
684
|
+
if (!t || !t.commandId) throw new Error("runCommand requires a commandId");
|
|
685
|
+
const { commandId: e, params: i, openOverlay: s = !0, showInvocation: n = !0 } = t;
|
|
686
|
+
s && !this.isOpen && this.toggle();
|
|
687
|
+
const a = this.commandHandlers.get(e);
|
|
688
|
+
if (a && n && this.messagesContainer && this.addMessage(`Command: ${e}`, "user"), a)
|
|
689
|
+
try {
|
|
690
|
+
this.showLoading();
|
|
691
|
+
const o = await a(i);
|
|
692
|
+
if (this.hideLoading(), typeof o == "string")
|
|
693
|
+
this.addMessage(o, "system");
|
|
694
|
+
else if (o && typeof o == "object")
|
|
695
|
+
try {
|
|
696
|
+
this.addMessage(JSON.stringify(o, null, 2), "system");
|
|
697
|
+
} catch {
|
|
698
|
+
this.addMessage(String(o), "system");
|
|
699
|
+
}
|
|
700
|
+
else o == null || this.addMessage(String(o), "system");
|
|
701
|
+
return o;
|
|
702
|
+
} catch (o) {
|
|
703
|
+
throw this.hideLoading(), this.addMessage(`Command "${e}" failed: ${String(o)}`, "system"), o;
|
|
704
|
+
}
|
|
705
|
+
if (this.externalCommandExecutor)
|
|
706
|
+
try {
|
|
707
|
+
this.showLoading();
|
|
708
|
+
const o = await this.externalCommandExecutor({ commandId: e, params: i });
|
|
709
|
+
return this.hideLoading(), o;
|
|
710
|
+
} catch (o) {
|
|
711
|
+
throw this.hideLoading(), this.addMessage(`Command "${e}" failed: ${String(o)}`, "system"), o;
|
|
712
|
+
}
|
|
713
|
+
this.addMessage(`No handler registered for command "${e}".`, "system");
|
|
650
714
|
}
|
|
651
715
|
init() {
|
|
652
716
|
var e, i;
|
|
@@ -654,16 +718,16 @@ class Y {
|
|
|
654
718
|
this.injectOverlayStyles();
|
|
655
719
|
const t = document.getElementById("foisit-overlay-container");
|
|
656
720
|
if (t && t instanceof HTMLElement) {
|
|
657
|
-
this.container = t, this.chatWindow = t.querySelector(".foisit-chat"), this.messagesContainer = t.querySelector(".foisit-messages"), this.input = t.querySelector("input.foisit-input"), ((e = this.config.floatingButton) == null ? void 0 : e.visible) !== !1 && !t.querySelector(".foisit-floating-btn") && this.renderFloatingButton(), this.chatWindow || this.renderChatWindow();
|
|
721
|
+
this.container = t, this.chatWindow = t.querySelector(".foisit-chat"), this.messagesContainer = t.querySelector(".foisit-messages"), this.input = t.querySelector("input.foisit-input"), ((e = this.config.floatingButton) == null ? void 0 : e.visible) !== !1 && !t.querySelector(".foisit-floating-btn") && this.renderFloatingButton(), this.chatWindow || this.renderChatWindow(), this.config.enableGestureActivation && (this.gestureHandler = new R(), this.gestureHandler.setupTripleTapListener(() => this.toggle()));
|
|
658
722
|
return;
|
|
659
723
|
}
|
|
660
|
-
this.container = document.createElement("div"), this.container.id = "foisit-overlay-container", this.container.className = "foisit-overlay-container", document.body.appendChild(this.container), ((i = this.config.floatingButton) == null ? void 0 : i.visible) !== !1 && this.renderFloatingButton(), this.renderChatWindow();
|
|
724
|
+
this.container = document.createElement("div"), this.container.id = "foisit-overlay-container", this.container.className = "foisit-overlay-container", document.body.appendChild(this.container), ((i = this.config.floatingButton) == null ? void 0 : i.visible) !== !1 && this.renderFloatingButton(), this.renderChatWindow(), this.config.enableGestureActivation && (this.gestureHandler = new R(), this.gestureHandler.setupTripleTapListener(() => this.toggle()));
|
|
661
725
|
}
|
|
662
726
|
renderFloatingButton() {
|
|
663
|
-
var s, n,
|
|
727
|
+
var s, n, a, o, c, f;
|
|
664
728
|
const t = document.createElement("button");
|
|
665
729
|
t.innerHTML = ((s = this.config.floatingButton) == null ? void 0 : s.customHtml) || "🎙️";
|
|
666
|
-
const e = ((
|
|
730
|
+
const e = ((a = (n = this.config.floatingButton) == null ? void 0 : n.position) == null ? void 0 : a.bottom) || "20px", i = ((c = (o = this.config.floatingButton) == null ? void 0 : o.position) == null ? void 0 : c.right) || "20px";
|
|
667
731
|
t.className = "foisit-floating-btn", t.style.bottom = e, t.style.right = i, t.onclick = () => this.toggle(), t.onmouseenter = () => t.style.transform = "scale(1.05)", t.onmouseleave = () => t.style.transform = "scale(1)", (f = this.container) == null || f.appendChild(t);
|
|
668
732
|
}
|
|
669
733
|
renderChatWindow() {
|
|
@@ -677,9 +741,9 @@ class Y {
|
|
|
677
741
|
const i = document.createElement("button");
|
|
678
742
|
i.type = "button", i.className = "foisit-close", i.setAttribute("aria-label", "Close"), i.innerHTML = "×", i.addEventListener("click", () => this.toggle()), t.appendChild(e), t.appendChild(i), this.messagesContainer = document.createElement("div"), this.messagesContainer.className = "foisit-messages";
|
|
679
743
|
const s = document.createElement("div");
|
|
680
|
-
s.className = "foisit-input-area", this.input = document.createElement("input"), this.input.placeholder = this.config.inputPlaceholder || "Type a command...", this.input.className = "foisit-input", this.input.addEventListener("keydown", (
|
|
681
|
-
var
|
|
682
|
-
if (
|
|
744
|
+
s.className = "foisit-input-area", this.input = document.createElement("input"), this.input.placeholder = this.config.inputPlaceholder || "Type a command...", this.input.className = "foisit-input", this.input.addEventListener("keydown", (a) => {
|
|
745
|
+
var o;
|
|
746
|
+
if (a.key === "Enter" && ((o = this.input) != null && o.value.trim())) {
|
|
683
747
|
const c = this.input.value.trim();
|
|
684
748
|
this.input.value = "", this.onSubmit && this.onSubmit(c);
|
|
685
749
|
}
|
|
@@ -689,19 +753,27 @@ class Y {
|
|
|
689
753
|
this.active && (this.onSubmit = t, this.onClose = e);
|
|
690
754
|
}
|
|
691
755
|
toggle(t, e) {
|
|
692
|
-
this.active && (t && (this.onSubmit = t), e && (this.onClose = e), this.isOpen = !this.isOpen, this.chatWindow && (this.isOpen ? (this.chatWindow.style.display = "flex", requestAnimationFrame(() => {
|
|
756
|
+
this.active && (t && (this.onSubmit = t), e && (this.onClose = e), this.isOpen = !this.isOpen, this.chatWindow && (this.isOpen ? (this.container && (this.container.style.pointerEvents = "auto"), this.chatWindow.style.display = "flex", requestAnimationFrame(() => {
|
|
693
757
|
this.chatWindow && (this.chatWindow.style.opacity = "1", this.chatWindow.style.transform = "translateY(0) scale(1)");
|
|
694
758
|
}), setTimeout(() => {
|
|
695
759
|
var i;
|
|
696
760
|
return (i = this.input) == null ? void 0 : i.focus();
|
|
697
|
-
}, 100)) : (this.chatWindow.style.opacity = "0", this.chatWindow.style.transform = "translateY(20px) scale(0.95)", setTimeout(() => {
|
|
761
|
+
}, 100), this.addClickOutsideListener()) : (this.chatWindow.style.opacity = "0", this.chatWindow.style.transform = "translateY(20px) scale(0.95)", setTimeout(() => {
|
|
698
762
|
this.chatWindow && !this.isOpen && (this.chatWindow.style.display = "none");
|
|
699
|
-
}, 200), this.onClose && this.onClose())));
|
|
763
|
+
}, 200), this.onClose && this.onClose(), this.removeClickOutsideListener(), this.container && (this.container.style.pointerEvents = "none"))));
|
|
764
|
+
}
|
|
765
|
+
addClickOutsideListener() {
|
|
766
|
+
this.container && (this.removeClickOutsideListener(), this.container.addEventListener("click", this.handleClickOutside));
|
|
767
|
+
}
|
|
768
|
+
removeClickOutsideListener() {
|
|
769
|
+
this.container && this.container.removeEventListener("click", this.handleClickOutside);
|
|
700
770
|
}
|
|
701
771
|
addMessage(t, e) {
|
|
702
772
|
if (!this.messagesContainer) return;
|
|
703
773
|
const i = document.createElement("div");
|
|
704
|
-
i.textContent = t, i.className = e === "user" ? "foisit-bubble user" : "foisit-bubble system"
|
|
774
|
+
e === "system" ? i.innerHTML = this.renderMarkdown(t) : i.textContent = t, i.className = e === "user" ? "foisit-bubble user" : "foisit-bubble system";
|
|
775
|
+
const s = (t || "").length || 0, n = Math.max(120, 700 - Math.min(600, Math.floor(s * 6)));
|
|
776
|
+
i.style.opacity = "0", i.style.transform = "translateY(8px)", i.style.transition = "none", this.messagesContainer.appendChild(i), this.animateMessageEntrance(i, n), this.scrollToBottom();
|
|
705
777
|
}
|
|
706
778
|
addOptions(t) {
|
|
707
779
|
if (!this.messagesContainer) return;
|
|
@@ -714,11 +786,11 @@ class Y {
|
|
|
714
786
|
this.onSubmit && this.onSubmit({ commandId: i.commandId });
|
|
715
787
|
return;
|
|
716
788
|
}
|
|
717
|
-
const
|
|
718
|
-
this.onSubmit && this.onSubmit(
|
|
789
|
+
const a = i && typeof i.value == "string" && i.value.trim() ? i.value : i.label;
|
|
790
|
+
this.onSubmit && this.onSubmit(a);
|
|
719
791
|
};
|
|
720
|
-
s.onclick = n, s.onkeydown = (
|
|
721
|
-
(
|
|
792
|
+
s.onclick = n, s.onkeydown = (a) => {
|
|
793
|
+
(a.key === "Enter" || a.key === " ") && (a.preventDefault(), n());
|
|
722
794
|
}, e.appendChild(s);
|
|
723
795
|
}), this.messagesContainer.appendChild(e), this.scrollToBottom();
|
|
724
796
|
}
|
|
@@ -727,57 +799,57 @@ class Y {
|
|
|
727
799
|
this.addMessage(t, "system");
|
|
728
800
|
const s = document.createElement("form");
|
|
729
801
|
s.className = "foisit-form";
|
|
730
|
-
const n = [],
|
|
802
|
+
const n = [], a = (r, p) => {
|
|
731
803
|
const g = document.createElement("div");
|
|
732
|
-
return g.className = "foisit-form-label", g.innerHTML =
|
|
733
|
-
},
|
|
734
|
-
const
|
|
735
|
-
return
|
|
804
|
+
return g.className = "foisit-form-label", g.innerHTML = r + (p ? ' <span class="foisit-req-star">*</span>' : ""), g;
|
|
805
|
+
}, o = () => {
|
|
806
|
+
const r = document.createElement("div");
|
|
807
|
+
return r.className = "foisit-form-error", r.style.display = "none", r;
|
|
736
808
|
};
|
|
737
|
-
(e ?? []).forEach((
|
|
809
|
+
(e ?? []).forEach((r) => {
|
|
738
810
|
const p = document.createElement("div");
|
|
739
811
|
p.className = "foisit-form-group";
|
|
740
|
-
const g =
|
|
741
|
-
p.appendChild(
|
|
812
|
+
const g = r.description || r.name;
|
|
813
|
+
p.appendChild(a(g, r.required));
|
|
742
814
|
let m;
|
|
743
|
-
if (
|
|
815
|
+
if (r.type === "select") {
|
|
744
816
|
const l = document.createElement("select");
|
|
745
817
|
l.className = "foisit-form-input";
|
|
746
|
-
const
|
|
747
|
-
|
|
818
|
+
const y = document.createElement("option");
|
|
819
|
+
y.value = "", y.textContent = "Select...", l.appendChild(y);
|
|
748
820
|
const w = (h) => {
|
|
749
821
|
(h ?? []).forEach((x) => {
|
|
750
|
-
const
|
|
751
|
-
|
|
822
|
+
const b = document.createElement("option");
|
|
823
|
+
b.value = String(x.value ?? x.label ?? ""), b.textContent = String(x.label ?? x.value ?? ""), l.appendChild(b);
|
|
752
824
|
});
|
|
753
825
|
};
|
|
754
|
-
if (Array.isArray(
|
|
755
|
-
w(
|
|
756
|
-
else if (typeof
|
|
757
|
-
const h =
|
|
758
|
-
x.value = "", x.textContent = "Loading...", l.appendChild(x), Promise.resolve().then(() => h()).then((
|
|
826
|
+
if (Array.isArray(r.options) && r.options.length)
|
|
827
|
+
w(r.options);
|
|
828
|
+
else if (typeof r.getOptions == "function") {
|
|
829
|
+
const h = r.getOptions, x = document.createElement("option");
|
|
830
|
+
x.value = "", x.textContent = "Loading...", l.appendChild(x), Promise.resolve().then(() => h()).then((b) => {
|
|
759
831
|
for (; l.options.length > 1; ) l.remove(1);
|
|
760
|
-
w(
|
|
832
|
+
w(b);
|
|
761
833
|
}).catch(() => {
|
|
762
834
|
for (; l.options.length > 1; ) l.remove(1);
|
|
763
|
-
const
|
|
764
|
-
|
|
835
|
+
const b = document.createElement("option");
|
|
836
|
+
b.value = "", b.textContent = "Error loading options", l.appendChild(b);
|
|
765
837
|
});
|
|
766
838
|
}
|
|
767
|
-
|
|
768
|
-
} else if (
|
|
769
|
-
const l =
|
|
770
|
-
|
|
771
|
-
const w = Array.from(
|
|
839
|
+
r.defaultValue != null && (l.value = String(r.defaultValue)), m = l;
|
|
840
|
+
} else if (r.type === "file") {
|
|
841
|
+
const l = r, y = document.createElement("input");
|
|
842
|
+
y.className = "foisit-form-input", y.type = "file", l.accept && Array.isArray(l.accept) && (y.accept = l.accept.join(",")), l.multiple && (y.multiple = !0), l.capture && (l.capture === !0 ? y.setAttribute("capture", "") : y.setAttribute("capture", String(l.capture))), y.addEventListener("change", async () => {
|
|
843
|
+
const w = Array.from(y.files || []), h = C;
|
|
772
844
|
if (h.style.display = "none", h.textContent = "", w.length === 0) return;
|
|
773
845
|
const x = l.maxFiles ?? (l.multiple ? 10 : 1);
|
|
774
846
|
if (w.length > x) {
|
|
775
847
|
h.textContent = `Please select at most ${x} file(s).`, h.style.display = "block";
|
|
776
848
|
return;
|
|
777
849
|
}
|
|
778
|
-
const
|
|
779
|
-
if (w.some((v) => v.size >
|
|
780
|
-
h.textContent = `One or more files exceed the maximum size of ${Math.round(
|
|
850
|
+
const b = l.maxSizeBytes ?? 1 / 0, u = w.reduce((v, E) => v + E.size, 0);
|
|
851
|
+
if (w.some((v) => v.size > b)) {
|
|
852
|
+
h.textContent = `One or more files exceed the maximum size of ${Math.round(b / 1024)} KB.`, h.style.display = "block";
|
|
781
853
|
return;
|
|
782
854
|
}
|
|
783
855
|
const S = l.maxTotalBytes ?? 1 / 0;
|
|
@@ -787,29 +859,29 @@ class Y {
|
|
|
787
859
|
}
|
|
788
860
|
if (l.accept && Array.isArray(l.accept)) {
|
|
789
861
|
const v = l.accept;
|
|
790
|
-
if (!w.every((
|
|
862
|
+
if (!w.every((L) => L.type ? v.some((A) => A.startsWith(".") ? L.name.toLowerCase().endsWith(A.toLowerCase()) : L.type === A || L.type.startsWith(A.split("/")[0] + "/")) : !0)) {
|
|
791
863
|
h.textContent = "One or more files have an unsupported type.", h.style.display = "block";
|
|
792
864
|
return;
|
|
793
865
|
}
|
|
794
866
|
}
|
|
795
|
-
}), m =
|
|
867
|
+
}), m = y;
|
|
796
868
|
} else {
|
|
797
869
|
const l = document.createElement("input");
|
|
798
|
-
l.className = "foisit-form-input",
|
|
870
|
+
l.className = "foisit-form-input", r.type === "string" && (l.placeholder = r.placeholder || "Type here..."), r.type === "number" ? (l.type = "number", typeof r.min == "number" && (l.min = String(r.min)), typeof r.max == "number" && (l.max = String(r.max)), typeof r.step == "number" && (l.step = String(r.step)), r.defaultValue != null && (l.value = String(r.defaultValue))) : r.type === "date" ? (l.type = "date", typeof r.min == "string" && (l.min = r.min), typeof r.max == "string" && (l.max = r.max), r.defaultValue != null && (l.value = String(r.defaultValue))) : (l.type = "text", r.defaultValue != null && (l.value = String(r.defaultValue))), m = l;
|
|
799
871
|
}
|
|
800
|
-
const C =
|
|
872
|
+
const C = o();
|
|
801
873
|
p.appendChild(m), p.appendChild(C), n.push({
|
|
802
|
-
name:
|
|
803
|
-
type:
|
|
874
|
+
name: r.name,
|
|
875
|
+
type: r.type,
|
|
804
876
|
el: m,
|
|
805
|
-
required:
|
|
877
|
+
required: r.required
|
|
806
878
|
}), s.appendChild(p);
|
|
807
879
|
});
|
|
808
880
|
const c = document.createElement("div");
|
|
809
881
|
c.className = "foisit-form-actions";
|
|
810
882
|
const f = document.createElement("button");
|
|
811
|
-
f.type = "submit", f.textContent = "Submit", f.className = "foisit-option-chip", f.style.fontWeight = "600", c.appendChild(f), s.appendChild(c), s.onsubmit = async (
|
|
812
|
-
|
|
883
|
+
f.type = "submit", f.textContent = "Submit", f.className = "foisit-option-chip", f.style.fontWeight = "600", c.appendChild(f), s.appendChild(c), s.onsubmit = async (r) => {
|
|
884
|
+
r.preventDefault();
|
|
813
885
|
const p = {};
|
|
814
886
|
let g = !1;
|
|
815
887
|
s.querySelectorAll(".foisit-form-error").forEach((m) => {
|
|
@@ -819,16 +891,16 @@ class Y {
|
|
|
819
891
|
});
|
|
820
892
|
for (const m of n) {
|
|
821
893
|
if (m.type === "file") {
|
|
822
|
-
const w = m.el.parentElement, h = w == null ? void 0 : w.querySelector(".foisit-form-error"), x = m.el,
|
|
823
|
-
if (m.required &&
|
|
894
|
+
const w = m.el.parentElement, h = w == null ? void 0 : w.querySelector(".foisit-form-error"), x = m.el, b = Array.from(x.files || []);
|
|
895
|
+
if (m.required && b.length === 0) {
|
|
824
896
|
g = !0, x.classList.add("foisit-error-border"), h && (h.textContent = "This file is required", h.style.display = "block");
|
|
825
897
|
continue;
|
|
826
898
|
}
|
|
827
|
-
if (
|
|
899
|
+
if (b.length === 0) continue;
|
|
828
900
|
const u = (e ?? []).find((v) => v.name === m.name), S = (u == null ? void 0 : u.delivery) ?? "file";
|
|
829
901
|
if (u != null && u.maxWidth || u != null && u.maxHeight)
|
|
830
902
|
try {
|
|
831
|
-
const v = await this.getImageDimensions(
|
|
903
|
+
const v = await this.getImageDimensions(b[0]);
|
|
832
904
|
if (u.maxWidth && v.width > u.maxWidth) {
|
|
833
905
|
g = !0, h && (h.textContent = `Image width must be ≤ ${u.maxWidth}px`, h.style.display = "block");
|
|
834
906
|
continue;
|
|
@@ -841,7 +913,7 @@ class Y {
|
|
|
841
913
|
}
|
|
842
914
|
if (u != null && u.maxDurationSec)
|
|
843
915
|
try {
|
|
844
|
-
const v = await this.getMediaDuration(
|
|
916
|
+
const v = await this.getMediaDuration(b[0]);
|
|
845
917
|
if (v && v > u.maxDurationSec) {
|
|
846
918
|
g = !0, h && (h.textContent = `Media duration must be ≤ ${u.maxDurationSec}s`, h.style.display = "block");
|
|
847
919
|
continue;
|
|
@@ -849,10 +921,10 @@ class Y {
|
|
|
849
921
|
} catch {
|
|
850
922
|
}
|
|
851
923
|
if (S === "file")
|
|
852
|
-
p[m.name] = u != null && u.multiple ?
|
|
924
|
+
p[m.name] = u != null && u.multiple ? b : b[0];
|
|
853
925
|
else if (S === "base64")
|
|
854
926
|
try {
|
|
855
|
-
const v = await Promise.all(
|
|
927
|
+
const v = await Promise.all(b.map((E) => this.readFileAsDataURL(E)));
|
|
856
928
|
p[m.name] = u != null && u.multiple ? v : v[0];
|
|
857
929
|
} catch {
|
|
858
930
|
g = !0, h && (h.textContent = "Failed to encode file(s) to base64.", h.style.display = "block");
|
|
@@ -860,9 +932,9 @@ class Y {
|
|
|
860
932
|
}
|
|
861
933
|
continue;
|
|
862
934
|
}
|
|
863
|
-
const C = (m.el.value ?? "").toString().trim(), l = m.el.parentElement,
|
|
935
|
+
const C = (m.el.value ?? "").toString().trim(), l = m.el.parentElement, y = l == null ? void 0 : l.querySelector(".foisit-form-error");
|
|
864
936
|
if (m.required && (C == null || C === "")) {
|
|
865
|
-
g = !0, m.el.classList.add("foisit-error-border"),
|
|
937
|
+
g = !0, m.el.classList.add("foisit-error-border"), y && (y.textContent = "This field is required", y.style.display = "block");
|
|
866
938
|
continue;
|
|
867
939
|
}
|
|
868
940
|
if (C !== "")
|
|
@@ -898,9 +970,54 @@ class Y {
|
|
|
898
970
|
scrollToBottom() {
|
|
899
971
|
this.messagesContainer && (this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight);
|
|
900
972
|
}
|
|
973
|
+
/** Subtle entrance animation for new messages */
|
|
974
|
+
animateMessageEntrance(t, e) {
|
|
975
|
+
if (!t) return;
|
|
976
|
+
t.style.transition = `opacity ${e}ms cubic-bezier(0.22, 0.9, 0.32, 1), transform ${Math.max(120, e)}ms cubic-bezier(0.22, 0.9, 0.32, 1)`, requestAnimationFrame(() => {
|
|
977
|
+
t.style.opacity = "1", t.style.transform = "translateY(0)";
|
|
978
|
+
});
|
|
979
|
+
const i = () => {
|
|
980
|
+
try {
|
|
981
|
+
t.style.transition = "";
|
|
982
|
+
} catch {
|
|
983
|
+
}
|
|
984
|
+
t.removeEventListener("transitionend", i);
|
|
985
|
+
};
|
|
986
|
+
t.addEventListener("transitionend", i);
|
|
987
|
+
}
|
|
988
|
+
/** Smoothly scroll messages container to bottom over duration (ms) */
|
|
989
|
+
animateScrollToBottom(t) {
|
|
990
|
+
if (!this.messagesContainer) return;
|
|
991
|
+
const e = this.messagesContainer, i = e.scrollTop, s = e.scrollHeight - e.clientHeight;
|
|
992
|
+
if (s <= i || t <= 0) {
|
|
993
|
+
e.scrollTop = s;
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
const n = s - i, a = performance.now(), o = (c) => {
|
|
997
|
+
const f = Math.min(1, (c - a) / t), r = 1 - Math.pow(1 - f, 3);
|
|
998
|
+
e.scrollTop = Math.round(i + n * r), f < 1 && requestAnimationFrame(o);
|
|
999
|
+
};
|
|
1000
|
+
requestAnimationFrame(o);
|
|
1001
|
+
}
|
|
901
1002
|
destroy() {
|
|
902
1003
|
var t;
|
|
903
|
-
(t = this.container) == null || t.remove(), this.container = null, this.chatWindow = null, this.messagesContainer = null, this.input = null, this.isOpen = !1;
|
|
1004
|
+
this.removeClickOutsideListener(), (t = this.container) == null || t.remove(), this.container = null, this.chatWindow = null, this.messagesContainer = null, this.input = null, this.isOpen = !1;
|
|
1005
|
+
}
|
|
1006
|
+
/** Escape HTML special characters to prevent XSS */
|
|
1007
|
+
escapeHtml(t) {
|
|
1008
|
+
const e = {
|
|
1009
|
+
"&": "&",
|
|
1010
|
+
"<": "<",
|
|
1011
|
+
">": ">",
|
|
1012
|
+
'"': """,
|
|
1013
|
+
"'": "'"
|
|
1014
|
+
};
|
|
1015
|
+
return t.replace(/[&<>"']/g, (i) => e[i]);
|
|
1016
|
+
}
|
|
1017
|
+
/** Simple markdown renderer for AI responses */
|
|
1018
|
+
renderMarkdown(t) {
|
|
1019
|
+
let e = this.escapeHtml(t);
|
|
1020
|
+
return e = e.replace(/```(\w*)\n([\s\S]*?)```/g, (i, s, n) => `<pre class="foisit-code-block"><code${s ? ` class="language-${s}"` : ""}>${n.trim()}</code></pre>`), e = e.replace(/`([^`]+)`/g, '<code class="foisit-inline-code">$1</code>'), e = e.replace(/^###### (.+)$/gm, '<h6 class="foisit-md-h6">$1</h6>'), e = e.replace(/^##### (.+)$/gm, '<h5 class="foisit-md-h5">$1</h5>'), e = e.replace(/^#### (.+)$/gm, '<h4 class="foisit-md-h4">$1</h4>'), e = e.replace(/^### (.+)$/gm, '<h3 class="foisit-md-h3">$1</h3>'), e = e.replace(/^## (.+)$/gm, '<h2 class="foisit-md-h2">$1</h2>'), e = e.replace(/^# (.+)$/gm, '<h1 class="foisit-md-h1">$1</h1>'), e = e.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>"), e = e.replace(/__([^_]+)__/g, "<strong>$1</strong>"), e = e.replace(/\*([^*]+)\*/g, "<em>$1</em>"), e = e.replace(new RegExp("(?<!_)_([^_]+)_(?!_)", "g"), "<em>$1</em>"), e = e.replace(/~~([^~]+)~~/g, "<del>$1</del>"), e = e.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer" class="foisit-md-link">$1</a>'), e = e.replace(/^[\-\*] (.+)$/gm, '<li class="foisit-md-li">$1</li>'), e = e.replace(/(<li class="foisit-md-li">.*<\/li>\n?)+/g, (i) => `<ul class="foisit-md-ul">${i}</ul>`), e = e.replace(/^\d+\. (.+)$/gm, '<li class="foisit-md-li">$1</li>'), e = e.replace(new RegExp('(?<!<\\/ul>)(<li class="foisit-md-li">.*<\\/li>\\n?)+', "g"), (i) => i.includes("<ul") ? i : `<ol class="foisit-md-ol">${i}</ol>`), e = e.replace(/^> (.+)$/gm, '<blockquote class="foisit-md-blockquote">$1</blockquote>'), e = e.replace(/^(---|___|\*\*\*)$/gm, '<hr class="foisit-md-hr">'), e = e.replace(/\n\n+/g, '</p><p class="foisit-md-p">'), e = e.replace(/\n/g, "<br>"), e.match(/^<(h[1-6]|ul|ol|pre|blockquote|hr|p)/) || (e = `<p class="foisit-md-p">${e}</p>`), e;
|
|
904
1021
|
}
|
|
905
1022
|
readFileAsDataURL(t) {
|
|
906
1023
|
return new Promise((e, i) => {
|
|
@@ -928,16 +1045,16 @@ class Y {
|
|
|
928
1045
|
try {
|
|
929
1046
|
const i = URL.createObjectURL(t), s = t.type.startsWith("audio") ? document.createElement("audio") : document.createElement("video");
|
|
930
1047
|
let n = !1;
|
|
931
|
-
const
|
|
1048
|
+
const a = setTimeout(() => {
|
|
932
1049
|
n || (n = !0, URL.revokeObjectURL(i), e(0));
|
|
933
1050
|
}, 5e3);
|
|
934
1051
|
s.preload = "metadata", s.onloadedmetadata = () => {
|
|
935
1052
|
if (n) return;
|
|
936
|
-
n = !0, clearTimeout(
|
|
1053
|
+
n = !0, clearTimeout(a);
|
|
937
1054
|
const c = s.duration || 0;
|
|
938
1055
|
URL.revokeObjectURL(i), e(c);
|
|
939
1056
|
}, s.onerror = () => {
|
|
940
|
-
n || (n = !0, clearTimeout(
|
|
1057
|
+
n || (n = !0, clearTimeout(a), URL.revokeObjectURL(i), e(0));
|
|
941
1058
|
}, s.src = i;
|
|
942
1059
|
} catch {
|
|
943
1060
|
e(0);
|
|
@@ -1268,18 +1385,104 @@ class Y {
|
|
|
1268
1385
|
transition: transform 0.2s;
|
|
1269
1386
|
}
|
|
1270
1387
|
.foisit-floating-btn:hover { transform: scale(1.05); }
|
|
1388
|
+
|
|
1389
|
+
/* Markdown Styles */
|
|
1390
|
+
.foisit-bubble.system .foisit-md-p { margin: 0 0 0.5em 0; }
|
|
1391
|
+
.foisit-bubble.system .foisit-md-p:last-child { margin-bottom: 0; }
|
|
1392
|
+
|
|
1393
|
+
.foisit-bubble.system .foisit-md-h1,
|
|
1394
|
+
.foisit-bubble.system .foisit-md-h2,
|
|
1395
|
+
.foisit-bubble.system .foisit-md-h3,
|
|
1396
|
+
.foisit-bubble.system .foisit-md-h4,
|
|
1397
|
+
.foisit-bubble.system .foisit-md-h5,
|
|
1398
|
+
.foisit-bubble.system .foisit-md-h6 {
|
|
1399
|
+
margin: 0.8em 0 0.4em 0;
|
|
1400
|
+
font-weight: 600;
|
|
1401
|
+
line-height: 1.3;
|
|
1402
|
+
}
|
|
1403
|
+
.foisit-bubble.system .foisit-md-h1:first-child,
|
|
1404
|
+
.foisit-bubble.system .foisit-md-h2:first-child,
|
|
1405
|
+
.foisit-bubble.system .foisit-md-h3:first-child { margin-top: 0; }
|
|
1406
|
+
|
|
1407
|
+
.foisit-bubble.system .foisit-md-h1 { font-size: 1.4em; }
|
|
1408
|
+
.foisit-bubble.system .foisit-md-h2 { font-size: 1.25em; }
|
|
1409
|
+
.foisit-bubble.system .foisit-md-h3 { font-size: 1.1em; }
|
|
1410
|
+
.foisit-bubble.system .foisit-md-h4 { font-size: 1em; }
|
|
1411
|
+
.foisit-bubble.system .foisit-md-h5 { font-size: 0.95em; }
|
|
1412
|
+
.foisit-bubble.system .foisit-md-h6 { font-size: 0.9em; opacity: 0.85; }
|
|
1413
|
+
|
|
1414
|
+
.foisit-bubble.system .foisit-md-ul,
|
|
1415
|
+
.foisit-bubble.system .foisit-md-ol {
|
|
1416
|
+
margin: 0.5em 0;
|
|
1417
|
+
padding-left: 1.5em;
|
|
1418
|
+
}
|
|
1419
|
+
.foisit-bubble.system .foisit-md-li { margin: 0.25em 0; }
|
|
1420
|
+
|
|
1421
|
+
.foisit-bubble.system .foisit-code-block {
|
|
1422
|
+
background: rgba(0,0,0,0.15);
|
|
1423
|
+
border-radius: 6px;
|
|
1424
|
+
padding: 10px 12px;
|
|
1425
|
+
margin: 0.5em 0;
|
|
1426
|
+
overflow-x: auto;
|
|
1427
|
+
font-family: 'SF Mono', Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
|
1428
|
+
font-size: 0.85em;
|
|
1429
|
+
line-height: 1.4;
|
|
1430
|
+
}
|
|
1431
|
+
.foisit-bubble.system .foisit-code-block code {
|
|
1432
|
+
background: transparent;
|
|
1433
|
+
padding: 0;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
.foisit-bubble.system .foisit-inline-code {
|
|
1437
|
+
background: rgba(0,0,0,0.1);
|
|
1438
|
+
padding: 2px 6px;
|
|
1439
|
+
border-radius: 4px;
|
|
1440
|
+
font-family: 'SF Mono', Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
|
1441
|
+
font-size: 0.9em;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
.foisit-bubble.system .foisit-md-blockquote {
|
|
1445
|
+
border-left: 3px solid rgba(127,127,127,0.4);
|
|
1446
|
+
margin: 0.5em 0;
|
|
1447
|
+
padding-left: 12px;
|
|
1448
|
+
opacity: 0.9;
|
|
1449
|
+
font-style: italic;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
.foisit-bubble.system .foisit-md-link {
|
|
1453
|
+
color: inherit;
|
|
1454
|
+
text-decoration: underline;
|
|
1455
|
+
opacity: 0.9;
|
|
1456
|
+
}
|
|
1457
|
+
.foisit-bubble.system .foisit-md-link:hover { opacity: 1; }
|
|
1458
|
+
|
|
1459
|
+
.foisit-bubble.system .foisit-md-hr {
|
|
1460
|
+
border: none;
|
|
1461
|
+
border-top: 1px solid rgba(127,127,127,0.3);
|
|
1462
|
+
margin: 0.8em 0;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
.foisit-bubble.system strong { font-weight: 600; }
|
|
1466
|
+
.foisit-bubble.system em { font-style: italic; }
|
|
1467
|
+
.foisit-bubble.system del { text-decoration: line-through; opacity: 0.7; }
|
|
1468
|
+
|
|
1469
|
+
@media (prefers-color-scheme: dark) {
|
|
1470
|
+
.foisit-bubble.system .foisit-code-block { background: rgba(255,255,255,0.08); }
|
|
1471
|
+
.foisit-bubble.system .foisit-inline-code { background: rgba(255,255,255,0.1); }
|
|
1472
|
+
}
|
|
1271
1473
|
`, document.head.appendChild(t);
|
|
1272
1474
|
}
|
|
1273
1475
|
}
|
|
1274
|
-
class
|
|
1476
|
+
class Y {
|
|
1275
1477
|
constructor(t) {
|
|
1276
|
-
this.config = t, this.isActivated = !1, this.lastProcessedInput = "", this.processingLock = !1, this.defaultIntroMessage = "How can I help you?", this.commandHandler = new
|
|
1478
|
+
this.config = t, this.isActivated = !1, this.lastProcessedInput = "", this.processingLock = !1, this.defaultIntroMessage = "How can I help you?", this.commandHandler = new z({
|
|
1277
1479
|
enableSmartIntent: this.config.enableSmartIntent !== !1,
|
|
1278
1480
|
intentEndpoint: this.config.intentEndpoint
|
|
1279
|
-
}), this.fallbackHandler = new
|
|
1481
|
+
}), this.fallbackHandler = new W(), typeof window < "u" && typeof document < "u" ? (this.voiceProcessor = new B(), this.textToSpeech = new P(), this.stateManager = new _(), this.gestureHandler = new R(), this.overlayManager = new G({
|
|
1280
1482
|
floatingButton: this.config.floatingButton,
|
|
1281
|
-
inputPlaceholder: this.config.inputPlaceholder
|
|
1282
|
-
|
|
1483
|
+
inputPlaceholder: this.config.inputPlaceholder,
|
|
1484
|
+
enableGestureActivation: this.config.enableGestureActivation
|
|
1485
|
+
}), this.overlayManager.setExternalCommandExecutor(async (e) => this.commandHandler.executeCommand(e)), this.config.commands.forEach((e) => this.commandHandler.addCommand(e)), this.config.fallbackResponse && this.fallbackHandler.setFallbackMessage(this.config.fallbackResponse), this.overlayManager.registerCallbacks(
|
|
1283
1486
|
async (e) => {
|
|
1284
1487
|
if (typeof e == "string") {
|
|
1285
1488
|
this.overlayManager.addMessage(e, "user"), await this.handleCommand(e);
|
|
@@ -1406,6 +1609,19 @@ class K {
|
|
|
1406
1609
|
removeCommand(t) {
|
|
1407
1610
|
console.log(`AssistantService: Removing command "${t}".`), this.commandHandler.removeCommand(t);
|
|
1408
1611
|
}
|
|
1612
|
+
/** Expose programmatic command handler registration to host apps */
|
|
1613
|
+
registerCommandHandler(t, e) {
|
|
1614
|
+
this.overlayManager && this.overlayManager.registerCommandHandler(t, e);
|
|
1615
|
+
}
|
|
1616
|
+
unregisterCommandHandler(t) {
|
|
1617
|
+
this.overlayManager && this.overlayManager.unregisterCommandHandler(t);
|
|
1618
|
+
}
|
|
1619
|
+
/** Programmatically run a registered command (proxies to OverlayManager) */
|
|
1620
|
+
async runCommand(t) {
|
|
1621
|
+
if (!this.overlayManager) throw new Error("Overlay manager not available.");
|
|
1622
|
+
const e = await this.overlayManager.runCommand(t);
|
|
1623
|
+
return e && typeof e == "object" && "type" in e && this.processResponse(e), e;
|
|
1624
|
+
}
|
|
1409
1625
|
/** Get all registered commands */
|
|
1410
1626
|
getCommands() {
|
|
1411
1627
|
return this.commandHandler.getCommands();
|
|
@@ -1421,13 +1637,13 @@ class K {
|
|
|
1421
1637
|
if (i && typeof i == "object") {
|
|
1422
1638
|
const s = i, n = s.label ?? s.commandId ?? "Selection";
|
|
1423
1639
|
this.overlayManager.addMessage(String(n), "user"), this.overlayManager.showLoading();
|
|
1424
|
-
let
|
|
1640
|
+
let a;
|
|
1425
1641
|
try {
|
|
1426
|
-
|
|
1642
|
+
a = await this.commandHandler.executeCommand(s);
|
|
1427
1643
|
} finally {
|
|
1428
1644
|
this.overlayManager.hideLoading();
|
|
1429
1645
|
}
|
|
1430
|
-
this.processResponse(
|
|
1646
|
+
this.processResponse(a);
|
|
1431
1647
|
}
|
|
1432
1648
|
},
|
|
1433
1649
|
() => {
|
|
@@ -1437,20 +1653,20 @@ class K {
|
|
|
1437
1653
|
}
|
|
1438
1654
|
}
|
|
1439
1655
|
const q = F(null);
|
|
1440
|
-
let
|
|
1656
|
+
let M = null;
|
|
1441
1657
|
const Z = ({ config: d, children: t }) => {
|
|
1442
|
-
const [e, i] =
|
|
1443
|
-
return
|
|
1444
|
-
|
|
1658
|
+
const [e, i] = I(null), [s, n] = I(!1);
|
|
1659
|
+
return $(() => {
|
|
1660
|
+
M ? console.warn(
|
|
1445
1661
|
"Multiple AssistantProvider instances detected. Reusing global AssistantService."
|
|
1446
|
-
) : (console.log("Initializing global AssistantService..."),
|
|
1447
|
-
const
|
|
1448
|
-
return i(
|
|
1449
|
-
var
|
|
1450
|
-
console.log("Cleaning up AssistantService..."), (
|
|
1662
|
+
) : (console.log("Initializing global AssistantService..."), M = new Y(d));
|
|
1663
|
+
const a = M;
|
|
1664
|
+
return i(a), n(!0), () => {
|
|
1665
|
+
var o;
|
|
1666
|
+
console.log("Cleaning up AssistantService..."), (o = a.destroy) == null || o.call(a), M = null;
|
|
1451
1667
|
};
|
|
1452
1668
|
}, [d]), !s || !e ? /* @__PURE__ */ k("div", { children: "Loading Assistant..." }) : /* @__PURE__ */ k(q.Provider, { value: e, children: t });
|
|
1453
|
-
},
|
|
1669
|
+
}, K = () => {
|
|
1454
1670
|
const d = N(q);
|
|
1455
1671
|
if (console.log("assistant", d), !d)
|
|
1456
1672
|
throw new Error("useAssistant must be used within an AssistantProvider");
|
|
@@ -1459,13 +1675,13 @@ const Z = ({ config: d, children: t }) => {
|
|
|
1459
1675
|
label: d = "Activate Assistant",
|
|
1460
1676
|
onActivate: t
|
|
1461
1677
|
}) => {
|
|
1462
|
-
const e =
|
|
1678
|
+
const e = K();
|
|
1463
1679
|
return /* @__PURE__ */ k("button", { onClick: () => {
|
|
1464
1680
|
t && t(), e.reactivate();
|
|
1465
1681
|
}, className: "assistant-activator", children: d });
|
|
1466
1682
|
}, et = (d) => {
|
|
1467
|
-
const [t, e] =
|
|
1468
|
-
return
|
|
1683
|
+
const [t, e] = I(d.getState());
|
|
1684
|
+
return $(() => {
|
|
1469
1685
|
const i = (s) => {
|
|
1470
1686
|
e(s);
|
|
1471
1687
|
};
|
|
@@ -1479,8 +1695,8 @@ export {
|
|
|
1479
1695
|
tt as AssistantActivator,
|
|
1480
1696
|
q as AssistantContext,
|
|
1481
1697
|
Z as AssistantProvider,
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1698
|
+
Y as AssistantService,
|
|
1699
|
+
Q as ReactWrapper,
|
|
1700
|
+
K as useAssistant,
|
|
1485
1701
|
et as useAssistantState
|
|
1486
1702
|
};
|