interview-widget 1.0.0 → 1.0.1
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 +214 -223
- package/dist/assets/alert-triangle-icon.d.ts +1 -0
- package/dist/assets/bot-icon.d.ts +1 -0
- package/dist/assets/circle-play-icon.d.ts +1 -0
- package/dist/assets/clock-fading-icon.d.ts +1 -0
- package/dist/assets/clock-icon.d.ts +1 -0
- package/dist/assets/eye-icon.d.ts +1 -0
- package/dist/assets/focus-icon.d.ts +1 -0
- package/dist/assets/index.d.ts +12 -0
- package/dist/assets/keyboard-icon.d.ts +1 -0
- package/dist/assets/loader-icon.d.ts +1 -0
- package/dist/assets/monitor-icon.d.ts +1 -0
- package/dist/assets/mouse-pointer-click-icon.d.ts +1 -0
- package/dist/assets/shield-icon.d.ts +2 -0
- package/dist/assets/speak-icon.d.ts +1 -0
- package/dist/components/interview/answer-area.d.ts +12 -0
- package/dist/components/interview/interview-content.d.ts +11 -0
- package/dist/components/interview/interview-controller.d.ts +10 -0
- package/dist/components/interview/interview-header.d.ts +7 -0
- package/dist/components/interview/phases/animated-blob.d.ts +13 -0
- package/dist/components/interview/phases/answering-phase.d.ts +10 -0
- package/dist/components/interview/phases/file-generation-animation.d.ts +1 -0
- package/dist/components/interview/phases/interview-completion-modal.d.ts +7 -0
- package/dist/components/interview/phases/question-reading-animation.d.ts +5 -0
- package/dist/components/interview/phases/thinking-phase.d.ts +8 -0
- package/dist/components/interview/phases/transcription-animation.d.ts +6 -0
- package/dist/components/interview/proctoring/cheating-warning-modal.d.ts +10 -0
- package/dist/components/interview/proctoring/interview-proctoring.d.ts +6 -0
- package/dist/components/interview/question-display.d.ts +9 -0
- package/dist/components/media/audio-wave-visualizer.d.ts +14 -0
- package/dist/components/media/video-feed.d.ts +6 -0
- package/dist/components/modals/exit-confirmation-modal.d.ts +7 -0
- package/dist/components/modals/hard-reload-warning.d.ts +16 -0
- package/dist/components/modals/onboarding-modal.d.ts +8 -0
- package/dist/components/timer/circular-timer.d.ts +11 -0
- package/dist/components/timer/timer-display.d.ts +13 -0
- package/dist/components/ui/button.d.ts +9 -0
- package/dist/components/ui/dialog.d.ts +13 -0
- package/dist/components/ui/extended/styled-button.d.ts +7 -0
- package/dist/components/ui/input.d.ts +8 -0
- package/dist/components/ui/textarea.d.ts +8 -0
- package/dist/context/index.d.ts +2 -0
- package/dist/context/interview-widget-context.d.ts +34 -0
- package/dist/context/proctoring-context.d.ts +17 -0
- package/dist/dev.d.ts +0 -1
- package/dist/hooks/index.d.ts +11 -0
- package/dist/hooks/use-api.d.ts +26 -0
- package/dist/hooks/use-dialog.d.ts +6 -0
- package/dist/hooks/use-full-screen.d.ts +17 -0
- package/dist/hooks/use-interview-api.d.ts +5 -0
- package/dist/hooks/use-keyboard-prevention.d.ts +2 -0
- package/dist/hooks/use-stt.d.ts +20 -0
- package/dist/hooks/use-tab-switch.d.ts +2 -0
- package/dist/hooks/use-text-selection-prevention.d.ts +1 -0
- package/dist/hooks/use-timer.d.ts +13 -0
- package/dist/hooks/use-tts.d.ts +15 -0
- package/dist/hooks/use-violation-logger.d.ts +13 -0
- package/dist/index.d.ts +6 -8
- package/dist/interview-widget.d.ts +4 -0
- 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 +79 -0
- package/dist/services/timer/index.d.ts +6 -0
- package/dist/services/timer/timer-service.d.ts +82 -0
- package/dist/services/tts/index.d.ts +1 -0
- package/dist/services/tts/tts-service.d.ts +44 -0
- package/dist/styles.d.ts +0 -0
- package/dist/types.d.ts +89 -23
- package/dist/utils/api-error-classifier.d.ts +2 -0
- package/dist/utils/constants.d.ts +3 -0
- package/dist/utils/helper.d.ts +8 -0
- package/dist/utils/resilient-fetch.d.ts +9 -0
- package/dist/widget.css +1 -0
- package/dist/widget.es.js +3204 -0
- package/dist/widget.umd.js +127 -0
- package/package.json +37 -23
- package/dist/ChatWidget.d.ts +0 -5
- package/dist/Message.d.ts +0 -10
- package/dist/chat-widget.css +0 -1
- package/dist/chat-widget.es.js +0 -189
- package/dist/chat-widget.umd.js +0 -9
package/README.md
CHANGED
|
@@ -1,281 +1,272 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Interview Widget
|
|
2
2
|
|
|
3
|
-
A
|
|
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
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
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
|
|
16
17
|
|
|
17
18
|
## Quick Start
|
|
18
19
|
|
|
19
|
-
###
|
|
20
|
-
|
|
21
|
-
Add these scripts to your HTML:
|
|
22
|
-
|
|
23
|
-
```html
|
|
24
|
-
<!-- Load React and ReactDOM from CDN -->
|
|
25
|
-
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
|
|
26
|
-
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
|
|
27
|
-
|
|
28
|
-
<!-- Load the chat widget CSS -->
|
|
29
|
-
<link rel="stylesheet" href="https://your-cdn.com/chat-widget.css">
|
|
30
|
-
|
|
31
|
-
<!-- Load the chat widget JavaScript -->
|
|
32
|
-
<script src="https://your-cdn.com/chat-widget.umd.js"></script>
|
|
33
|
-
|
|
34
|
-
<script>
|
|
35
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
36
|
-
const { ChatWidget } = window.ChatWidget;
|
|
37
|
-
|
|
38
|
-
ReactDOM.render(
|
|
39
|
-
React.createElement(ChatWidget, {
|
|
40
|
-
title: 'Customer Support',
|
|
41
|
-
placeholder: 'How can we help you?',
|
|
42
|
-
position: 'bottom-right'
|
|
43
|
-
}),
|
|
44
|
-
document.getElementById('chat-widget-container')
|
|
45
|
-
);
|
|
46
|
-
});
|
|
47
|
-
</script>
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### React Application Integration
|
|
20
|
+
### 1) Install (React apps)
|
|
51
21
|
|
|
52
22
|
```bash
|
|
53
|
-
npm install
|
|
23
|
+
npm install interview-widget
|
|
54
24
|
```
|
|
55
25
|
|
|
56
|
-
|
|
57
|
-
import React from 'react';
|
|
58
|
-
import { ChatWidget, Message } from 'chat-widget';
|
|
59
|
-
|
|
60
|
-
function App() {
|
|
61
|
-
const [messages, setMessages] = useState<Message[]>([]);
|
|
26
|
+
Minimal usage:
|
|
62
27
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
28
|
+
```tsx
|
|
29
|
+
import React from "react";
|
|
30
|
+
import { InterviewWidget, InterviewWidgetProvider } from "interview-widget";
|
|
31
|
+
import "interview-widget/style.css";
|
|
67
32
|
|
|
33
|
+
export default function App() {
|
|
68
34
|
return (
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
35
|
+
<InterviewWidgetProvider
|
|
36
|
+
config={{
|
|
37
|
+
api: { baseUrl: "/api" },
|
|
38
|
+
interview: {
|
|
39
|
+
stt: {
|
|
40
|
+
provider: "groq",
|
|
41
|
+
model: "whisper-large-v3-turbo",
|
|
42
|
+
language: "en",
|
|
43
|
+
},
|
|
44
|
+
tts: { provider: "piper" },
|
|
45
|
+
timers: {
|
|
46
|
+
thinkingDuration: 30,
|
|
47
|
+
answeringDuration: 120,
|
|
48
|
+
editingDuration: 30,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<InterviewWidget
|
|
54
|
+
interviewId="your_interview_id"
|
|
55
|
+
title="Interview for JS developer"
|
|
56
|
+
className="iw-rounded-none iw-shadow-none"
|
|
57
|
+
onInterviewEnd={() => {
|
|
58
|
+
console.log("🎉🎉 Interview ended 🎉🎉");
|
|
59
|
+
}}
|
|
75
60
|
/>
|
|
76
|
-
</
|
|
61
|
+
</InterviewWidgetProvider>
|
|
77
62
|
);
|
|
78
63
|
}
|
|
79
64
|
```
|
|
80
65
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
66
|
+
```html
|
|
67
|
+
<!-- React 18 UMD -->
|
|
68
|
+
<script
|
|
69
|
+
crossorigin
|
|
70
|
+
src="https://unpkg.com/react@18/umd/react.production.min.js"
|
|
71
|
+
></script>
|
|
72
|
+
<script
|
|
73
|
+
crossorigin
|
|
74
|
+
src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"
|
|
75
|
+
></script>
|
|
76
|
+
|
|
77
|
+
<!-- Styles + Widget UMD -->
|
|
78
|
+
<link
|
|
79
|
+
rel="stylesheet"
|
|
80
|
+
href="https://unpkg.com/interview-widget@latest/dist/widget.css"
|
|
81
|
+
/>
|
|
82
|
+
<script src="https://unpkg.com/interview-widget@latest/dist/widget.umd.js"></script>
|
|
83
|
+
|
|
84
|
+
<div id="interview-widget-container"></div>
|
|
85
|
+
<script>
|
|
86
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
87
|
+
const { InterviewWidget, InterviewWidgetProvider } = window.InterviewWidget;
|
|
88
|
+
|
|
89
|
+
const app = React.createElement(
|
|
90
|
+
InterviewWidgetProvider,
|
|
91
|
+
{
|
|
92
|
+
config: {
|
|
93
|
+
api: { baseUrl: "/api" },
|
|
94
|
+
interview: {
|
|
95
|
+
timers: {
|
|
96
|
+
thinkingDuration: 30,
|
|
97
|
+
answeringDuration: 120,
|
|
98
|
+
editingDuration: 30,
|
|
99
|
+
},
|
|
100
|
+
stt: {
|
|
101
|
+
provider: "groq",
|
|
102
|
+
model: "whisper-large-v3-turbo",
|
|
103
|
+
language: "en",
|
|
104
|
+
},
|
|
105
|
+
tts: { provider: "piper" },
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
React.createElement(InterviewWidget, { interviewId="your_interview_id", title: "Developer Interview", onInterviewEnd={() => {}} }
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
ReactDOM.render(app, document.getElementById("interview-widget-container"));
|
|
113
|
+
});
|
|
114
|
+
</script>
|
|
108
115
|
```
|
|
109
116
|
|
|
110
|
-
##
|
|
117
|
+
## Public API
|
|
111
118
|
|
|
112
|
-
###
|
|
119
|
+
### <InterviewWidget />
|
|
113
120
|
|
|
114
|
-
|
|
115
|
-
<ChatWidget
|
|
116
|
-
title="AI Assistant"
|
|
117
|
-
placeholder="Ask me anything..."
|
|
118
|
-
botName="AI Helper"
|
|
119
|
-
userName="Visitor"
|
|
120
|
-
/>
|
|
121
|
-
```
|
|
121
|
+
### InterviewWidget Props
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
| Prop | Type | Default | Description |
|
|
124
|
+
| ----------------------- | ------------ | ------------- | --------------------------------------------------------------------------- |
|
|
125
|
+
| `interviewId` | `string` | Required | Unique interview identifier used for backend API calls |
|
|
126
|
+
| `title` | `string` | `"Interview"` | Title displayed in the interview header |
|
|
127
|
+
| `onInterviewEnd` | `() => void` | `undefined` | Called when the interview completes or the user exits |
|
|
128
|
+
| `onInterviewDisqualify` | `() => void` | `undefined` | Called when the interview is disqualified (e.g., due to cheating detection) |
|
|
129
|
+
| `className` | `string` | `""` | Additional CSS classes applied to the outer widget container |
|
|
124
130
|
|
|
125
|
-
|
|
126
|
-
const [messages, setMessages] = useState<Message[]>([]);
|
|
127
|
-
|
|
128
|
-
const handleMessage = async (text: string) => {
|
|
129
|
-
// Add user message
|
|
130
|
-
const userMessage = {
|
|
131
|
-
id: Date.now().toString(),
|
|
132
|
-
text,
|
|
133
|
-
sender: 'user' as const,
|
|
134
|
-
timestamp: new Date()
|
|
135
|
-
};
|
|
136
|
-
setMessages(prev => [...prev, userMessage]);
|
|
137
|
-
|
|
138
|
-
// Get bot response from your API
|
|
139
|
-
const response = await fetch('/api/chat', {
|
|
140
|
-
method: 'POST',
|
|
141
|
-
body: JSON.stringify({ message: text })
|
|
142
|
-
});
|
|
143
|
-
const data = await response.json();
|
|
144
|
-
|
|
145
|
-
// Add bot response
|
|
146
|
-
const botMessage = {
|
|
147
|
-
id: (Date.now() + 1).toString(),
|
|
148
|
-
text: data.reply,
|
|
149
|
-
sender: 'bot' as const,
|
|
150
|
-
timestamp: new Date()
|
|
151
|
-
};
|
|
152
|
-
setMessages(prev => [...prev, botMessage]);
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
<ChatWidget
|
|
156
|
-
messages={messages}
|
|
157
|
-
onSendMessage={handleMessage}
|
|
158
|
-
/>
|
|
159
|
-
```
|
|
131
|
+
### <InterviewWidgetProvider />
|
|
160
132
|
|
|
161
|
-
|
|
133
|
+
Wrap your app (or the widget) to provide configuration. See full config reference below.
|
|
162
134
|
|
|
163
135
|
```tsx
|
|
164
|
-
<
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
height="500px"
|
|
168
|
-
width="300px"
|
|
169
|
-
/>
|
|
136
|
+
<InterviewWidgetProvider config={{ api: { baseUrl: "/api" } }}>
|
|
137
|
+
<InterviewWidget />
|
|
138
|
+
</InterviewWidgetProvider>
|
|
170
139
|
```
|
|
171
140
|
|
|
172
|
-
|
|
141
|
+
## Configuration reference (Provider)
|
|
173
142
|
|
|
174
|
-
|
|
175
|
-
<ChatWidget
|
|
176
|
-
theme="dark"
|
|
177
|
-
title="Night Support"
|
|
178
|
-
botName="Night Owl Bot"
|
|
179
|
-
/>
|
|
180
|
-
```
|
|
143
|
+
Pass this object to `InterviewWidgetProvider` via the `config` prop. Tables list all keys, types, and defaults.
|
|
181
144
|
|
|
182
|
-
|
|
145
|
+
### Top-level
|
|
183
146
|
|
|
184
|
-
|
|
147
|
+
| Prop | Type | Default | Description |
|
|
148
|
+
| --------- | -------- | ----------------------- | ---------------------------------------------- |
|
|
149
|
+
| api | `object` | [see below](#api) | Backend/API configuration |
|
|
150
|
+
| ui | `object` | [see below](#ui) | UI customization tokens |
|
|
151
|
+
| interview | `object` | [see below](#interview) | Interview behavior settings (timers, STT, TTS) |
|
|
185
152
|
|
|
186
|
-
|
|
187
|
-
git clone https://github.com/your-username/chat-widget.git
|
|
188
|
-
cd chat-widget
|
|
189
|
-
npm install
|
|
190
|
-
```
|
|
153
|
+
### API
|
|
191
154
|
|
|
192
|
-
|
|
155
|
+
| Prop | Type | Default | Description |
|
|
156
|
+
| ----------- | -------- | -------------------------- | ------------------------------------------------------ |
|
|
157
|
+
| baseUrl | `string` | "/api" | Base URL for backend endpoints |
|
|
158
|
+
| authToken | `string` | undefined | Optional bearer token appended as Authorization header |
|
|
159
|
+
| retryConfig | `object` | [see below](#retry-config) | Retry policy for fetch calls |
|
|
193
160
|
|
|
194
|
-
|
|
195
|
-
npm run dev
|
|
196
|
-
```
|
|
161
|
+
#### Retry Config
|
|
197
162
|
|
|
198
|
-
|
|
163
|
+
| Prop | Type | Default | Description |
|
|
164
|
+
| --------- | -------------------------- | ------------- | ------------------------------------------ |
|
|
165
|
+
| attempts | `number` | 3 | Number of retry attempts |
|
|
166
|
+
| backoff | `"fixed" \| "exponential"` | "exponential" | Backoff strategy |
|
|
167
|
+
| baseDelay | `number (ms)` | 1000 | Base delay between retries in milliseconds |
|
|
199
168
|
|
|
200
|
-
###
|
|
169
|
+
### UI
|
|
201
170
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
171
|
+
| Prop | Type | Default | Description |
|
|
172
|
+
| ------------ | -------------- | --------- | -------------------------------------- |
|
|
173
|
+
| baseColor | `string (hex)` | "#3B82F6" | Primary brand color used by the widget |
|
|
174
|
+
| borderRadius | `string (CSS)` | "8px" | Global corner radius for components |
|
|
205
175
|
|
|
206
|
-
|
|
207
|
-
- `dist/chat-widget.umd.js` - UMD build for CDN
|
|
208
|
-
- `dist/chat-widget.es.js` - ES modules build
|
|
209
|
-
- `dist/chat-widget.css` - Styles
|
|
210
|
-
- `dist/index.d.ts` - TypeScript definitions
|
|
176
|
+
### Interview
|
|
211
177
|
|
|
212
|
-
|
|
178
|
+
| Prop | Type | Default | Description |
|
|
179
|
+
| ---------- | -------- | -------------------------------- | ------------------------------------------ |
|
|
180
|
+
| timers | `object` | [see below](#timers) | Per-phase and global timing configuration |
|
|
181
|
+
| stt | `object` | [see below](#stt-speech-to-text) | Speech-to-Text provider settings |
|
|
182
|
+
| tts | `object` | [see below](#tts-text-to-speech) | Text-to-Speech provider settings |
|
|
183
|
+
| proctoring | `object` | [see below](#proctoring) | Proctoring settings and cheating detection |
|
|
213
184
|
|
|
214
|
-
|
|
185
|
+
#### Timers
|
|
215
186
|
|
|
216
|
-
|
|
187
|
+
| Prop | Type | Default | Description |
|
|
188
|
+
| -------------------------- | -------- | ------- | --------------------------------------------------------- |
|
|
189
|
+
| thinkingDuration | `number` | 30s | Timebox for the Thinking phase |
|
|
190
|
+
| answeringDuration | `number` | 120s | Timebox for the Answering phase |
|
|
191
|
+
| editingDuration | `number` | 30s | Timebox for the Editing phase |
|
|
192
|
+
| totalInterviewDuration | `number` | 600s | Overall interview time cap |
|
|
193
|
+
| minimumTimeForNextQuestion | `number` | 120s | Minimum time required to allow starting the next question |
|
|
217
194
|
|
|
218
|
-
|
|
195
|
+
#### STT (Speech-To-Text)
|
|
219
196
|
|
|
220
|
-
|
|
197
|
+
| Prop | Type | Default | Description |
|
|
198
|
+
| -------- | ------------------------------------ | ------------------------ | -------------------------------------- |
|
|
199
|
+
| provider | `"groq" \| "deepgram"` | "groq" | STT vendor to use |
|
|
200
|
+
| model | `"whisper-large-v3-turbo" \| string` | "whisper-large-v3-turbo" | STT model identifier |
|
|
201
|
+
| language | `string` | "en" | Language code passed to the STT engine |
|
|
221
202
|
|
|
222
|
-
|
|
223
|
-
.chat-widget-container {
|
|
224
|
-
/* Your custom styles */
|
|
225
|
-
}
|
|
203
|
+
#### TTS (Text-To-Speech)
|
|
226
204
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
```
|
|
205
|
+
| Prop | Type | Default | Description |
|
|
206
|
+
| -------- | --------- | ------- | ----------------- |
|
|
207
|
+
| provider | `"piper"` | "piper" | TTS vendor to use |
|
|
231
208
|
|
|
232
|
-
|
|
209
|
+
#### Proctoring
|
|
233
210
|
|
|
234
|
-
|
|
211
|
+
| Prop | Type | Default | Description |
|
|
212
|
+
| ------- | --------- | ------- | --------------------------------------------------------- |
|
|
213
|
+
| enabled | `boolean` | false | Enable/disable proctoring and cheating detection features |
|
|
235
214
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
})
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
const data = await response.json();
|
|
250
|
-
// Handle response...
|
|
251
|
-
} catch (error) {
|
|
252
|
-
// Handle error...
|
|
253
|
-
}
|
|
254
|
-
};
|
|
255
|
-
```
|
|
215
|
+
## How it works
|
|
216
|
+
|
|
217
|
+
The widget composes several parts:
|
|
218
|
+
|
|
219
|
+
- TimerService controls phases and timeboxes
|
|
220
|
+
- TTS speaks the question in the Reading phase
|
|
221
|
+
- STT records and transcribes the answer in the Answering/Transcribing phases
|
|
222
|
+
- A resilient API client hits your backend to fetch the next question and submit answers
|
|
223
|
+
|
|
224
|
+
## Backend API Interface
|
|
256
225
|
|
|
257
|
-
|
|
226
|
+
The Interview Widget interacts with a backend endpoint to fetch questions and submit answers. The main endpoint is:
|
|
258
227
|
|
|
259
|
-
|
|
260
|
-
- Firefox (latest)
|
|
261
|
-
- Safari (latest)
|
|
262
|
-
- Edge (latest)
|
|
263
|
-
- IE 11+ (with polyfills)
|
|
228
|
+
### Endpoint
|
|
264
229
|
|
|
265
|
-
|
|
230
|
+
**POST** `/interview/questions/next`
|
|
266
231
|
|
|
267
|
-
|
|
232
|
+
#### Request Body
|
|
268
233
|
|
|
269
|
-
|
|
234
|
+
Uses the `InterviewQuestionPayload` interface:
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"interviewId": "string",
|
|
239
|
+
"isInterviewDone": false,
|
|
240
|
+
"qnaId": "string",
|
|
241
|
+
"question": "string",
|
|
242
|
+
"answer": "string",
|
|
243
|
+
"answerDuration": "string"
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### Response Body
|
|
248
|
+
|
|
249
|
+
Uses the `InterviewQuestionResponse` interface:
|
|
250
|
+
|
|
251
|
+
```json
|
|
252
|
+
{
|
|
253
|
+
"success": true,
|
|
254
|
+
"message": "Question generated successfully",
|
|
255
|
+
"data": {
|
|
256
|
+
"interview_id": "string",
|
|
257
|
+
"qna_id": "string",
|
|
258
|
+
"question": "What is your experience with React?",
|
|
259
|
+
"question_audio_data_base64": null,
|
|
260
|
+
"audio_length_in_milliseconds": 0,
|
|
261
|
+
"estimated_answering_duration": "00:00:30"
|
|
262
|
+
},
|
|
263
|
+
"error": null,
|
|
264
|
+
"code": 200
|
|
265
|
+
}
|
|
266
|
+
```
|
|
270
267
|
|
|
271
|
-
|
|
272
|
-
2. Create a feature branch
|
|
273
|
-
3. Make your changes
|
|
274
|
-
4. Add tests if applicable
|
|
275
|
-
5. Submit a pull request
|
|
268
|
+
### Timer phases
|
|
276
269
|
|
|
277
|
-
|
|
270
|
+
`idle → fetching_question → reading_question → thinking → answering → transcribing → editing → submitting → completed`
|
|
278
271
|
|
|
279
|
-
|
|
280
|
-
- 🐛 Issues: [GitHub Issues](https://github.com/your-username/chat-widget/issues)
|
|
281
|
-
- 📖 Docs: [Documentation](https://your-docs-site.com)
|
|
272
|
+
You’ll see a Start button, a Next Phase button during active phases, a live countdown, and a completion screen.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const AlertTriangleIcon: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BotIcon: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const CirclePlayIcon: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ClockFadingIcon: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ClockIcon: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const EyeIcon: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const FocusIcon: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './alert-triangle-icon';
|
|
2
|
+
export * from './bot-icon';
|
|
3
|
+
export * from './clock-fading-icon';
|
|
4
|
+
export * from './clock-icon';
|
|
5
|
+
export * from './eye-icon';
|
|
6
|
+
export * from './focus-icon';
|
|
7
|
+
export * from './keyboard-icon';
|
|
8
|
+
export * from './loader-icon';
|
|
9
|
+
export * from './monitor-icon';
|
|
10
|
+
export * from './mouse-pointer-click-icon';
|
|
11
|
+
export * from './shield-icon';
|
|
12
|
+
export * from './speak-icon';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const KeyboardIcon: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const LoaderIcon: ({ className, ...props }: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const MonitorIcon: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const MousePointerClickIcon: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SpeakIcon: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { TimerState } from '../../services/timer';
|
|
3
|
+
interface AnswerAreaProps {
|
|
4
|
+
value: string;
|
|
5
|
+
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
|
|
6
|
+
onSubmit: () => void;
|
|
7
|
+
isSubmitDisabled: boolean;
|
|
8
|
+
state: TimerState;
|
|
9
|
+
editingTime: number;
|
|
10
|
+
}
|
|
11
|
+
declare const AnswerArea: React.FC<AnswerAreaProps>;
|
|
12
|
+
export default AnswerArea;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { default as React, ReactNode } from 'react';
|
|
2
|
+
import { TimerPhase } from '../../services/timer/timer-service';
|
|
3
|
+
import { InterviewQuestionData } from '../../types';
|
|
4
|
+
interface InterviewContentProps {
|
|
5
|
+
currentQuestion: InterviewQuestionData | null;
|
|
6
|
+
phase: TimerPhase;
|
|
7
|
+
className?: string;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export declare const InterviewContent: React.FC<InterviewContentProps>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
interface InterviewControllerProps {
|
|
3
|
+
interviewTitle: string;
|
|
4
|
+
interviewId: string;
|
|
5
|
+
onComplete?: (() => void) | undefined;
|
|
6
|
+
onDisqualify?: (() => void) | undefined;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
declare const InterviewController: React.FC<InterviewControllerProps>;
|
|
10
|
+
export default InterviewController;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface SiriOrbProps {
|
|
2
|
+
size?: string;
|
|
3
|
+
className?: string;
|
|
4
|
+
colors?: {
|
|
5
|
+
bg?: string;
|
|
6
|
+
c1?: string;
|
|
7
|
+
c2?: string;
|
|
8
|
+
c3?: string;
|
|
9
|
+
};
|
|
10
|
+
animationDuration?: number;
|
|
11
|
+
}
|
|
12
|
+
declare const AnimatedOrb: React.FC<SiriOrbProps>;
|
|
13
|
+
export default AnimatedOrb;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { STTError } from '../../../services/stt';
|
|
2
|
+
import { TimerState } from '../../../services/timer';
|
|
3
|
+
interface Props {
|
|
4
|
+
state: TimerState;
|
|
5
|
+
answeringTime: number;
|
|
6
|
+
nextPhase: () => void;
|
|
7
|
+
sttError: STTError | null;
|
|
8
|
+
}
|
|
9
|
+
export declare const AnsweringPhase: ({ state, answeringTime, nextPhase, sttError, }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function FileGenerationAnimation(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { TimerState } from '../../../services/timer';
|
|
2
|
+
interface Props {
|
|
3
|
+
state: TimerState;
|
|
4
|
+
thinkingTime: number;
|
|
5
|
+
nextPhase: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare const ThinkingPhase: ({ state, thinkingTime, nextPhase }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|