interview-widget 0.0.8 → 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 +55 -29
- package/dist/utils/constants.d.ts +3 -0
- package/dist/utils/helper.d.ts +6 -0
- package/dist/widget.css +1 -1
- package/dist/widget.es.js +1594 -432
- package/dist/widget.umd.js +2 -2
- package/package.json +1 -1
- package/dist/examples/APIUsageExample.d.ts +0 -5
- package/dist/hooks/useAPI.d.ts +0 -12
- package/dist/services/index.d.ts +0 -2
- package/dist/services/interview-api.d.ts +0 -47
- /package/dist/components/{onboarding-modal.d.ts → modals/onboarding-modal.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,27 +1,70 @@
|
|
|
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
7
|
- 📸 **Video capture** with camera integration
|
|
8
8
|
- 📱 **Responsive design** with mobile support
|
|
9
|
-
- 🔧 **Flexible positioning** (inline, fixed bottom-right/left)
|
|
10
9
|
- 🧩 **TypeScript support** with full type definitions
|
|
11
10
|
- 🎯 **CDN-ready** for easy integration into any website
|
|
12
11
|
- 🔄 **Q&A structured interview flow**
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
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
|
+
### 1) Install (React apps)
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
```bash
|
|
23
|
+
npm install interview-widget
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Minimal usage:
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import React from "react";
|
|
30
|
+
import { InterviewWidget, InterviewWidgetProvider } from "interview-widget";
|
|
31
|
+
import "interview-widget/style.css";
|
|
32
|
+
|
|
33
|
+
export default function App() {
|
|
34
|
+
return (
|
|
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
|
+
title="Technical Interview"
|
|
55
|
+
onInterviewEnd={() => {
|
|
56
|
+
console.log("🎉🎉 Interview ended 🎉🎉");
|
|
57
|
+
}}
|
|
58
|
+
/>
|
|
59
|
+
</InterviewWidgetProvider>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2) CDN usage (Any website)
|
|
22
65
|
|
|
23
66
|
```html
|
|
24
|
-
<!--
|
|
67
|
+
<!-- React 18 UMD -->
|
|
25
68
|
<script
|
|
26
69
|
crossorigin
|
|
27
70
|
src="https://unpkg.com/react@18/umd/react.production.min.js"
|
|
@@ -31,123 +74,176 @@ Add these scripts to your HTML:
|
|
|
31
74
|
src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"
|
|
32
75
|
></script>
|
|
33
76
|
|
|
34
|
-
<!--
|
|
77
|
+
<!-- Styles + Widget UMD -->
|
|
35
78
|
<link
|
|
36
79
|
rel="stylesheet"
|
|
37
80
|
href="https://unpkg.com/interview-widget@latest/dist/widget.css"
|
|
38
81
|
/>
|
|
39
|
-
|
|
40
|
-
<!-- Load the interview widget JavaScript -->
|
|
41
82
|
<script src="https://unpkg.com/interview-widget@latest/dist/widget.umd.js"></script>
|
|
42
83
|
|
|
84
|
+
<div id="interview-widget-container"></div>
|
|
43
85
|
<script>
|
|
44
86
|
document.addEventListener("DOMContentLoaded", function () {
|
|
45
|
-
const { InterviewWidget } = window.InterviewWidget;
|
|
87
|
+
const { InterviewWidget, InterviewWidgetProvider } = window.InterviewWidget;
|
|
46
88
|
|
|
47
|
-
|
|
48
|
-
|
|
89
|
+
const app = React.createElement(
|
|
90
|
+
InterviewWidgetProvider,
|
|
49
91
|
{
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
+
},
|
|
53
108
|
},
|
|
54
|
-
{
|
|
55
|
-
id: "2",
|
|
56
|
-
text: "What experience do you have with our required technologies?",
|
|
57
|
-
timestamp: new Date(),
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
id: "3",
|
|
61
|
-
text: "What are your strengths and weaknesses?",
|
|
62
|
-
timestamp: new Date(),
|
|
63
|
-
},
|
|
64
|
-
];
|
|
65
|
-
|
|
66
|
-
ReactDOM.render(
|
|
67
|
-
React.createElement(InterviewWidget, {
|
|
68
|
-
title: "Developer Interview",
|
|
69
|
-
questions: questions,
|
|
70
|
-
position: "bottom-right",
|
|
71
|
-
}),
|
|
72
|
-
document.getElementById("interview-widget-container")
|
|
109
|
+
React.createElement(InterviewWidget, { title: "Developer Interview" })
|
|
73
110
|
);
|
|
111
|
+
|
|
112
|
+
ReactDOM.render(app, document.getElementById("interview-widget-container"));
|
|
74
113
|
});
|
|
75
114
|
</script>
|
|
76
115
|
```
|
|
77
116
|
|
|
78
|
-
|
|
117
|
+
## Public API
|
|
79
118
|
|
|
80
|
-
|
|
81
|
-
npm install interview-widget
|
|
82
|
-
```
|
|
119
|
+
### <InterviewWidget />
|
|
83
120
|
|
|
84
|
-
|
|
85
|
-
import React, { useState } from "react";
|
|
86
|
-
import {
|
|
87
|
-
InterviewWidget,
|
|
88
|
-
InterviewQuestion,
|
|
89
|
-
InterviewAnswer,
|
|
90
|
-
} from "interview-widget";
|
|
91
|
-
import "interview-widget/style.css";
|
|
121
|
+
### InterviewWidget Props
|
|
92
122
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
id: "2",
|
|
102
|
-
text: "What experience do you have with our required technologies?",
|
|
103
|
-
timestamp: new Date(),
|
|
104
|
-
},
|
|
105
|
-
];
|
|
106
|
-
|
|
107
|
-
const handleAnswerSubmit = (answer: InterviewAnswer) => {
|
|
108
|
-
// Handle submitting answer to your backend
|
|
109
|
-
console.log("User answered:", answer);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const handleComplete = (answers: InterviewAnswer[]) => {
|
|
113
|
-
// Handle interview completion
|
|
114
|
-
console.log("All answers:", answers);
|
|
115
|
-
};
|
|
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
|
+
| `className` | `string` | `""` | Additional CSS classes applied to the outer widget container |
|
|
116
129
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
130
|
+
Notes:
|
|
131
|
+
|
|
132
|
+
- Internally uses an InterviewController that orchestrates the full flow using the configured API/STT/TTS/Timer.
|
|
133
|
+
- The interview id is currently derived internally; integrate with your backend by configuring the API base and auth.
|
|
134
|
+
|
|
135
|
+
### <InterviewWidgetProvider />
|
|
136
|
+
|
|
137
|
+
Wrap your app (or the widget) to provide configuration. See full config reference below.
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
<InterviewWidgetProvider config={{ api: { baseUrl: "/api" } }}>
|
|
141
|
+
<InterviewWidget />
|
|
142
|
+
</InterviewWidgetProvider>
|
|
128
143
|
```
|
|
129
144
|
|
|
130
|
-
##
|
|
145
|
+
## Configuration reference (Provider)
|
|
131
146
|
|
|
132
|
-
|
|
147
|
+
Pass this object to `InterviewWidgetProvider` via the `config` prop. Tables list all keys, types, and defaults.
|
|
148
|
+
|
|
149
|
+
### Top-level
|
|
150
|
+
|
|
151
|
+
| Prop | Type | Default | Description |
|
|
152
|
+
| --------- | ------ | --------- | ---------------------------------------------- |
|
|
153
|
+
| api | object | see below | Backend/API configuration |
|
|
154
|
+
| ui | object | see below | UI customization tokens |
|
|
155
|
+
| interview | object | see below | Interview behavior settings (timers, STT, TTS) |
|
|
156
|
+
|
|
157
|
+
### api
|
|
158
|
+
|
|
159
|
+
| Prop | Type | Default | Description |
|
|
160
|
+
| ----------- | ------ | --------- | ------------------------------------------------------ |
|
|
161
|
+
| baseUrl | string | "/api" | Base URL for backend endpoints |
|
|
162
|
+
| authToken | string | undefined | Optional bearer token appended as Authorization header |
|
|
163
|
+
| retryConfig | object | see below | Retry policy for fetch calls |
|
|
164
|
+
|
|
165
|
+
retryConfig
|
|
166
|
+
|
|
167
|
+
| Prop | Type | Default | Description |
|
|
168
|
+
| --------- | ------------------------ | ------------- | ------------------------------------------ |
|
|
169
|
+
| attempts | number | 3 | Number of retry attempts |
|
|
170
|
+
| backoff | "fixed" \| "exponential" | "exponential" | Backoff strategy |
|
|
171
|
+
| baseDelay | number (ms) | 1000 | Base delay between retries in milliseconds |
|
|
172
|
+
|
|
173
|
+
### ui
|
|
174
|
+
|
|
175
|
+
| Prop | Type | Default | Description |
|
|
176
|
+
| ------------ | ------------ | --------- | -------------------------------------- |
|
|
177
|
+
| baseColor | string (hex) | "#3B82F6" | Primary brand color used by the widget |
|
|
178
|
+
| borderRadius | string (CSS) | "8px" | Global corner radius for components |
|
|
179
|
+
|
|
180
|
+
### interview
|
|
181
|
+
|
|
182
|
+
| Prop | Type | Default | Description |
|
|
183
|
+
| ------ | ------ | --------- | ----------------------------------------- |
|
|
184
|
+
| timers | object | see below | Per-phase and global timing configuration |
|
|
185
|
+
| stt | object | see below | Speech-to-Text provider settings |
|
|
186
|
+
| tts | object | see below | Text-to-Speech provider settings |
|
|
187
|
+
|
|
188
|
+
timers
|
|
189
|
+
|
|
190
|
+
| Prop | Type | Default | Description |
|
|
191
|
+
| -------------------------- | ---------- | ------- | --------------------------------------------------------- |
|
|
192
|
+
| thinkingDuration | number (s) | 30 | Timebox for the Thinking phase |
|
|
193
|
+
| answeringDuration | number (s) | 120 | Timebox for the Answering phase |
|
|
194
|
+
| editingDuration | number (s) | 30 | Timebox for the Editing phase |
|
|
195
|
+
| totalInterviewDuration | number (s) | 600 | Overall interview time cap |
|
|
196
|
+
| minimumTimeForNextQuestion | number (s) | 120 | Minimum time required to allow starting the next question |
|
|
197
|
+
|
|
198
|
+
stt
|
|
199
|
+
|
|
200
|
+
| Prop | Type | Default | Description |
|
|
201
|
+
| -------- | ---------------------------------- | ------------------------ | -------------------------------------- |
|
|
202
|
+
| provider | "groq" \| "deepgram" | "groq" | STT vendor to use |
|
|
203
|
+
| model | "whisper-large-v3-turbo" \| string | "whisper-large-v3-turbo" | STT model identifier |
|
|
204
|
+
| language | "en" | "en" | Language code passed to the STT engine |
|
|
205
|
+
|
|
206
|
+
tts
|
|
207
|
+
|
|
208
|
+
| Prop | Type | Default | Description |
|
|
209
|
+
| -------- | ------- | ------- | ----------------- |
|
|
210
|
+
| provider | "piper" | "piper" | TTS vendor to use |
|
|
211
|
+
|
|
212
|
+
Notes on defaults:
|
|
213
|
+
|
|
214
|
+
- Base defaults come from `src/utils/constants.ts` (`defaultConfig`).
|
|
215
|
+
- `totalInterviewDuration` and `minimumTimeForNextQuestion` default to 600s and 120s respectively via the TimerService if not explicitly provided.
|
|
216
|
+
|
|
217
|
+
## How it works
|
|
218
|
+
|
|
219
|
+
The widget composes several parts:
|
|
220
|
+
|
|
221
|
+
- TimerService controls phases and timeboxes
|
|
222
|
+
- TTS speaks the question in the Reading phase
|
|
223
|
+
- STT records and transcribes the answer in the Answering/Transcribing phases
|
|
224
|
+
- A resilient API client hits your backend to fetch the next question and submit answers
|
|
225
|
+
|
|
226
|
+
### Timer phases
|
|
227
|
+
|
|
228
|
+
`idle → fetching_question → reading_question → thinking → answering → transcribing → editing → submitting → completed`
|
|
229
|
+
|
|
230
|
+
You’ll see a Start button, a Next Phase button during active phases, a live countdown, and a completion screen.
|
|
231
|
+
|
|
232
|
+
## Documentation
|
|
233
|
+
|
|
234
|
+
- Timer system: `docs/timer.md`
|
|
235
|
+
- STT integration: `docs/stt-integration.md`
|
|
236
|
+
- TTS integration: `docs/tts-integration.md`
|
|
237
|
+
- API layer overview: `docs/api-layer.md`
|
|
238
|
+
- Flow simulation and diagrams: `docs/flow-simulation.md`
|
|
239
|
+
|
|
240
|
+
## Development
|
|
241
|
+
|
|
242
|
+
Local scripts:
|
|
133
243
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
| `candidateName` | `string` | `""` | Optional name of the candidate |
|
|
138
|
-
| `questions` | `InterviewQuestion[]` | Required | Array of interview questions |
|
|
139
|
-
| `onAnswerSubmit` | `(answer: InterviewAnswer) => void` | `undefined` | Callback when user submits an answer |
|
|
140
|
-
| `onComplete` | `(answers: InterviewAnswer[]) => void` | `undefined` | Callback when interview is completed |
|
|
141
|
-
| `className` | `string` | `""` | Additional CSS classes |
|
|
142
|
-
| `height` | `string` | `"600px"` | Height of the interview widget |
|
|
143
|
-
| `width` | `string` | `"100%"` | Width of the interview widget |
|
|
144
|
-
|
|
145
|
-
## Browser Support
|
|
146
|
-
|
|
147
|
-
- Chrome (latest)
|
|
148
|
-
- Firefox (latest)
|
|
149
|
-
- Safari (latest)
|
|
150
|
-
- Edge (latest)
|
|
244
|
+
- `npm run dev` – Start Vite dev server
|
|
245
|
+
- `npm run build` – Type-check and build library bundles (UMD/ESM)
|
|
246
|
+
- `npm run preview` – Preview the production build
|
|
151
247
|
|
|
152
248
|
## Contributing
|
|
153
249
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
interface InterviewControllerProps {
|
|
3
|
+
interviewId: string;
|
|
4
|
+
onComplete?: () => void;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const InterviewController: React.FC<InterviewControllerProps>;
|
|
8
|
+
export default InterviewController;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { InterviewQuestionData } from '../../types';
|
|
3
3
|
interface QuestionDisplayProps {
|
|
4
|
-
question:
|
|
4
|
+
question: InterviewQuestionData | null;
|
|
5
|
+
isLoading?: boolean;
|
|
5
6
|
}
|
|
6
7
|
declare const QuestionDisplay: React.FC<QuestionDisplayProps>;
|
|
7
8
|
export default QuestionDisplay;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { TimerState } from '../../services/timer/timer-service';
|
|
3
|
+
interface TimerDisplayProps {
|
|
4
|
+
state: TimerState;
|
|
5
|
+
className?: string;
|
|
6
|
+
defaultTimers?: {
|
|
7
|
+
thinking?: number;
|
|
8
|
+
answering?: number;
|
|
9
|
+
editing?: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
declare const TimerDisplay: React.FC<TimerDisplayProps>;
|
|
13
|
+
export default TimerDisplay;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { default as React, ReactNode } from 'react';
|
|
2
|
+
interface DialogProps {
|
|
3
|
+
isOpen: boolean;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
title?: string;
|
|
7
|
+
showCloseButton?: boolean;
|
|
8
|
+
closeOnOverlayClick?: boolean;
|
|
9
|
+
closeOnEscape?: boolean;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const Dialog: React.FC<DialogProps>;
|
|
13
|
+
export default Dialog;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { InterviewWidgetConfig } from '../types';
|
|
3
|
+
interface InterviewWidgetProviderProps {
|
|
4
|
+
config?: InterviewWidgetConfig;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export declare function InterviewWidgetProvider({ config, children, }: InterviewWidgetProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function useInterviewConfig(): InterviewWidgetConfig;
|
|
9
|
+
/**
|
|
10
|
+
* Hook to access specific config sections
|
|
11
|
+
*/
|
|
12
|
+
export declare function useAPIConfig(): {
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
authToken?: string;
|
|
15
|
+
retryConfig?: {
|
|
16
|
+
attempts?: number;
|
|
17
|
+
backoff?: "fixed" | "exponential";
|
|
18
|
+
baseDelay?: number;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare function useUIConfig(): {
|
|
22
|
+
baseColor?: string;
|
|
23
|
+
borderRadius?: string;
|
|
24
|
+
};
|
|
25
|
+
export declare function useInterviewConfigSection(): NonNullable<InterviewWidgetConfig["interview"]>;
|
|
26
|
+
export declare function useSTTConfig(): {
|
|
27
|
+
provider?: "groq" | "deepgram";
|
|
28
|
+
model?: "whisper-large-v3-turbo" | (string & {});
|
|
29
|
+
language?: "en";
|
|
30
|
+
} | undefined;
|
|
31
|
+
export declare function useTTSConfig(): {
|
|
32
|
+
provider?: "piper";
|
|
33
|
+
} | undefined;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { APIError, APIHookState } from '../types';
|
|
2
|
+
type UseQueryAPIOptions<T> = {
|
|
3
|
+
immediate?: boolean;
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
onError?: (error: APIError) => void;
|
|
6
|
+
onSuccess?: (data: T) => void;
|
|
7
|
+
onSettled?: (data: T | null, error: APIError | null) => void;
|
|
8
|
+
};
|
|
9
|
+
type UseMutationAPIOptions<T> = {
|
|
10
|
+
onError?: (error: APIError) => void;
|
|
11
|
+
onSuccess?: (data: T) => void;
|
|
12
|
+
onSettled?: (data: T | null, error: APIError | null) => void;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Hook for GET requests (queries) - auto-executes and provides refetch
|
|
16
|
+
*/
|
|
17
|
+
export declare function useQueryAPI<T>(apiCall: () => Promise<T>, options?: UseQueryAPIOptions<T>): APIHookState<T> & {
|
|
18
|
+
refetch: () => Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Hook for mutations (POST/PUT/PATCH/DELETE) - manual execution with parameters
|
|
22
|
+
*/
|
|
23
|
+
export declare function useMutationAPI<T, P extends any[] = []>(apiCall: (...args: P) => Promise<T>, options?: UseMutationAPIOptions<T>): APIHookState<T> & {
|
|
24
|
+
execute: (...args: P) => Promise<void>;
|
|
25
|
+
};
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { STTConfig, STTError, STTRequest, STTResponse } from '../services/stt';
|
|
2
|
+
export interface UseSTTReturn {
|
|
3
|
+
startRecording: (maxDuration?: number) => Promise<void>;
|
|
4
|
+
stopRecording: () => Promise<Blob>;
|
|
5
|
+
transcribe: (audioBlob: Blob, options?: Partial<STTRequest>) => Promise<STTResponse>;
|
|
6
|
+
cancelRecording: () => void;
|
|
7
|
+
isRecording: boolean;
|
|
8
|
+
isTranscribing: boolean;
|
|
9
|
+
transcript: string | null;
|
|
10
|
+
error: STTError | null;
|
|
11
|
+
audioBlob: Blob | null;
|
|
12
|
+
}
|
|
13
|
+
export interface UseSTTOptions {
|
|
14
|
+
config?: Partial<STTConfig>;
|
|
15
|
+
onStart?: () => void;
|
|
16
|
+
onStop?: () => void;
|
|
17
|
+
onTranscriptionComplete?: (result: STTResponse) => void;
|
|
18
|
+
onError?: (error: STTError) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare const useSTT: (options?: UseSTTOptions) => UseSTTReturn;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TimerService, TimerState, TimerConfig, TimerCallbacks } from '../services/timer/timer-service';
|
|
2
|
+
export interface UseTimerOptions {
|
|
3
|
+
config?: Partial<TimerConfig>;
|
|
4
|
+
callbacks?: TimerCallbacks;
|
|
5
|
+
}
|
|
6
|
+
export interface UseTimerReturn {
|
|
7
|
+
state: TimerState;
|
|
8
|
+
startQuestion: () => void;
|
|
9
|
+
nextPhase: () => void;
|
|
10
|
+
timerService: TimerService;
|
|
11
|
+
}
|
|
12
|
+
export declare function useTimer(options?: UseTimerOptions): UseTimerReturn;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { TTSConfig, TTSRequest } from '../services/tts';
|
|
2
|
+
export interface UseTTSReturn {
|
|
3
|
+
speak: (text: string, options?: Partial<TTSRequest>) => Promise<void>;
|
|
4
|
+
stop: () => void;
|
|
5
|
+
isPlaying: boolean;
|
|
6
|
+
isLoading: boolean;
|
|
7
|
+
error: Error | null;
|
|
8
|
+
}
|
|
9
|
+
export interface UseTTSOptions {
|
|
10
|
+
config?: Partial<TTSConfig>;
|
|
11
|
+
onStart?: () => void;
|
|
12
|
+
onEnd?: () => void;
|
|
13
|
+
onError?: (error: Error) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare const useTTS: (options?: UseTTSOptions) => UseTTSReturn;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import { InterviewWidgetProvider } from './context/interview-widget-context';
|
|
1
2
|
import { default as InterviewWidget } from './interview-widget';
|
|
2
|
-
export { InterviewWidget };
|
|
3
3
|
export * from './types';
|
|
4
|
-
export { InterviewWidget as default };
|
|
4
|
+
export { InterviewWidget as default, InterviewWidget, InterviewWidgetProvider };
|
|
5
5
|
declare global {
|
|
6
6
|
interface Window {
|
|
7
7
|
InterviewWidget: {
|
|
8
8
|
InterviewWidget: typeof InterviewWidget;
|
|
9
|
+
InterviewWidgetProvider: typeof InterviewWidgetProvider;
|
|
9
10
|
};
|
|
10
11
|
React: any;
|
|
11
12
|
ReactDOM: any;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { InterviewQuestionPayload, InterviewQuestionResponse, InterviewWidgetConfig } from '../../types';
|
|
2
|
+
declare class InterviewAPI {
|
|
3
|
+
private config;
|
|
4
|
+
constructor(config?: InterviewWidgetConfig["api"]);
|
|
5
|
+
/**
|
|
6
|
+
* Update configuration
|
|
7
|
+
*/
|
|
8
|
+
updateConfig(config: InterviewWidgetConfig["api"]): void;
|
|
9
|
+
/**
|
|
10
|
+
* Get default headers for API requests
|
|
11
|
+
*/
|
|
12
|
+
private getHeaders;
|
|
13
|
+
/**
|
|
14
|
+
* Get base URL from config with fallback
|
|
15
|
+
*/
|
|
16
|
+
private getBaseUrl;
|
|
17
|
+
/**
|
|
18
|
+
* Get questions for an interview
|
|
19
|
+
*/
|
|
20
|
+
generateQuestion({ interviewId, isInterviewDone, qnaId, question, answer, answerDuration, }: InterviewQuestionPayload): Promise<InterviewQuestionResponse>;
|
|
21
|
+
}
|
|
22
|
+
export declare const interviewAPI: InterviewAPI;
|
|
23
|
+
export { InterviewAPI };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { sttService, STTService, STTError, type STTConfig, type STTRequest, type STTResponse, type RecordingEvents, } from './stt-service';
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export interface STTConfig {
|
|
2
|
+
baseUrl?: string;
|
|
3
|
+
provider?: string;
|
|
4
|
+
model?: string;
|
|
5
|
+
language?: string;
|
|
6
|
+
includeTimestamps?: boolean;
|
|
7
|
+
temperature?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface STTRequest {
|
|
10
|
+
audioBlob: Blob;
|
|
11
|
+
model?: string;
|
|
12
|
+
language?: string;
|
|
13
|
+
includeTimestamps?: boolean;
|
|
14
|
+
temperature?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface STTResponse {
|
|
17
|
+
transcript: string;
|
|
18
|
+
confidence?: number;
|
|
19
|
+
language?: string;
|
|
20
|
+
duration?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface RecordingEvents {
|
|
23
|
+
onStart?: () => void;
|
|
24
|
+
onStop?: () => void;
|
|
25
|
+
onDataAvailable?: (blob: Blob) => void;
|
|
26
|
+
onError?: (error: Error) => void;
|
|
27
|
+
}
|
|
28
|
+
export declare class STTError extends Error {
|
|
29
|
+
readonly code: string;
|
|
30
|
+
readonly recoverable: boolean;
|
|
31
|
+
constructor(message: string, code: string, recoverable?: boolean);
|
|
32
|
+
}
|
|
33
|
+
declare class STTService {
|
|
34
|
+
private config;
|
|
35
|
+
private mediaRecorder;
|
|
36
|
+
private audioChunks;
|
|
37
|
+
private recordingStream;
|
|
38
|
+
private autoStopTimeoutId;
|
|
39
|
+
constructor(config?: STTConfig);
|
|
40
|
+
/**
|
|
41
|
+
* Update STT configuration
|
|
42
|
+
*/
|
|
43
|
+
updateConfig(config: Partial<STTConfig>): void;
|
|
44
|
+
/**
|
|
45
|
+
* Check if browser supports audio recording
|
|
46
|
+
*/
|
|
47
|
+
isRecordingSupported(): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Start recording audio from user's microphone
|
|
50
|
+
*/
|
|
51
|
+
startRecording(maxDuration?: number, events?: RecordingEvents): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Stop recording and return the audio blob
|
|
54
|
+
*/
|
|
55
|
+
stopRecording(): Promise<Blob>;
|
|
56
|
+
/**
|
|
57
|
+
* Transcribe audio blob using the STT API
|
|
58
|
+
*/
|
|
59
|
+
transcribe(request: STTRequest): Promise<STTResponse>;
|
|
60
|
+
/**
|
|
61
|
+
* Cancel current recording without processing
|
|
62
|
+
*/
|
|
63
|
+
cancelRecording(): void;
|
|
64
|
+
/**
|
|
65
|
+
* Check if currently recording
|
|
66
|
+
*/
|
|
67
|
+
isRecording(): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Get supported MIME type for recording
|
|
70
|
+
*/
|
|
71
|
+
private getSupportedMimeType;
|
|
72
|
+
/**
|
|
73
|
+
* Clean up recording resources
|
|
74
|
+
*/
|
|
75
|
+
private cleanup;
|
|
76
|
+
}
|
|
77
|
+
export declare const sttService: STTService;
|
|
78
|
+
export { STTService };
|