interview-widget 0.0.7 → 0.0.9
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 +197 -101
- package/dist/components/interview/interview-controller.d.ts +8 -0
- package/dist/components/interview/interview-header.d.ts +1 -0
- package/dist/components/interview/question-display.d.ts +3 -2
- package/dist/components/modals/exit-confirmation-modal.d.ts +7 -0
- package/dist/components/timer/timer-display.d.ts +13 -0
- package/dist/components/ui/dialog.d.ts +13 -0
- package/dist/context/interview-widget-context.d.ts +34 -0
- package/dist/hooks/use-api.d.ts +26 -0
- package/dist/hooks/use-dialog.d.ts +6 -0
- package/dist/hooks/use-interview-api.d.ts +5 -0
- package/dist/hooks/use-stt.d.ts +20 -0
- package/dist/hooks/use-timer.d.ts +12 -0
- package/dist/hooks/use-tts.d.ts +15 -0
- package/dist/index.d.ts +3 -2
- package/dist/services/api/index.d.ts +2 -0
- package/dist/services/api/interview-api.d.ts +23 -0
- package/dist/services/stt/index.d.ts +1 -0
- package/dist/services/stt/stt-service.d.ts +78 -0
- package/dist/services/timer/index.d.ts +6 -0
- package/dist/services/timer/timer-service.d.ts +81 -0
- package/dist/services/tts/index.d.ts +1 -0
- package/dist/services/tts/tts-service.d.ts +43 -0
- package/dist/types.d.ts +69 -14
- package/dist/utils/api-error-classifier.d.ts +2 -0
- package/dist/utils/constants.d.ts +3 -0
- package/dist/utils/helper.d.ts +6 -0
- package/dist/utils/resilient-fetch.d.ts +9 -0
- package/dist/widget.css +1 -1
- package/dist/widget.es.js +1714 -250
- package/dist/widget.umd.js +2 -2
- package/package.json +1 -1
- /package/dist/components/{onboarding-modal.d.ts → modals/onboarding-modal.d.ts} +0 -0
package/dist/widget.es.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
var
|
|
1
|
+
var me = Object.defineProperty;
|
|
2
|
+
var ge = (i, t, e) => t in i ? me(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
|
|
3
|
+
var I = (i, t, e) => ge(i, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import { createContext as he, useContext as fe, useEffect as A, useState as y, useRef as D, useCallback as v, useMemo as xe } from "react";
|
|
5
|
+
import { createPortal as pe } from "react-dom";
|
|
6
|
+
var X = { exports: {} }, U = {};
|
|
3
7
|
/**
|
|
4
8
|
* @license React
|
|
5
9
|
* react-jsx-runtime.production.js
|
|
@@ -9,56 +13,281 @@ var E = { exports: {} }, y = {};
|
|
|
9
13
|
* This source code is licensed under the MIT license found in the
|
|
10
14
|
* LICENSE file in the root directory of this source tree.
|
|
11
15
|
*/
|
|
12
|
-
var
|
|
13
|
-
function
|
|
16
|
+
var be = Symbol.for("react.transitional.element"), ye = Symbol.for("react.fragment");
|
|
17
|
+
function Z(i, t, e) {
|
|
14
18
|
var a = null;
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
for (var
|
|
18
|
-
|
|
19
|
-
} else
|
|
20
|
-
return
|
|
21
|
-
$$typeof:
|
|
22
|
-
type:
|
|
19
|
+
if (e !== void 0 && (a = "" + e), t.key !== void 0 && (a = "" + t.key), "key" in t) {
|
|
20
|
+
e = {};
|
|
21
|
+
for (var s in t)
|
|
22
|
+
s !== "key" && (e[s] = t[s]);
|
|
23
|
+
} else e = t;
|
|
24
|
+
return t = e.ref, {
|
|
25
|
+
$$typeof: be,
|
|
26
|
+
type: i,
|
|
23
27
|
key: a,
|
|
24
|
-
ref:
|
|
25
|
-
props:
|
|
28
|
+
ref: t !== void 0 ? t : null,
|
|
29
|
+
props: e
|
|
26
30
|
};
|
|
27
31
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
var
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
U.Fragment = ye;
|
|
33
|
+
U.jsx = Z;
|
|
34
|
+
U.jsxs = Z;
|
|
35
|
+
X.exports = U;
|
|
36
|
+
var r = X.exports;
|
|
37
|
+
const C = {
|
|
38
|
+
api: {
|
|
39
|
+
baseUrl: "/api",
|
|
40
|
+
retryConfig: {
|
|
41
|
+
attempts: 3,
|
|
42
|
+
backoff: "exponential",
|
|
43
|
+
baseDelay: 1e3
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
ui: {
|
|
47
|
+
baseColor: "#3B82F6",
|
|
48
|
+
borderRadius: "8px"
|
|
49
|
+
},
|
|
50
|
+
interview: {
|
|
51
|
+
timers: {
|
|
52
|
+
thinkingDuration: 30,
|
|
53
|
+
answeringDuration: 120,
|
|
54
|
+
editingDuration: 30
|
|
55
|
+
},
|
|
56
|
+
stt: {
|
|
57
|
+
provider: "groq",
|
|
58
|
+
model: "whisper-large-v3-turbo",
|
|
59
|
+
language: "en"
|
|
60
|
+
},
|
|
61
|
+
tts: {
|
|
62
|
+
provider: "piper"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}, ee = he(
|
|
66
|
+
null
|
|
67
|
+
);
|
|
68
|
+
function Ne({
|
|
69
|
+
config: i = {},
|
|
70
|
+
children: t
|
|
71
|
+
}) {
|
|
72
|
+
var a, s, c, n;
|
|
73
|
+
const e = {
|
|
74
|
+
api: {
|
|
75
|
+
...C.api,
|
|
76
|
+
...i.api,
|
|
77
|
+
retryConfig: {
|
|
78
|
+
...C.api.retryConfig,
|
|
79
|
+
...(a = i.api) == null ? void 0 : a.retryConfig
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
ui: {
|
|
83
|
+
...C.ui,
|
|
84
|
+
...i.ui
|
|
85
|
+
},
|
|
86
|
+
interview: {
|
|
87
|
+
...C.interview,
|
|
88
|
+
...i.interview,
|
|
89
|
+
timers: {
|
|
90
|
+
...C.interview.timers,
|
|
91
|
+
...(s = i.interview) == null ? void 0 : s.timers
|
|
92
|
+
},
|
|
93
|
+
stt: {
|
|
94
|
+
...C.interview.stt,
|
|
95
|
+
...(c = i.interview) == null ? void 0 : c.stt
|
|
96
|
+
},
|
|
97
|
+
tts: {
|
|
98
|
+
...C.interview.tts,
|
|
99
|
+
...(n = i.interview) == null ? void 0 : n.tts
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
return /* @__PURE__ */ r.jsx(ee.Provider, { value: e, children: t });
|
|
104
|
+
}
|
|
105
|
+
function q() {
|
|
106
|
+
const i = fe(ee);
|
|
107
|
+
if (!i)
|
|
108
|
+
throw new Error(
|
|
109
|
+
"useInterviewConfig must be used within an InterviewWidgetProvider. Wrap your component tree with <InterviewWidgetProvider config={...}>"
|
|
110
|
+
);
|
|
111
|
+
return i;
|
|
112
|
+
}
|
|
113
|
+
function Te() {
|
|
114
|
+
return q().api || C.api;
|
|
115
|
+
}
|
|
116
|
+
function F() {
|
|
117
|
+
return q().ui || C.ui;
|
|
118
|
+
}
|
|
119
|
+
function Ie() {
|
|
120
|
+
return q().interview || C.interview;
|
|
121
|
+
}
|
|
122
|
+
const ve = ({
|
|
123
|
+
isOpen: i,
|
|
124
|
+
onClose: t,
|
|
125
|
+
children: e,
|
|
126
|
+
title: a,
|
|
127
|
+
showCloseButton: s = !0,
|
|
128
|
+
closeOnOverlayClick: c = !0,
|
|
129
|
+
closeOnEscape: n = !0,
|
|
130
|
+
className: o = ""
|
|
131
|
+
}) => {
|
|
132
|
+
if (A(() => {
|
|
133
|
+
if (!i || !n) return;
|
|
134
|
+
const d = (u) => {
|
|
135
|
+
u.key === "Escape" && t();
|
|
136
|
+
};
|
|
137
|
+
return document.addEventListener("keydown", d), () => document.removeEventListener("keydown", d);
|
|
138
|
+
}, [i, n, t]), A(() => (i ? (document.body.style.overflow = "hidden", document.body.classList.add("interview-widget-container")) : (document.body.style.overflow = "unset", document.body.classList.remove("interview-widget-container")), () => {
|
|
139
|
+
document.body.style.overflow = "unset";
|
|
140
|
+
}), [i]), !i) return null;
|
|
141
|
+
const m = (d) => {
|
|
142
|
+
c && d.target === d.currentTarget && t();
|
|
143
|
+
}, g = /* @__PURE__ */ r.jsxs("div", { className: "iw-fixed iw-inset-0 iw-z-50 iw-flex iw-items-center iw-justify-center", children: [
|
|
144
|
+
/* @__PURE__ */ r.jsx(
|
|
145
|
+
"div",
|
|
146
|
+
{
|
|
147
|
+
className: "iw-fixed iw-inset-0 iw-bg-black iw-bg-opacity-50 iw-transition-opacity",
|
|
148
|
+
onClick: m
|
|
149
|
+
}
|
|
150
|
+
),
|
|
151
|
+
/* @__PURE__ */ r.jsxs(
|
|
152
|
+
"div",
|
|
153
|
+
{
|
|
154
|
+
className: `iw-relative iw-bg-white iw-rounded-lg iw-shadow-xl iw-max-w-md iw-w-full iw-mx-4 iw-max-h-[90vh] iw-overflow-hidden ${o}`,
|
|
155
|
+
role: "dialog",
|
|
156
|
+
"aria-modal": "true",
|
|
157
|
+
"aria-labelledby": a ? "dialog-title" : void 0,
|
|
158
|
+
children: [
|
|
159
|
+
(a || s) && /* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-items-center iw-justify-between iw-p-4 iw-border-b iw-border-gray-200", children: [
|
|
160
|
+
a && /* @__PURE__ */ r.jsx(
|
|
161
|
+
"h2",
|
|
162
|
+
{
|
|
163
|
+
id: "dialog-title",
|
|
164
|
+
className: "iw-text-lg iw-font-semibold iw-text-gray-900",
|
|
165
|
+
children: a
|
|
166
|
+
}
|
|
167
|
+
),
|
|
168
|
+
s && /* @__PURE__ */ r.jsx(
|
|
169
|
+
"button",
|
|
170
|
+
{
|
|
171
|
+
onClick: t,
|
|
172
|
+
className: "iw-p-1 iw-text-gray-400 iw-hover:text-gray-600 iw-transition-colors iw-rounded iw-hover:bg-gray-100",
|
|
173
|
+
"aria-label": "Close dialog",
|
|
174
|
+
children: /* @__PURE__ */ r.jsx(
|
|
175
|
+
"svg",
|
|
176
|
+
{
|
|
177
|
+
className: "iw-w-5 iw-h-5",
|
|
178
|
+
fill: "none",
|
|
179
|
+
stroke: "currentColor",
|
|
180
|
+
viewBox: "0 0 24 24",
|
|
181
|
+
children: /* @__PURE__ */ r.jsx(
|
|
182
|
+
"path",
|
|
183
|
+
{
|
|
184
|
+
strokeLinecap: "round",
|
|
185
|
+
strokeLinejoin: "round",
|
|
186
|
+
strokeWidth: 2,
|
|
187
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
188
|
+
}
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
] }),
|
|
195
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-p-4 iw-overflow-y-auto", children: e })
|
|
196
|
+
]
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
] });
|
|
200
|
+
return pe(g, document.body);
|
|
201
|
+
}, Ee = ({
|
|
202
|
+
confirmExitInterview: i,
|
|
203
|
+
isOpen: t,
|
|
204
|
+
onClose: e
|
|
205
|
+
}) => /* @__PURE__ */ r.jsx(ve, { isOpen: t, onClose: e, title: "Exit Interview", children: /* @__PURE__ */ r.jsxs("div", { className: "iw-space-y-4", children: [
|
|
206
|
+
/* @__PURE__ */ r.jsx("p", { className: "iw-text-base iw-text-gray-700", children: "Are you sure you want to exit the interview? All progress will be lost and you will not be able to resume." }),
|
|
207
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-justify-end iw-space-x-2", children: [
|
|
208
|
+
/* @__PURE__ */ r.jsx(
|
|
209
|
+
"button",
|
|
210
|
+
{
|
|
211
|
+
className: "iw-px-4 iw-py-2 iw-bg-gray-200 iw-rounded iw-text-gray-700 iw-font-medium",
|
|
212
|
+
onClick: e,
|
|
213
|
+
children: "Cancel"
|
|
214
|
+
}
|
|
215
|
+
),
|
|
216
|
+
/* @__PURE__ */ r.jsx(
|
|
217
|
+
"button",
|
|
218
|
+
{
|
|
219
|
+
className: "iw-px-4 iw-py-2 iw-bg-red-600 iw-text-white iw-rounded iw-font-medium",
|
|
220
|
+
onClick: i,
|
|
221
|
+
children: "Confirm Exit"
|
|
222
|
+
}
|
|
223
|
+
)
|
|
224
|
+
] })
|
|
225
|
+
] }) }), je = ({ title: i, onExit: t }) => {
|
|
226
|
+
const { baseColor: e } = F(), [a, s] = y(!1);
|
|
227
|
+
return /* @__PURE__ */ r.jsxs("header", { className: "iw-w-full iw-text-gray-900", children: [
|
|
228
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-mx-auto iw-flex iw-items-center iw-justify-between iw-px-4 iw-py-3", children: [
|
|
229
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-items-center iw-space-x-2", children: [
|
|
230
|
+
/* @__PURE__ */ r.jsx(
|
|
231
|
+
"div",
|
|
232
|
+
{
|
|
233
|
+
className: "iw-h-7 iw-w-7 iw-rounded-md iw-flex iw-items-center iw-justify-center iw-text-white iw-font-semibold",
|
|
234
|
+
style: { backgroundColor: e },
|
|
235
|
+
children: "N"
|
|
236
|
+
}
|
|
237
|
+
),
|
|
238
|
+
/* @__PURE__ */ r.jsx("p", { className: "iw-text-sm iw-font-medium", children: "Novara" })
|
|
239
|
+
] }),
|
|
240
|
+
/* @__PURE__ */ r.jsx("h1", { className: "iw-text-base iw-font-medium", children: i }),
|
|
241
|
+
/* @__PURE__ */ r.jsx(
|
|
242
|
+
"button",
|
|
243
|
+
{
|
|
244
|
+
className: "iw-text-sm iw-text-gray-500 hover:iw-text-gray-700",
|
|
245
|
+
onClick: () => s(!0),
|
|
246
|
+
children: "Exit Interview"
|
|
247
|
+
}
|
|
248
|
+
)
|
|
249
|
+
] }),
|
|
250
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-h-px iw-bg-gray-200" }),
|
|
251
|
+
/* @__PURE__ */ r.jsx(
|
|
252
|
+
Ee,
|
|
253
|
+
{
|
|
254
|
+
isOpen: a,
|
|
255
|
+
confirmExitInterview: () => {
|
|
256
|
+
t(), s(!1);
|
|
257
|
+
},
|
|
258
|
+
onClose: () => s(!1)
|
|
259
|
+
}
|
|
260
|
+
)
|
|
261
|
+
] });
|
|
262
|
+
}, $ = ({
|
|
263
|
+
children: i,
|
|
264
|
+
variant: t = "primary",
|
|
265
|
+
size: e = "md",
|
|
37
266
|
fullWidth: a = !1,
|
|
38
|
-
isLoading:
|
|
39
|
-
disabled:
|
|
40
|
-
className:
|
|
41
|
-
...
|
|
267
|
+
isLoading: s = !1,
|
|
268
|
+
disabled: c,
|
|
269
|
+
className: n = "",
|
|
270
|
+
...o
|
|
42
271
|
}) => {
|
|
43
|
-
const
|
|
272
|
+
const m = "iw-inline-flex iw-items-center iw-justify-center iw-rounded-md iw-font-medium iw-transition-colors iw-focus:outline-none iw-focus:ring-2 iw-focus:ring-primary-500 iw-focus:ring-offset-2", g = {
|
|
44
273
|
primary: "iw-bg-primary-600 iw-text-white iw-hover:bg-primary-700 iw-border iw-border-transparent",
|
|
45
274
|
secondary: "iw-bg-primary-100 iw-text-primary-700 iw-hover:bg-primary-200 iw-border iw-border-transparent",
|
|
46
275
|
outline: "iw-bg-transparent iw-text-primary-700 iw-border iw-border-primary-500 iw-hover:bg-primary-50",
|
|
47
276
|
text: "iw-bg-transparent iw-text-primary-600 iw-hover:bg-primary-50 iw-border iw-border-transparent",
|
|
48
277
|
gradient: "iw-text-white iw-border iw-border-transparent iw-bg-gradient-to-r iw-from-purple-500 iw-to-indigo-500 hover:iw-from-purple-600 hover:iw-to-indigo-600"
|
|
49
|
-
},
|
|
278
|
+
}, d = {
|
|
50
279
|
sm: "iw-px-3 iw-py-1.5 iw-text-sm",
|
|
51
280
|
md: "iw-px-4 iw-py-2 iw-text-sm",
|
|
52
281
|
lg: "iw-px-5 iw-py-2.5 iw-text-base"
|
|
53
|
-
}, u = "iw-disabled:opacity-50 iw-disabled:cursor-not-allowed iw-disabled:pointer-events-none",
|
|
54
|
-
return /* @__PURE__ */
|
|
282
|
+
}, u = "iw-disabled:opacity-50 iw-disabled:cursor-not-allowed iw-disabled:pointer-events-none", h = a ? "iw-w-full" : "";
|
|
283
|
+
return /* @__PURE__ */ r.jsxs(
|
|
55
284
|
"button",
|
|
56
285
|
{
|
|
57
|
-
className: `${
|
|
58
|
-
disabled:
|
|
59
|
-
...
|
|
286
|
+
className: `${m} ${g[t]} ${d[e]} ${h} ${u} ${n}`,
|
|
287
|
+
disabled: c || s,
|
|
288
|
+
...o,
|
|
60
289
|
children: [
|
|
61
|
-
|
|
290
|
+
s && /* @__PURE__ */ r.jsxs(
|
|
62
291
|
"svg",
|
|
63
292
|
{
|
|
64
293
|
className: "iw-animate-spin iw-mr-2 iw-h-4 iw-w-4 iw-text-white",
|
|
@@ -66,7 +295,7 @@ const k = ({
|
|
|
66
295
|
fill: "none",
|
|
67
296
|
viewBox: "0 0 24 24",
|
|
68
297
|
children: [
|
|
69
|
-
/* @__PURE__ */
|
|
298
|
+
/* @__PURE__ */ r.jsx(
|
|
70
299
|
"circle",
|
|
71
300
|
{
|
|
72
301
|
className: "iw-opacity-25",
|
|
@@ -77,7 +306,7 @@ const k = ({
|
|
|
77
306
|
strokeWidth: "4"
|
|
78
307
|
}
|
|
79
308
|
),
|
|
80
|
-
/* @__PURE__ */
|
|
309
|
+
/* @__PURE__ */ r.jsx(
|
|
81
310
|
"path",
|
|
82
311
|
{
|
|
83
312
|
className: "iw-opacity-75",
|
|
@@ -88,63 +317,63 @@ const k = ({
|
|
|
88
317
|
]
|
|
89
318
|
}
|
|
90
319
|
),
|
|
91
|
-
|
|
320
|
+
i
|
|
92
321
|
]
|
|
93
322
|
}
|
|
94
323
|
);
|
|
95
|
-
},
|
|
96
|
-
isOpen:
|
|
97
|
-
onStart:
|
|
98
|
-
onClose:
|
|
324
|
+
}, Se = ({
|
|
325
|
+
isOpen: i,
|
|
326
|
+
onStart: t,
|
|
327
|
+
onClose: e
|
|
99
328
|
}) => {
|
|
100
|
-
var
|
|
101
|
-
const a =
|
|
102
|
-
|
|
103
|
-
},
|
|
104
|
-
|
|
329
|
+
var N;
|
|
330
|
+
const a = D(null), s = D(null), { baseColor: c, borderRadius: n } = F(), [o, m] = y(!1), [g, d] = y(null), [u, h] = y(!1), x = () => {
|
|
331
|
+
s.current && (s.current.getTracks().forEach((w) => w.stop()), s.current = null);
|
|
332
|
+
}, k = async () => {
|
|
333
|
+
h(!0), d(null);
|
|
105
334
|
try {
|
|
106
|
-
const
|
|
335
|
+
const w = await navigator.mediaDevices.getUserMedia({
|
|
107
336
|
video: { width: { ideal: 1280 }, height: { ideal: 720 } },
|
|
108
337
|
audio: !0
|
|
109
338
|
});
|
|
110
|
-
|
|
111
|
-
} catch (
|
|
112
|
-
console.error("Media permission error:",
|
|
113
|
-
let
|
|
114
|
-
(
|
|
339
|
+
s.current = w, a.current && (a.current.srcObject = w), m(!0);
|
|
340
|
+
} catch (w) {
|
|
341
|
+
console.error("Media permission error:", w);
|
|
342
|
+
let p = "Unable to access camera or microphone.";
|
|
343
|
+
(w == null ? void 0 : w.name) === "NotAllowedError" ? p = "Permissions denied. Please allow access to camera and microphone." : (w == null ? void 0 : w.name) === "NotFoundError" ? p = "No camera/microphone found. Please connect a device and retry." : w != null && w.message && (p = w.message), m(!1), d(p);
|
|
115
344
|
} finally {
|
|
116
|
-
|
|
345
|
+
h(!1);
|
|
117
346
|
}
|
|
118
347
|
};
|
|
119
|
-
if (
|
|
120
|
-
if (!
|
|
121
|
-
|
|
348
|
+
if (A(() => {
|
|
349
|
+
if (!i) {
|
|
350
|
+
x();
|
|
122
351
|
return;
|
|
123
352
|
}
|
|
124
|
-
return
|
|
125
|
-
|
|
353
|
+
return k(), () => {
|
|
354
|
+
x();
|
|
126
355
|
};
|
|
127
|
-
}, [
|
|
128
|
-
const
|
|
129
|
-
|
|
356
|
+
}, [i]), !i) return null;
|
|
357
|
+
const j = () => {
|
|
358
|
+
t(), x();
|
|
130
359
|
};
|
|
131
|
-
return /* @__PURE__ */
|
|
132
|
-
/* @__PURE__ */
|
|
133
|
-
/* @__PURE__ */
|
|
134
|
-
|
|
360
|
+
return /* @__PURE__ */ r.jsx("div", { className: "iw-fixed iw-inset-0 iw-z-50 iw-flex iw-items-center iw-justify-center iw-bg-black/50 iw-backdrop-blur-sm", children: /* @__PURE__ */ r.jsxs("div", { className: "iw-bg-white iw-rounded-xl iw-shadow-2xl iw-w-full iw-max-w-3xl iw-mx-4", children: [
|
|
361
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-px-5 iw-py-4 iw-border-b iw-border-gray-200 iw-flex iw-items-center iw-justify-between", children: [
|
|
362
|
+
/* @__PURE__ */ r.jsx("h2", { className: "iw-text-base iw-font-semibold", children: "Camera & Microphone Check" }),
|
|
363
|
+
e && /* @__PURE__ */ r.jsx(
|
|
135
364
|
"button",
|
|
136
365
|
{
|
|
137
366
|
"aria-label": "Close",
|
|
138
367
|
className: "iw-text-gray-500 hover:iw-text-gray-700",
|
|
139
368
|
onClick: () => {
|
|
140
|
-
|
|
369
|
+
x(), e == null || e();
|
|
141
370
|
},
|
|
142
371
|
children: "✕"
|
|
143
372
|
}
|
|
144
373
|
)
|
|
145
374
|
] }),
|
|
146
|
-
/* @__PURE__ */
|
|
147
|
-
/* @__PURE__ */
|
|
375
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-p-4 iw-grid iw-grid-cols-2 iw-gap-4", children: [
|
|
376
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-border iw-border-gray-200 iw-rounded-lg iw-overflow-hidden iw-bg-gray-900", children: /* @__PURE__ */ r.jsx(
|
|
148
377
|
"video",
|
|
149
378
|
{
|
|
150
379
|
ref: a,
|
|
@@ -154,183 +383,1107 @@ const k = ({
|
|
|
154
383
|
className: "iw-w-full iw-h-64 iw-object-cover"
|
|
155
384
|
}
|
|
156
385
|
) }),
|
|
157
|
-
/* @__PURE__ */
|
|
158
|
-
/* @__PURE__ */
|
|
159
|
-
!((
|
|
160
|
-
|
|
161
|
-
/* @__PURE__ */
|
|
162
|
-
/* @__PURE__ */
|
|
163
|
-
|
|
386
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-flex-col iw-gap-3", children: [
|
|
387
|
+
/* @__PURE__ */ r.jsx("p", { className: "iw-text-sm iw-text-gray-700", children: "We will need access to your camera and microphone. Grant permission to preview your setup and to enable the Start Interview button." }),
|
|
388
|
+
!((N = navigator.mediaDevices) != null && N.getUserMedia) && /* @__PURE__ */ r.jsx("div", { className: "iw-text-xs iw-text-red-600", children: "Your browser does not support media devices. Please use a modern browser like Chrome, Edge, or Firefox." }),
|
|
389
|
+
g && /* @__PURE__ */ r.jsx("div", { className: "iw-text-xs iw-text-red-600", children: g }),
|
|
390
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-items-center iw-gap-2", children: [
|
|
391
|
+
/* @__PURE__ */ r.jsx(
|
|
392
|
+
$,
|
|
164
393
|
{
|
|
165
|
-
onClick:
|
|
166
|
-
isLoading:
|
|
394
|
+
onClick: k,
|
|
395
|
+
isLoading: u,
|
|
167
396
|
variant: "outline",
|
|
168
397
|
size: "sm",
|
|
169
|
-
|
|
398
|
+
style: {
|
|
399
|
+
borderColor: c,
|
|
400
|
+
borderRadius: n,
|
|
401
|
+
color: c
|
|
402
|
+
},
|
|
403
|
+
children: o ? "Recheck Permissions" : "Enable Camera & Mic"
|
|
170
404
|
}
|
|
171
405
|
),
|
|
172
|
-
/* @__PURE__ */
|
|
173
|
-
|
|
406
|
+
/* @__PURE__ */ r.jsx(
|
|
407
|
+
$,
|
|
174
408
|
{
|
|
175
|
-
onClick:
|
|
176
|
-
disabled: !
|
|
409
|
+
onClick: j,
|
|
410
|
+
disabled: !o,
|
|
177
411
|
size: "sm",
|
|
178
|
-
|
|
412
|
+
style: { backgroundColor: c, borderRadius: n },
|
|
413
|
+
children: "Proceed"
|
|
179
414
|
}
|
|
180
415
|
)
|
|
181
416
|
] }),
|
|
182
|
-
/* @__PURE__ */
|
|
183
|
-
/* @__PURE__ */
|
|
184
|
-
/* @__PURE__ */
|
|
417
|
+
/* @__PURE__ */ r.jsxs("ul", { className: "iw-text-xs iw-text-gray-500 iw-pt-2 iw-list-disc iw-pl-4", children: [
|
|
418
|
+
/* @__PURE__ */ r.jsx("li", { children: "Your preview is muted to avoid echo." }),
|
|
419
|
+
/* @__PURE__ */ r.jsx("li", { children: "You can change devices from your browser’s site settings." })
|
|
185
420
|
] })
|
|
186
421
|
] })
|
|
187
422
|
] })
|
|
188
423
|
] }) });
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
424
|
+
};
|
|
425
|
+
var l = /* @__PURE__ */ ((i) => (i.IDLE = "idle", i.FETCHING_QUESTION = "fetching_question", i.READING_QUESTION = "reading_question", i.THINKING = "thinking", i.ANSWERING = "answering", i.TRANSCRIBING = "transcribing", i.EDITING = "editing", i.SUBMITTING = "submitting", i.COMPLETED = "completed", i))(l || {});
|
|
426
|
+
const Re = {
|
|
427
|
+
thinkingDuration: 30,
|
|
428
|
+
answeringDuration: 120,
|
|
429
|
+
editingDuration: 30,
|
|
430
|
+
totalInterviewDuration: 600,
|
|
431
|
+
minimumTimeForNextQuestion: 120
|
|
432
|
+
}, Ce = {
|
|
433
|
+
idle: {
|
|
434
|
+
next: "fetching_question"
|
|
435
|
+
/* FETCHING_QUESTION */
|
|
436
|
+
},
|
|
437
|
+
fetching_question: {
|
|
438
|
+
next: "reading_question"
|
|
439
|
+
/* READING_QUESTION */
|
|
440
|
+
},
|
|
441
|
+
reading_question: {
|
|
442
|
+
next: "thinking"
|
|
443
|
+
/* THINKING */
|
|
444
|
+
},
|
|
445
|
+
thinking: { next: "answering", duration: 30 },
|
|
446
|
+
answering: { next: "transcribing", duration: 120 },
|
|
447
|
+
transcribing: {
|
|
448
|
+
next: "editing"
|
|
449
|
+
/* EDITING */
|
|
450
|
+
},
|
|
451
|
+
editing: { next: "submitting", duration: 30 },
|
|
452
|
+
submitting: {
|
|
453
|
+
next: "completed"
|
|
454
|
+
/* COMPLETED */
|
|
455
|
+
},
|
|
456
|
+
completed: {
|
|
457
|
+
next: "completed"
|
|
458
|
+
/* COMPLETED */
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
class ke {
|
|
462
|
+
constructor(t = {}, e = {}) {
|
|
463
|
+
I(this, "config");
|
|
464
|
+
I(this, "state");
|
|
465
|
+
I(this, "phaseIntervalId", null);
|
|
466
|
+
I(this, "globalIntervalId", null);
|
|
467
|
+
I(this, "callbacks");
|
|
468
|
+
this.config = { ...Re, ...t }, this.callbacks = e, this.state = {
|
|
469
|
+
phase: "idle",
|
|
470
|
+
currentPhaseTimeRemaining: 0,
|
|
471
|
+
totalTimeRemaining: this.config.totalInterviewDuration,
|
|
472
|
+
totalTimeElapsed: 0,
|
|
473
|
+
currentQuestionNumber: 0
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Get current state
|
|
478
|
+
*/
|
|
479
|
+
getState() {
|
|
480
|
+
return { ...this.state };
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Start a new question cycle
|
|
484
|
+
*/
|
|
485
|
+
startQuestion() {
|
|
486
|
+
var t, e;
|
|
487
|
+
if (this.state.totalTimeRemaining < this.config.minimumTimeForNextQuestion) {
|
|
488
|
+
this.state.phase = "completed", this.stopGlobalTimer(), this.stopPhaseTimer(), (e = (t = this.callbacks).onInterviewEnd) == null || e.call(t), this.notifyChange();
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
this.state.currentQuestionNumber === 0 && this.startGlobalTimer(), this.state.currentQuestionNumber = this.state.currentQuestionNumber + 1, this.state.phase = "fetching_question", this.notifyChange();
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Move to next phase
|
|
495
|
+
*/
|
|
496
|
+
nextPhase() {
|
|
497
|
+
const t = this.state.phase, e = Ce[t];
|
|
498
|
+
if (!e) return;
|
|
499
|
+
this.stopPhaseTimer(), this.state.phase = e.next;
|
|
500
|
+
const a = this.getDurationForPhase(e.next);
|
|
501
|
+
a > 0 ? (this.state.currentPhaseTimeRemaining = a, this.startPhaseTimer()) : this.state.currentPhaseTimeRemaining = 0, this.notifyChange();
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Cleanup
|
|
505
|
+
*/
|
|
506
|
+
destroy() {
|
|
507
|
+
this.stopPhaseTimer(), this.stopGlobalTimer();
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Get duration for a phase
|
|
511
|
+
*/
|
|
512
|
+
getDurationForPhase(t) {
|
|
513
|
+
switch (t) {
|
|
514
|
+
case "thinking":
|
|
515
|
+
return this.config.thinkingDuration;
|
|
516
|
+
case "answering":
|
|
517
|
+
return this.config.answeringDuration;
|
|
518
|
+
case "editing":
|
|
519
|
+
return this.config.editingDuration;
|
|
520
|
+
default:
|
|
521
|
+
return 0;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Start global timer (runs continuously during entire interview)
|
|
526
|
+
*/
|
|
527
|
+
startGlobalTimer() {
|
|
528
|
+
this.globalIntervalId = setInterval(() => {
|
|
529
|
+
var t, e, a, s;
|
|
530
|
+
this.state.totalTimeRemaining--, this.state.totalTimeElapsed++, (e = (t = this.callbacks).onTick) == null || e.call(t, this.getState()), this.state.totalTimeRemaining <= 0 && (this.stopGlobalTimer(), this.stopPhaseTimer(), this.state.phase = "completed", (s = (a = this.callbacks).onInterviewEnd) == null || s.call(a), this.notifyChange());
|
|
531
|
+
}, 1e3);
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Stop global timer
|
|
535
|
+
*/
|
|
536
|
+
stopGlobalTimer() {
|
|
537
|
+
this.globalIntervalId && (clearInterval(this.globalIntervalId), this.globalIntervalId = null);
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Start phase timer (only for timed phases)
|
|
541
|
+
*/
|
|
542
|
+
startPhaseTimer() {
|
|
543
|
+
this.phaseIntervalId = setInterval(() => {
|
|
544
|
+
this.state.currentPhaseTimeRemaining--, this.state.currentPhaseTimeRemaining <= 0 && this.nextPhase();
|
|
545
|
+
}, 1e3);
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Stop phase timer
|
|
549
|
+
*/
|
|
550
|
+
stopPhaseTimer() {
|
|
551
|
+
this.phaseIntervalId && (clearInterval(this.phaseIntervalId), this.phaseIntervalId = null);
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Notify phase change
|
|
555
|
+
*/
|
|
556
|
+
notifyChange() {
|
|
557
|
+
var t, e;
|
|
558
|
+
(e = (t = this.callbacks).onPhaseChange) == null || e.call(t, this.state.phase, this.getState());
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
function De(i = {}) {
|
|
562
|
+
const { config: t = {}, callbacks: e = {} } = i, a = D(null);
|
|
563
|
+
a.current || (a.current = new ke(t, {}));
|
|
564
|
+
const s = a.current, [c, n] = y(s.getState()), o = v(() => {
|
|
565
|
+
n(s.getState());
|
|
566
|
+
}, [s]);
|
|
567
|
+
A(() => {
|
|
568
|
+
const d = {
|
|
569
|
+
onPhaseChange: (u, h) => {
|
|
570
|
+
var x;
|
|
571
|
+
o(), (x = e.onPhaseChange) == null || x.call(e, u, h);
|
|
572
|
+
},
|
|
573
|
+
onTick: (u) => {
|
|
574
|
+
var h;
|
|
575
|
+
o(), (h = e.onTick) == null || h.call(e, u);
|
|
576
|
+
},
|
|
577
|
+
onInterviewEnd: () => {
|
|
578
|
+
var u;
|
|
579
|
+
o(), (u = e.onInterviewEnd) == null || u.call(e);
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
s.callbacks = d;
|
|
583
|
+
}, [s, e, o]), A(() => () => {
|
|
584
|
+
s.destroy();
|
|
585
|
+
}, [s]);
|
|
586
|
+
const m = v(() => {
|
|
587
|
+
s.startQuestion(), o();
|
|
588
|
+
}, [s, o]), g = v(() => {
|
|
589
|
+
s.nextPhase(), o();
|
|
590
|
+
}, [s, o]);
|
|
591
|
+
return {
|
|
592
|
+
state: c,
|
|
593
|
+
startQuestion: m,
|
|
594
|
+
nextPhase: g,
|
|
595
|
+
timerService: s
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
function Pe(i, t = {}) {
|
|
599
|
+
const [e, a] = y({
|
|
600
|
+
data: null,
|
|
601
|
+
loading: !1,
|
|
602
|
+
error: null
|
|
603
|
+
}), s = v(
|
|
604
|
+
async (...c) => {
|
|
605
|
+
var n, o, m, g;
|
|
606
|
+
a((d) => ({ ...d, loading: !0, error: null }));
|
|
607
|
+
try {
|
|
608
|
+
const d = await i(...c);
|
|
609
|
+
a((u) => ({
|
|
610
|
+
...u,
|
|
611
|
+
data: d,
|
|
612
|
+
loading: !1,
|
|
613
|
+
error: null
|
|
614
|
+
})), (n = t.onSuccess) == null || n.call(t, d), (o = t.onSettled) == null || o.call(t, d, null);
|
|
615
|
+
} catch (d) {
|
|
616
|
+
const u = d.type ? d : {
|
|
617
|
+
type: "unknown",
|
|
618
|
+
message: d.message || "Unknown error",
|
|
619
|
+
retryable: !0,
|
|
620
|
+
userMessage: "Something went wrong. Please try again.",
|
|
621
|
+
originalError: d
|
|
622
|
+
};
|
|
623
|
+
a((h) => ({
|
|
624
|
+
...h,
|
|
625
|
+
loading: !1,
|
|
626
|
+
error: u
|
|
627
|
+
})), (m = t.onError) == null || m.call(t, u), (g = t.onSettled) == null || g.call(t, null, u);
|
|
628
|
+
}
|
|
214
629
|
},
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
630
|
+
[i, t]
|
|
631
|
+
);
|
|
632
|
+
return {
|
|
633
|
+
...e,
|
|
634
|
+
execute: s
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
function Ae(i) {
|
|
638
|
+
var t;
|
|
639
|
+
if (!navigator.onLine)
|
|
640
|
+
return {
|
|
641
|
+
type: "network",
|
|
642
|
+
message: "No internet connection",
|
|
643
|
+
retryable: !0,
|
|
644
|
+
userMessage: "Please check your internet connection and try again."
|
|
645
|
+
};
|
|
646
|
+
if (i.name === "AbortError" || (t = i.message) != null && t.includes("timeout"))
|
|
647
|
+
return {
|
|
648
|
+
type: "timeout",
|
|
649
|
+
message: "Request timed out",
|
|
650
|
+
retryable: !0,
|
|
651
|
+
userMessage: "The request is taking longer than expected. Please try again."
|
|
652
|
+
};
|
|
653
|
+
if (i.status) {
|
|
654
|
+
const { status: e } = i;
|
|
655
|
+
if (e === 401 || e === 403)
|
|
656
|
+
return {
|
|
657
|
+
type: "auth",
|
|
658
|
+
status: e,
|
|
659
|
+
message: "Authentication failed",
|
|
660
|
+
retryable: !1,
|
|
661
|
+
userMessage: "Your session has expired. Please refresh the page."
|
|
662
|
+
};
|
|
663
|
+
if (e === 429)
|
|
664
|
+
return {
|
|
665
|
+
type: "rate-limit",
|
|
666
|
+
status: e,
|
|
667
|
+
message: "Too many requests",
|
|
668
|
+
retryable: !0,
|
|
669
|
+
userMessage: "Please wait a moment before trying again."
|
|
670
|
+
};
|
|
671
|
+
if (e >= 500)
|
|
672
|
+
return {
|
|
673
|
+
type: "server",
|
|
674
|
+
status: e,
|
|
675
|
+
message: `Server error: ${e}`,
|
|
676
|
+
retryable: !0,
|
|
677
|
+
userMessage: "Our servers are experiencing issues. Please try again in a few moments."
|
|
678
|
+
};
|
|
679
|
+
if (e >= 400)
|
|
680
|
+
return {
|
|
681
|
+
type: "client",
|
|
682
|
+
status: e,
|
|
683
|
+
message: `Client error: ${e}`,
|
|
684
|
+
retryable: !1,
|
|
685
|
+
userMessage: "There was an issue with your request. Please check your input."
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
return {
|
|
689
|
+
type: "unknown",
|
|
690
|
+
message: i.message || "Unknown error occurred",
|
|
691
|
+
retryable: !0,
|
|
692
|
+
userMessage: "Something unexpected happened. Please try again.",
|
|
693
|
+
originalError: i
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
async function H(i, t = {}, e = {
|
|
697
|
+
attempts: 3,
|
|
698
|
+
backoff: "exponential",
|
|
699
|
+
baseDelay: 1e3,
|
|
700
|
+
maxDelay: 1e4,
|
|
701
|
+
jitter: !0
|
|
702
|
+
}) {
|
|
703
|
+
let a;
|
|
704
|
+
for (let s = 1; s <= e.attempts; s++)
|
|
705
|
+
try {
|
|
706
|
+
const c = new AbortController(), n = setTimeout(() => c.abort(), 6e4), o = await fetch(i, {
|
|
707
|
+
...t,
|
|
708
|
+
signal: c.signal
|
|
709
|
+
});
|
|
710
|
+
if (clearTimeout(n), o.status >= 400 && o.status < 500 && o.status !== 429)
|
|
711
|
+
return o;
|
|
712
|
+
if (!o.ok)
|
|
713
|
+
throw new Error(`HTTP ${o.status}: ${o.statusText}`);
|
|
714
|
+
return o;
|
|
715
|
+
} catch (c) {
|
|
716
|
+
a = c;
|
|
717
|
+
const n = Ae(c);
|
|
718
|
+
if (!n.retryable || s === e.attempts)
|
|
719
|
+
throw n;
|
|
720
|
+
const o = Ge(s, e);
|
|
721
|
+
console.warn(
|
|
722
|
+
`API request failed (attempt ${s}/${e.attempts}), retrying in ${o}ms:`,
|
|
723
|
+
n.message
|
|
724
|
+
), await new Promise((m) => setTimeout(m, o));
|
|
725
|
+
}
|
|
726
|
+
throw a;
|
|
727
|
+
}
|
|
728
|
+
function Ge(i, t) {
|
|
729
|
+
let e;
|
|
730
|
+
return t.backoff === "exponential" ? e = t.baseDelay * Math.pow(2, i - 1) : e = t.baseDelay, e = Math.min(e, t.maxDelay), t.jitter && (e = e * (0.5 + Math.random() * 0.5)), Math.round(e);
|
|
731
|
+
}
|
|
732
|
+
class Me {
|
|
733
|
+
constructor(t = {}) {
|
|
734
|
+
I(this, "config");
|
|
735
|
+
this.config = t;
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Update configuration
|
|
739
|
+
*/
|
|
740
|
+
updateConfig(t) {
|
|
741
|
+
this.config = { ...this.config, ...t };
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Get default headers for API requests
|
|
745
|
+
*/
|
|
746
|
+
getHeaders() {
|
|
747
|
+
var e;
|
|
748
|
+
const t = {
|
|
749
|
+
"Content-Type": "application/json",
|
|
750
|
+
"X-Auth-Token": "appkey"
|
|
751
|
+
};
|
|
752
|
+
return (e = this.config) != null && e.authToken && (t.Authorization = `Bearer ${this.config.authToken}`), t;
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Get base URL from config with fallback
|
|
756
|
+
*/
|
|
757
|
+
getBaseUrl() {
|
|
758
|
+
var t;
|
|
759
|
+
return ((t = this.config) == null ? void 0 : t.baseUrl) || "/api";
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Get questions for an interview
|
|
763
|
+
*/
|
|
764
|
+
async generateQuestion({
|
|
765
|
+
interviewId: t,
|
|
766
|
+
isInterviewDone: e = !1,
|
|
767
|
+
qnaId: a,
|
|
768
|
+
question: s,
|
|
769
|
+
answer: c,
|
|
770
|
+
answerDuration: n
|
|
771
|
+
}) {
|
|
772
|
+
const o = await H(
|
|
773
|
+
`${this.getBaseUrl()}/interview/generate-question`,
|
|
774
|
+
{
|
|
775
|
+
method: "POST",
|
|
776
|
+
headers: this.getHeaders(),
|
|
777
|
+
body: JSON.stringify({
|
|
778
|
+
interview_id: t,
|
|
779
|
+
is_interview_done: e,
|
|
780
|
+
qna_id: a,
|
|
781
|
+
question: s,
|
|
782
|
+
answer: c,
|
|
783
|
+
// TODO: Hardcoded for now, will be dynamic later
|
|
784
|
+
answer_duration: n ?? "00:00:30"
|
|
785
|
+
})
|
|
786
|
+
}
|
|
787
|
+
);
|
|
788
|
+
if (!o.ok)
|
|
789
|
+
throw new Error(`Failed to get questions: ${o.status}`);
|
|
790
|
+
return await o.json();
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
function Oe() {
|
|
794
|
+
const i = q();
|
|
795
|
+
return xe(() => {
|
|
796
|
+
const e = i.api || {};
|
|
797
|
+
return new Me(e);
|
|
798
|
+
}, [i.api]);
|
|
799
|
+
}
|
|
800
|
+
class b extends Error {
|
|
801
|
+
constructor(t, e, a = !1) {
|
|
802
|
+
super(t), this.code = e, this.recoverable = a, this.name = "STTError";
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
class $e {
|
|
806
|
+
constructor(t = {}) {
|
|
807
|
+
I(this, "config");
|
|
808
|
+
I(this, "mediaRecorder", null);
|
|
809
|
+
I(this, "audioChunks", []);
|
|
810
|
+
I(this, "recordingStream", null);
|
|
811
|
+
I(this, "autoStopTimeoutId", null);
|
|
812
|
+
this.config = {
|
|
813
|
+
baseUrl: "http://localhost:8000",
|
|
814
|
+
provider: "groq",
|
|
815
|
+
model: "whisper-large-v3-turbo",
|
|
816
|
+
language: "en",
|
|
817
|
+
includeTimestamps: !1,
|
|
818
|
+
temperature: 0,
|
|
819
|
+
...t
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Update STT configuration
|
|
824
|
+
*/
|
|
825
|
+
updateConfig(t) {
|
|
826
|
+
this.config = { ...this.config, ...t };
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Check if browser supports audio recording
|
|
830
|
+
*/
|
|
831
|
+
isRecordingSupported() {
|
|
832
|
+
return !!(navigator.mediaDevices && typeof navigator.mediaDevices.getUserMedia == "function" && window.MediaRecorder);
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Start recording audio from user's microphone
|
|
836
|
+
*/
|
|
837
|
+
async startRecording(t, e) {
|
|
838
|
+
var a;
|
|
839
|
+
if (!this.isRecordingSupported())
|
|
840
|
+
throw new b(
|
|
841
|
+
"Audio recording is not supported in this browser",
|
|
842
|
+
"RECORDING_NOT_SUPPORTED",
|
|
843
|
+
!1
|
|
844
|
+
);
|
|
845
|
+
if (this.isRecording())
|
|
846
|
+
throw new b(
|
|
847
|
+
"Recording is already in progress",
|
|
848
|
+
"ALREADY_RECORDING",
|
|
849
|
+
!0
|
|
850
|
+
);
|
|
851
|
+
try {
|
|
852
|
+
this.recordingStream = await navigator.mediaDevices.getUserMedia({
|
|
853
|
+
audio: {
|
|
854
|
+
echoCancellation: !0,
|
|
855
|
+
noiseSuppression: !0,
|
|
856
|
+
sampleRate: 44100
|
|
857
|
+
}
|
|
858
|
+
}), this.audioChunks = [];
|
|
859
|
+
const s = this.getSupportedMimeType();
|
|
860
|
+
this.mediaRecorder = new MediaRecorder(this.recordingStream, {
|
|
861
|
+
mimeType: s
|
|
862
|
+
}), this.mediaRecorder.ondataavailable = (c) => {
|
|
863
|
+
var n;
|
|
864
|
+
c.data.size > 0 && (this.audioChunks.push(c.data), (n = e == null ? void 0 : e.onDataAvailable) == null || n.call(e, c.data));
|
|
865
|
+
}, this.mediaRecorder.onstop = () => {
|
|
866
|
+
var c;
|
|
867
|
+
(c = e == null ? void 0 : e.onStop) == null || c.call(e);
|
|
868
|
+
}, this.mediaRecorder.onerror = (c) => {
|
|
869
|
+
var o;
|
|
870
|
+
const n = new b(
|
|
871
|
+
`Recording failed: ${c.error}`,
|
|
872
|
+
"RECORDING_ERROR",
|
|
873
|
+
!0
|
|
874
|
+
);
|
|
875
|
+
(o = e == null ? void 0 : e.onError) == null || o.call(e, n), this.cleanup();
|
|
876
|
+
}, this.mediaRecorder.start(100), (a = e == null ? void 0 : e.onStart) == null || a.call(e), t && t > 0 && (this.autoStopTimeoutId = setTimeout(() => {
|
|
877
|
+
this.isRecording() && this.stopRecording();
|
|
878
|
+
}, t * 1e3));
|
|
879
|
+
} catch (s) {
|
|
880
|
+
if (this.cleanup(), s instanceof Error) {
|
|
881
|
+
if (s.name === "NotAllowedError" || s.name === "PermissionDeniedError")
|
|
882
|
+
throw new b(
|
|
883
|
+
"Microphone permission was denied",
|
|
884
|
+
"PERMISSION_DENIED",
|
|
885
|
+
!1
|
|
886
|
+
);
|
|
887
|
+
if (s.name === "NotFoundError")
|
|
888
|
+
throw new b("No microphone found", "NO_MICROPHONE", !1);
|
|
889
|
+
}
|
|
890
|
+
throw new b(
|
|
891
|
+
`Failed to start recording: ${s instanceof Error ? s.message : String(s)}`,
|
|
892
|
+
"START_RECORDING_FAILED",
|
|
893
|
+
!0
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Stop recording and return the audio blob
|
|
899
|
+
*/
|
|
900
|
+
async stopRecording() {
|
|
901
|
+
if (this.autoStopTimeoutId && (clearTimeout(this.autoStopTimeoutId), this.autoStopTimeoutId = null), !this.mediaRecorder || !this.isRecording())
|
|
902
|
+
throw new b(
|
|
903
|
+
"No active recording to stop",
|
|
904
|
+
"NO_ACTIVE_RECORDING",
|
|
905
|
+
!1
|
|
906
|
+
);
|
|
907
|
+
return new Promise((t, e) => {
|
|
908
|
+
if (!this.mediaRecorder) {
|
|
909
|
+
e(
|
|
910
|
+
new b("MediaRecorder is null", "MEDIARECORDER_NULL", !1)
|
|
911
|
+
);
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
const a = this.mediaRecorder, s = () => {
|
|
915
|
+
try {
|
|
916
|
+
const c = a.mimeType || "audio/webm", n = new Blob(this.audioChunks, { type: c });
|
|
917
|
+
this.cleanup(), t(n);
|
|
918
|
+
} catch (c) {
|
|
919
|
+
e(
|
|
920
|
+
new b(
|
|
921
|
+
`Failed to create audio blob: ${c instanceof Error ? c.message : String(c)}`,
|
|
922
|
+
"BLOB_CREATION_FAILED",
|
|
923
|
+
!1
|
|
924
|
+
)
|
|
925
|
+
);
|
|
926
|
+
}
|
|
927
|
+
};
|
|
928
|
+
a.addEventListener("stop", s, { once: !0 }), a.stop();
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Transcribe audio blob using the STT API
|
|
933
|
+
*/
|
|
934
|
+
async transcribe(t) {
|
|
935
|
+
const {
|
|
936
|
+
audioBlob: e,
|
|
937
|
+
model: a = this.config.model,
|
|
938
|
+
language: s = this.config.language,
|
|
939
|
+
includeTimestamps: c = this.config.includeTimestamps,
|
|
940
|
+
temperature: n = this.config.temperature
|
|
941
|
+
} = t;
|
|
942
|
+
if (!e || e.size === 0)
|
|
943
|
+
throw new b(
|
|
944
|
+
"Audio blob is empty or invalid",
|
|
945
|
+
"INVALID_AUDIO",
|
|
946
|
+
!1
|
|
947
|
+
);
|
|
948
|
+
try {
|
|
949
|
+
const o = new FormData(), m = new File([e], "recording.wav", {
|
|
950
|
+
type: e.type || "audio/wav"
|
|
951
|
+
});
|
|
952
|
+
o.append("file", m), o.append("model", a || "whisper-large-v3-turbo"), o.append("language", s || "en"), o.append("include_timestamps", String(c || !1)), o.append("temperature", String(n || 0));
|
|
953
|
+
const g = await H(
|
|
954
|
+
`${this.config.baseUrl}/speech/transcribe`,
|
|
232
955
|
{
|
|
233
|
-
|
|
234
|
-
|
|
956
|
+
method: "POST",
|
|
957
|
+
headers: {
|
|
958
|
+
accept: "application/json",
|
|
959
|
+
"X-STT-Provider": this.config.provider || "groq"
|
|
960
|
+
},
|
|
961
|
+
body: o
|
|
235
962
|
},
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
963
|
+
{
|
|
964
|
+
attempts: 1,
|
|
965
|
+
backoff: "exponential",
|
|
966
|
+
baseDelay: 1e3,
|
|
967
|
+
maxDelay: 3e3,
|
|
968
|
+
jitter: !0
|
|
969
|
+
}
|
|
970
|
+
);
|
|
971
|
+
if (!g.ok) {
|
|
972
|
+
const u = await g.text();
|
|
973
|
+
let h = `STT request failed: ${g.status} ${g.statusText}`;
|
|
974
|
+
try {
|
|
975
|
+
const x = JSON.parse(u);
|
|
976
|
+
h = x.message || x.error || h;
|
|
977
|
+
} catch {
|
|
978
|
+
h = u || h;
|
|
979
|
+
}
|
|
980
|
+
throw new b(
|
|
981
|
+
h,
|
|
982
|
+
`HTTP_${g.status}`,
|
|
983
|
+
g.status >= 500
|
|
984
|
+
);
|
|
985
|
+
}
|
|
986
|
+
return {
|
|
987
|
+
transcript: (await g.json()).data.text ?? ""
|
|
988
|
+
};
|
|
989
|
+
} catch (o) {
|
|
990
|
+
throw o instanceof b ? o : new b(
|
|
991
|
+
`Transcription failed: ${o instanceof Error ? o.message : String(o)}`,
|
|
992
|
+
"TRANSCRIPTION_FAILED",
|
|
993
|
+
!0
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Cancel current recording without processing
|
|
999
|
+
*/
|
|
1000
|
+
cancelRecording() {
|
|
1001
|
+
this.autoStopTimeoutId && (clearTimeout(this.autoStopTimeoutId), this.autoStopTimeoutId = null), this.mediaRecorder && this.isRecording() && this.mediaRecorder.stop(), this.cleanup();
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Check if currently recording
|
|
1005
|
+
*/
|
|
1006
|
+
isRecording() {
|
|
1007
|
+
return this.mediaRecorder !== null && this.mediaRecorder.state === "recording";
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Get supported MIME type for recording
|
|
1011
|
+
*/
|
|
1012
|
+
getSupportedMimeType() {
|
|
1013
|
+
const t = [
|
|
1014
|
+
"audio/webm",
|
|
1015
|
+
"audio/webm;codecs=opus",
|
|
1016
|
+
"audio/ogg;codecs=opus",
|
|
1017
|
+
"audio/mp4",
|
|
1018
|
+
"audio/wav"
|
|
1019
|
+
];
|
|
1020
|
+
for (const e of t)
|
|
1021
|
+
if (MediaRecorder.isTypeSupported(e))
|
|
1022
|
+
return e;
|
|
1023
|
+
return "audio/webm";
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* Clean up recording resources
|
|
1027
|
+
*/
|
|
1028
|
+
cleanup() {
|
|
1029
|
+
this.recordingStream && (this.recordingStream.getTracks().forEach((t) => t.stop()), this.recordingStream = null), this.mediaRecorder = null, this.audioChunks = [], this.autoStopTimeoutId && (clearTimeout(this.autoStopTimeoutId), this.autoStopTimeoutId = null);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
const O = new $e(), _e = (i = {}) => {
|
|
1033
|
+
const [t, e] = y(!1), [a, s] = y(!1), [c, n] = y(null), [o, m] = y(null), [g, d] = y(null);
|
|
1034
|
+
i.config && O.updateConfig(i.config);
|
|
1035
|
+
const u = v(async (j) => {
|
|
1036
|
+
var N;
|
|
1037
|
+
try {
|
|
1038
|
+
m(null), n(null), d(null), await O.startRecording(j, {
|
|
1039
|
+
onStart: () => {
|
|
1040
|
+
var w;
|
|
1041
|
+
e(!0), (w = i.onStart) == null || w.call(i);
|
|
1042
|
+
},
|
|
1043
|
+
onStop: () => {
|
|
1044
|
+
var w;
|
|
1045
|
+
e(!1), (w = i.onStop) == null || w.call(i);
|
|
1046
|
+
},
|
|
1047
|
+
onError: (w) => {
|
|
1048
|
+
var T;
|
|
1049
|
+
const p = w instanceof b ? w : new b(w.message, "RECORDING_ERROR", !0);
|
|
1050
|
+
m(p), e(!1), (T = i.onError) == null || T.call(i, p);
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
} catch (w) {
|
|
1054
|
+
const p = w instanceof b ? w : new b(
|
|
1055
|
+
w instanceof Error ? w.message : String(w),
|
|
1056
|
+
"START_FAILED",
|
|
1057
|
+
!1
|
|
1058
|
+
);
|
|
1059
|
+
throw m(p), e(!1), (N = i.onError) == null || N.call(i, p), p;
|
|
1060
|
+
}
|
|
1061
|
+
}, []), h = v(async () => {
|
|
1062
|
+
var j, N;
|
|
1063
|
+
try {
|
|
1064
|
+
const w = await O.stopRecording();
|
|
1065
|
+
return d(w), e(!1), (j = i.onStop) == null || j.call(i), w;
|
|
1066
|
+
} catch (w) {
|
|
1067
|
+
const p = w instanceof b ? w : new b(
|
|
1068
|
+
w instanceof Error ? w.message : String(w),
|
|
1069
|
+
"STOP_FAILED",
|
|
1070
|
+
!1
|
|
1071
|
+
);
|
|
1072
|
+
throw m(p), e(!1), (N = i.onError) == null || N.call(i, p), p;
|
|
1073
|
+
}
|
|
1074
|
+
}, []), x = v(
|
|
1075
|
+
async (j, N = {}) => {
|
|
1076
|
+
var w, p;
|
|
245
1077
|
try {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
1078
|
+
m(null), s(!0);
|
|
1079
|
+
const T = {
|
|
1080
|
+
audioBlob: j,
|
|
1081
|
+
...N
|
|
1082
|
+
}, S = await O.transcribe(T);
|
|
1083
|
+
return n(S.transcript), s(!1), (w = i.onTranscriptionComplete) == null || w.call(i, S), S;
|
|
1084
|
+
} catch (T) {
|
|
1085
|
+
const S = T instanceof b ? T : new b(
|
|
1086
|
+
T instanceof Error ? T.message : String(T),
|
|
1087
|
+
"TRANSCRIPTION_FAILED",
|
|
1088
|
+
!0
|
|
1089
|
+
);
|
|
1090
|
+
throw m(S), s(!1), (p = i.onError) == null || p.call(i, S), S;
|
|
252
1091
|
}
|
|
253
|
-
}
|
|
254
|
-
|
|
1092
|
+
},
|
|
1093
|
+
[]
|
|
1094
|
+
), k = v(() => {
|
|
1095
|
+
O.cancelRecording(), e(!1), d(null);
|
|
1096
|
+
}, []);
|
|
1097
|
+
return {
|
|
1098
|
+
startRecording: u,
|
|
1099
|
+
stopRecording: h,
|
|
1100
|
+
transcribe: x,
|
|
1101
|
+
cancelRecording: k,
|
|
1102
|
+
isRecording: t,
|
|
1103
|
+
isTranscribing: a,
|
|
1104
|
+
transcript: c,
|
|
1105
|
+
error: o,
|
|
1106
|
+
audioBlob: g
|
|
1107
|
+
};
|
|
1108
|
+
};
|
|
1109
|
+
class Le {
|
|
1110
|
+
constructor(t = {}) {
|
|
1111
|
+
I(this, "config");
|
|
1112
|
+
I(this, "currentAudio", null);
|
|
1113
|
+
this.config = {
|
|
1114
|
+
baseUrl: "http://localhost:8000",
|
|
1115
|
+
provider: "piper",
|
|
1116
|
+
voice: "string",
|
|
1117
|
+
speed: 1,
|
|
1118
|
+
...t
|
|
255
1119
|
};
|
|
256
|
-
}
|
|
257
|
-
|
|
1120
|
+
}
|
|
1121
|
+
/**
|
|
1122
|
+
* Update TTS configuration
|
|
1123
|
+
*/
|
|
1124
|
+
updateConfig(t) {
|
|
1125
|
+
this.config = { ...this.config, ...t };
|
|
1126
|
+
}
|
|
1127
|
+
/**
|
|
1128
|
+
* Get TTS audio from the API and return as blob
|
|
1129
|
+
*/
|
|
1130
|
+
async synthesizeSpeech(t) {
|
|
1131
|
+
const {
|
|
1132
|
+
text: e,
|
|
1133
|
+
voice: a = this.config.voice,
|
|
1134
|
+
speed: s = this.config.speed
|
|
1135
|
+
} = t, c = new URLSearchParams();
|
|
1136
|
+
c.append("text", e), c.append("voice", a || "string"), c.append("speed", (s == null ? void 0 : s.toString()) || "1");
|
|
1137
|
+
const n = await H(
|
|
1138
|
+
`${this.config.baseUrl}/speech/synthesize`,
|
|
1139
|
+
{
|
|
1140
|
+
method: "POST",
|
|
1141
|
+
headers: {
|
|
1142
|
+
accept: "application/json",
|
|
1143
|
+
"X-TTS-Provider": this.config.provider || "piper",
|
|
1144
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
1145
|
+
},
|
|
1146
|
+
body: c
|
|
1147
|
+
},
|
|
1148
|
+
{
|
|
1149
|
+
attempts: 1,
|
|
1150
|
+
backoff: "fixed",
|
|
1151
|
+
baseDelay: 1e3,
|
|
1152
|
+
maxDelay: 1e3,
|
|
1153
|
+
jitter: !1
|
|
1154
|
+
}
|
|
1155
|
+
);
|
|
1156
|
+
if (!n.ok)
|
|
1157
|
+
throw new Error(
|
|
1158
|
+
`TTS request failed: ${n.status} ${n.statusText}`
|
|
1159
|
+
);
|
|
1160
|
+
const o = n.headers.get("content-type");
|
|
1161
|
+
if (o && o.includes("audio/"))
|
|
1162
|
+
return n.blob();
|
|
1163
|
+
try {
|
|
1164
|
+
const m = await n.json();
|
|
1165
|
+
throw new Error(`TTS Error: ${JSON.stringify(m)}`);
|
|
1166
|
+
} catch {
|
|
1167
|
+
throw new Error("TTS request failed with unknown error");
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Speak text and return a promise that resolves when playback completes
|
|
1172
|
+
*/
|
|
1173
|
+
async speak(t, e) {
|
|
1174
|
+
var a, s;
|
|
1175
|
+
try {
|
|
1176
|
+
this.stop(), (a = e == null ? void 0 : e.onStart) == null || a.call(e);
|
|
1177
|
+
const c = await this.synthesizeSpeech(t), n = URL.createObjectURL(c);
|
|
1178
|
+
return this.currentAudio = new Audio(n), new Promise((o, m) => {
|
|
1179
|
+
if (!this.currentAudio) {
|
|
1180
|
+
m(new Error("Audio element not created"));
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
const g = this.currentAudio;
|
|
1184
|
+
g.onended = () => {
|
|
1185
|
+
var d;
|
|
1186
|
+
URL.revokeObjectURL(n), this.currentAudio = null, (d = e == null ? void 0 : e.onEnd) == null || d.call(e), o();
|
|
1187
|
+
}, g.onerror = (d) => {
|
|
1188
|
+
var h;
|
|
1189
|
+
URL.revokeObjectURL(n), this.currentAudio = null;
|
|
1190
|
+
const u = new Error(`Audio playback failed: ${d}`);
|
|
1191
|
+
(h = e == null ? void 0 : e.onError) == null || h.call(e, u), m(u);
|
|
1192
|
+
}, g.play().catch((d) => {
|
|
1193
|
+
var h;
|
|
1194
|
+
URL.revokeObjectURL(n), this.currentAudio = null;
|
|
1195
|
+
const u = new Error(`Failed to play audio: ${d.message}`);
|
|
1196
|
+
(h = e == null ? void 0 : e.onError) == null || h.call(e, u), m(u);
|
|
1197
|
+
});
|
|
1198
|
+
});
|
|
1199
|
+
} catch (c) {
|
|
1200
|
+
const n = c instanceof Error ? c : new Error(`TTS Error: ${String(c)}`);
|
|
1201
|
+
throw (s = e == null ? void 0 : e.onError) == null || s.call(e, n), n;
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
/**
|
|
1205
|
+
* Stop current audio playback
|
|
1206
|
+
*/
|
|
1207
|
+
stop() {
|
|
1208
|
+
this.currentAudio && (this.currentAudio.pause(), this.currentAudio.currentTime = 0, this.currentAudio = null);
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Check if audio is currently playing
|
|
1212
|
+
*/
|
|
1213
|
+
isPlaying() {
|
|
1214
|
+
return this.currentAudio !== null && !this.currentAudio.paused;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
const B = new Le(), Ue = (i = {}) => {
|
|
1218
|
+
const [t, e] = y(!1), [a, s] = y(!1), [c, n] = y(null);
|
|
1219
|
+
i.config && B.updateConfig(i.config);
|
|
1220
|
+
const o = v(
|
|
1221
|
+
async (g, d = {}) => {
|
|
1222
|
+
var u;
|
|
1223
|
+
try {
|
|
1224
|
+
n(null), s(!0);
|
|
1225
|
+
const h = {
|
|
1226
|
+
text: g,
|
|
1227
|
+
...d
|
|
1228
|
+
};
|
|
1229
|
+
await B.speak(h, {
|
|
1230
|
+
onStart: () => {
|
|
1231
|
+
var x;
|
|
1232
|
+
s(!1), e(!0), (x = i.onStart) == null || x.call(i);
|
|
1233
|
+
},
|
|
1234
|
+
onEnd: () => {
|
|
1235
|
+
var x;
|
|
1236
|
+
e(!1), (x = i.onEnd) == null || x.call(i);
|
|
1237
|
+
},
|
|
1238
|
+
onError: (x) => {
|
|
1239
|
+
var k;
|
|
1240
|
+
e(!1), s(!1), n(x), (k = i.onError) == null || k.call(i, x);
|
|
1241
|
+
}
|
|
1242
|
+
});
|
|
1243
|
+
} catch (h) {
|
|
1244
|
+
const x = h instanceof Error ? h : new Error(String(h));
|
|
1245
|
+
throw n(x), e(!1), s(!1), (u = i.onError) == null || u.call(i, x), x;
|
|
1246
|
+
}
|
|
1247
|
+
},
|
|
1248
|
+
[i]
|
|
1249
|
+
), m = v(() => {
|
|
1250
|
+
B.stop(), e(!1), s(!1);
|
|
1251
|
+
}, []);
|
|
1252
|
+
return {
|
|
1253
|
+
speak: o,
|
|
1254
|
+
stop: m,
|
|
1255
|
+
isPlaying: t,
|
|
1256
|
+
isLoading: a,
|
|
1257
|
+
error: c
|
|
1258
|
+
};
|
|
1259
|
+
};
|
|
1260
|
+
function qe(i) {
|
|
1261
|
+
const t = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(i);
|
|
1262
|
+
return t ? {
|
|
1263
|
+
r: parseInt(t[1], 16),
|
|
1264
|
+
g: parseInt(t[2], 16),
|
|
1265
|
+
b: parseInt(t[3], 16)
|
|
1266
|
+
} : null;
|
|
1267
|
+
}
|
|
1268
|
+
function Fe(i, t, e) {
|
|
1269
|
+
return "#" + [i, t, e].map((a) => {
|
|
1270
|
+
const s = Math.round(a).toString(16);
|
|
1271
|
+
return s.length === 1 ? "0" + s : s;
|
|
1272
|
+
}).join("");
|
|
1273
|
+
}
|
|
1274
|
+
function V(i, t) {
|
|
1275
|
+
const e = qe(i);
|
|
1276
|
+
if (!e) return i;
|
|
1277
|
+
const a = e.r + (255 - e.r) * t, s = e.g + (255 - e.g) * t, c = e.b + (255 - e.b) * t;
|
|
1278
|
+
return Fe(a, s, c);
|
|
1279
|
+
}
|
|
1280
|
+
function Qe(i, t = 0.8) {
|
|
1281
|
+
const e = V(i, t), a = V(i, 0.7);
|
|
1282
|
+
return {
|
|
1283
|
+
background: `linear-gradient(to bottom, ${e}, #ffffff)`,
|
|
1284
|
+
border: `1px solid ${a}`,
|
|
1285
|
+
color: "#1f2937"
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
function Be(i) {
|
|
1289
|
+
return new Promise((t) => setTimeout(t, i));
|
|
1290
|
+
}
|
|
1291
|
+
const He = ({
|
|
1292
|
+
state: i,
|
|
1293
|
+
className: t = "",
|
|
1294
|
+
defaultTimers: e = { thinking: 30, answering: 120, editing: 30 }
|
|
1295
|
+
}) => {
|
|
1296
|
+
const a = (d) => {
|
|
1297
|
+
const u = Math.floor(d / 60), h = d % 60;
|
|
1298
|
+
return `${u.toString().padStart(2, "0")}:${h.toString().padStart(2, "0")}`;
|
|
1299
|
+
}, s = (d) => ({
|
|
1300
|
+
[l.IDLE]: "Ready",
|
|
1301
|
+
[l.FETCHING_QUESTION]: "Loading Question...",
|
|
1302
|
+
[l.READING_QUESTION]: "Reading Question...",
|
|
1303
|
+
[l.THINKING]: "Preparation Time",
|
|
1304
|
+
[l.ANSWERING]: "Recording Answer",
|
|
1305
|
+
[l.TRANSCRIBING]: "Processing Speech...",
|
|
1306
|
+
[l.EDITING]: "Edit Your Answer",
|
|
1307
|
+
[l.SUBMITTING]: "Submitting...",
|
|
1308
|
+
[l.COMPLETED]: "Interview Complete"
|
|
1309
|
+
})[d] || d, c = (d) => ({
|
|
1310
|
+
[l.IDLE]: "iw-bg-gray-500",
|
|
1311
|
+
[l.FETCHING_QUESTION]: "iw-bg-blue-500",
|
|
1312
|
+
[l.READING_QUESTION]: "iw-bg-indigo-500",
|
|
1313
|
+
[l.THINKING]: "iw-bg-yellow-500",
|
|
1314
|
+
[l.ANSWERING]: "iw-bg-red-500",
|
|
1315
|
+
[l.TRANSCRIBING]: "iw-bg-purple-500",
|
|
1316
|
+
[l.EDITING]: "iw-bg-orange-500",
|
|
1317
|
+
[l.SUBMITTING]: "iw-bg-green-500",
|
|
1318
|
+
[l.COMPLETED]: "iw-bg-green-600"
|
|
1319
|
+
})[d] || "iw-bg-gray-500", n = (d) => ({
|
|
1320
|
+
[l.IDLE]: "iw-bg-gray-100 iw-text-gray-800",
|
|
1321
|
+
[l.FETCHING_QUESTION]: "iw-bg-blue-100 iw-text-blue-800",
|
|
1322
|
+
[l.READING_QUESTION]: "iw-bg-indigo-100 iw-text-indigo-800",
|
|
1323
|
+
[l.THINKING]: "iw-bg-yellow-100 iw-text-yellow-800",
|
|
1324
|
+
[l.ANSWERING]: "iw-bg-red-100 iw-text-red-800",
|
|
1325
|
+
[l.TRANSCRIBING]: "iw-bg-purple-100 iw-text-purple-800",
|
|
1326
|
+
[l.EDITING]: "iw-bg-orange-100 iw-text-orange-800",
|
|
1327
|
+
[l.SUBMITTING]: "iw-bg-green-100 iw-text-green-800",
|
|
1328
|
+
[l.COMPLETED]: "iw-bg-green-200 iw-text-green-900"
|
|
1329
|
+
})[d] || "iw-bg-gray-100 iw-text-gray-800", o = (d) => ({
|
|
1330
|
+
[l.IDLE]: "Ready to start next question.",
|
|
1331
|
+
[l.FETCHING_QUESTION]: "Please wait while we load the next question...",
|
|
1332
|
+
[l.READING_QUESTION]: "Listening to the question...",
|
|
1333
|
+
[l.THINKING]: "Take time to think about your answer.",
|
|
1334
|
+
[l.ANSWERING]: "Speak clearly into your microphone.",
|
|
1335
|
+
[l.TRANSCRIBING]: "Converting your speech to text...",
|
|
1336
|
+
[l.EDITING]: "Review and edit your answer.",
|
|
1337
|
+
[l.SUBMITTING]: "Submitting your answer...",
|
|
1338
|
+
[l.COMPLETED]: "Thank you for completing the interview!"
|
|
1339
|
+
})[d] || "";
|
|
1340
|
+
function m(d) {
|
|
1341
|
+
return {
|
|
1342
|
+
[l.THINKING]: e.thinking || 30,
|
|
1343
|
+
[l.ANSWERING]: e.answering || 120,
|
|
1344
|
+
[l.EDITING]: e.editing || 30
|
|
1345
|
+
}[d] || 1;
|
|
1346
|
+
}
|
|
1347
|
+
const g = i.currentPhaseTimeRemaining > 0;
|
|
1348
|
+
return /* @__PURE__ */ r.jsxs(
|
|
1349
|
+
"div",
|
|
258
1350
|
{
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
1351
|
+
className: `iw-iw-bg-white iw-rounded-lg iw-shadow-md iw-p-4 iw-border iw-border-gray-200 ${t}`,
|
|
1352
|
+
children: [
|
|
1353
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-justify-between iw-items-center iw-mb-4", children: [
|
|
1354
|
+
/* @__PURE__ */ r.jsxs("div", { children: [
|
|
1355
|
+
/* @__PURE__ */ r.jsx("h3", { className: "iw-text-sm iw-font-semibold iw-text-gray-700", children: "Interview Timer" }),
|
|
1356
|
+
/* @__PURE__ */ r.jsxs("p", { className: "iw-text-xs iw-text-gray-700 iw-my-3 iw-font-mono", children: [
|
|
1357
|
+
"Phase",
|
|
1358
|
+
" ",
|
|
1359
|
+
/* @__PURE__ */ r.jsx(
|
|
1360
|
+
"span",
|
|
1361
|
+
{
|
|
1362
|
+
className: `iw-px-3 iw-py-1.5 iw-rounded-md iw-font-medium ${n(
|
|
1363
|
+
i.phase
|
|
1364
|
+
)}`,
|
|
1365
|
+
children: i.phase
|
|
1366
|
+
}
|
|
1367
|
+
)
|
|
1368
|
+
] }),
|
|
1369
|
+
/* @__PURE__ */ r.jsxs("p", { className: "iw-text-xs iw-text-gray-700 iw-font-mono", children: [
|
|
1370
|
+
"Question ",
|
|
1371
|
+
i.currentQuestionNumber
|
|
1372
|
+
] })
|
|
1373
|
+
] }),
|
|
1374
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-text-right", children: [
|
|
1375
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-text-2xl iw-font-bold iw-text-gray-900", children: a(i.totalTimeRemaining) }),
|
|
1376
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-text-xs iw-text-gray-500", children: "Total Time Left" })
|
|
1377
|
+
] })
|
|
1378
|
+
] }),
|
|
1379
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-mb-4", children: /* @__PURE__ */ r.jsx("div", { className: "iw-w-full iw-h-2 iw-iw-bg-gray-200 iw-rounded-full iw-overflow-hidden", children: /* @__PURE__ */ r.jsx(
|
|
1380
|
+
"div",
|
|
1381
|
+
{
|
|
1382
|
+
className: "iw-h-full iw-iw-bg-gradient-to-r iw-from-blue-500 iw-to-purple-500 iw-transition-all iw-duration-300",
|
|
1383
|
+
style: {
|
|
1384
|
+
width: `${i.totalTimeElapsed / (i.totalTimeElapsed + i.totalTimeRemaining) * 100}%`
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
) }) }),
|
|
1388
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-mb-4", children: [
|
|
1389
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-items-center iw-justify-between iw-mb-2", children: [
|
|
1390
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-items-center iw-space-x-2", children: [
|
|
1391
|
+
/* @__PURE__ */ r.jsx(
|
|
1392
|
+
"div",
|
|
1393
|
+
{
|
|
1394
|
+
className: `iw-w-3 iw-h-3 iw-rounded-full ${c(
|
|
1395
|
+
i.phase
|
|
1396
|
+
)} ${g ? "iw-animate-pulse" : ""}`
|
|
1397
|
+
}
|
|
1398
|
+
),
|
|
1399
|
+
/* @__PURE__ */ r.jsx("span", { className: "iw-text-sm iw-font-medium iw-text-gray-700", children: s(i.phase) })
|
|
1400
|
+
] }),
|
|
1401
|
+
g && /* @__PURE__ */ r.jsx("span", { className: "iw-text-lg iw-font-bold iw-text-gray-900", children: a(i.currentPhaseTimeRemaining) })
|
|
1402
|
+
] }),
|
|
1403
|
+
g && /* @__PURE__ */ r.jsx("div", { className: "iw-w-full iw-h-1.5 iw-iw-bg-gray-200 iw-rounded-full iw-overflow-hidden", children: /* @__PURE__ */ r.jsx(
|
|
1404
|
+
"div",
|
|
1405
|
+
{
|
|
1406
|
+
className: `iw-h-full ${c(
|
|
1407
|
+
i.phase
|
|
1408
|
+
)} iw-transition-all iw-duration-300`,
|
|
1409
|
+
style: {
|
|
1410
|
+
width: `${i.currentPhaseTimeRemaining / m(i.phase) * 100}%`
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
) })
|
|
1414
|
+
] }),
|
|
1415
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-mt-3 iw-pt-3 iw-border-t iw-border-gray-200", children: /* @__PURE__ */ r.jsx("p", { className: "iw-text-xs iw-text-gray-600", children: o(i.phase) }) })
|
|
1416
|
+
]
|
|
264
1417
|
}
|
|
265
|
-
)
|
|
266
|
-
},
|
|
267
|
-
label:
|
|
268
|
-
error:
|
|
269
|
-
fullWidth:
|
|
1418
|
+
);
|
|
1419
|
+
}, We = ({
|
|
1420
|
+
label: i,
|
|
1421
|
+
error: t,
|
|
1422
|
+
fullWidth: e = !1,
|
|
270
1423
|
className: a = "",
|
|
271
|
-
id:
|
|
272
|
-
...
|
|
1424
|
+
id: s,
|
|
1425
|
+
...c
|
|
273
1426
|
}) => {
|
|
274
|
-
const
|
|
275
|
-
return /* @__PURE__ */
|
|
1427
|
+
const n = s || `textarea-${Math.random().toString(36).substring(2, 9)}`, o = "iw-block iw-rounded-md iw-border iw-border-gray-300 iw-shadow-sm iw-px-4 iw-py-2 iw-text-sm iw-focus:border-primary-500 iw-focus:ring-primary-500 iw-focus:outline-none iw-transition-all", m = t ? "iw-border-red-500 iw-focus:border-red-500 iw-focus:ring-red-500" : "", g = e ? "iw-w-full" : "", d = a.includes("iw-h-full") ? "iw-h-full" : "";
|
|
1428
|
+
return /* @__PURE__ */ r.jsxs(
|
|
276
1429
|
"div",
|
|
277
1430
|
{
|
|
278
|
-
className: `${
|
|
1431
|
+
className: `${e ? "iw-w-full iw-h-full" : ""} ${d ? "iw-flex iw-flex-col" : ""}`,
|
|
279
1432
|
children: [
|
|
280
|
-
|
|
1433
|
+
i && /* @__PURE__ */ r.jsx(
|
|
281
1434
|
"label",
|
|
282
1435
|
{
|
|
283
|
-
htmlFor:
|
|
1436
|
+
htmlFor: n,
|
|
284
1437
|
className: "iw-block iw-text-sm iw-font-medium iw-text-gray-700 iw-mb-1",
|
|
285
|
-
children:
|
|
1438
|
+
children: i
|
|
286
1439
|
}
|
|
287
1440
|
),
|
|
288
|
-
/* @__PURE__ */
|
|
1441
|
+
/* @__PURE__ */ r.jsx(
|
|
289
1442
|
"textarea",
|
|
290
1443
|
{
|
|
291
|
-
id:
|
|
292
|
-
className: `${
|
|
293
|
-
"aria-invalid":
|
|
294
|
-
...
|
|
1444
|
+
id: n,
|
|
1445
|
+
className: `${o} ${m} ${g} ${d} ${a}`,
|
|
1446
|
+
"aria-invalid": t ? "true" : "false",
|
|
1447
|
+
...c
|
|
295
1448
|
}
|
|
296
1449
|
),
|
|
297
|
-
|
|
1450
|
+
t && /* @__PURE__ */ r.jsx("p", { className: "iw-mt-1 iw-text-sm iw-text-red-600", children: t })
|
|
298
1451
|
]
|
|
299
1452
|
}
|
|
300
1453
|
);
|
|
301
|
-
},
|
|
302
|
-
value:
|
|
303
|
-
onChange:
|
|
304
|
-
onSubmit:
|
|
1454
|
+
}, ze = ({
|
|
1455
|
+
value: i,
|
|
1456
|
+
onChange: t,
|
|
1457
|
+
onSubmit: e,
|
|
305
1458
|
isSubmitDisabled: a,
|
|
306
|
-
remainingTimeText:
|
|
1459
|
+
remainingTimeText: s
|
|
307
1460
|
}) => {
|
|
308
|
-
const
|
|
309
|
-
|
|
1461
|
+
const c = (n) => {
|
|
1462
|
+
n.key === "Enter" && (n.ctrlKey || n.metaKey) && !a && (n.preventDefault(), e());
|
|
310
1463
|
};
|
|
311
|
-
return /* @__PURE__ */
|
|
312
|
-
/* @__PURE__ */
|
|
313
|
-
/* @__PURE__ */
|
|
314
|
-
|
|
1464
|
+
return /* @__PURE__ */ r.jsx("div", { className: "iw-mt-auto", children: /* @__PURE__ */ r.jsxs("div", { className: "iw-rounded-xl iw-overflow-hidden iw-border iw-border-gray-200", children: [
|
|
1465
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-items-center iw-justify-between iw-px-3 iw-py-2 iw-bg-gray-50 iw-border-b iw-border-gray-200", children: [
|
|
1466
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-text-sm iw-font-medium", children: "Your answer" }),
|
|
1467
|
+
s && /* @__PURE__ */ r.jsx("div", { className: "iw-text-xs iw-text-gray-500", children: s })
|
|
315
1468
|
] }),
|
|
316
|
-
/* @__PURE__ */
|
|
317
|
-
|
|
1469
|
+
/* @__PURE__ */ r.jsx(
|
|
1470
|
+
We,
|
|
318
1471
|
{
|
|
319
|
-
value:
|
|
320
|
-
onChange:
|
|
321
|
-
onKeyDown:
|
|
1472
|
+
value: i,
|
|
1473
|
+
onChange: t,
|
|
1474
|
+
onKeyDown: c,
|
|
322
1475
|
placeholder: "Type your answer here...",
|
|
323
1476
|
className: "iw-bg-gray-50 iw-w-full iw-resize-none iw-focus:outline-none iw-bg-transparent iw-min-h-[112px]",
|
|
324
1477
|
rows: 5,
|
|
325
1478
|
fullWidth: !0
|
|
326
1479
|
}
|
|
327
1480
|
),
|
|
328
|
-
/* @__PURE__ */
|
|
329
|
-
/* @__PURE__ */
|
|
330
|
-
/* @__PURE__ */
|
|
331
|
-
|
|
1481
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-p-2 iw-flex iw-justify-between iw-items-center iw-bg-gray-50", children: [
|
|
1482
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-text-xs iw-text-gray-500", children: /* @__PURE__ */ r.jsx("kbd", { children: " Press Ctrl+Enter to submit" }) }),
|
|
1483
|
+
/* @__PURE__ */ r.jsx(
|
|
1484
|
+
$,
|
|
332
1485
|
{
|
|
333
|
-
onClick:
|
|
1486
|
+
onClick: e,
|
|
334
1487
|
disabled: a,
|
|
335
1488
|
size: "sm",
|
|
336
1489
|
variant: "gradient",
|
|
@@ -339,72 +1492,383 @@ const k = ({
|
|
|
339
1492
|
)
|
|
340
1493
|
] })
|
|
341
1494
|
] }) });
|
|
342
|
-
},
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
onComplete: i,
|
|
346
|
-
onAnswerSubmit: a,
|
|
347
|
-
className: t = ""
|
|
1495
|
+
}, Ye = ({
|
|
1496
|
+
question: i,
|
|
1497
|
+
isLoading: t = !1
|
|
348
1498
|
}) => {
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
questionId: (p == null ? void 0 : p.id) || "",
|
|
352
|
-
answerText: m,
|
|
353
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
354
|
-
};
|
|
355
|
-
x([...c, v]), a && a(v), l < s.length - 1 ? (w((b) => b + 1), o("")) : (f(!0), i && i(c));
|
|
356
|
-
}, M = A(() => {
|
|
357
|
-
const b = 60 - Math.floor(Date.now() / 1e3 % 60), T = Math.floor(b / 60).toString().padStart(2, "0"), R = (b % 60).toString().padStart(2, "0");
|
|
358
|
-
return `Time to Talk: ${T}:${R} min`;
|
|
359
|
-
}, [l]);
|
|
360
|
-
return n ? /* @__PURE__ */ e.jsx("div", { className: "interview-widget-container", children: /* @__PURE__ */ e.jsx(
|
|
1499
|
+
const { baseColor: e } = F();
|
|
1500
|
+
return t ? /* @__PURE__ */ r.jsxs(
|
|
361
1501
|
"div",
|
|
362
1502
|
{
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
/* @__PURE__ */
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
"
|
|
375
|
-
{
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
/* @__PURE__ */
|
|
381
|
-
|
|
382
|
-
{
|
|
383
|
-
value: m,
|
|
384
|
-
onChange: (v) => o(v.target.value),
|
|
385
|
-
onSubmit: S,
|
|
386
|
-
isSubmitDisabled: !m.trim() || !n,
|
|
387
|
-
remainingTimeText: M
|
|
388
|
-
}
|
|
389
|
-
)
|
|
1503
|
+
className: "iw-rounded-xl iw-mb-4 iw-p-5",
|
|
1504
|
+
style: {
|
|
1505
|
+
background: "linear-gradient(to bottom, #eef2ff, #ffffff)",
|
|
1506
|
+
border: "1px solid #e0e7ff",
|
|
1507
|
+
color: "#1f2937"
|
|
1508
|
+
},
|
|
1509
|
+
children: [
|
|
1510
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-items-center iw-space-x-3 iw-mb-3", children: [
|
|
1511
|
+
/* @__PURE__ */ r.jsx(
|
|
1512
|
+
"div",
|
|
1513
|
+
{
|
|
1514
|
+
className: "iw-h-12 iw-w-12 iw-rounded-lg iw-flex iw-items-center iw-justify-center iw-text-white iw-font-semibold iw-animate-pulse",
|
|
1515
|
+
style: { backgroundColor: e },
|
|
1516
|
+
children: "N"
|
|
1517
|
+
}
|
|
1518
|
+
),
|
|
1519
|
+
/* @__PURE__ */ r.jsxs("div", { children: [
|
|
1520
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-text-sm iw-font-semibold", children: "Novara" }),
|
|
1521
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-text-xs iw-text-gray-500", children: "Assistant" })
|
|
390
1522
|
] })
|
|
391
|
-
] })
|
|
392
|
-
|
|
1523
|
+
] }),
|
|
1524
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-animate-pulse", children: [
|
|
1525
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-h-4 iw-bg-gray-200 iw-rounded iw-w-3/4 iw-mb-2" }),
|
|
1526
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-h-4 iw-bg-gray-200 iw-rounded iw-w-full" })
|
|
1527
|
+
] })
|
|
1528
|
+
]
|
|
1529
|
+
}
|
|
1530
|
+
) : i ? /* @__PURE__ */ r.jsxs(
|
|
1531
|
+
"div",
|
|
1532
|
+
{
|
|
1533
|
+
className: "iw-rounded-xl iw-mb-4 message-animation iw-text-gray-800 iw-border iw-border-indigo-100 iw-p-5",
|
|
1534
|
+
style: Qe(e ?? "#8C75FB", 0.85),
|
|
1535
|
+
children: [
|
|
1536
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-items-center iw-space-x-3 iw-mb-3", children: [
|
|
1537
|
+
/* @__PURE__ */ r.jsx(
|
|
1538
|
+
"div",
|
|
1539
|
+
{
|
|
1540
|
+
className: "iw-h-12 iw-w-12 iw-rounded-lg iw-flex iw-items-center iw-justify-center iw-text-white iw-font-semibold",
|
|
1541
|
+
style: { backgroundColor: e },
|
|
1542
|
+
children: "N"
|
|
1543
|
+
}
|
|
1544
|
+
),
|
|
1545
|
+
/* @__PURE__ */ r.jsxs("div", { children: [
|
|
1546
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-text-sm iw-font-semibold", children: "Novara" }),
|
|
1547
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-text-xs iw-text-gray-500", children: "Assistant" })
|
|
1548
|
+
] })
|
|
1549
|
+
] }),
|
|
1550
|
+
/* @__PURE__ */ r.jsx("p", { className: "iw-text-[15px] iw-leading-6", children: i.question })
|
|
1551
|
+
]
|
|
393
1552
|
}
|
|
394
|
-
)
|
|
395
|
-
|
|
1553
|
+
) : /* @__PURE__ */ r.jsx(
|
|
1554
|
+
"div",
|
|
396
1555
|
{
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
1556
|
+
className: "iw-rounded-xl iw-mb-4 iw-bg-gray-50 iw-text-gray-500 iw-border iw-border-gray-200 iw-p-5 iw-text-center",
|
|
1557
|
+
children: /* @__PURE__ */ r.jsx("p", { className: "iw-text-sm", children: "No question available" })
|
|
1558
|
+
}
|
|
1559
|
+
);
|
|
1560
|
+
}, Ke = ({
|
|
1561
|
+
interviewId: i,
|
|
1562
|
+
onComplete: t,
|
|
1563
|
+
className: e = ""
|
|
1564
|
+
}) => {
|
|
1565
|
+
const a = Oe(), { baseColor: s } = F(), { baseUrl: c } = Te(), { timers: n, stt: o, tts: m } = Ie(), [g, d] = y(null), [u, h] = y(""), [x, k] = y(!1), j = D(""), N = D(null), w = {
|
|
1566
|
+
thinkingTime: (n == null ? void 0 : n.thinkingDuration) || 30,
|
|
1567
|
+
answeringTime: (n == null ? void 0 : n.answeringDuration) || 120,
|
|
1568
|
+
editingTime: (n == null ? void 0 : n.editingDuration) || 30,
|
|
1569
|
+
totalTime: (n == null ? void 0 : n.totalInterviewDuration) || 600,
|
|
1570
|
+
minimumBufferTime: (n == null ? void 0 : n.minimumTimeForNextQuestion) || 120
|
|
1571
|
+
}, {
|
|
1572
|
+
thinkingTime: p,
|
|
1573
|
+
answeringTime: T,
|
|
1574
|
+
editingTime: S,
|
|
1575
|
+
totalTime: ie,
|
|
1576
|
+
minimumBufferTime: re
|
|
1577
|
+
} = w;
|
|
1578
|
+
A(() => {
|
|
1579
|
+
j.current = u;
|
|
1580
|
+
}, [u]);
|
|
1581
|
+
const _ = D(!1), {
|
|
1582
|
+
speak: te,
|
|
1583
|
+
isPlaying: se,
|
|
1584
|
+
error: W
|
|
1585
|
+
} = Ue({
|
|
1586
|
+
config: {
|
|
1587
|
+
baseUrl: c,
|
|
1588
|
+
provider: m == null ? void 0 : m.provider
|
|
1589
|
+
},
|
|
1590
|
+
onEnd: () => {
|
|
1591
|
+
console.log("TTS playback completed"), _.current = !1, E();
|
|
1592
|
+
},
|
|
1593
|
+
onError: (f) => {
|
|
1594
|
+
console.error("TTS Error:", f), _.current || (_.current = !0, E());
|
|
1595
|
+
}
|
|
1596
|
+
}), G = D(!1), L = D(!1), {
|
|
1597
|
+
startRecording: z,
|
|
1598
|
+
stopRecording: Y,
|
|
1599
|
+
transcribe: K,
|
|
1600
|
+
isRecording: ne,
|
|
1601
|
+
isTranscribing: ae,
|
|
1602
|
+
error: M
|
|
1603
|
+
} = _e({
|
|
1604
|
+
config: {
|
|
1605
|
+
baseUrl: c,
|
|
1606
|
+
provider: o == null ? void 0 : o.provider,
|
|
1607
|
+
model: o == null ? void 0 : o.model,
|
|
1608
|
+
language: o == null ? void 0 : o.language
|
|
1609
|
+
},
|
|
1610
|
+
onStart: () => {
|
|
1611
|
+
console.log("STT recording started"), G.current = !1, L.current = !1;
|
|
1612
|
+
},
|
|
1613
|
+
onStop: () => {
|
|
1614
|
+
console.log("STT recording stopped");
|
|
1615
|
+
},
|
|
1616
|
+
onTranscriptionComplete: (f) => {
|
|
1617
|
+
console.log("Transcription completed:", f), h(f.transcript), L.current || (L.current = !0, E());
|
|
1618
|
+
},
|
|
1619
|
+
onError: (f) => {
|
|
1620
|
+
console.error("STT Error:", f), G.current || (G.current = !0, E());
|
|
1621
|
+
}
|
|
1622
|
+
}), { state: R, startQuestion: Q, nextPhase: E } = De({
|
|
1623
|
+
config: {
|
|
1624
|
+
thinkingDuration: p,
|
|
1625
|
+
answeringDuration: T,
|
|
1626
|
+
editingDuration: S,
|
|
1627
|
+
totalInterviewDuration: ie,
|
|
1628
|
+
minimumTimeForNextQuestion: re
|
|
1629
|
+
},
|
|
1630
|
+
callbacks: {
|
|
1631
|
+
onPhaseChange: (f) => {
|
|
1632
|
+
switch (console.log("Phase changed:", f), f) {
|
|
1633
|
+
case l.FETCHING_QUESTION:
|
|
1634
|
+
oe();
|
|
1635
|
+
break;
|
|
1636
|
+
case l.READING_QUESTION:
|
|
1637
|
+
le();
|
|
1638
|
+
break;
|
|
1639
|
+
case l.ANSWERING:
|
|
1640
|
+
de();
|
|
1641
|
+
break;
|
|
1642
|
+
case l.TRANSCRIBING:
|
|
1643
|
+
we();
|
|
1644
|
+
break;
|
|
1645
|
+
case l.SUBMITTING:
|
|
1646
|
+
ce();
|
|
1647
|
+
break;
|
|
1648
|
+
}
|
|
1649
|
+
},
|
|
1650
|
+
onInterviewEnd: () => {
|
|
1651
|
+
t == null || t();
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
}), { execute: oe } = Pe(
|
|
1655
|
+
async () => {
|
|
1656
|
+
var P, J;
|
|
1657
|
+
const f = await a.generateQuestion({
|
|
1658
|
+
interviewId: i,
|
|
1659
|
+
isInterviewDone: R.totalTimeRemaining < 120,
|
|
1660
|
+
question: ((P = N.current) == null ? void 0 : P.question) || "",
|
|
1661
|
+
qnaId: ((J = N.current) == null ? void 0 : J.qna_id) || "",
|
|
1662
|
+
answer: j.current
|
|
1663
|
+
});
|
|
1664
|
+
return N.current = f.data, f;
|
|
1665
|
+
},
|
|
1666
|
+
{
|
|
1667
|
+
onSuccess: async (f) => {
|
|
1668
|
+
console.log("Questions fetched successfully", f), f && f.data && (h(""), d(f.data), E());
|
|
1669
|
+
},
|
|
1670
|
+
onError: (f) => {
|
|
1671
|
+
console.error("Failed to fetch questions:", f);
|
|
400
1672
|
}
|
|
401
1673
|
}
|
|
1674
|
+
), ce = v(async () => {
|
|
1675
|
+
console.log("Answer submitted successfully"), await Be(1500), Q();
|
|
1676
|
+
}, [Q]), le = v(async () => {
|
|
1677
|
+
var f;
|
|
1678
|
+
if ((f = N.current) != null && f.question)
|
|
1679
|
+
try {
|
|
1680
|
+
_.current = !1, console.log("Starting TTS for question"), await te(N.current.question);
|
|
1681
|
+
} catch (P) {
|
|
1682
|
+
console.error("Failed to speak question:", P);
|
|
1683
|
+
}
|
|
1684
|
+
else
|
|
1685
|
+
E();
|
|
1686
|
+
}, []), de = v(async () => {
|
|
1687
|
+
console.log("Starting recording...");
|
|
1688
|
+
try {
|
|
1689
|
+
const f = T;
|
|
1690
|
+
console.log("🚀 ~ maxDuration:", f), await z(f);
|
|
1691
|
+
} catch (f) {
|
|
1692
|
+
console.error("Failed to start recording:", f), E();
|
|
1693
|
+
}
|
|
1694
|
+
}, [z, E]), we = v(async () => {
|
|
1695
|
+
console.log("Stopping recording and processing STT...");
|
|
1696
|
+
try {
|
|
1697
|
+
const f = await Y();
|
|
1698
|
+
console.log("Recording stopped, audio blob size:", f.size), await K(f);
|
|
1699
|
+
} catch (f) {
|
|
1700
|
+
console.error("STT processing failed:", f), !G.current && !L.current && (G.current = !0, E());
|
|
1701
|
+
}
|
|
1702
|
+
}, [Y, K, E]), ue = () => {
|
|
1703
|
+
const { phase: f } = R;
|
|
1704
|
+
switch (f) {
|
|
1705
|
+
case l.IDLE:
|
|
1706
|
+
return /* @__PURE__ */ r.jsx("div", { className: "iw-text-center iw-py-8", children: /* @__PURE__ */ r.jsx("p", { className: "iw-text-gray-600", children: "Ready to start..." }) });
|
|
1707
|
+
case l.FETCHING_QUESTION:
|
|
1708
|
+
return /* @__PURE__ */ r.jsx("div", { className: "iw-space-y-4" });
|
|
1709
|
+
case l.READING_QUESTION:
|
|
1710
|
+
return /* @__PURE__ */ r.jsx("div", { className: "iw-space-y-4", children: /* @__PURE__ */ r.jsxs("div", { className: "iw-p-4 iw-bg-indigo-50 iw-border iw-border-indigo-200 iw-rounded-lg", children: [
|
|
1711
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-items-center iw-space-x-2", children: [
|
|
1712
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-w-3 iw-h-3 iw-bg-indigo-500 iw-rounded-full iw-animate-pulse" }),
|
|
1713
|
+
/* @__PURE__ */ r.jsx("span", { className: "iw-text-sm iw-font-medium iw-text-indigo-700", children: se ? "Playing question audio..." : "Reading the question..." })
|
|
1714
|
+
] }),
|
|
1715
|
+
W && /* @__PURE__ */ r.jsxs("div", { className: "iw-mt-2 iw-text-xs iw-text-red-600", children: [
|
|
1716
|
+
"Audio playback failed: ",
|
|
1717
|
+
W.message
|
|
1718
|
+
] })
|
|
1719
|
+
] }) });
|
|
1720
|
+
case l.THINKING:
|
|
1721
|
+
case l.ANSWERING:
|
|
1722
|
+
return /* @__PURE__ */ r.jsx("div", { className: "iw-space-y-4", children: f === l.ANSWERING && /* @__PURE__ */ r.jsxs("div", { className: "iw-p-4 iw-bg-red-50 iw-border iw-border-red-200 iw-rounded-lg", children: [
|
|
1723
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-items-center iw-space-x-2", children: [
|
|
1724
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-w-3 iw-h-3 iw-bg-red-500 iw-rounded-full iw-animate-pulse" }),
|
|
1725
|
+
/* @__PURE__ */ r.jsx("span", { className: "iw-text-sm iw-font-medium iw-text-red-700", children: ne ? "Recording in progress..." : "Preparing to record..." })
|
|
1726
|
+
] }),
|
|
1727
|
+
M && /* @__PURE__ */ r.jsxs("div", { className: "iw-mt-2 iw-text-xs iw-text-red-600", children: [
|
|
1728
|
+
"Recording error: ",
|
|
1729
|
+
M.message
|
|
1730
|
+
] })
|
|
1731
|
+
] }) });
|
|
1732
|
+
case l.TRANSCRIBING:
|
|
1733
|
+
return /* @__PURE__ */ r.jsx("div", { className: "iw-space-y-4", children: /* @__PURE__ */ r.jsxs("div", { className: "iw-p-4 iw-bg-purple-50 iw-border iw-border-purple-200 iw-rounded-lg", children: [
|
|
1734
|
+
/* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-items-center iw-space-x-2", children: [
|
|
1735
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-animate-spin iw-h-4 iw-w-4 iw-border-2 iw-border-purple-500 iw-border-t-transparent iw-rounded-full" }),
|
|
1736
|
+
/* @__PURE__ */ r.jsx("span", { className: "iw-text-sm iw-font-medium iw-text-purple-700", children: ae ? "Transcribing your speech..." : "Processing audio..." })
|
|
1737
|
+
] }),
|
|
1738
|
+
M && /* @__PURE__ */ r.jsxs("div", { className: "iw-mt-2 iw-text-xs iw-text-red-600", children: [
|
|
1739
|
+
"Transcription error: ",
|
|
1740
|
+
M.message,
|
|
1741
|
+
M.recoverable && " (attempting to continue)"
|
|
1742
|
+
] })
|
|
1743
|
+
] }) });
|
|
1744
|
+
case l.EDITING:
|
|
1745
|
+
return /* @__PURE__ */ r.jsx("div", { className: "iw-space-y-4", children: /* @__PURE__ */ r.jsx(
|
|
1746
|
+
ze,
|
|
1747
|
+
{
|
|
1748
|
+
value: u,
|
|
1749
|
+
onChange: (P) => h(P.target.value),
|
|
1750
|
+
onSubmit: () => E(),
|
|
1751
|
+
isSubmitDisabled: !u.trim(),
|
|
1752
|
+
remainingTimeText: `${R.currentPhaseTimeRemaining}s remaining`
|
|
1753
|
+
}
|
|
1754
|
+
) });
|
|
1755
|
+
case l.SUBMITTING:
|
|
1756
|
+
return /* @__PURE__ */ r.jsx("div", { className: "iw-space-y-4", children: /* @__PURE__ */ r.jsx("div", { className: "iw-p-4 iw-bg-green-50 iw-border iw-border-green-200 iw-rounded-lg", children: /* @__PURE__ */ r.jsxs("div", { className: "iw-flex iw-items-center iw-space-x-2", children: [
|
|
1757
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-animate-spin iw-h-4 iw-w-4 iw-border-2 iw-border-green-500 iw-border-t-transparent iw-rounded-full" }),
|
|
1758
|
+
/* @__PURE__ */ r.jsx("span", { className: "iw-text-sm iw-font-medium iw-text-green-700", children: "Submitting your answer..." })
|
|
1759
|
+
] }) }) });
|
|
1760
|
+
case l.COMPLETED:
|
|
1761
|
+
return /* @__PURE__ */ r.jsxs("div", { className: "iw-text-center iw-py-8", children: [
|
|
1762
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-mb-4", children: /* @__PURE__ */ r.jsx(
|
|
1763
|
+
"svg",
|
|
1764
|
+
{
|
|
1765
|
+
className: "iw-w-16 iw-h-16 iw-mx-auto iw-text-green-500",
|
|
1766
|
+
fill: "none",
|
|
1767
|
+
stroke: "currentColor",
|
|
1768
|
+
viewBox: "0 0 24 24",
|
|
1769
|
+
children: /* @__PURE__ */ r.jsx(
|
|
1770
|
+
"path",
|
|
1771
|
+
{
|
|
1772
|
+
strokeLinecap: "round",
|
|
1773
|
+
strokeLinejoin: "round",
|
|
1774
|
+
strokeWidth: 2,
|
|
1775
|
+
d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
1776
|
+
}
|
|
1777
|
+
)
|
|
1778
|
+
}
|
|
1779
|
+
) }),
|
|
1780
|
+
/* @__PURE__ */ r.jsx("h3", { className: "iw-text-xl iw-font-bold iw-text-gray-900 iw-mb-2", children: "Interview Complete!" }),
|
|
1781
|
+
/* @__PURE__ */ r.jsx("p", { className: "iw-text-gray-600", children: "Thank you for your time. Your answers have been recorded." })
|
|
1782
|
+
] });
|
|
1783
|
+
default:
|
|
1784
|
+
return null;
|
|
1785
|
+
}
|
|
1786
|
+
};
|
|
1787
|
+
return /* @__PURE__ */ r.jsx("div", { className: "interview-widget-container", children: /* @__PURE__ */ r.jsxs(
|
|
1788
|
+
"div",
|
|
1789
|
+
{
|
|
1790
|
+
className: ` iw-max-w-3xl iw-mx-auto iw-space-y-4 iw-py-8 ${e}`,
|
|
1791
|
+
children: [
|
|
1792
|
+
R.phase !== l.IDLE && R.phase !== l.COMPLETED && /* @__PURE__ */ r.jsx(
|
|
1793
|
+
Ye,
|
|
1794
|
+
{
|
|
1795
|
+
question: g,
|
|
1796
|
+
isLoading: R.phase === l.FETCHING_QUESTION
|
|
1797
|
+
}
|
|
1798
|
+
),
|
|
1799
|
+
/* @__PURE__ */ r.jsx("div", { className: "iw-bg-white iw-rounded-lg iw-shadow-md iw-p-6", children: ue() }),
|
|
1800
|
+
/* @__PURE__ */ r.jsx(
|
|
1801
|
+
He,
|
|
1802
|
+
{
|
|
1803
|
+
state: R,
|
|
1804
|
+
defaultTimers: {
|
|
1805
|
+
thinking: p,
|
|
1806
|
+
answering: T,
|
|
1807
|
+
editing: S
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
),
|
|
1811
|
+
x && (R.phase === l.THINKING || R.phase === l.ANSWERING || R.phase === l.EDITING) && /* @__PURE__ */ r.jsx($, { onClick: E, children: "Next Phase" }),
|
|
1812
|
+
!x && /* @__PURE__ */ r.jsx("div", { className: "iw-text-center iw-py-12 w-full", children: /* @__PURE__ */ r.jsx(
|
|
1813
|
+
$,
|
|
1814
|
+
{
|
|
1815
|
+
className: "w-full",
|
|
1816
|
+
style: { backgroundColor: s },
|
|
1817
|
+
onClick: () => {
|
|
1818
|
+
Q(), k(!0);
|
|
1819
|
+
},
|
|
1820
|
+
children: "Start Interview"
|
|
1821
|
+
}
|
|
1822
|
+
) })
|
|
1823
|
+
]
|
|
1824
|
+
}
|
|
1825
|
+
) });
|
|
1826
|
+
}, Je = ({
|
|
1827
|
+
interviewId: i,
|
|
1828
|
+
title: t = "Interview",
|
|
1829
|
+
onInterviewEnd: e,
|
|
1830
|
+
className: a = ""
|
|
1831
|
+
}) => {
|
|
1832
|
+
const [s, c] = y(!1), [n, o] = y(!0), m = D(null);
|
|
1833
|
+
if (!s)
|
|
1834
|
+
return /* @__PURE__ */ r.jsx("div", { className: "interview-widget-container", children: /* @__PURE__ */ r.jsx(
|
|
1835
|
+
Se,
|
|
1836
|
+
{
|
|
1837
|
+
isOpen: n,
|
|
1838
|
+
onStart: () => {
|
|
1839
|
+
console.log("Permissions granted, starting interview"), c(!0), o(!1);
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
) });
|
|
1843
|
+
const g = () => {
|
|
1844
|
+
e == null || e();
|
|
1845
|
+
};
|
|
1846
|
+
return /* @__PURE__ */ r.jsx("div", { className: "interview-widget-container", children: /* @__PURE__ */ r.jsx(
|
|
1847
|
+
"div",
|
|
1848
|
+
{
|
|
1849
|
+
ref: m,
|
|
1850
|
+
className: `iw-flex iw-flex-col iw-rounded-xl iw-shadow-lg iw-overflow-hidden iw-h-[calc(100vh-1rem)] ${a}`,
|
|
1851
|
+
children: /* @__PURE__ */ r.jsxs("div", { className: " iw-h-full iw-flex iw-flex-col", children: [
|
|
1852
|
+
/* @__PURE__ */ r.jsx(je, { title: t, onExit: g }),
|
|
1853
|
+
/* @__PURE__ */ r.jsx(
|
|
1854
|
+
Ke,
|
|
1855
|
+
{
|
|
1856
|
+
interviewId: i,
|
|
1857
|
+
className: a,
|
|
1858
|
+
onComplete: e || (() => {
|
|
1859
|
+
})
|
|
1860
|
+
}
|
|
1861
|
+
)
|
|
1862
|
+
] })
|
|
1863
|
+
}
|
|
402
1864
|
) });
|
|
403
1865
|
};
|
|
404
1866
|
typeof window < "u" && (window.InterviewWidget = {
|
|
405
|
-
InterviewWidget:
|
|
1867
|
+
InterviewWidget: Je,
|
|
1868
|
+
InterviewWidgetProvider: Ne
|
|
406
1869
|
});
|
|
407
1870
|
export {
|
|
408
|
-
|
|
409
|
-
|
|
1871
|
+
Je as InterviewWidget,
|
|
1872
|
+
Ne as InterviewWidgetProvider,
|
|
1873
|
+
Je as default
|
|
410
1874
|
};
|