interview-widget 1.0.12 → 1.0.14
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 +306 -306
- package/dist/components/media/video-feed.d.ts +1 -3
- package/dist/widget.es.js +249 -250
- package/dist/widget.umd.js +4 -4
- package/package.json +66 -66
package/README.md
CHANGED
|
@@ -1,306 +1,306 @@
|
|
|
1
|
-
# Interview Widget
|
|
2
|
-
|
|
3
|
-
A modern React interview experience widget with built‑in timer flow, STT (speech‑to‑text), and TTS (text‑to‑speech). It can be embedded via NPM or a CDN and configured through a single provider.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Video capture** with camera integration
|
|
8
|
-
- **Responsive design** with mobile support
|
|
9
|
-
- **TypeScript support** with full type definitions
|
|
10
|
-
- **CDN-ready** for easy integration into any website
|
|
11
|
-
- **Q&A structured interview flow**
|
|
12
|
-
- **Advanced Timer System** with phase management
|
|
13
|
-
- **Text-to-Speech integration** for transcribing
|
|
14
|
-
- **Speech-to-Text integration** for voice answers
|
|
15
|
-
- **Automatic phase transitions** (thinking → answering → editing)
|
|
16
|
-
- **Time validation** before starting new questions
|
|
17
|
-
|
|
18
|
-
## Quick Start
|
|
19
|
-
|
|
20
|
-
### 1) Environment Setup
|
|
21
|
-
|
|
22
|
-
The Interview Widget uses encryption for session storage integrity. Set up your encryption secret based on your environment:
|
|
23
|
-
|
|
24
|
-
#### Vite React
|
|
25
|
-
|
|
26
|
-
```env
|
|
27
|
-
# .env
|
|
28
|
-
VITE_IW_SECRET=your-secure-encryption-seed-here
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
#### Next.js
|
|
32
|
-
|
|
33
|
-
```env
|
|
34
|
-
# .env.local
|
|
35
|
-
NEXT_PUBLIC_IW_SECRET=your-secure-encryption-seed-here
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
#### Vanilla JS / Custom Framework
|
|
39
|
-
|
|
40
|
-
```html
|
|
41
|
-
<script>
|
|
42
|
-
// Define the secret before loading your widget
|
|
43
|
-
window.__IW_SECRET__ = "your-secure-encryption-seed-here";
|
|
44
|
-
</script>
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### 2) Install (React apps)
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
npm install interview-widget
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Minimal usage:
|
|
54
|
-
|
|
55
|
-
```tsx
|
|
56
|
-
import React from "react";
|
|
57
|
-
import { InterviewWidget, InterviewWidgetProvider } from "interview-widget";
|
|
58
|
-
import "interview-widget/style.css";
|
|
59
|
-
|
|
60
|
-
export default function App() {
|
|
61
|
-
return (
|
|
62
|
-
<InterviewWidgetProvider
|
|
63
|
-
config={{
|
|
64
|
-
api: {
|
|
65
|
-
baseUrl: "/api" // Your backend endpoint
|
|
66
|
-
authToken: getTokenFromYourAuthSystem(), // Get from secure backend
|
|
67
|
-
},
|
|
68
|
-
interview: {
|
|
69
|
-
stt: {
|
|
70
|
-
provider: "groq",
|
|
71
|
-
model: "whisper-large-v3-turbo",
|
|
72
|
-
language: "en",
|
|
73
|
-
},
|
|
74
|
-
tts: { provider: "piper" },
|
|
75
|
-
timers: {
|
|
76
|
-
thinkingDuration: 30,
|
|
77
|
-
answeringDuration: 120,
|
|
78
|
-
editingDuration: 30,
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
}}
|
|
82
|
-
>
|
|
83
|
-
<InterviewWidget
|
|
84
|
-
interviewId="your_interview_id"
|
|
85
|
-
title="Interview for JS developer"
|
|
86
|
-
className="iw-rounded-none iw-shadow-none"
|
|
87
|
-
onInterviewEnd={() => {
|
|
88
|
-
console.log("🎉🎉 Interview ended 🎉🎉");
|
|
89
|
-
}}
|
|
90
|
-
/>
|
|
91
|
-
</InterviewWidgetProvider>
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
```html
|
|
97
|
-
<!-- React 18 UMD -->
|
|
98
|
-
<script
|
|
99
|
-
crossorigin
|
|
100
|
-
src="https://unpkg.com/react@18/umd/react.production.min.js"
|
|
101
|
-
></script>
|
|
102
|
-
<script
|
|
103
|
-
crossorigin
|
|
104
|
-
src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"
|
|
105
|
-
></script>
|
|
106
|
-
|
|
107
|
-
<!-- Styles + Widget UMD -->
|
|
108
|
-
<link
|
|
109
|
-
rel="stylesheet"
|
|
110
|
-
href="https://unpkg.com/interview-widget@latest/dist/widget.css"
|
|
111
|
-
/>
|
|
112
|
-
<script src="https://unpkg.com/interview-widget@latest/dist/widget.umd.js"></script>
|
|
113
|
-
|
|
114
|
-
<div id="interview-widget-container"></div>
|
|
115
|
-
<script>
|
|
116
|
-
document.addEventListener("DOMContentLoaded", function () {
|
|
117
|
-
const { InterviewWidget, InterviewWidgetProvider } = window.InterviewWidget;
|
|
118
|
-
|
|
119
|
-
const app = React.createElement(
|
|
120
|
-
InterviewWidgetProvider,
|
|
121
|
-
{
|
|
122
|
-
config: {
|
|
123
|
-
api: { baseUrl: "/api" },
|
|
124
|
-
interview: {
|
|
125
|
-
timers: {
|
|
126
|
-
thinkingDuration: 30,
|
|
127
|
-
answeringDuration: 120,
|
|
128
|
-
editingDuration: 30,
|
|
129
|
-
},
|
|
130
|
-
stt: {
|
|
131
|
-
provider: "groq",
|
|
132
|
-
model: "whisper-large-v3-turbo",
|
|
133
|
-
language: "en",
|
|
134
|
-
},
|
|
135
|
-
tts: { provider: "piper" },
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
React.createElement(InterviewWidget, { interviewId="your_interview_id", title: "Developer Interview", onInterviewEnd={() => {}} }
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
ReactDOM.render(app, document.getElementById("interview-widget-container"));
|
|
143
|
-
});
|
|
144
|
-
</script>
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Public API
|
|
148
|
-
|
|
149
|
-
### <InterviewWidget />
|
|
150
|
-
|
|
151
|
-
### InterviewWidget Props
|
|
152
|
-
|
|
153
|
-
| Prop | Type | Default | Description |
|
|
154
|
-
| ----------------------- | ------------ | ------------- | --------------------------------------------------------------------------- |
|
|
155
|
-
| `interviewId` | `string` | Required | Unique interview identifier used for backend API calls |
|
|
156
|
-
| `title` | `string` | `"Interview"` | Title displayed in the interview header |
|
|
157
|
-
| `onInterviewEnd` | `() => void` | `undefined` | Called when the interview completes or the user exits |
|
|
158
|
-
| `onInterviewDisqualify` | `() => void` | `undefined` | Called when the interview is disqualified (e.g., due to cheating detection) |
|
|
159
|
-
| `className` | `string` | `""` | Additional CSS classes applied to the outer widget container |
|
|
160
|
-
|
|
161
|
-
### <InterviewWidgetProvider />
|
|
162
|
-
|
|
163
|
-
Wrap your app (or the widget) to provide configuration. See full config reference below.
|
|
164
|
-
|
|
165
|
-
```tsx
|
|
166
|
-
<InterviewWidgetProvider config={{ api: { baseUrl: "/api" } }}>
|
|
167
|
-
<InterviewWidget />
|
|
168
|
-
</InterviewWidgetProvider>
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
## Configuration reference (Provider)
|
|
172
|
-
|
|
173
|
-
Pass this object to `InterviewWidgetProvider` via the `config` prop. Tables list all keys, types, and defaults.
|
|
174
|
-
|
|
175
|
-
### Top-level
|
|
176
|
-
|
|
177
|
-
| Prop | Type | Default | Description |
|
|
178
|
-
| --------- | -------- | ----------------------- | ---------------------------------------------- |
|
|
179
|
-
| api | `object` | [see below](#api) | Backend/API configuration |
|
|
180
|
-
| ui | `object` | [see below](#ui) | UI customization tokens |
|
|
181
|
-
| interview | `object` | [see below](#interview) | Interview behavior settings (timers, STT, TTS) |
|
|
182
|
-
|
|
183
|
-
### API
|
|
184
|
-
|
|
185
|
-
| Prop | Type | Default | Description |
|
|
186
|
-
| ----------- | -------- | -------------------------- | ------------------------------------------------------ |
|
|
187
|
-
| baseUrl | `string` | "/api" | Base URL for backend endpoints |
|
|
188
|
-
| authToken | `string` | undefined | Optional bearer token appended as Authorization header |
|
|
189
|
-
| retryConfig | `object` | [see below](#retry-config) | Retry policy for fetch calls |
|
|
190
|
-
|
|
191
|
-
#### Retry Config
|
|
192
|
-
|
|
193
|
-
| Prop | Type | Default | Description |
|
|
194
|
-
| --------- | -------------------------- | ------------- | ------------------------------------------ |
|
|
195
|
-
| attempts | `number` | 3 | Number of retry attempts |
|
|
196
|
-
| backoff | `"fixed" \| "exponential"` | "exponential" | Backoff strategy |
|
|
197
|
-
| baseDelay | `number (ms)` | 1000 | Base delay between retries in milliseconds |
|
|
198
|
-
|
|
199
|
-
### UI
|
|
200
|
-
|
|
201
|
-
| Prop | Type | Default | Description |
|
|
202
|
-
| ------------ | -------------- | --------- | -------------------------------------- |
|
|
203
|
-
| baseColor | `string (hex)` | "#3B82F6" | Primary brand color used by the widget |
|
|
204
|
-
| borderRadius | `string (CSS)` | "8px" | Global corner radius for components |
|
|
205
|
-
|
|
206
|
-
### Interview
|
|
207
|
-
|
|
208
|
-
| Prop | Type | Default | Description |
|
|
209
|
-
| ---------- | -------- | -------------------------------- | ------------------------------------------ |
|
|
210
|
-
| timers | `object` | [see below](#timers) | Per-phase and global timing configuration |
|
|
211
|
-
| stt | `object` | [see below](#stt-speech-to-text) | Speech-to-Text provider settings |
|
|
212
|
-
| tts | `object` | [see below](#tts-text-to-speech) | Text-to-Speech provider settings |
|
|
213
|
-
| proctoring | `object` | [see below](#proctoring) | Proctoring settings and cheating detection |
|
|
214
|
-
|
|
215
|
-
#### Timers
|
|
216
|
-
|
|
217
|
-
| Prop | Type | Default | Description |
|
|
218
|
-
| -------------------------- | -------- | ------- | --------------------------------------------------------- |
|
|
219
|
-
| thinkingDuration | `number` | 30s | Timebox for the Thinking phase |
|
|
220
|
-
| answeringDuration | `number` | 120s | Timebox for the Answering phase |
|
|
221
|
-
| editingDuration | `number` | 30s | Timebox for the Editing phase |
|
|
222
|
-
| totalInterviewDuration | `number` | 600s | Overall interview time cap |
|
|
223
|
-
| minimumTimeForNextQuestion | `number` | 120s | Minimum time required to allow starting the next question |
|
|
224
|
-
|
|
225
|
-
#### STT (Speech-To-Text)
|
|
226
|
-
|
|
227
|
-
| Prop | Type | Default | Description |
|
|
228
|
-
| -------- | ------------------------------------ | ------------------------ | -------------------------------------- |
|
|
229
|
-
| provider | `"groq" \| "deepgram"` | "groq" | STT vendor to use |
|
|
230
|
-
| model | `"whisper-large-v3-turbo" \| string` | "whisper-large-v3-turbo" | STT model identifier |
|
|
231
|
-
| language | `string` | "en" | Language code passed to the STT engine |
|
|
232
|
-
|
|
233
|
-
#### TTS (Text-To-Speech)
|
|
234
|
-
|
|
235
|
-
| Prop | Type | Default | Description |
|
|
236
|
-
| -------- | --------- | ------- | ----------------- |
|
|
237
|
-
| provider | `"piper"` | "piper" | TTS vendor to use |
|
|
238
|
-
|
|
239
|
-
#### Proctoring
|
|
240
|
-
|
|
241
|
-
| Prop | Type | Default | Description |
|
|
242
|
-
| ------- | --------- | ------- | --------------------------------------------------------- |
|
|
243
|
-
| enabled | `boolean` | true | Enable/disable proctoring and cheating detection features |
|
|
244
|
-
| gazeAnalysisEnabled | `boolean` | true | Enable/disable gaze tracking and analysis |
|
|
245
|
-
| showControls | `boolean` | false | Show/hide proctoring control panel |
|
|
246
|
-
| showEngagementBar | `boolean` | true | Show/hide engagement metrics bar |
|
|
247
|
-
| showLandmarks | `boolean` | false | Show/hide facial landmark visualization |
|
|
248
|
-
|
|
249
|
-
## How it works
|
|
250
|
-
|
|
251
|
-
The widget composes several parts:
|
|
252
|
-
|
|
253
|
-
- TimerService controls phases and timeboxes
|
|
254
|
-
- TTS speaks the question in the Reading phase
|
|
255
|
-
- STT records and transcribes the answer in the Answering/Transcribing phases
|
|
256
|
-
- A resilient API client hits your backend to fetch the next question and submit answers
|
|
257
|
-
|
|
258
|
-
## Backend API Interface
|
|
259
|
-
|
|
260
|
-
The Interview Widget interacts with a backend endpoint to fetch questions and submit answers. The main endpoint is:
|
|
261
|
-
|
|
262
|
-
### Endpoint
|
|
263
|
-
|
|
264
|
-
**POST** `/interview/questions/next`
|
|
265
|
-
|
|
266
|
-
#### Request Body
|
|
267
|
-
|
|
268
|
-
Uses the `InterviewQuestionPayload` interface:
|
|
269
|
-
|
|
270
|
-
```json
|
|
271
|
-
{
|
|
272
|
-
"interviewId": "string",
|
|
273
|
-
"isInterviewDone": false,
|
|
274
|
-
"qnaId": "string",
|
|
275
|
-
"question": "string",
|
|
276
|
-
"answer": "string",
|
|
277
|
-
"answerDuration": "string"
|
|
278
|
-
}
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
#### Response Body
|
|
282
|
-
|
|
283
|
-
Uses the `InterviewQuestionResponse` interface:
|
|
284
|
-
|
|
285
|
-
```json
|
|
286
|
-
{
|
|
287
|
-
"success": true,
|
|
288
|
-
"message": "Question generated successfully",
|
|
289
|
-
"data": {
|
|
290
|
-
"interview_id": "string",
|
|
291
|
-
"qna_id": "string",
|
|
292
|
-
"question": "What is your experience with React?",
|
|
293
|
-
"question_audio_data_base64": null,
|
|
294
|
-
"audio_length_in_milliseconds": 0,
|
|
295
|
-
"estimated_answering_duration": "00:00:30"
|
|
296
|
-
},
|
|
297
|
-
"error": null,
|
|
298
|
-
"code": 200
|
|
299
|
-
}
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
### Timer phases
|
|
303
|
-
|
|
304
|
-
`idle → fetching_question → reading_question → thinking → answering → transcribing → editing → submitting → completed`
|
|
305
|
-
|
|
306
|
-
You’ll see a Start button, a Next Phase button during active phases, a live countdown, and a completion screen.
|
|
1
|
+
# Interview Widget
|
|
2
|
+
|
|
3
|
+
A modern React interview experience widget with built‑in timer flow, STT (speech‑to‑text), and TTS (text‑to‑speech). It can be embedded via NPM or a CDN and configured through a single provider.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Video capture** with camera integration
|
|
8
|
+
- **Responsive design** with mobile support
|
|
9
|
+
- **TypeScript support** with full type definitions
|
|
10
|
+
- **CDN-ready** for easy integration into any website
|
|
11
|
+
- **Q&A structured interview flow**
|
|
12
|
+
- **Advanced Timer System** with phase management
|
|
13
|
+
- **Text-to-Speech integration** for transcribing
|
|
14
|
+
- **Speech-to-Text integration** for voice answers
|
|
15
|
+
- **Automatic phase transitions** (thinking → answering → editing)
|
|
16
|
+
- **Time validation** before starting new questions
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
### 1) Environment Setup
|
|
21
|
+
|
|
22
|
+
The Interview Widget uses encryption for session storage integrity. Set up your encryption secret based on your environment:
|
|
23
|
+
|
|
24
|
+
#### Vite React
|
|
25
|
+
|
|
26
|
+
```env
|
|
27
|
+
# .env
|
|
28
|
+
VITE_IW_SECRET=your-secure-encryption-seed-here
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
#### Next.js
|
|
32
|
+
|
|
33
|
+
```env
|
|
34
|
+
# .env.local
|
|
35
|
+
NEXT_PUBLIC_IW_SECRET=your-secure-encryption-seed-here
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
#### Vanilla JS / Custom Framework
|
|
39
|
+
|
|
40
|
+
```html
|
|
41
|
+
<script>
|
|
42
|
+
// Define the secret before loading your widget
|
|
43
|
+
window.__IW_SECRET__ = "your-secure-encryption-seed-here";
|
|
44
|
+
</script>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2) Install (React apps)
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install interview-widget
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Minimal usage:
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
import React from "react";
|
|
57
|
+
import { InterviewWidget, InterviewWidgetProvider } from "interview-widget";
|
|
58
|
+
import "interview-widget/style.css";
|
|
59
|
+
|
|
60
|
+
export default function App() {
|
|
61
|
+
return (
|
|
62
|
+
<InterviewWidgetProvider
|
|
63
|
+
config={{
|
|
64
|
+
api: {
|
|
65
|
+
baseUrl: "/api" // Your backend endpoint
|
|
66
|
+
authToken: getTokenFromYourAuthSystem(), // Get from secure backend
|
|
67
|
+
},
|
|
68
|
+
interview: {
|
|
69
|
+
stt: {
|
|
70
|
+
provider: "groq",
|
|
71
|
+
model: "whisper-large-v3-turbo",
|
|
72
|
+
language: "en",
|
|
73
|
+
},
|
|
74
|
+
tts: { provider: "piper" },
|
|
75
|
+
timers: {
|
|
76
|
+
thinkingDuration: 30,
|
|
77
|
+
answeringDuration: 120,
|
|
78
|
+
editingDuration: 30,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
}}
|
|
82
|
+
>
|
|
83
|
+
<InterviewWidget
|
|
84
|
+
interviewId="your_interview_id"
|
|
85
|
+
title="Interview for JS developer"
|
|
86
|
+
className="iw-rounded-none iw-shadow-none"
|
|
87
|
+
onInterviewEnd={() => {
|
|
88
|
+
console.log("🎉🎉 Interview ended 🎉🎉");
|
|
89
|
+
}}
|
|
90
|
+
/>
|
|
91
|
+
</InterviewWidgetProvider>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```html
|
|
97
|
+
<!-- React 18 UMD -->
|
|
98
|
+
<script
|
|
99
|
+
crossorigin
|
|
100
|
+
src="https://unpkg.com/react@18/umd/react.production.min.js"
|
|
101
|
+
></script>
|
|
102
|
+
<script
|
|
103
|
+
crossorigin
|
|
104
|
+
src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"
|
|
105
|
+
></script>
|
|
106
|
+
|
|
107
|
+
<!-- Styles + Widget UMD -->
|
|
108
|
+
<link
|
|
109
|
+
rel="stylesheet"
|
|
110
|
+
href="https://unpkg.com/interview-widget@latest/dist/widget.css"
|
|
111
|
+
/>
|
|
112
|
+
<script src="https://unpkg.com/interview-widget@latest/dist/widget.umd.js"></script>
|
|
113
|
+
|
|
114
|
+
<div id="interview-widget-container"></div>
|
|
115
|
+
<script>
|
|
116
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
117
|
+
const { InterviewWidget, InterviewWidgetProvider } = window.InterviewWidget;
|
|
118
|
+
|
|
119
|
+
const app = React.createElement(
|
|
120
|
+
InterviewWidgetProvider,
|
|
121
|
+
{
|
|
122
|
+
config: {
|
|
123
|
+
api: { baseUrl: "/api" },
|
|
124
|
+
interview: {
|
|
125
|
+
timers: {
|
|
126
|
+
thinkingDuration: 30,
|
|
127
|
+
answeringDuration: 120,
|
|
128
|
+
editingDuration: 30,
|
|
129
|
+
},
|
|
130
|
+
stt: {
|
|
131
|
+
provider: "groq",
|
|
132
|
+
model: "whisper-large-v3-turbo",
|
|
133
|
+
language: "en",
|
|
134
|
+
},
|
|
135
|
+
tts: { provider: "piper" },
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
React.createElement(InterviewWidget, { interviewId="your_interview_id", title: "Developer Interview", onInterviewEnd={() => {}} }
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
ReactDOM.render(app, document.getElementById("interview-widget-container"));
|
|
143
|
+
});
|
|
144
|
+
</script>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Public API
|
|
148
|
+
|
|
149
|
+
### <InterviewWidget />
|
|
150
|
+
|
|
151
|
+
### InterviewWidget Props
|
|
152
|
+
|
|
153
|
+
| Prop | Type | Default | Description |
|
|
154
|
+
| ----------------------- | ------------ | ------------- | --------------------------------------------------------------------------- |
|
|
155
|
+
| `interviewId` | `string` | Required | Unique interview identifier used for backend API calls |
|
|
156
|
+
| `title` | `string` | `"Interview"` | Title displayed in the interview header |
|
|
157
|
+
| `onInterviewEnd` | `() => void` | `undefined` | Called when the interview completes or the user exits |
|
|
158
|
+
| `onInterviewDisqualify` | `() => void` | `undefined` | Called when the interview is disqualified (e.g., due to cheating detection) |
|
|
159
|
+
| `className` | `string` | `""` | Additional CSS classes applied to the outer widget container |
|
|
160
|
+
|
|
161
|
+
### <InterviewWidgetProvider />
|
|
162
|
+
|
|
163
|
+
Wrap your app (or the widget) to provide configuration. See full config reference below.
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
<InterviewWidgetProvider config={{ api: { baseUrl: "/api" } }}>
|
|
167
|
+
<InterviewWidget />
|
|
168
|
+
</InterviewWidgetProvider>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Configuration reference (Provider)
|
|
172
|
+
|
|
173
|
+
Pass this object to `InterviewWidgetProvider` via the `config` prop. Tables list all keys, types, and defaults.
|
|
174
|
+
|
|
175
|
+
### Top-level
|
|
176
|
+
|
|
177
|
+
| Prop | Type | Default | Description |
|
|
178
|
+
| --------- | -------- | ----------------------- | ---------------------------------------------- |
|
|
179
|
+
| api | `object` | [see below](#api) | Backend/API configuration |
|
|
180
|
+
| ui | `object` | [see below](#ui) | UI customization tokens |
|
|
181
|
+
| interview | `object` | [see below](#interview) | Interview behavior settings (timers, STT, TTS) |
|
|
182
|
+
|
|
183
|
+
### API
|
|
184
|
+
|
|
185
|
+
| Prop | Type | Default | Description |
|
|
186
|
+
| ----------- | -------- | -------------------------- | ------------------------------------------------------ |
|
|
187
|
+
| baseUrl | `string` | "/api" | Base URL for backend endpoints |
|
|
188
|
+
| authToken | `string` | undefined | Optional bearer token appended as Authorization header |
|
|
189
|
+
| retryConfig | `object` | [see below](#retry-config) | Retry policy for fetch calls |
|
|
190
|
+
|
|
191
|
+
#### Retry Config
|
|
192
|
+
|
|
193
|
+
| Prop | Type | Default | Description |
|
|
194
|
+
| --------- | -------------------------- | ------------- | ------------------------------------------ |
|
|
195
|
+
| attempts | `number` | 3 | Number of retry attempts |
|
|
196
|
+
| backoff | `"fixed" \| "exponential"` | "exponential" | Backoff strategy |
|
|
197
|
+
| baseDelay | `number (ms)` | 1000 | Base delay between retries in milliseconds |
|
|
198
|
+
|
|
199
|
+
### UI
|
|
200
|
+
|
|
201
|
+
| Prop | Type | Default | Description |
|
|
202
|
+
| ------------ | -------------- | --------- | -------------------------------------- |
|
|
203
|
+
| baseColor | `string (hex)` | "#3B82F6" | Primary brand color used by the widget |
|
|
204
|
+
| borderRadius | `string (CSS)` | "8px" | Global corner radius for components |
|
|
205
|
+
|
|
206
|
+
### Interview
|
|
207
|
+
|
|
208
|
+
| Prop | Type | Default | Description |
|
|
209
|
+
| ---------- | -------- | -------------------------------- | ------------------------------------------ |
|
|
210
|
+
| timers | `object` | [see below](#timers) | Per-phase and global timing configuration |
|
|
211
|
+
| stt | `object` | [see below](#stt-speech-to-text) | Speech-to-Text provider settings |
|
|
212
|
+
| tts | `object` | [see below](#tts-text-to-speech) | Text-to-Speech provider settings |
|
|
213
|
+
| proctoring | `object` | [see below](#proctoring) | Proctoring settings and cheating detection |
|
|
214
|
+
|
|
215
|
+
#### Timers
|
|
216
|
+
|
|
217
|
+
| Prop | Type | Default | Description |
|
|
218
|
+
| -------------------------- | -------- | ------- | --------------------------------------------------------- |
|
|
219
|
+
| thinkingDuration | `number` | 30s | Timebox for the Thinking phase |
|
|
220
|
+
| answeringDuration | `number` | 120s | Timebox for the Answering phase |
|
|
221
|
+
| editingDuration | `number` | 30s | Timebox for the Editing phase |
|
|
222
|
+
| totalInterviewDuration | `number` | 600s | Overall interview time cap |
|
|
223
|
+
| minimumTimeForNextQuestion | `number` | 120s | Minimum time required to allow starting the next question |
|
|
224
|
+
|
|
225
|
+
#### STT (Speech-To-Text)
|
|
226
|
+
|
|
227
|
+
| Prop | Type | Default | Description |
|
|
228
|
+
| -------- | ------------------------------------ | ------------------------ | -------------------------------------- |
|
|
229
|
+
| provider | `"groq" \| "deepgram"` | "groq" | STT vendor to use |
|
|
230
|
+
| model | `"whisper-large-v3-turbo" \| string` | "whisper-large-v3-turbo" | STT model identifier |
|
|
231
|
+
| language | `string` | "en" | Language code passed to the STT engine |
|
|
232
|
+
|
|
233
|
+
#### TTS (Text-To-Speech)
|
|
234
|
+
|
|
235
|
+
| Prop | Type | Default | Description |
|
|
236
|
+
| -------- | --------- | ------- | ----------------- |
|
|
237
|
+
| provider | `"piper"` | "piper" | TTS vendor to use |
|
|
238
|
+
|
|
239
|
+
#### Proctoring
|
|
240
|
+
|
|
241
|
+
| Prop | Type | Default | Description |
|
|
242
|
+
| ------- | --------- | ------- | --------------------------------------------------------- |
|
|
243
|
+
| enabled | `boolean` | true | Enable/disable proctoring and cheating detection features |
|
|
244
|
+
| gazeAnalysisEnabled | `boolean` | true | Enable/disable gaze tracking and analysis |
|
|
245
|
+
| showControls | `boolean` | false | Show/hide proctoring control panel |
|
|
246
|
+
| showEngagementBar | `boolean` | true | Show/hide engagement metrics bar |
|
|
247
|
+
| showLandmarks | `boolean` | false | Show/hide facial landmark visualization |
|
|
248
|
+
|
|
249
|
+
## How it works
|
|
250
|
+
|
|
251
|
+
The widget composes several parts:
|
|
252
|
+
|
|
253
|
+
- TimerService controls phases and timeboxes
|
|
254
|
+
- TTS speaks the question in the Reading phase
|
|
255
|
+
- STT records and transcribes the answer in the Answering/Transcribing phases
|
|
256
|
+
- A resilient API client hits your backend to fetch the next question and submit answers
|
|
257
|
+
|
|
258
|
+
## Backend API Interface
|
|
259
|
+
|
|
260
|
+
The Interview Widget interacts with a backend endpoint to fetch questions and submit answers. The main endpoint is:
|
|
261
|
+
|
|
262
|
+
### Endpoint
|
|
263
|
+
|
|
264
|
+
**POST** `/interview/questions/next`
|
|
265
|
+
|
|
266
|
+
#### Request Body
|
|
267
|
+
|
|
268
|
+
Uses the `InterviewQuestionPayload` interface:
|
|
269
|
+
|
|
270
|
+
```json
|
|
271
|
+
{
|
|
272
|
+
"interviewId": "string",
|
|
273
|
+
"isInterviewDone": false,
|
|
274
|
+
"qnaId": "string",
|
|
275
|
+
"question": "string",
|
|
276
|
+
"answer": "string",
|
|
277
|
+
"answerDuration": "string"
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
#### Response Body
|
|
282
|
+
|
|
283
|
+
Uses the `InterviewQuestionResponse` interface:
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"success": true,
|
|
288
|
+
"message": "Question generated successfully",
|
|
289
|
+
"data": {
|
|
290
|
+
"interview_id": "string",
|
|
291
|
+
"qna_id": "string",
|
|
292
|
+
"question": "What is your experience with React?",
|
|
293
|
+
"question_audio_data_base64": null,
|
|
294
|
+
"audio_length_in_milliseconds": 0,
|
|
295
|
+
"estimated_answering_duration": "00:00:30"
|
|
296
|
+
},
|
|
297
|
+
"error": null,
|
|
298
|
+
"code": 200
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Timer phases
|
|
303
|
+
|
|
304
|
+
`idle → fetching_question → reading_question → thinking → answering → transcribing → editing → submitting → completed`
|
|
305
|
+
|
|
306
|
+
You’ll see a Start button, a Next Phase button during active phases, a live countdown, and a completion screen.
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { default as React } from 'react';
|
|
2
1
|
export interface VideoFeedHandle {
|
|
3
2
|
setReference: () => void;
|
|
4
|
-
faceLandmarkerRef?: React.RefObject<any>;
|
|
5
3
|
}
|
|
6
4
|
interface VideoFeedProps {
|
|
7
5
|
className?: string;
|
|
@@ -9,5 +7,5 @@ interface VideoFeedProps {
|
|
|
9
7
|
interview_duration?: number | undefined;
|
|
10
8
|
showProctoringUI?: boolean;
|
|
11
9
|
}
|
|
12
|
-
declare const VideoFeed:
|
|
10
|
+
declare const VideoFeed: import('react').ForwardRefExoticComponent<VideoFeedProps & import('react').RefAttributes<VideoFeedHandle>>;
|
|
13
11
|
export default VideoFeed;
|