react-native-voice-ts 1.0.3 → 1.0.4
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.
|
@@ -32,7 +32,7 @@ const VoiceMicrophone = ({ onSpeechResult, onPartialResult, onStart, onStop, onE
|
|
|
32
32
|
const [recognizedText, setRecognizedText] = useState('');
|
|
33
33
|
const [partialText, setPartialText] = useState('');
|
|
34
34
|
const [error, setError] = useState(null);
|
|
35
|
-
const
|
|
35
|
+
const shouldContinueRef = React.useRef(false);
|
|
36
36
|
const silenceTimerRef = React.useRef(null);
|
|
37
37
|
useEffect(() => {
|
|
38
38
|
// Clear any existing timers on cleanup
|
|
@@ -55,10 +55,10 @@ const VoiceMicrophone = ({ onSpeechResult, onPartialResult, onStart, onStop, onE
|
|
|
55
55
|
Voice.onSpeechEnd = async () => {
|
|
56
56
|
setIsRecording(false);
|
|
57
57
|
// In continuous mode, restart listening after results
|
|
58
|
-
if (continuous &&
|
|
58
|
+
if (continuous && shouldContinueRef.current) {
|
|
59
59
|
// Small delay before restarting
|
|
60
60
|
setTimeout(async () => {
|
|
61
|
-
if (
|
|
61
|
+
if (shouldContinueRef.current) {
|
|
62
62
|
try {
|
|
63
63
|
await Voice.start(locale, {
|
|
64
64
|
EXTRA_PARTIAL_RESULTS: enablePartialResults,
|
|
@@ -78,7 +78,7 @@ const VoiceMicrophone = ({ onSpeechResult, onPartialResult, onStart, onStop, onE
|
|
|
78
78
|
const errorMessage = e.error?.message || 'Unknown error';
|
|
79
79
|
setError(errorMessage);
|
|
80
80
|
setIsRecording(false);
|
|
81
|
-
|
|
81
|
+
shouldContinueRef.current = false;
|
|
82
82
|
if (silenceTimerRef.current) {
|
|
83
83
|
clearTimeout(silenceTimerRef.current);
|
|
84
84
|
}
|
|
@@ -109,9 +109,15 @@ const VoiceMicrophone = ({ onSpeechResult, onPartialResult, onStart, onStop, onE
|
|
|
109
109
|
// Reset silence timer on partial results (user is speaking)
|
|
110
110
|
if (continuous && silenceTimerRef.current) {
|
|
111
111
|
clearTimeout(silenceTimerRef.current);
|
|
112
|
-
silenceTimerRef.current = setTimeout(() => {
|
|
113
|
-
if (
|
|
114
|
-
|
|
112
|
+
silenceTimerRef.current = setTimeout(async () => {
|
|
113
|
+
if (shouldContinueRef.current) {
|
|
114
|
+
shouldContinueRef.current = false;
|
|
115
|
+
if (silenceTimerRef.current) {
|
|
116
|
+
clearTimeout(silenceTimerRef.current);
|
|
117
|
+
silenceTimerRef.current = null;
|
|
118
|
+
}
|
|
119
|
+
await Voice.stop();
|
|
120
|
+
onStop?.();
|
|
115
121
|
}
|
|
116
122
|
}, maxSilenceDuration);
|
|
117
123
|
}
|
|
@@ -130,7 +136,6 @@ const VoiceMicrophone = ({ onSpeechResult, onPartialResult, onStart, onStop, onE
|
|
|
130
136
|
onError,
|
|
131
137
|
enablePartialResults,
|
|
132
138
|
continuous,
|
|
133
|
-
shouldContinue,
|
|
134
139
|
recognizedText,
|
|
135
140
|
locale,
|
|
136
141
|
maxSilenceDuration,
|
|
@@ -149,7 +154,7 @@ const VoiceMicrophone = ({ onSpeechResult, onPartialResult, onStart, onStop, onE
|
|
|
149
154
|
setRecognizedText('');
|
|
150
155
|
setPartialText('');
|
|
151
156
|
}
|
|
152
|
-
|
|
157
|
+
shouldContinueRef.current = true;
|
|
153
158
|
// Check permission (Android only)
|
|
154
159
|
const hasPermission = await Voice.checkMicrophonePermission();
|
|
155
160
|
if (!hasPermission) {
|
|
@@ -164,9 +169,15 @@ const VoiceMicrophone = ({ onSpeechResult, onPartialResult, onStart, onStop, onE
|
|
|
164
169
|
});
|
|
165
170
|
// Start silence timer if in continuous mode
|
|
166
171
|
if (continuous) {
|
|
167
|
-
silenceTimerRef.current = setTimeout(() => {
|
|
168
|
-
if (
|
|
169
|
-
|
|
172
|
+
silenceTimerRef.current = setTimeout(async () => {
|
|
173
|
+
if (shouldContinueRef.current) {
|
|
174
|
+
shouldContinueRef.current = false;
|
|
175
|
+
if (silenceTimerRef.current) {
|
|
176
|
+
clearTimeout(silenceTimerRef.current);
|
|
177
|
+
silenceTimerRef.current = null;
|
|
178
|
+
}
|
|
179
|
+
await Voice.stop();
|
|
180
|
+
onStop?.();
|
|
170
181
|
}
|
|
171
182
|
}, maxSilenceDuration);
|
|
172
183
|
}
|
|
@@ -174,7 +185,7 @@ const VoiceMicrophone = ({ onSpeechResult, onPartialResult, onStart, onStop, onE
|
|
|
174
185
|
catch (e) {
|
|
175
186
|
const errorMessage = e instanceof Error ? e.message : 'Failed to start recording';
|
|
176
187
|
setError(errorMessage);
|
|
177
|
-
|
|
188
|
+
shouldContinueRef.current = false;
|
|
178
189
|
onError?.(errorMessage);
|
|
179
190
|
}
|
|
180
191
|
}, [
|
|
@@ -183,11 +194,11 @@ const VoiceMicrophone = ({ onSpeechResult, onPartialResult, onStart, onStop, onE
|
|
|
183
194
|
onError,
|
|
184
195
|
continuous,
|
|
185
196
|
maxSilenceDuration,
|
|
186
|
-
|
|
197
|
+
onStop,
|
|
187
198
|
]);
|
|
188
199
|
const stop = useCallback(async () => {
|
|
189
200
|
try {
|
|
190
|
-
|
|
201
|
+
shouldContinueRef.current = false;
|
|
191
202
|
if (silenceTimerRef.current) {
|
|
192
203
|
clearTimeout(silenceTimerRef.current);
|
|
193
204
|
silenceTimerRef.current = null;
|
|
@@ -203,7 +214,7 @@ const VoiceMicrophone = ({ onSpeechResult, onPartialResult, onStart, onStop, onE
|
|
|
203
214
|
}, [onError, onStop]);
|
|
204
215
|
const cancel = useCallback(async () => {
|
|
205
216
|
try {
|
|
206
|
-
|
|
217
|
+
shouldContinueRef.current = false;
|
|
207
218
|
if (silenceTimerRef.current) {
|
|
208
219
|
clearTimeout(silenceTimerRef.current);
|
|
209
220
|
silenceTimerRef.current = null;
|
|
@@ -27,7 +27,7 @@ export const useVoiceRecognition = (options = {}) => {
|
|
|
27
27
|
const [results, setResults] = useState([]);
|
|
28
28
|
const [partialResults, setPartialResults] = useState([]);
|
|
29
29
|
const [error, setError] = useState(null);
|
|
30
|
-
const
|
|
30
|
+
const shouldContinueRef = React.useRef(false);
|
|
31
31
|
const silenceTimerRef = React.useRef(null);
|
|
32
32
|
const accumulatedTextRef = React.useRef('');
|
|
33
33
|
useEffect(() => {
|
|
@@ -50,9 +50,9 @@ export const useVoiceRecognition = (options = {}) => {
|
|
|
50
50
|
Voice.onSpeechEnd = async () => {
|
|
51
51
|
setIsRecording(false);
|
|
52
52
|
// In continuous mode, restart listening after results
|
|
53
|
-
if (continuous &&
|
|
53
|
+
if (continuous && shouldContinueRef.current) {
|
|
54
54
|
setTimeout(async () => {
|
|
55
|
-
if (
|
|
55
|
+
if (shouldContinueRef.current) {
|
|
56
56
|
try {
|
|
57
57
|
await Voice.start(locale, {
|
|
58
58
|
EXTRA_PARTIAL_RESULTS: enablePartialResults,
|
|
@@ -69,7 +69,7 @@ export const useVoiceRecognition = (options = {}) => {
|
|
|
69
69
|
const errorMessage = e.error?.message || 'Unknown error';
|
|
70
70
|
setError(errorMessage);
|
|
71
71
|
setIsRecording(false);
|
|
72
|
-
|
|
72
|
+
shouldContinueRef.current = false;
|
|
73
73
|
if (silenceTimerRef.current) {
|
|
74
74
|
clearTimeout(silenceTimerRef.current);
|
|
75
75
|
}
|
|
@@ -102,9 +102,14 @@ export const useVoiceRecognition = (options = {}) => {
|
|
|
102
102
|
// Reset silence timer on partial results (user is speaking)
|
|
103
103
|
if (continuous && silenceTimerRef.current) {
|
|
104
104
|
clearTimeout(silenceTimerRef.current);
|
|
105
|
-
silenceTimerRef.current = setTimeout(() => {
|
|
106
|
-
if (
|
|
107
|
-
|
|
105
|
+
silenceTimerRef.current = setTimeout(async () => {
|
|
106
|
+
if (shouldContinueRef.current) {
|
|
107
|
+
shouldContinueRef.current = false;
|
|
108
|
+
if (silenceTimerRef.current) {
|
|
109
|
+
clearTimeout(silenceTimerRef.current);
|
|
110
|
+
silenceTimerRef.current = null;
|
|
111
|
+
}
|
|
112
|
+
await Voice.stop();
|
|
108
113
|
}
|
|
109
114
|
}, maxSilenceDuration);
|
|
110
115
|
}
|
|
@@ -120,7 +125,6 @@ export const useVoiceRecognition = (options = {}) => {
|
|
|
120
125
|
onResult,
|
|
121
126
|
onError,
|
|
122
127
|
continuous,
|
|
123
|
-
shouldContinue,
|
|
124
128
|
locale,
|
|
125
129
|
maxSilenceDuration,
|
|
126
130
|
]);
|
|
@@ -132,7 +136,7 @@ export const useVoiceRecognition = (options = {}) => {
|
|
|
132
136
|
setPartialResults([]);
|
|
133
137
|
accumulatedTextRef.current = '';
|
|
134
138
|
}
|
|
135
|
-
|
|
139
|
+
shouldContinueRef.current = true;
|
|
136
140
|
// Check permission (Android only)
|
|
137
141
|
const hasPermission = await Voice.checkMicrophonePermission();
|
|
138
142
|
if (!hasPermission) {
|
|
@@ -147,9 +151,14 @@ export const useVoiceRecognition = (options = {}) => {
|
|
|
147
151
|
});
|
|
148
152
|
// Start silence timer if in continuous mode
|
|
149
153
|
if (continuous) {
|
|
150
|
-
silenceTimerRef.current = setTimeout(() => {
|
|
151
|
-
if (
|
|
152
|
-
|
|
154
|
+
silenceTimerRef.current = setTimeout(async () => {
|
|
155
|
+
if (shouldContinueRef.current) {
|
|
156
|
+
shouldContinueRef.current = false;
|
|
157
|
+
if (silenceTimerRef.current) {
|
|
158
|
+
clearTimeout(silenceTimerRef.current);
|
|
159
|
+
silenceTimerRef.current = null;
|
|
160
|
+
}
|
|
161
|
+
await Voice.stop();
|
|
153
162
|
}
|
|
154
163
|
}, maxSilenceDuration);
|
|
155
164
|
}
|
|
@@ -157,20 +166,13 @@ export const useVoiceRecognition = (options = {}) => {
|
|
|
157
166
|
catch (e) {
|
|
158
167
|
const errorMessage = e instanceof Error ? e.message : 'Failed to start recording';
|
|
159
168
|
setError(errorMessage);
|
|
160
|
-
|
|
169
|
+
shouldContinueRef.current = false;
|
|
161
170
|
onError?.(errorMessage);
|
|
162
171
|
}
|
|
163
|
-
}, [
|
|
164
|
-
locale,
|
|
165
|
-
enablePartialResults,
|
|
166
|
-
onError,
|
|
167
|
-
continuous,
|
|
168
|
-
maxSilenceDuration,
|
|
169
|
-
shouldContinue,
|
|
170
|
-
]);
|
|
172
|
+
}, [locale, enablePartialResults, onError, continuous, maxSilenceDuration]);
|
|
171
173
|
const stop = useCallback(async () => {
|
|
172
174
|
try {
|
|
173
|
-
|
|
175
|
+
shouldContinueRef.current = false;
|
|
174
176
|
if (silenceTimerRef.current) {
|
|
175
177
|
clearTimeout(silenceTimerRef.current);
|
|
176
178
|
silenceTimerRef.current = null;
|
|
@@ -185,7 +187,7 @@ export const useVoiceRecognition = (options = {}) => {
|
|
|
185
187
|
}, [onError]);
|
|
186
188
|
const cancel = useCallback(async () => {
|
|
187
189
|
try {
|
|
188
|
-
|
|
190
|
+
shouldContinueRef.current = false;
|
|
189
191
|
if (silenceTimerRef.current) {
|
|
190
192
|
clearTimeout(silenceTimerRef.current);
|
|
191
193
|
silenceTimerRef.current = null;
|
|
@@ -207,7 +209,7 @@ export const useVoiceRecognition = (options = {}) => {
|
|
|
207
209
|
setError(null);
|
|
208
210
|
setIsRecording(false);
|
|
209
211
|
accumulatedTextRef.current = '';
|
|
210
|
-
|
|
212
|
+
shouldContinueRef.current = false;
|
|
211
213
|
if (silenceTimerRef.current) {
|
|
212
214
|
clearTimeout(silenceTimerRef.current);
|
|
213
215
|
silenceTimerRef.current = null;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-voice-ts",
|
|
3
3
|
"description": "Advanced Speech-to-Text library for React Native with TypeScript support. Features ready-to-use components (VoiceMicrophone), custom hooks (useVoiceRecognition), real-time transcription, multi-language support, and comprehensive voice recognition capabilities for iOS and Android.",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.4",
|
|
5
5
|
"author": "Noor Mohammad <noor.jsdivs@gmail.com>",
|
|
6
6
|
"private": false,
|
|
7
7
|
"homepage": "https://github.com/noorjsdivs/react-native-voice-ts",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"lint:plugin": "eslint plugin/src/* --fix",
|
|
95
95
|
"clean": "rm -rf dist && rm -rf plugin/build",
|
|
96
96
|
"prepack": "yarn clean && yarn build && yarn build:plugin",
|
|
97
|
-
"test": "
|
|
97
|
+
"test": "echo \"No tests in library root. Run 'yarn --cwd example test' to test the example app.\"",
|
|
98
98
|
"validate": "yarn type-check && yarn lint:check && yarn format:check"
|
|
99
99
|
},
|
|
100
100
|
"dependencies": {
|