@speechos/react 1.0.10 → 1.0.11
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/context.d.cts +10 -4
- package/dist/context.d.ts +10 -4
- package/dist/hooks/index.d.cts +1 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useCommand.d.cts +16 -11
- package/dist/hooks/useCommand.d.ts +16 -11
- package/dist/hooks/useTTS.d.cts +59 -0
- package/dist/hooks/useTTS.d.ts +59 -0
- package/dist/index.cjs +136 -13
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +136 -14
- package/package.json +4 -4
package/dist/context.d.cts
CHANGED
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import React, { type ReactNode } from "react";
|
|
8
8
|
import { type SpeechOSCoreConfig, type SpeechOSState, type SpeechOSEventMap, type UnsubscribeFn, type CommandDefinition, type CommandResult } from "@speechos/core";
|
|
9
|
-
import type { FormDetectorInterface } from "@speechos/client";
|
|
10
|
-
import type { TextInputHandlerInterface } from "@speechos/client";
|
|
9
|
+
import type { FormDetectorInterface, TextInputHandlerInterface, ReadAloudConfig } from "@speechos/client";
|
|
11
10
|
/**
|
|
12
11
|
* Context value exposed by SpeechOSProvider
|
|
13
12
|
*/
|
|
@@ -19,8 +18,8 @@ export interface SpeechOSContextValue {
|
|
|
19
18
|
stopDictation: () => Promise<string>;
|
|
20
19
|
edit: (text: string) => Promise<string>;
|
|
21
20
|
stopEdit: () => Promise<string>;
|
|
22
|
-
command: (commands: CommandDefinition[]) => Promise<CommandResult
|
|
23
|
-
stopCommand: () => Promise<CommandResult
|
|
21
|
+
command: (commands: CommandDefinition[]) => Promise<CommandResult[]>;
|
|
22
|
+
stopCommand: () => Promise<CommandResult[]>;
|
|
24
23
|
cancel: () => Promise<void>;
|
|
25
24
|
on: <K extends keyof SpeechOSEventMap>(event: K, callback: (payload: SpeechOSEventMap[K]) => void) => UnsubscribeFn;
|
|
26
25
|
off: <K extends keyof SpeechOSEventMap>(event: K, callback: (payload: SpeechOSEventMap[K]) => void) => void;
|
|
@@ -55,6 +54,13 @@ export interface SpeechOSReactConfig extends SpeechOSCoreConfig {
|
|
|
55
54
|
* Default: false
|
|
56
55
|
*/
|
|
57
56
|
useExternalSettings?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Read-aloud behavior for selected text.
|
|
59
|
+
* - true (default): enable with defaults
|
|
60
|
+
* - false: disable read-aloud
|
|
61
|
+
* - ReadAloudConfig: customize behavior
|
|
62
|
+
*/
|
|
63
|
+
readAloud?: boolean | ReadAloudConfig;
|
|
58
64
|
}
|
|
59
65
|
/**
|
|
60
66
|
* Props for SpeechOSProvider
|
package/dist/context.d.ts
CHANGED
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import React, { type ReactNode } from "react";
|
|
8
8
|
import { type SpeechOSCoreConfig, type SpeechOSState, type SpeechOSEventMap, type UnsubscribeFn, type CommandDefinition, type CommandResult } from "@speechos/core";
|
|
9
|
-
import type { FormDetectorInterface } from "@speechos/client";
|
|
10
|
-
import type { TextInputHandlerInterface } from "@speechos/client";
|
|
9
|
+
import type { FormDetectorInterface, TextInputHandlerInterface, ReadAloudConfig } from "@speechos/client";
|
|
11
10
|
/**
|
|
12
11
|
* Context value exposed by SpeechOSProvider
|
|
13
12
|
*/
|
|
@@ -19,8 +18,8 @@ export interface SpeechOSContextValue {
|
|
|
19
18
|
stopDictation: () => Promise<string>;
|
|
20
19
|
edit: (text: string) => Promise<string>;
|
|
21
20
|
stopEdit: () => Promise<string>;
|
|
22
|
-
command: (commands: CommandDefinition[]) => Promise<CommandResult
|
|
23
|
-
stopCommand: () => Promise<CommandResult
|
|
21
|
+
command: (commands: CommandDefinition[]) => Promise<CommandResult[]>;
|
|
22
|
+
stopCommand: () => Promise<CommandResult[]>;
|
|
24
23
|
cancel: () => Promise<void>;
|
|
25
24
|
on: <K extends keyof SpeechOSEventMap>(event: K, callback: (payload: SpeechOSEventMap[K]) => void) => UnsubscribeFn;
|
|
26
25
|
off: <K extends keyof SpeechOSEventMap>(event: K, callback: (payload: SpeechOSEventMap[K]) => void) => void;
|
|
@@ -55,6 +54,13 @@ export interface SpeechOSReactConfig extends SpeechOSCoreConfig {
|
|
|
55
54
|
* Default: false
|
|
56
55
|
*/
|
|
57
56
|
useExternalSettings?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Read-aloud behavior for selected text.
|
|
59
|
+
* - true (default): enable with defaults
|
|
60
|
+
* - false: disable read-aloud
|
|
61
|
+
* - ReadAloudConfig: customize behavior
|
|
62
|
+
*/
|
|
63
|
+
readAloud?: boolean | ReadAloudConfig;
|
|
58
64
|
}
|
|
59
65
|
/**
|
|
60
66
|
* Props for SpeechOSProvider
|
package/dist/hooks/index.d.cts
CHANGED
|
@@ -9,4 +9,5 @@ export { useSpeechOSEvents } from "./useSpeechOSEvents.js";
|
|
|
9
9
|
export { useDictation, type UseDictationResult } from "./useDictation.js";
|
|
10
10
|
export { useEdit, type UseEditResult } from "./useEdit.js";
|
|
11
11
|
export { useCommand, type UseCommandResult } from "./useCommand.js";
|
|
12
|
+
export { useTTS, type UseTTSResult, type SpeakOptions } from "./useTTS.js";
|
|
12
13
|
export { useSpeechOSWidget, type UseSpeechOSWidgetResult } from "./useSpeechOSWidget.js";
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -9,4 +9,5 @@ export { useSpeechOSEvents } from "./useSpeechOSEvents.js";
|
|
|
9
9
|
export { useDictation, type UseDictationResult } from "./useDictation.js";
|
|
10
10
|
export { useEdit, type UseEditResult } from "./useEdit.js";
|
|
11
11
|
export { useCommand, type UseCommandResult } from "./useCommand.js";
|
|
12
|
+
export { useTTS, type UseTTSResult, type SpeakOptions } from "./useTTS.js";
|
|
12
13
|
export { useSpeechOSWidget, type UseSpeechOSWidgetResult } from "./useSpeechOSWidget.js";
|
|
@@ -10,24 +10,25 @@ import type { CommandDefinition, CommandResult } from "@speechos/core";
|
|
|
10
10
|
export interface UseCommandResult {
|
|
11
11
|
/** Start command listening - begins recording */
|
|
12
12
|
start: (commands: CommandDefinition[]) => Promise<void>;
|
|
13
|
-
/** Stop command listening - ends recording and returns matched
|
|
14
|
-
stop: () => Promise<CommandResult
|
|
13
|
+
/** Stop command listening - ends recording and returns matched commands */
|
|
14
|
+
stop: () => Promise<CommandResult[]>;
|
|
15
15
|
/** Whether currently listening for commands */
|
|
16
16
|
isListening: boolean;
|
|
17
17
|
/** Whether processing the command */
|
|
18
18
|
isProcessing: boolean;
|
|
19
|
-
/** The matched command
|
|
20
|
-
|
|
19
|
+
/** The matched command results (empty array if no matches or not yet processed) */
|
|
20
|
+
results: CommandResult[];
|
|
21
21
|
/** Any error that occurred */
|
|
22
22
|
error: string | null;
|
|
23
|
-
/** Clear the
|
|
23
|
+
/** Clear the results and error state */
|
|
24
24
|
clear: () => void;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* Simplified hook for voice command workflows
|
|
28
28
|
*
|
|
29
29
|
* Provides an easy-to-use interface for voice command matching
|
|
30
|
-
* with automatic state management.
|
|
30
|
+
* with automatic state management. Supports matching multiple
|
|
31
|
+
* commands from a single voice input.
|
|
31
32
|
*
|
|
32
33
|
* @example
|
|
33
34
|
* ```tsx
|
|
@@ -42,7 +43,7 @@ export interface UseCommandResult {
|
|
|
42
43
|
* ];
|
|
43
44
|
*
|
|
44
45
|
* function VoiceCommands() {
|
|
45
|
-
* const { start, stop, isListening, isProcessing,
|
|
46
|
+
* const { start, stop, isListening, isProcessing, results, error } = useCommand();
|
|
46
47
|
*
|
|
47
48
|
* const handleCommand = async () => {
|
|
48
49
|
* await start(commands);
|
|
@@ -50,9 +51,9 @@ export interface UseCommandResult {
|
|
|
50
51
|
*
|
|
51
52
|
* const handleStop = async () => {
|
|
52
53
|
* const matched = await stop();
|
|
53
|
-
*
|
|
54
|
-
* console.log('Matched command:',
|
|
55
|
-
* }
|
|
54
|
+
* matched.forEach(cmd => {
|
|
55
|
+
* console.log('Matched command:', cmd.name, cmd.arguments);
|
|
56
|
+
* });
|
|
56
57
|
* };
|
|
57
58
|
*
|
|
58
59
|
* return (
|
|
@@ -61,7 +62,11 @@ export interface UseCommandResult {
|
|
|
61
62
|
* {isListening ? 'Execute' : 'Say Command'}
|
|
62
63
|
* </button>
|
|
63
64
|
* {isProcessing && <span>Processing...</span>}
|
|
64
|
-
* {
|
|
65
|
+
* {results.length > 0 && (
|
|
66
|
+
* <div>
|
|
67
|
+
* {results.map((cmd, i) => <p key={i}>Command: {cmd.name}</p>)}
|
|
68
|
+
* </div>
|
|
69
|
+
* )}
|
|
65
70
|
* {error && <p style={{ color: 'red' }}>{error}</p>}
|
|
66
71
|
* </div>
|
|
67
72
|
* );
|
|
@@ -10,24 +10,25 @@ import type { CommandDefinition, CommandResult } from "@speechos/core";
|
|
|
10
10
|
export interface UseCommandResult {
|
|
11
11
|
/** Start command listening - begins recording */
|
|
12
12
|
start: (commands: CommandDefinition[]) => Promise<void>;
|
|
13
|
-
/** Stop command listening - ends recording and returns matched
|
|
14
|
-
stop: () => Promise<CommandResult
|
|
13
|
+
/** Stop command listening - ends recording and returns matched commands */
|
|
14
|
+
stop: () => Promise<CommandResult[]>;
|
|
15
15
|
/** Whether currently listening for commands */
|
|
16
16
|
isListening: boolean;
|
|
17
17
|
/** Whether processing the command */
|
|
18
18
|
isProcessing: boolean;
|
|
19
|
-
/** The matched command
|
|
20
|
-
|
|
19
|
+
/** The matched command results (empty array if no matches or not yet processed) */
|
|
20
|
+
results: CommandResult[];
|
|
21
21
|
/** Any error that occurred */
|
|
22
22
|
error: string | null;
|
|
23
|
-
/** Clear the
|
|
23
|
+
/** Clear the results and error state */
|
|
24
24
|
clear: () => void;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* Simplified hook for voice command workflows
|
|
28
28
|
*
|
|
29
29
|
* Provides an easy-to-use interface for voice command matching
|
|
30
|
-
* with automatic state management.
|
|
30
|
+
* with automatic state management. Supports matching multiple
|
|
31
|
+
* commands from a single voice input.
|
|
31
32
|
*
|
|
32
33
|
* @example
|
|
33
34
|
* ```tsx
|
|
@@ -42,7 +43,7 @@ export interface UseCommandResult {
|
|
|
42
43
|
* ];
|
|
43
44
|
*
|
|
44
45
|
* function VoiceCommands() {
|
|
45
|
-
* const { start, stop, isListening, isProcessing,
|
|
46
|
+
* const { start, stop, isListening, isProcessing, results, error } = useCommand();
|
|
46
47
|
*
|
|
47
48
|
* const handleCommand = async () => {
|
|
48
49
|
* await start(commands);
|
|
@@ -50,9 +51,9 @@ export interface UseCommandResult {
|
|
|
50
51
|
*
|
|
51
52
|
* const handleStop = async () => {
|
|
52
53
|
* const matched = await stop();
|
|
53
|
-
*
|
|
54
|
-
* console.log('Matched command:',
|
|
55
|
-
* }
|
|
54
|
+
* matched.forEach(cmd => {
|
|
55
|
+
* console.log('Matched command:', cmd.name, cmd.arguments);
|
|
56
|
+
* });
|
|
56
57
|
* };
|
|
57
58
|
*
|
|
58
59
|
* return (
|
|
@@ -61,7 +62,11 @@ export interface UseCommandResult {
|
|
|
61
62
|
* {isListening ? 'Execute' : 'Say Command'}
|
|
62
63
|
* </button>
|
|
63
64
|
* {isProcessing && <span>Processing...</span>}
|
|
64
|
-
* {
|
|
65
|
+
* {results.length > 0 && (
|
|
66
|
+
* <div>
|
|
67
|
+
* {results.map((cmd, i) => <p key={i}>Command: {cmd.name}</p>)}
|
|
68
|
+
* </div>
|
|
69
|
+
* )}
|
|
65
70
|
* {error && <p style={{ color: 'red' }}>{error}</p>}
|
|
66
71
|
* </div>
|
|
67
72
|
* );
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useTTS - React hook for text-to-speech
|
|
3
|
+
*
|
|
4
|
+
* Provides a simple interface for TTS synthesis and playback.
|
|
5
|
+
*/
|
|
6
|
+
import { type TTSOptions, type TTSResult } from "@speechos/core";
|
|
7
|
+
/**
|
|
8
|
+
* Return type for useTTS hook
|
|
9
|
+
*/
|
|
10
|
+
export interface UseTTSResult {
|
|
11
|
+
/** Synthesize text and play audio immediately */
|
|
12
|
+
speak: (text: string, options?: SpeakOptions) => Promise<void>;
|
|
13
|
+
/** Synthesize text and return audio bytes */
|
|
14
|
+
synthesize: (text: string, options?: TTSOptions) => Promise<TTSResult>;
|
|
15
|
+
/** Stop current playback */
|
|
16
|
+
stop: () => void;
|
|
17
|
+
/** Whether currently synthesizing (HTTP request in progress) */
|
|
18
|
+
isSynthesizing: boolean;
|
|
19
|
+
/** Whether audio is currently playing */
|
|
20
|
+
isPlaying: boolean;
|
|
21
|
+
/** The last synthesized audio result (from synthesize()) */
|
|
22
|
+
audioResult: TTSResult | null;
|
|
23
|
+
/** Any error that occurred */
|
|
24
|
+
error: string | null;
|
|
25
|
+
/** Clear error and audio result state */
|
|
26
|
+
clear: () => void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Options for speaking text (extends TTSOptions with playback options)
|
|
30
|
+
*/
|
|
31
|
+
export interface SpeakOptions extends TTSOptions {
|
|
32
|
+
/** Output audio device ID (if supported by browser) */
|
|
33
|
+
audioDeviceId?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* React hook for text-to-speech
|
|
37
|
+
*
|
|
38
|
+
* Provides an easy-to-use interface for TTS synthesis and playback
|
|
39
|
+
* with automatic state management.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```tsx
|
|
43
|
+
* function TTSButton() {
|
|
44
|
+
* const { speak, stop, isSynthesizing, isPlaying, error } = useTTS();
|
|
45
|
+
*
|
|
46
|
+
* return (
|
|
47
|
+
* <div>
|
|
48
|
+
* <button onClick={() => speak('Hello!')}>
|
|
49
|
+
* {isSynthesizing ? 'Loading...' : isPlaying ? 'Stop' : 'Speak'}
|
|
50
|
+
* </button>
|
|
51
|
+
* {error && <p style={{ color: 'red' }}>{error}</p>}
|
|
52
|
+
* </div>
|
|
53
|
+
* );
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @returns TTS controls and state
|
|
58
|
+
*/
|
|
59
|
+
export declare function useTTS(): UseTTSResult;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useTTS - React hook for text-to-speech
|
|
3
|
+
*
|
|
4
|
+
* Provides a simple interface for TTS synthesis and playback.
|
|
5
|
+
*/
|
|
6
|
+
import { type TTSOptions, type TTSResult } from "@speechos/core";
|
|
7
|
+
/**
|
|
8
|
+
* Return type for useTTS hook
|
|
9
|
+
*/
|
|
10
|
+
export interface UseTTSResult {
|
|
11
|
+
/** Synthesize text and play audio immediately */
|
|
12
|
+
speak: (text: string, options?: SpeakOptions) => Promise<void>;
|
|
13
|
+
/** Synthesize text and return audio bytes */
|
|
14
|
+
synthesize: (text: string, options?: TTSOptions) => Promise<TTSResult>;
|
|
15
|
+
/** Stop current playback */
|
|
16
|
+
stop: () => void;
|
|
17
|
+
/** Whether currently synthesizing (HTTP request in progress) */
|
|
18
|
+
isSynthesizing: boolean;
|
|
19
|
+
/** Whether audio is currently playing */
|
|
20
|
+
isPlaying: boolean;
|
|
21
|
+
/** The last synthesized audio result (from synthesize()) */
|
|
22
|
+
audioResult: TTSResult | null;
|
|
23
|
+
/** Any error that occurred */
|
|
24
|
+
error: string | null;
|
|
25
|
+
/** Clear error and audio result state */
|
|
26
|
+
clear: () => void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Options for speaking text (extends TTSOptions with playback options)
|
|
30
|
+
*/
|
|
31
|
+
export interface SpeakOptions extends TTSOptions {
|
|
32
|
+
/** Output audio device ID (if supported by browser) */
|
|
33
|
+
audioDeviceId?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* React hook for text-to-speech
|
|
37
|
+
*
|
|
38
|
+
* Provides an easy-to-use interface for TTS synthesis and playback
|
|
39
|
+
* with automatic state management.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```tsx
|
|
43
|
+
* function TTSButton() {
|
|
44
|
+
* const { speak, stop, isSynthesizing, isPlaying, error } = useTTS();
|
|
45
|
+
*
|
|
46
|
+
* return (
|
|
47
|
+
* <div>
|
|
48
|
+
* <button onClick={() => speak('Hello!')}>
|
|
49
|
+
* {isSynthesizing ? 'Loading...' : isPlaying ? 'Stop' : 'Speak'}
|
|
50
|
+
* </button>
|
|
51
|
+
* {error && <p style={{ color: 'red' }}>{error}</p>}
|
|
52
|
+
* </div>
|
|
53
|
+
* );
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @returns TTS controls and state
|
|
58
|
+
*/
|
|
59
|
+
export declare function useTTS(): UseTTSResult;
|
package/dist/index.cjs
CHANGED
|
@@ -339,7 +339,8 @@ function useEdit() {
|
|
|
339
339
|
* Simplified hook for voice command workflows
|
|
340
340
|
*
|
|
341
341
|
* Provides an easy-to-use interface for voice command matching
|
|
342
|
-
* with automatic state management.
|
|
342
|
+
* with automatic state management. Supports matching multiple
|
|
343
|
+
* commands from a single voice input.
|
|
343
344
|
*
|
|
344
345
|
* @example
|
|
345
346
|
* ```tsx
|
|
@@ -354,7 +355,7 @@ function useEdit() {
|
|
|
354
355
|
* ];
|
|
355
356
|
*
|
|
356
357
|
* function VoiceCommands() {
|
|
357
|
-
* const { start, stop, isListening, isProcessing,
|
|
358
|
+
* const { start, stop, isListening, isProcessing, results, error } = useCommand();
|
|
358
359
|
*
|
|
359
360
|
* const handleCommand = async () => {
|
|
360
361
|
* await start(commands);
|
|
@@ -362,9 +363,9 @@ function useEdit() {
|
|
|
362
363
|
*
|
|
363
364
|
* const handleStop = async () => {
|
|
364
365
|
* const matched = await stop();
|
|
365
|
-
*
|
|
366
|
-
* console.log('Matched command:',
|
|
367
|
-
* }
|
|
366
|
+
* matched.forEach(cmd => {
|
|
367
|
+
* console.log('Matched command:', cmd.name, cmd.arguments);
|
|
368
|
+
* });
|
|
368
369
|
* };
|
|
369
370
|
*
|
|
370
371
|
* return (
|
|
@@ -373,7 +374,11 @@ function useEdit() {
|
|
|
373
374
|
* {isListening ? 'Execute' : 'Say Command'}
|
|
374
375
|
* </button>
|
|
375
376
|
* {isProcessing && <span>Processing...</span>}
|
|
376
|
-
* {
|
|
377
|
+
* {results.length > 0 && (
|
|
378
|
+
* <div>
|
|
379
|
+
* {results.map((cmd, i) => <p key={i}>Command: {cmd.name}</p>)}
|
|
380
|
+
* </div>
|
|
381
|
+
* )}
|
|
377
382
|
* {error && <p style={{ color: 'red' }}>{error}</p>}
|
|
378
383
|
* </div>
|
|
379
384
|
* );
|
|
@@ -384,7 +389,7 @@ function useEdit() {
|
|
|
384
389
|
*/
|
|
385
390
|
function useCommand() {
|
|
386
391
|
const { state: state$2, command, stopCommand } = useSpeechOSContext();
|
|
387
|
-
const [
|
|
392
|
+
const [results, setResults] = (0, react.useState)([]);
|
|
388
393
|
const [error, setError] = (0, react.useState)(null);
|
|
389
394
|
const isListening = state$2.recordingState === "recording" && state$2.activeAction === "command";
|
|
390
395
|
const isProcessing = state$2.recordingState === "processing";
|
|
@@ -399,10 +404,10 @@ function useCommand() {
|
|
|
399
404
|
}, [command]);
|
|
400
405
|
const stop = (0, react.useCallback)(async () => {
|
|
401
406
|
try {
|
|
402
|
-
const
|
|
403
|
-
|
|
407
|
+
const commandResults = await stopCommand();
|
|
408
|
+
setResults(commandResults);
|
|
404
409
|
setError(null);
|
|
405
|
-
return
|
|
410
|
+
return commandResults;
|
|
406
411
|
} catch (err) {
|
|
407
412
|
const message = err instanceof Error ? err.message : "Failed to process command";
|
|
408
413
|
setError(message);
|
|
@@ -410,7 +415,7 @@ function useCommand() {
|
|
|
410
415
|
}
|
|
411
416
|
}, [stopCommand]);
|
|
412
417
|
const clear = (0, react.useCallback)(() => {
|
|
413
|
-
|
|
418
|
+
setResults([]);
|
|
414
419
|
setError(null);
|
|
415
420
|
}, []);
|
|
416
421
|
return {
|
|
@@ -418,7 +423,124 @@ function useCommand() {
|
|
|
418
423
|
stop,
|
|
419
424
|
isListening,
|
|
420
425
|
isProcessing,
|
|
421
|
-
|
|
426
|
+
results,
|
|
427
|
+
error,
|
|
428
|
+
clear
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
//#endregion
|
|
433
|
+
//#region src/hooks/useTTS.ts
|
|
434
|
+
let clientTTS = null;
|
|
435
|
+
async function getClientTTS() {
|
|
436
|
+
if (clientTTS) return clientTTS;
|
|
437
|
+
try {
|
|
438
|
+
const client = await import("@speechos/client");
|
|
439
|
+
clientTTS = client.tts;
|
|
440
|
+
return clientTTS;
|
|
441
|
+
} catch {
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* React hook for text-to-speech
|
|
447
|
+
*
|
|
448
|
+
* Provides an easy-to-use interface for TTS synthesis and playback
|
|
449
|
+
* with automatic state management.
|
|
450
|
+
*
|
|
451
|
+
* @example
|
|
452
|
+
* ```tsx
|
|
453
|
+
* function TTSButton() {
|
|
454
|
+
* const { speak, stop, isSynthesizing, isPlaying, error } = useTTS();
|
|
455
|
+
*
|
|
456
|
+
* return (
|
|
457
|
+
* <div>
|
|
458
|
+
* <button onClick={() => speak('Hello!')}>
|
|
459
|
+
* {isSynthesizing ? 'Loading...' : isPlaying ? 'Stop' : 'Speak'}
|
|
460
|
+
* </button>
|
|
461
|
+
* {error && <p style={{ color: 'red' }}>{error}</p>}
|
|
462
|
+
* </div>
|
|
463
|
+
* );
|
|
464
|
+
* }
|
|
465
|
+
* ```
|
|
466
|
+
*
|
|
467
|
+
* @returns TTS controls and state
|
|
468
|
+
*/
|
|
469
|
+
function useTTS() {
|
|
470
|
+
const [isSynthesizing, setIsSynthesizing] = (0, react.useState)(false);
|
|
471
|
+
const [isPlaying, setIsPlaying] = (0, react.useState)(false);
|
|
472
|
+
const [audioResult, setAudioResult] = (0, react.useState)(null);
|
|
473
|
+
const [error, setError] = (0, react.useState)(null);
|
|
474
|
+
(0, react.useEffect)(() => {
|
|
475
|
+
const unsubStart = __speechos_core.events.on("tts:playback:start", () => {
|
|
476
|
+
setIsPlaying(true);
|
|
477
|
+
});
|
|
478
|
+
const unsubComplete = __speechos_core.events.on("tts:playback:complete", () => {
|
|
479
|
+
setIsPlaying(false);
|
|
480
|
+
});
|
|
481
|
+
const unsubStop = __speechos_core.events.on("tts:playback:stop", () => {
|
|
482
|
+
setIsPlaying(false);
|
|
483
|
+
});
|
|
484
|
+
const unsubError = __speechos_core.events.on("tts:error", ({ message, phase }) => {
|
|
485
|
+
if (phase === "playback") setIsPlaying(false);
|
|
486
|
+
setError(message);
|
|
487
|
+
});
|
|
488
|
+
return () => {
|
|
489
|
+
unsubStart();
|
|
490
|
+
unsubComplete();
|
|
491
|
+
unsubStop();
|
|
492
|
+
unsubError();
|
|
493
|
+
};
|
|
494
|
+
}, []);
|
|
495
|
+
const speak = (0, react.useCallback)(async (text, options) => {
|
|
496
|
+
setError(null);
|
|
497
|
+
setIsSynthesizing(true);
|
|
498
|
+
try {
|
|
499
|
+
const client = await getClientTTS();
|
|
500
|
+
if (client) await client.speak(text, options);
|
|
501
|
+
else {
|
|
502
|
+
await __speechos_core.tts.synthesize(text, options);
|
|
503
|
+
console.warn("[useTTS] @speechos/client not available, audio not played");
|
|
504
|
+
}
|
|
505
|
+
} catch (err) {
|
|
506
|
+
const message = err instanceof Error ? err.message : "TTS failed";
|
|
507
|
+
setError(message);
|
|
508
|
+
throw err;
|
|
509
|
+
} finally {
|
|
510
|
+
setIsSynthesizing(false);
|
|
511
|
+
}
|
|
512
|
+
}, []);
|
|
513
|
+
const synthesize = (0, react.useCallback)(async (text, options) => {
|
|
514
|
+
setError(null);
|
|
515
|
+
setIsSynthesizing(true);
|
|
516
|
+
try {
|
|
517
|
+
const result = await __speechos_core.tts.synthesize(text, options);
|
|
518
|
+
setAudioResult(result);
|
|
519
|
+
return result;
|
|
520
|
+
} catch (err) {
|
|
521
|
+
const message = err instanceof Error ? err.message : "Synthesis failed";
|
|
522
|
+
setError(message);
|
|
523
|
+
throw err;
|
|
524
|
+
} finally {
|
|
525
|
+
setIsSynthesizing(false);
|
|
526
|
+
}
|
|
527
|
+
}, []);
|
|
528
|
+
const stop = (0, react.useCallback)(async () => {
|
|
529
|
+
const client = await getClientTTS();
|
|
530
|
+
if (client) client.stop();
|
|
531
|
+
setIsPlaying(false);
|
|
532
|
+
}, []);
|
|
533
|
+
const clear = (0, react.useCallback)(() => {
|
|
534
|
+
setAudioResult(null);
|
|
535
|
+
setError(null);
|
|
536
|
+
}, []);
|
|
537
|
+
return {
|
|
538
|
+
speak,
|
|
539
|
+
synthesize,
|
|
540
|
+
stop,
|
|
541
|
+
isSynthesizing,
|
|
542
|
+
isPlaying,
|
|
543
|
+
audioResult,
|
|
422
544
|
error,
|
|
423
545
|
clear
|
|
424
546
|
};
|
|
@@ -599,4 +721,5 @@ exports.useSpeechOS = useSpeechOS;
|
|
|
599
721
|
exports.useSpeechOSContext = useSpeechOSContext;
|
|
600
722
|
exports.useSpeechOSEvents = useSpeechOSEvents;
|
|
601
723
|
exports.useSpeechOSState = useSpeechOSState;
|
|
602
|
-
exports.useSpeechOSWidget = useSpeechOSWidget;
|
|
724
|
+
exports.useSpeechOSWidget = useSpeechOSWidget;
|
|
725
|
+
exports.useTTS = useTTS;
|
package/dist/index.d.cts
CHANGED
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
*
|
|
38
38
|
*/
|
|
39
39
|
export { SpeechOSProvider, SpeechOSContext, useSpeechOSContext, type SpeechOSContextValue, type SpeechOSProviderProps, type SpeechOSReactConfig, } from "./context.js";
|
|
40
|
-
export { useSpeechOS, useSpeechOSState, useSpeechOSEvents, useDictation, useEdit, useCommand, useSpeechOSWidget, type UseDictationResult, type UseEditResult, type UseCommandResult, type UseSpeechOSWidgetResult, } from "./hooks/index.js";
|
|
40
|
+
export { useSpeechOS, useSpeechOSState, useSpeechOSEvents, useDictation, useEdit, useCommand, useTTS, useSpeechOSWidget, type UseDictationResult, type UseEditResult, type UseCommandResult, type UseTTSResult, type SpeakOptions, type UseSpeechOSWidgetResult, } from "./hooks/index.js";
|
|
41
41
|
export { SpeechOSWidget, type SpeechOSWidgetProps, } from "./components/index.js";
|
|
42
|
-
export type { SpeechOSCoreConfig, SpeechOSState, SpeechOSAction, SpeechOSEventMap, RecordingState, UnsubscribeFn, CommandArgument, CommandDefinition, CommandResult, } from "@speechos/core";
|
|
42
|
+
export type { SpeechOSCoreConfig, SpeechOSState, SpeechOSAction, SpeechOSEventMap, RecordingState, UnsubscribeFn, CommandArgument, CommandDefinition, CommandResult, TTSOptions, TTSResult, } from "@speechos/core";
|
|
43
43
|
export type { SpeechOSCoreConfig as SpeechOSConfig } from "@speechos/core";
|
|
44
44
|
export declare const VERSION = "0.1.0";
|
package/dist/index.d.ts
CHANGED
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
*
|
|
38
38
|
*/
|
|
39
39
|
export { SpeechOSProvider, SpeechOSContext, useSpeechOSContext, type SpeechOSContextValue, type SpeechOSProviderProps, type SpeechOSReactConfig, } from "./context.js";
|
|
40
|
-
export { useSpeechOS, useSpeechOSState, useSpeechOSEvents, useDictation, useEdit, useCommand, useSpeechOSWidget, type UseDictationResult, type UseEditResult, type UseCommandResult, type UseSpeechOSWidgetResult, } from "./hooks/index.js";
|
|
40
|
+
export { useSpeechOS, useSpeechOSState, useSpeechOSEvents, useDictation, useEdit, useCommand, useTTS, useSpeechOSWidget, type UseDictationResult, type UseEditResult, type UseCommandResult, type UseTTSResult, type SpeakOptions, type UseSpeechOSWidgetResult, } from "./hooks/index.js";
|
|
41
41
|
export { SpeechOSWidget, type SpeechOSWidgetProps, } from "./components/index.js";
|
|
42
|
-
export type { SpeechOSCoreConfig, SpeechOSState, SpeechOSAction, SpeechOSEventMap, RecordingState, UnsubscribeFn, CommandArgument, CommandDefinition, CommandResult, } from "@speechos/core";
|
|
42
|
+
export type { SpeechOSCoreConfig, SpeechOSState, SpeechOSAction, SpeechOSEventMap, RecordingState, UnsubscribeFn, CommandArgument, CommandDefinition, CommandResult, TTSOptions, TTSResult, } from "@speechos/core";
|
|
43
43
|
export type { SpeechOSCoreConfig as SpeechOSConfig } from "@speechos/core";
|
|
44
44
|
export declare const VERSION = "0.1.0";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
2
|
-
import { events, speechOS, state } from "@speechos/core";
|
|
2
|
+
import { events, speechOS, state, tts } from "@speechos/core";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/context.tsx
|
|
@@ -316,7 +316,8 @@ function useEdit() {
|
|
|
316
316
|
* Simplified hook for voice command workflows
|
|
317
317
|
*
|
|
318
318
|
* Provides an easy-to-use interface for voice command matching
|
|
319
|
-
* with automatic state management.
|
|
319
|
+
* with automatic state management. Supports matching multiple
|
|
320
|
+
* commands from a single voice input.
|
|
320
321
|
*
|
|
321
322
|
* @example
|
|
322
323
|
* ```tsx
|
|
@@ -331,7 +332,7 @@ function useEdit() {
|
|
|
331
332
|
* ];
|
|
332
333
|
*
|
|
333
334
|
* function VoiceCommands() {
|
|
334
|
-
* const { start, stop, isListening, isProcessing,
|
|
335
|
+
* const { start, stop, isListening, isProcessing, results, error } = useCommand();
|
|
335
336
|
*
|
|
336
337
|
* const handleCommand = async () => {
|
|
337
338
|
* await start(commands);
|
|
@@ -339,9 +340,9 @@ function useEdit() {
|
|
|
339
340
|
*
|
|
340
341
|
* const handleStop = async () => {
|
|
341
342
|
* const matched = await stop();
|
|
342
|
-
*
|
|
343
|
-
* console.log('Matched command:',
|
|
344
|
-
* }
|
|
343
|
+
* matched.forEach(cmd => {
|
|
344
|
+
* console.log('Matched command:', cmd.name, cmd.arguments);
|
|
345
|
+
* });
|
|
345
346
|
* };
|
|
346
347
|
*
|
|
347
348
|
* return (
|
|
@@ -350,7 +351,11 @@ function useEdit() {
|
|
|
350
351
|
* {isListening ? 'Execute' : 'Say Command'}
|
|
351
352
|
* </button>
|
|
352
353
|
* {isProcessing && <span>Processing...</span>}
|
|
353
|
-
* {
|
|
354
|
+
* {results.length > 0 && (
|
|
355
|
+
* <div>
|
|
356
|
+
* {results.map((cmd, i) => <p key={i}>Command: {cmd.name}</p>)}
|
|
357
|
+
* </div>
|
|
358
|
+
* )}
|
|
354
359
|
* {error && <p style={{ color: 'red' }}>{error}</p>}
|
|
355
360
|
* </div>
|
|
356
361
|
* );
|
|
@@ -361,7 +366,7 @@ function useEdit() {
|
|
|
361
366
|
*/
|
|
362
367
|
function useCommand() {
|
|
363
368
|
const { state: state$1, command, stopCommand } = useSpeechOSContext();
|
|
364
|
-
const [
|
|
369
|
+
const [results, setResults] = useState([]);
|
|
365
370
|
const [error, setError] = useState(null);
|
|
366
371
|
const isListening = state$1.recordingState === "recording" && state$1.activeAction === "command";
|
|
367
372
|
const isProcessing = state$1.recordingState === "processing";
|
|
@@ -376,10 +381,10 @@ function useCommand() {
|
|
|
376
381
|
}, [command]);
|
|
377
382
|
const stop = useCallback(async () => {
|
|
378
383
|
try {
|
|
379
|
-
const
|
|
380
|
-
|
|
384
|
+
const commandResults = await stopCommand();
|
|
385
|
+
setResults(commandResults);
|
|
381
386
|
setError(null);
|
|
382
|
-
return
|
|
387
|
+
return commandResults;
|
|
383
388
|
} catch (err) {
|
|
384
389
|
const message = err instanceof Error ? err.message : "Failed to process command";
|
|
385
390
|
setError(message);
|
|
@@ -387,7 +392,7 @@ function useCommand() {
|
|
|
387
392
|
}
|
|
388
393
|
}, [stopCommand]);
|
|
389
394
|
const clear = useCallback(() => {
|
|
390
|
-
|
|
395
|
+
setResults([]);
|
|
391
396
|
setError(null);
|
|
392
397
|
}, []);
|
|
393
398
|
return {
|
|
@@ -395,7 +400,124 @@ function useCommand() {
|
|
|
395
400
|
stop,
|
|
396
401
|
isListening,
|
|
397
402
|
isProcessing,
|
|
398
|
-
|
|
403
|
+
results,
|
|
404
|
+
error,
|
|
405
|
+
clear
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
//#endregion
|
|
410
|
+
//#region src/hooks/useTTS.ts
|
|
411
|
+
let clientTTS = null;
|
|
412
|
+
async function getClientTTS() {
|
|
413
|
+
if (clientTTS) return clientTTS;
|
|
414
|
+
try {
|
|
415
|
+
const client = await import("@speechos/client");
|
|
416
|
+
clientTTS = client.tts;
|
|
417
|
+
return clientTTS;
|
|
418
|
+
} catch {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* React hook for text-to-speech
|
|
424
|
+
*
|
|
425
|
+
* Provides an easy-to-use interface for TTS synthesis and playback
|
|
426
|
+
* with automatic state management.
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* ```tsx
|
|
430
|
+
* function TTSButton() {
|
|
431
|
+
* const { speak, stop, isSynthesizing, isPlaying, error } = useTTS();
|
|
432
|
+
*
|
|
433
|
+
* return (
|
|
434
|
+
* <div>
|
|
435
|
+
* <button onClick={() => speak('Hello!')}>
|
|
436
|
+
* {isSynthesizing ? 'Loading...' : isPlaying ? 'Stop' : 'Speak'}
|
|
437
|
+
* </button>
|
|
438
|
+
* {error && <p style={{ color: 'red' }}>{error}</p>}
|
|
439
|
+
* </div>
|
|
440
|
+
* );
|
|
441
|
+
* }
|
|
442
|
+
* ```
|
|
443
|
+
*
|
|
444
|
+
* @returns TTS controls and state
|
|
445
|
+
*/
|
|
446
|
+
function useTTS() {
|
|
447
|
+
const [isSynthesizing, setIsSynthesizing] = useState(false);
|
|
448
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
449
|
+
const [audioResult, setAudioResult] = useState(null);
|
|
450
|
+
const [error, setError] = useState(null);
|
|
451
|
+
useEffect(() => {
|
|
452
|
+
const unsubStart = events.on("tts:playback:start", () => {
|
|
453
|
+
setIsPlaying(true);
|
|
454
|
+
});
|
|
455
|
+
const unsubComplete = events.on("tts:playback:complete", () => {
|
|
456
|
+
setIsPlaying(false);
|
|
457
|
+
});
|
|
458
|
+
const unsubStop = events.on("tts:playback:stop", () => {
|
|
459
|
+
setIsPlaying(false);
|
|
460
|
+
});
|
|
461
|
+
const unsubError = events.on("tts:error", ({ message, phase }) => {
|
|
462
|
+
if (phase === "playback") setIsPlaying(false);
|
|
463
|
+
setError(message);
|
|
464
|
+
});
|
|
465
|
+
return () => {
|
|
466
|
+
unsubStart();
|
|
467
|
+
unsubComplete();
|
|
468
|
+
unsubStop();
|
|
469
|
+
unsubError();
|
|
470
|
+
};
|
|
471
|
+
}, []);
|
|
472
|
+
const speak = useCallback(async (text, options) => {
|
|
473
|
+
setError(null);
|
|
474
|
+
setIsSynthesizing(true);
|
|
475
|
+
try {
|
|
476
|
+
const client = await getClientTTS();
|
|
477
|
+
if (client) await client.speak(text, options);
|
|
478
|
+
else {
|
|
479
|
+
await tts.synthesize(text, options);
|
|
480
|
+
console.warn("[useTTS] @speechos/client not available, audio not played");
|
|
481
|
+
}
|
|
482
|
+
} catch (err) {
|
|
483
|
+
const message = err instanceof Error ? err.message : "TTS failed";
|
|
484
|
+
setError(message);
|
|
485
|
+
throw err;
|
|
486
|
+
} finally {
|
|
487
|
+
setIsSynthesizing(false);
|
|
488
|
+
}
|
|
489
|
+
}, []);
|
|
490
|
+
const synthesize = useCallback(async (text, options) => {
|
|
491
|
+
setError(null);
|
|
492
|
+
setIsSynthesizing(true);
|
|
493
|
+
try {
|
|
494
|
+
const result = await tts.synthesize(text, options);
|
|
495
|
+
setAudioResult(result);
|
|
496
|
+
return result;
|
|
497
|
+
} catch (err) {
|
|
498
|
+
const message = err instanceof Error ? err.message : "Synthesis failed";
|
|
499
|
+
setError(message);
|
|
500
|
+
throw err;
|
|
501
|
+
} finally {
|
|
502
|
+
setIsSynthesizing(false);
|
|
503
|
+
}
|
|
504
|
+
}, []);
|
|
505
|
+
const stop = useCallback(async () => {
|
|
506
|
+
const client = await getClientTTS();
|
|
507
|
+
if (client) client.stop();
|
|
508
|
+
setIsPlaying(false);
|
|
509
|
+
}, []);
|
|
510
|
+
const clear = useCallback(() => {
|
|
511
|
+
setAudioResult(null);
|
|
512
|
+
setError(null);
|
|
513
|
+
}, []);
|
|
514
|
+
return {
|
|
515
|
+
speak,
|
|
516
|
+
synthesize,
|
|
517
|
+
stop,
|
|
518
|
+
isSynthesizing,
|
|
519
|
+
isPlaying,
|
|
520
|
+
audioResult,
|
|
399
521
|
error,
|
|
400
522
|
clear
|
|
401
523
|
};
|
|
@@ -565,4 +687,4 @@ function SpeechOSWidget({ apiKey, userId, host, zIndex, debug, onTranscription,
|
|
|
565
687
|
const VERSION = "0.1.0";
|
|
566
688
|
|
|
567
689
|
//#endregion
|
|
568
|
-
export { SpeechOSContext, SpeechOSProvider, SpeechOSWidget, VERSION, useCommand, useDictation, useEdit, useSpeechOS, useSpeechOSContext, useSpeechOSEvents, useSpeechOSState, useSpeechOSWidget };
|
|
690
|
+
export { SpeechOSContext, SpeechOSProvider, SpeechOSWidget, VERSION, useCommand, useDictation, useEdit, useSpeechOS, useSpeechOSContext, useSpeechOSEvents, useSpeechOSState, useSpeechOSWidget, useTTS };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@speechos/react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "React hooks and components for SpeechOS voice integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"author": "SpeechOS",
|
|
49
49
|
"license": "MIT",
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"@speechos/client": "^0.2.
|
|
52
|
-
"@speechos/core": "^0.2.
|
|
51
|
+
"@speechos/client": "^0.2.12",
|
|
52
|
+
"@speechos/core": "^0.2.11",
|
|
53
53
|
"react": ">=18.0.0"
|
|
54
54
|
},
|
|
55
55
|
"peerDependenciesMeta": {
|
|
@@ -69,6 +69,6 @@
|
|
|
69
69
|
"vitest": "^4.0.16"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@speechos/core": "^0.2.
|
|
72
|
+
"@speechos/core": "^0.2.11"
|
|
73
73
|
}
|
|
74
74
|
}
|