@speechos/react 1.0.0
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/dist/components/SpeechOSWidget.d.cts +101 -0
- package/dist/components/SpeechOSWidget.d.ts +101 -0
- package/dist/components/index.d.cts +6 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/context.d.cts +63 -0
- package/dist/context.d.ts +63 -0
- package/dist/hooks/index.d.cts +11 -0
- package/dist/hooks/index.d.ts +11 -0
- package/dist/hooks/useDictation.d.cts +51 -0
- package/dist/hooks/useDictation.d.ts +51 -0
- package/dist/hooks/useEdit.d.cts +63 -0
- package/dist/hooks/useEdit.d.ts +63 -0
- package/dist/hooks/useSpeechOS.d.cts +35 -0
- package/dist/hooks/useSpeechOS.d.ts +35 -0
- package/dist/hooks/useSpeechOSEvents.d.cts +32 -0
- package/dist/hooks/useSpeechOSEvents.d.ts +32 -0
- package/dist/hooks/useSpeechOSState.d.cts +30 -0
- package/dist/hooks/useSpeechOSState.d.ts +30 -0
- package/dist/hooks/useTranscription.d.cts +87 -0
- package/dist/hooks/useTranscription.d.ts +87 -0
- package/dist/index.cjs +550 -0
- package/dist/index.d.cts +59 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.js +517 -0
- package/package.json +73 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
const react = __toESM(require("react"));
|
|
25
|
+
const __speechos_core = __toESM(require("@speechos/core"));
|
|
26
|
+
const react_jsx_runtime = __toESM(require("react/jsx-runtime"));
|
|
27
|
+
|
|
28
|
+
//#region src/context.tsx
|
|
29
|
+
const SpeechOSContext = (0, react.createContext)(void 0);
|
|
30
|
+
SpeechOSContext.displayName = "SpeechOSContext";
|
|
31
|
+
/**
|
|
32
|
+
* SpeechOS Provider component
|
|
33
|
+
*
|
|
34
|
+
* Wraps your app to provide SpeechOS context to all child components.
|
|
35
|
+
* Can optionally auto-initialize with a config.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```tsx
|
|
39
|
+
* <SpeechOSProvider config={{ apiKey: 'your-key' }}>
|
|
40
|
+
* <App />
|
|
41
|
+
* </SpeechOSProvider>
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
function SpeechOSProvider({ config, children }) {
|
|
45
|
+
const currentState = (0, react.useSyncExternalStore)((0, react.useCallback)((onStoreChange) => {
|
|
46
|
+
return __speechos_core.state.subscribe(onStoreChange);
|
|
47
|
+
}, []), (0, react.useCallback)(() => __speechos_core.state.getState(), []), (0, react.useCallback)(() => __speechos_core.state.getState(), []));
|
|
48
|
+
const isInitialized = __speechos_core.speechOS.isInitialized();
|
|
49
|
+
if (config && !isInitialized) __speechos_core.speechOS.init(config);
|
|
50
|
+
const contextValue = (0, react.useMemo)(() => {
|
|
51
|
+
return {
|
|
52
|
+
state: currentState,
|
|
53
|
+
isInitialized: __speechos_core.speechOS.isInitialized(),
|
|
54
|
+
init: (cfg) => __speechos_core.speechOS.init(cfg),
|
|
55
|
+
dictate: () => __speechos_core.speechOS.dictate(),
|
|
56
|
+
stopDictation: () => __speechos_core.speechOS.stopDictation(),
|
|
57
|
+
edit: (text) => __speechos_core.speechOS.edit(text),
|
|
58
|
+
stopEdit: () => __speechos_core.speechOS.stopEdit(),
|
|
59
|
+
cancel: () => __speechos_core.speechOS.cancel(),
|
|
60
|
+
connect: () => __speechos_core.speechOS.connect(),
|
|
61
|
+
disconnect: () => __speechos_core.speechOS.disconnect(),
|
|
62
|
+
enableMicrophone: () => __speechos_core.speechOS.enableMicrophone(),
|
|
63
|
+
waitUntilReady: () => __speechos_core.speechOS.waitUntilReady(),
|
|
64
|
+
stopAndGetTranscript: () => __speechos_core.speechOS.stopAndGetTranscript(),
|
|
65
|
+
stopAndEdit: (originalText) => __speechos_core.speechOS.stopAndEdit(originalText),
|
|
66
|
+
on: (event, callback) => __speechos_core.events.on(event, callback),
|
|
67
|
+
off: (event, callback) => {
|
|
68
|
+
console.warn("SpeechOS: Use the unsubscribe function returned by on() instead of off()");
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}, [currentState]);
|
|
72
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SpeechOSContext.Provider, {
|
|
73
|
+
value: contextValue,
|
|
74
|
+
children
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Hook to access the SpeechOS context
|
|
79
|
+
*
|
|
80
|
+
* @throws Error if used outside of SpeechOSProvider
|
|
81
|
+
* @returns The SpeechOS context value
|
|
82
|
+
*/
|
|
83
|
+
function useSpeechOSContext() {
|
|
84
|
+
const context = (0, react.useContext)(SpeechOSContext);
|
|
85
|
+
if (context === void 0) throw new Error("useSpeechOSContext must be used within a SpeechOSProvider");
|
|
86
|
+
return context;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/hooks/useSpeechOS.ts
|
|
91
|
+
/**
|
|
92
|
+
* Main hook for accessing the full SpeechOS context
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```tsx
|
|
96
|
+
* function MyComponent() {
|
|
97
|
+
* const { state, dictate, cancel, connect, enableMicrophone } = useSpeechOS();
|
|
98
|
+
*
|
|
99
|
+
* // High-level usage
|
|
100
|
+
* const handleDictate = async () => {
|
|
101
|
+
* const text = await dictate();
|
|
102
|
+
* console.log('Transcribed:', text);
|
|
103
|
+
* };
|
|
104
|
+
*
|
|
105
|
+
* // Low-level usage
|
|
106
|
+
* const handleCustomFlow = async () => {
|
|
107
|
+
* await connect();
|
|
108
|
+
* await waitUntilReady();
|
|
109
|
+
* await enableMicrophone();
|
|
110
|
+
* // ... custom logic
|
|
111
|
+
* const text = await stopAndGetTranscript();
|
|
112
|
+
* };
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @returns The full SpeechOS context value
|
|
117
|
+
*/
|
|
118
|
+
function useSpeechOS() {
|
|
119
|
+
return useSpeechOSContext();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region src/hooks/useSpeechOSState.ts
|
|
124
|
+
/**
|
|
125
|
+
* Hook to access just the SpeechOS state
|
|
126
|
+
*
|
|
127
|
+
* Use this when you only need to read state values like
|
|
128
|
+
* isConnected, recordingState, etc. without needing the API methods.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```tsx
|
|
132
|
+
* function RecordingIndicator() {
|
|
133
|
+
* const state = useSpeechOSState();
|
|
134
|
+
*
|
|
135
|
+
* return (
|
|
136
|
+
* <div>
|
|
137
|
+
* {state.recordingState === 'recording' && <span>Recording...</span>}
|
|
138
|
+
* {state.isConnected && <span>Connected</span>}
|
|
139
|
+
* </div>
|
|
140
|
+
* );
|
|
141
|
+
* }
|
|
142
|
+
* ```
|
|
143
|
+
*
|
|
144
|
+
* @returns The current SpeechOS state
|
|
145
|
+
*/
|
|
146
|
+
function useSpeechOSState() {
|
|
147
|
+
const context = useSpeechOSContext();
|
|
148
|
+
return context.state;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/hooks/useSpeechOSEvents.ts
|
|
153
|
+
/**
|
|
154
|
+
* Hook to subscribe to SpeechOS events
|
|
155
|
+
*
|
|
156
|
+
* Automatically subscribes on mount and unsubscribes on unmount.
|
|
157
|
+
* The callback is stable - changes to it will update the subscription.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```tsx
|
|
161
|
+
* function TranscriptionListener() {
|
|
162
|
+
* useSpeechOSEvents('transcription:complete', (payload) => {
|
|
163
|
+
* console.log('Transcription received:', payload.text);
|
|
164
|
+
* });
|
|
165
|
+
*
|
|
166
|
+
* useSpeechOSEvents('error', (payload) => {
|
|
167
|
+
* console.error('Error:', payload.message);
|
|
168
|
+
* });
|
|
169
|
+
*
|
|
170
|
+
* return <div>Listening for events...</div>;
|
|
171
|
+
* }
|
|
172
|
+
* ```
|
|
173
|
+
*
|
|
174
|
+
* @param event - The event name to subscribe to
|
|
175
|
+
* @param callback - The callback to invoke when the event fires
|
|
176
|
+
* @returns Cleanup function (automatically called on unmount)
|
|
177
|
+
*/
|
|
178
|
+
function useSpeechOSEvents(event, callback) {
|
|
179
|
+
(0, react.useEffect)(() => {
|
|
180
|
+
const unsubscribe = __speechos_core.events.on(event, callback);
|
|
181
|
+
return unsubscribe;
|
|
182
|
+
}, [event, callback]);
|
|
183
|
+
return () => {};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region src/hooks/useDictation.ts
|
|
188
|
+
/**
|
|
189
|
+
* Simplified hook for dictation workflows
|
|
190
|
+
*
|
|
191
|
+
* Provides an easy-to-use interface for voice-to-text dictation
|
|
192
|
+
* with automatic state management.
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```tsx
|
|
196
|
+
* function VoiceInput() {
|
|
197
|
+
* const { start, stop, isRecording, isProcessing, transcript, error } = useDictation();
|
|
198
|
+
*
|
|
199
|
+
* return (
|
|
200
|
+
* <div>
|
|
201
|
+
* <button onClick={isRecording ? stop : start} disabled={isProcessing}>
|
|
202
|
+
* {isRecording ? 'Stop' : 'Start'} Recording
|
|
203
|
+
* </button>
|
|
204
|
+
* {isProcessing && <span>Processing...</span>}
|
|
205
|
+
* {transcript && <p>You said: {transcript}</p>}
|
|
206
|
+
* {error && <p style={{ color: 'red' }}>{error}</p>}
|
|
207
|
+
* </div>
|
|
208
|
+
* );
|
|
209
|
+
* }
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* @returns Dictation controls and state
|
|
213
|
+
*/
|
|
214
|
+
function useDictation() {
|
|
215
|
+
const { state: state$1, dictate, stopDictation, cancel } = useSpeechOSContext();
|
|
216
|
+
const [transcript, setTranscript] = (0, react.useState)(null);
|
|
217
|
+
const [error, setError] = (0, react.useState)(null);
|
|
218
|
+
const isRecording = state$1.recordingState === "recording";
|
|
219
|
+
const isProcessing = state$1.recordingState === "processing";
|
|
220
|
+
const start = (0, react.useCallback)(async () => {
|
|
221
|
+
setError(null);
|
|
222
|
+
try {
|
|
223
|
+
await dictate();
|
|
224
|
+
} catch (err) {
|
|
225
|
+
const message = err instanceof Error ? err.message : "Failed to start dictation";
|
|
226
|
+
setError(message);
|
|
227
|
+
}
|
|
228
|
+
}, [dictate]);
|
|
229
|
+
const stop = (0, react.useCallback)(async () => {
|
|
230
|
+
try {
|
|
231
|
+
const result = await stopDictation();
|
|
232
|
+
setTranscript(result);
|
|
233
|
+
setError(null);
|
|
234
|
+
return result;
|
|
235
|
+
} catch (err) {
|
|
236
|
+
const message = err instanceof Error ? err.message : "Failed to get transcript";
|
|
237
|
+
setError(message);
|
|
238
|
+
throw err;
|
|
239
|
+
}
|
|
240
|
+
}, [stopDictation]);
|
|
241
|
+
const clear = (0, react.useCallback)(() => {
|
|
242
|
+
setTranscript(null);
|
|
243
|
+
setError(null);
|
|
244
|
+
}, []);
|
|
245
|
+
return {
|
|
246
|
+
start,
|
|
247
|
+
stop,
|
|
248
|
+
isRecording,
|
|
249
|
+
isProcessing,
|
|
250
|
+
transcript,
|
|
251
|
+
error,
|
|
252
|
+
clear
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
//#endregion
|
|
257
|
+
//#region src/hooks/useEdit.ts
|
|
258
|
+
/**
|
|
259
|
+
* Simplified hook for voice editing workflows
|
|
260
|
+
*
|
|
261
|
+
* Provides an easy-to-use interface for voice-based text editing
|
|
262
|
+
* with automatic state management.
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```tsx
|
|
266
|
+
* function TextEditor() {
|
|
267
|
+
* const [text, setText] = useState('Hello world');
|
|
268
|
+
* const { start, stop, isEditing, isProcessing, result, error } = useEdit();
|
|
269
|
+
*
|
|
270
|
+
* const handleEdit = async () => {
|
|
271
|
+
* await start(text);
|
|
272
|
+
* };
|
|
273
|
+
*
|
|
274
|
+
* const handleStop = async () => {
|
|
275
|
+
* const edited = await stop();
|
|
276
|
+
* setText(edited);
|
|
277
|
+
* };
|
|
278
|
+
*
|
|
279
|
+
* return (
|
|
280
|
+
* <div>
|
|
281
|
+
* <textarea value={text} onChange={(e) => setText(e.target.value)} />
|
|
282
|
+
* <button onClick={isEditing ? handleStop : handleEdit} disabled={isProcessing}>
|
|
283
|
+
* {isEditing ? 'Apply Edit' : 'Edit with Voice'}
|
|
284
|
+
* </button>
|
|
285
|
+
* {isProcessing && <span>Processing...</span>}
|
|
286
|
+
* {error && <p style={{ color: 'red' }}>{error}</p>}
|
|
287
|
+
* </div>
|
|
288
|
+
* );
|
|
289
|
+
* }
|
|
290
|
+
* ```
|
|
291
|
+
*
|
|
292
|
+
* @returns Edit controls and state
|
|
293
|
+
*/
|
|
294
|
+
function useEdit() {
|
|
295
|
+
const { state: state$1, edit, stopEdit, cancel } = useSpeechOSContext();
|
|
296
|
+
const [originalText, setOriginalText] = (0, react.useState)(null);
|
|
297
|
+
const [result, setResult] = (0, react.useState)(null);
|
|
298
|
+
const [error, setError] = (0, react.useState)(null);
|
|
299
|
+
const isEditing = state$1.recordingState === "recording" && state$1.activeAction === "edit";
|
|
300
|
+
const isProcessing = state$1.recordingState === "processing";
|
|
301
|
+
const start = (0, react.useCallback)(async (textToEdit) => {
|
|
302
|
+
setError(null);
|
|
303
|
+
setOriginalText(textToEdit);
|
|
304
|
+
try {
|
|
305
|
+
await edit(textToEdit);
|
|
306
|
+
} catch (err) {
|
|
307
|
+
const message = err instanceof Error ? err.message : "Failed to start edit";
|
|
308
|
+
setError(message);
|
|
309
|
+
}
|
|
310
|
+
}, [edit]);
|
|
311
|
+
const stop = (0, react.useCallback)(async () => {
|
|
312
|
+
try {
|
|
313
|
+
const editedResult = await stopEdit();
|
|
314
|
+
setResult(editedResult);
|
|
315
|
+
setError(null);
|
|
316
|
+
return editedResult;
|
|
317
|
+
} catch (err) {
|
|
318
|
+
const message = err instanceof Error ? err.message : "Failed to apply edit";
|
|
319
|
+
setError(message);
|
|
320
|
+
throw err;
|
|
321
|
+
}
|
|
322
|
+
}, [stopEdit]);
|
|
323
|
+
const clear = (0, react.useCallback)(() => {
|
|
324
|
+
setOriginalText(null);
|
|
325
|
+
setResult(null);
|
|
326
|
+
setError(null);
|
|
327
|
+
}, []);
|
|
328
|
+
return {
|
|
329
|
+
start,
|
|
330
|
+
stop,
|
|
331
|
+
isEditing,
|
|
332
|
+
isProcessing,
|
|
333
|
+
originalText,
|
|
334
|
+
result,
|
|
335
|
+
error,
|
|
336
|
+
clear
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
//#endregion
|
|
341
|
+
//#region src/hooks/useTranscription.ts
|
|
342
|
+
/**
|
|
343
|
+
* Low-level hook for granular transcription control
|
|
344
|
+
*
|
|
345
|
+
* Use this when you need fine-grained control over the LiveKit
|
|
346
|
+
* connection lifecycle. For most use cases, prefer useDictation()
|
|
347
|
+
* or useEdit() which provide simpler interfaces.
|
|
348
|
+
*
|
|
349
|
+
* @example
|
|
350
|
+
* ```tsx
|
|
351
|
+
* function CustomVoiceUI() {
|
|
352
|
+
* const {
|
|
353
|
+
* connect,
|
|
354
|
+
* waitUntilReady,
|
|
355
|
+
* enableMicrophone,
|
|
356
|
+
* getTranscript,
|
|
357
|
+
* disconnect,
|
|
358
|
+
* isConnected,
|
|
359
|
+
* isMicEnabled,
|
|
360
|
+
* recordingState,
|
|
361
|
+
* } = useTranscription();
|
|
362
|
+
*
|
|
363
|
+
* const handleRecord = async () => {
|
|
364
|
+
* // Step 1: Connect to LiveKit
|
|
365
|
+
* await connect();
|
|
366
|
+
*
|
|
367
|
+
* // Step 2: Wait for agent to be ready
|
|
368
|
+
* await waitUntilReady();
|
|
369
|
+
*
|
|
370
|
+
* // Step 3: Enable microphone
|
|
371
|
+
* await enableMicrophone();
|
|
372
|
+
*
|
|
373
|
+
* // ... user speaks ...
|
|
374
|
+
*
|
|
375
|
+
* // Step 4: Get transcript
|
|
376
|
+
* const text = await getTranscript();
|
|
377
|
+
* console.log('Transcribed:', text);
|
|
378
|
+
*
|
|
379
|
+
* // Step 5: Cleanup
|
|
380
|
+
* await disconnect();
|
|
381
|
+
* };
|
|
382
|
+
*
|
|
383
|
+
* return (
|
|
384
|
+
* <div>
|
|
385
|
+
* <p>Connected: {isConnected ? 'Yes' : 'No'}</p>
|
|
386
|
+
* <p>Mic: {isMicEnabled ? 'On' : 'Off'}</p>
|
|
387
|
+
* <p>State: {recordingState}</p>
|
|
388
|
+
* <button onClick={handleRecord}>Record</button>
|
|
389
|
+
* </div>
|
|
390
|
+
* );
|
|
391
|
+
* }
|
|
392
|
+
* ```
|
|
393
|
+
*
|
|
394
|
+
* @returns Low-level transcription controls and state
|
|
395
|
+
*/
|
|
396
|
+
function useTranscription() {
|
|
397
|
+
const { state: state$1, connect: contextConnect, waitUntilReady: contextWaitUntilReady, enableMicrophone: contextEnableMicrophone, stopAndGetTranscript, stopAndEdit, disconnect: contextDisconnect, cancel } = useSpeechOSContext();
|
|
398
|
+
const connect = (0, react.useCallback)(async () => {
|
|
399
|
+
await contextConnect();
|
|
400
|
+
}, [contextConnect]);
|
|
401
|
+
const waitUntilReady = (0, react.useCallback)(async () => {
|
|
402
|
+
await contextWaitUntilReady();
|
|
403
|
+
}, [contextWaitUntilReady]);
|
|
404
|
+
const enableMicrophone = (0, react.useCallback)(async () => {
|
|
405
|
+
await contextEnableMicrophone();
|
|
406
|
+
}, [contextEnableMicrophone]);
|
|
407
|
+
const getTranscript = (0, react.useCallback)(async () => {
|
|
408
|
+
return await stopAndGetTranscript();
|
|
409
|
+
}, [stopAndGetTranscript]);
|
|
410
|
+
const getEdit = (0, react.useCallback)(async (originalText) => {
|
|
411
|
+
return await stopAndEdit(originalText);
|
|
412
|
+
}, [stopAndEdit]);
|
|
413
|
+
const disconnect = (0, react.useCallback)(async () => {
|
|
414
|
+
await contextDisconnect();
|
|
415
|
+
}, [contextDisconnect]);
|
|
416
|
+
return {
|
|
417
|
+
connect,
|
|
418
|
+
waitUntilReady,
|
|
419
|
+
enableMicrophone,
|
|
420
|
+
getTranscript,
|
|
421
|
+
getEdit,
|
|
422
|
+
disconnect,
|
|
423
|
+
cancel,
|
|
424
|
+
isConnected: state$1.isConnected,
|
|
425
|
+
isMicEnabled: state$1.isMicEnabled,
|
|
426
|
+
recordingState: state$1.recordingState
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
//#endregion
|
|
431
|
+
//#region src/components/SpeechOSWidget.tsx
|
|
432
|
+
/**
|
|
433
|
+
* SpeechOSWidget - React wrapper for the SpeechOS Web Component
|
|
434
|
+
*
|
|
435
|
+
* This component mounts the existing <speechos-widget> Lit Web Component
|
|
436
|
+
* and bridges React props to the Web Component's attributes and events.
|
|
437
|
+
*
|
|
438
|
+
* Note: Requires @speechos/client to be installed and imported somewhere
|
|
439
|
+
* in your app to register the Web Component.
|
|
440
|
+
*
|
|
441
|
+
* @example
|
|
442
|
+
* ```tsx
|
|
443
|
+
* import { SpeechOSProvider, SpeechOSWidget } from '@speechos/react';
|
|
444
|
+
* import '@speechos/client'; // Registers the Web Component
|
|
445
|
+
*
|
|
446
|
+
* function App() {
|
|
447
|
+
* return (
|
|
448
|
+
* <SpeechOSProvider>
|
|
449
|
+
* <MyForm />
|
|
450
|
+
* <SpeechOSWidget
|
|
451
|
+
* apiKey="your-key"
|
|
452
|
+
* onTranscription={(text) => console.log('Transcribed:', text)}
|
|
453
|
+
* onError={(error) => console.error(error)}
|
|
454
|
+
* />
|
|
455
|
+
* </SpeechOSProvider>
|
|
456
|
+
* );
|
|
457
|
+
* }
|
|
458
|
+
* ```
|
|
459
|
+
*/
|
|
460
|
+
function SpeechOSWidget({ apiKey, userId, position = "bottom-center", host, zIndex, debug, onTranscription, onEdit, onError, onShow, onHide, className }) {
|
|
461
|
+
const containerRef = (0, react.useRef)(null);
|
|
462
|
+
const widgetRef = (0, react.useRef)(null);
|
|
463
|
+
const { init, isInitialized } = useSpeechOSContext();
|
|
464
|
+
(0, react.useEffect)(() => {
|
|
465
|
+
if (!isInitialized && apiKey) init({
|
|
466
|
+
apiKey,
|
|
467
|
+
userId,
|
|
468
|
+
host,
|
|
469
|
+
position,
|
|
470
|
+
zIndex,
|
|
471
|
+
debug
|
|
472
|
+
});
|
|
473
|
+
}, [
|
|
474
|
+
isInitialized,
|
|
475
|
+
init,
|
|
476
|
+
apiKey,
|
|
477
|
+
userId,
|
|
478
|
+
host,
|
|
479
|
+
position,
|
|
480
|
+
zIndex,
|
|
481
|
+
debug
|
|
482
|
+
]);
|
|
483
|
+
(0, react.useEffect)(() => {
|
|
484
|
+
const unsubscribers = [];
|
|
485
|
+
if (onTranscription) unsubscribers.push(__speechos_core.events.on("transcription:inserted", (payload) => {
|
|
486
|
+
onTranscription(payload.text, payload.element);
|
|
487
|
+
}));
|
|
488
|
+
if (onEdit) unsubscribers.push(__speechos_core.events.on("edit:applied", (payload) => {
|
|
489
|
+
onEdit(payload.editedContent, payload.originalContent, payload.element);
|
|
490
|
+
}));
|
|
491
|
+
if (onError) unsubscribers.push(__speechos_core.events.on("error", (payload) => {
|
|
492
|
+
onError(payload);
|
|
493
|
+
}));
|
|
494
|
+
if (onShow) unsubscribers.push(__speechos_core.events.on("widget:show", () => {
|
|
495
|
+
onShow();
|
|
496
|
+
}));
|
|
497
|
+
if (onHide) unsubscribers.push(__speechos_core.events.on("widget:hide", () => {
|
|
498
|
+
onHide();
|
|
499
|
+
}));
|
|
500
|
+
return () => {
|
|
501
|
+
unsubscribers.forEach((unsub) => unsub());
|
|
502
|
+
};
|
|
503
|
+
}, [
|
|
504
|
+
onTranscription,
|
|
505
|
+
onEdit,
|
|
506
|
+
onError,
|
|
507
|
+
onShow,
|
|
508
|
+
onHide
|
|
509
|
+
]);
|
|
510
|
+
(0, react.useEffect)(() => {
|
|
511
|
+
if (!containerRef.current) return;
|
|
512
|
+
const isWebComponentRegistered = customElements.get("speechos-widget") !== void 0;
|
|
513
|
+
if (!isWebComponentRegistered) {
|
|
514
|
+
console.warn("SpeechOSWidget: <speechos-widget> Web Component is not registered. Make sure to import @speechos/client in your app.");
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
const widget = document.createElement("speechos-widget");
|
|
518
|
+
widget.setAttribute("position", position);
|
|
519
|
+
containerRef.current.appendChild(widget);
|
|
520
|
+
widgetRef.current = widget;
|
|
521
|
+
return () => {
|
|
522
|
+
if (widgetRef.current && containerRef.current) {
|
|
523
|
+
containerRef.current.removeChild(widgetRef.current);
|
|
524
|
+
widgetRef.current = null;
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
}, [position]);
|
|
528
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
529
|
+
ref: containerRef,
|
|
530
|
+
className,
|
|
531
|
+
style: { display: "contents" }
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
//#endregion
|
|
536
|
+
//#region src/index.ts
|
|
537
|
+
const VERSION = "0.1.0";
|
|
538
|
+
|
|
539
|
+
//#endregion
|
|
540
|
+
exports.SpeechOSContext = SpeechOSContext;
|
|
541
|
+
exports.SpeechOSProvider = SpeechOSProvider;
|
|
542
|
+
exports.SpeechOSWidget = SpeechOSWidget;
|
|
543
|
+
exports.VERSION = VERSION;
|
|
544
|
+
exports.useDictation = useDictation;
|
|
545
|
+
exports.useEdit = useEdit;
|
|
546
|
+
exports.useSpeechOS = useSpeechOS;
|
|
547
|
+
exports.useSpeechOSContext = useSpeechOSContext;
|
|
548
|
+
exports.useSpeechOSEvents = useSpeechOSEvents;
|
|
549
|
+
exports.useSpeechOSState = useSpeechOSState;
|
|
550
|
+
exports.useTranscription = useTranscription;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @speechos/react
|
|
3
|
+
*
|
|
4
|
+
* React hooks and components for SpeechOS voice integration.
|
|
5
|
+
*
|
|
6
|
+
* @example Basic usage with widget
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { SpeechOSProvider, SpeechOSWidget } from '@speechos/react';
|
|
9
|
+
* import '@speechos/client'; // Registers Web Component
|
|
10
|
+
*
|
|
11
|
+
* function App() {
|
|
12
|
+
* return (
|
|
13
|
+
* <SpeechOSProvider config={{ apiKey: 'your-key' }}>
|
|
14
|
+
* <MyForm />
|
|
15
|
+
* <SpeechOSWidget
|
|
16
|
+
* onTranscription={(text) => console.log(text)}
|
|
17
|
+
* />
|
|
18
|
+
* </SpeechOSProvider>
|
|
19
|
+
* );
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example Hook-based usage
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import { SpeechOSProvider, useDictation } from '@speechos/react';
|
|
26
|
+
*
|
|
27
|
+
* function VoiceInput() {
|
|
28
|
+
* const { start, stop, isRecording, transcript } = useDictation();
|
|
29
|
+
*
|
|
30
|
+
* return (
|
|
31
|
+
* <button onClick={isRecording ? stop : start}>
|
|
32
|
+
* {isRecording ? 'Stop' : 'Start'}
|
|
33
|
+
* </button>
|
|
34
|
+
* );
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example Low-level usage
|
|
39
|
+
* ```tsx
|
|
40
|
+
* import { useSpeechOS } from '@speechos/react';
|
|
41
|
+
*
|
|
42
|
+
* function CustomUI() {
|
|
43
|
+
* const { connect, waitUntilReady, enableMicrophone, stopAndGetTranscript } = useSpeechOS();
|
|
44
|
+
*
|
|
45
|
+
* const handleRecord = async () => {
|
|
46
|
+
* await connect();
|
|
47
|
+
* await waitUntilReady();
|
|
48
|
+
* await enableMicrophone();
|
|
49
|
+
* // ... recording ...
|
|
50
|
+
* const text = await stopAndGetTranscript();
|
|
51
|
+
* };
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export { SpeechOSProvider, SpeechOSContext, useSpeechOSContext, type SpeechOSContextValue, type SpeechOSProviderProps, } from "./context.js";
|
|
56
|
+
export { useSpeechOS, useSpeechOSState, useSpeechOSEvents, useDictation, useEdit, useTranscription, type UseDictationResult, type UseEditResult, type UseTranscriptionResult, } from "./hooks/index.js";
|
|
57
|
+
export { SpeechOSWidget, type SpeechOSWidgetProps } from "./components/index.js";
|
|
58
|
+
export type { SpeechOSConfig, SpeechOSState, SpeechOSAction, SpeechOSEventMap, RecordingState, UnsubscribeFn, } from "@speechos/core";
|
|
59
|
+
export declare const VERSION = "0.1.0";
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @speechos/react
|
|
3
|
+
*
|
|
4
|
+
* React hooks and components for SpeechOS voice integration.
|
|
5
|
+
*
|
|
6
|
+
* @example Basic usage with widget
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { SpeechOSProvider, SpeechOSWidget } from '@speechos/react';
|
|
9
|
+
* import '@speechos/client'; // Registers Web Component
|
|
10
|
+
*
|
|
11
|
+
* function App() {
|
|
12
|
+
* return (
|
|
13
|
+
* <SpeechOSProvider config={{ apiKey: 'your-key' }}>
|
|
14
|
+
* <MyForm />
|
|
15
|
+
* <SpeechOSWidget
|
|
16
|
+
* onTranscription={(text) => console.log(text)}
|
|
17
|
+
* />
|
|
18
|
+
* </SpeechOSProvider>
|
|
19
|
+
* );
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example Hook-based usage
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import { SpeechOSProvider, useDictation } from '@speechos/react';
|
|
26
|
+
*
|
|
27
|
+
* function VoiceInput() {
|
|
28
|
+
* const { start, stop, isRecording, transcript } = useDictation();
|
|
29
|
+
*
|
|
30
|
+
* return (
|
|
31
|
+
* <button onClick={isRecording ? stop : start}>
|
|
32
|
+
* {isRecording ? 'Stop' : 'Start'}
|
|
33
|
+
* </button>
|
|
34
|
+
* );
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example Low-level usage
|
|
39
|
+
* ```tsx
|
|
40
|
+
* import { useSpeechOS } from '@speechos/react';
|
|
41
|
+
*
|
|
42
|
+
* function CustomUI() {
|
|
43
|
+
* const { connect, waitUntilReady, enableMicrophone, stopAndGetTranscript } = useSpeechOS();
|
|
44
|
+
*
|
|
45
|
+
* const handleRecord = async () => {
|
|
46
|
+
* await connect();
|
|
47
|
+
* await waitUntilReady();
|
|
48
|
+
* await enableMicrophone();
|
|
49
|
+
* // ... recording ...
|
|
50
|
+
* const text = await stopAndGetTranscript();
|
|
51
|
+
* };
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export { SpeechOSProvider, SpeechOSContext, useSpeechOSContext, type SpeechOSContextValue, type SpeechOSProviderProps, } from "./context.js";
|
|
56
|
+
export { useSpeechOS, useSpeechOSState, useSpeechOSEvents, useDictation, useEdit, useTranscription, type UseDictationResult, type UseEditResult, type UseTranscriptionResult, } from "./hooks/index.js";
|
|
57
|
+
export { SpeechOSWidget, type SpeechOSWidgetProps } from "./components/index.js";
|
|
58
|
+
export type { SpeechOSConfig, SpeechOSState, SpeechOSAction, SpeechOSEventMap, RecordingState, UnsubscribeFn, } from "@speechos/core";
|
|
59
|
+
export declare const VERSION = "0.1.0";
|