react-native-srschat 0.1.19 → 0.1.21

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.
Files changed (65) hide show
  1. package/README.md +1 -0
  2. package/lib/commonjs/components/email.js +1 -1
  3. package/lib/commonjs/components/email.js.map +1 -1
  4. package/lib/commonjs/components/header.js +1 -0
  5. package/lib/commonjs/components/header.js.map +1 -1
  6. package/lib/commonjs/components/input.js +2 -7
  7. package/lib/commonjs/components/input.js.map +1 -1
  8. package/lib/commonjs/components/voice.js +47 -38
  9. package/lib/commonjs/components/voice.js.map +1 -1
  10. package/lib/commonjs/components/welcomeInput.js +4 -9
  11. package/lib/commonjs/components/welcomeInput.js.map +1 -1
  12. package/lib/commonjs/contexts/AppContext.js +6 -1
  13. package/lib/commonjs/contexts/AppContext.js.map +1 -1
  14. package/lib/commonjs/layout/disclaimer.js +1 -1
  15. package/lib/commonjs/layout/disclaimer.js.map +1 -1
  16. package/lib/commonjs/layout/layout.js +8 -23
  17. package/lib/commonjs/layout/layout.js.map +1 -1
  18. package/lib/commonjs/layout/welcome.js +8 -4
  19. package/lib/commonjs/layout/welcome.js.map +1 -1
  20. package/lib/commonjs/layout/window.js +4 -4
  21. package/lib/commonjs/layout/window.js.map +1 -1
  22. package/lib/commonjs/utils/audioRecorder.js +234 -44
  23. package/lib/commonjs/utils/audioRecorder.js.map +1 -1
  24. package/lib/module/components/email.js +1 -1
  25. package/lib/module/components/email.js.map +1 -1
  26. package/lib/module/components/header.js +1 -0
  27. package/lib/module/components/header.js.map +1 -1
  28. package/lib/module/components/input.js +2 -7
  29. package/lib/module/components/input.js.map +1 -1
  30. package/lib/module/components/voice.js +51 -41
  31. package/lib/module/components/voice.js.map +1 -1
  32. package/lib/module/components/welcomeInput.js +4 -9
  33. package/lib/module/components/welcomeInput.js.map +1 -1
  34. package/lib/module/contexts/AppContext.js +6 -1
  35. package/lib/module/contexts/AppContext.js.map +1 -1
  36. package/lib/module/layout/disclaimer.js +1 -1
  37. package/lib/module/layout/disclaimer.js.map +1 -1
  38. package/lib/module/layout/layout.js +8 -23
  39. package/lib/module/layout/layout.js.map +1 -1
  40. package/lib/module/layout/welcome.js +6 -4
  41. package/lib/module/layout/welcome.js.map +1 -1
  42. package/lib/module/layout/window.js +4 -4
  43. package/lib/module/layout/window.js.map +1 -1
  44. package/lib/module/utils/audioRecorder.js +232 -45
  45. package/lib/module/utils/audioRecorder.js.map +1 -1
  46. package/lib/typescript/components/input.d.ts.map +1 -1
  47. package/lib/typescript/components/voice.d.ts.map +1 -1
  48. package/lib/typescript/components/welcomeInput.d.ts.map +1 -1
  49. package/lib/typescript/contexts/AppContext.d.ts.map +1 -1
  50. package/lib/typescript/layout/layout.d.ts.map +1 -1
  51. package/lib/typescript/layout/window.d.ts.map +1 -1
  52. package/lib/typescript/utils/audioRecorder.d.ts +6 -3
  53. package/lib/typescript/utils/audioRecorder.d.ts.map +1 -1
  54. package/package.json +5 -1
  55. package/src/components/email.js +1 -1
  56. package/src/components/header.js +1 -0
  57. package/src/components/input.js +2 -3
  58. package/src/components/voice.js +77 -50
  59. package/src/components/welcomeInput.js +6 -4
  60. package/src/contexts/AppContext.js +6 -1
  61. package/src/layout/disclaimer.js +1 -1
  62. package/src/layout/layout.js +8 -12
  63. package/src/layout/welcome.js +5 -2
  64. package/src/layout/window.js +5 -4
  65. package/src/utils/audioRecorder.js +266 -45
@@ -1,54 +1,247 @@
1
1
  // audioRecorder.js
2
- import AudioRecorderPlayer from 'react-native-audio-recorder-player';
3
- import { Platform, PermissionsAndroid } from 'react-native';
4
- import { NativeModules } from 'react-native';
5
2
 
6
- const audioRecorderPlayer = new AudioRecorderPlayer();
3
+ import { Platform, PermissionsAndroid } from 'react-native';
4
+ import Voice from '@react-native-community/voice';
5
+ import { check, PERMISSIONS, request, RESULTS } from 'react-native-permissions';
7
6
 
7
+ let resultCallback = null;
8
8
  let silenceTimer = null;
9
- let rmsValues = [];
10
- const SILENCE_RMS_THRESHOLD = 0.02;
11
- const SILENCE_LENGTH_MS = 2000;
12
-
13
- export async function startRecording(handleStopRecording) {
9
+ let isCurrentlyRecording = false;
10
+ let finalResult = '';
11
+ const SILENCE_DURATION = 1500; // 1.5 seconds of silence before stopping
14
12
 
15
- audioRecorderPlayer = new AudioRecorderPlayer();
13
+ // Initialize Voice handlers
14
+ export async function initVoice(onResult) {
15
+ try {
16
+ resultCallback = onResult;
17
+ finalResult = '';
16
18
 
17
- rmsValues = [];
18
- audioRecorderPlayer.startRecorder();
19
+ // First check if speech recognition is available
20
+ const isAvailable = await Voice.isAvailable();
21
+ if (!isAvailable) {
22
+ console.error('Speech recognition is not available on this device');
23
+ return false;
24
+ }
19
25
 
20
- audioRecorderPlayer.addRecordBackListener((e) => {
21
- const rms = Math.sqrt(
22
- e.currentMetering.reduce((sum, value) => sum + Math.pow(value / 100, 2), 0) / e.currentMetering.length
23
- );
24
- rmsValues.push(rms);
26
+ // Set up all event listeners
27
+ Voice.onSpeechStart = (e) => {
28
+ console.log('onSpeechStart: ', e);
29
+ isCurrentlyRecording = true;
30
+ finalResult = '';
31
+
32
+ if (silenceTimer) {
33
+ clearTimeout(silenceTimer);
34
+ silenceTimer = null;
35
+ }
36
+ };
37
+
38
+ Voice.onSpeechRecognized = (e) => {
39
+ console.log('onSpeechRecognized: ', e);
40
+ if (e.isFinal) {
41
+ console.log('Speech recognition final');
42
+ handleFinalResult();
43
+ }
44
+ };
25
45
 
26
- // Detect silence
27
- if (rms > SILENCE_RMS_THRESHOLD) {
46
+ Voice.onSpeechEnd = async (e) => {
47
+ console.log('onSpeechEnd: ', e);
48
+
28
49
  if (silenceTimer) {
29
50
  clearTimeout(silenceTimer);
30
51
  silenceTimer = null;
31
52
  }
32
- } else if (!silenceTimer) {
33
- silenceTimer = setTimeout(() => {
34
- handleStopRecording();
35
- }, SILENCE_LENGTH_MS);
53
+
54
+ // Only handle final result if we're still recording
55
+ if (isCurrentlyRecording) {
56
+ await handleFinalResult();
57
+ }
58
+ };
59
+
60
+ Voice.onSpeechError = async (e) => {
61
+ console.error('onSpeechError: ', e);
62
+
63
+
64
+ if (silenceTimer) {
65
+ clearTimeout(silenceTimer);
66
+ silenceTimer = null;
67
+ }
68
+
69
+
70
+ await cleanupVoiceSession();
71
+ resultCallback(null, e.error?.message || 'Speech recognition error');
72
+ };
73
+
74
+ Voice.onSpeechResults = (e) => {
75
+ console.log('onSpeechResults: ', e);
76
+ if (e.value && e.value.length > 0) {
77
+ finalResult = e.value[0];
78
+ handleSilenceDetection();
79
+ }
80
+ };
81
+
82
+ Voice.onSpeechPartialResults = (e) => {
83
+ console.log('onSpeechPartialResults: ', e);
84
+
85
+ if (silenceTimer) {
86
+ clearTimeout(silenceTimer);
87
+ }
88
+
89
+ if (e.value && e.value.length > 0) {
90
+ finalResult = e.value[0];
91
+ handleSilenceDetection();
92
+ }
93
+ };
94
+
95
+ if (Platform.OS === 'android') {
96
+ Voice.onSpeechVolumeChanged = (e) => {
97
+ console.log('onSpeechVolumeChanged: ', e);
98
+ };
36
99
  }
37
- });
38
- console.log('Recording started...');
100
+
101
+ return true;
102
+ } catch (error) {
103
+ console.error('Error initializing Voice:', error);
104
+ return false;
105
+ }
39
106
  }
40
107
 
41
- export async function stopRecording() {
42
- if (!audioRecorderPlayer) {
43
- console.error('AudioRecorderPlayer instance is null');
44
- return null;
108
+ const handleSilenceDetection = () => {
109
+ if (silenceTimer) {
110
+ clearTimeout(silenceTimer);
45
111
  }
112
+
113
+ silenceTimer = setTimeout(async () => {
114
+ if (isCurrentlyRecording) {
115
+ await handleFinalResult();
116
+ }
117
+ }, SILENCE_DURATION);
118
+ };
119
+
120
+ const handleFinalResult = async () => {
121
+ if (!isCurrentlyRecording) return;
122
+
123
+ if (finalResult) {
124
+ resultCallback(finalResult);
125
+ }
126
+
127
+ // Stop recording first
128
+ await stopRecording();
129
+
130
+ // Then clean up the session
131
+ await cleanupVoiceSession();
132
+ };
133
+
134
+ const cleanupVoiceSession = async () => {
135
+ isCurrentlyRecording = false;
136
+
46
137
  if (silenceTimer) {
47
138
  clearTimeout(silenceTimer);
139
+ silenceTimer = null;
140
+ }
141
+
142
+ try {
143
+ // First try to stop if still recognizing
144
+ const isRecognizing = await Voice.isRecognizing();
145
+ if (isRecognizing) {
146
+ try {
147
+ await Voice.stop();
148
+ await new Promise(resolve => setTimeout(resolve, 100));
149
+ } catch (e) {
150
+ console.error('Error stopping in cleanup:', e);
151
+ }
152
+ }
153
+
154
+ // Then force destroy
155
+ await Voice.destroy();
156
+ await new Promise(resolve => setTimeout(resolve, 300));
157
+
158
+ // Double check and force destroy again if needed
159
+ const stillRecognizing = await Voice.isRecognizing();
160
+ if (stillRecognizing) {
161
+ await Voice.destroy();
162
+ await new Promise(resolve => setTimeout(resolve, 300));
163
+ }
164
+ } catch (error) {
165
+ console.error('Error in cleanupVoiceSession:', error);
166
+ // Final attempt to destroy on error
167
+ try {
168
+ await Voice.destroy();
169
+ } catch (e) {
170
+ console.error('Final destroy attempt failed:', e);
171
+ }
172
+ }
173
+
174
+ finalResult = '';
175
+ };
176
+
177
+ export async function startRecording() {
178
+ try {
179
+ // Ensure cleanup of any existing session
180
+ await cleanupVoiceSession();
181
+
182
+ const hasPermission = await requestAudioPermission();
183
+ if (!hasPermission) {
184
+ console.error('No permission to record audio');
185
+ return false;
186
+ }
187
+
188
+ await Voice.start('en-US');
189
+ isCurrentlyRecording = true;
190
+ return true;
191
+ } catch (error) {
192
+ console.error('Error starting voice recognition:', error);
193
+ await cleanupVoiceSession();
194
+ return false;
195
+ }
196
+ }
197
+
198
+ export async function stopRecording() {
199
+ try {
200
+ if (!isCurrentlyRecording) return;
201
+
202
+ // Set this first to prevent race conditions
203
+ isCurrentlyRecording = false;
204
+
205
+ if (silenceTimer) {
206
+ clearTimeout(silenceTimer);
207
+ silenceTimer = null;
208
+ }
209
+
210
+ // First try to stop
211
+ try {
212
+ await Voice.stop();
213
+ // Wait a bit for stop to complete
214
+ await new Promise(resolve => setTimeout(resolve, 100));
215
+ } catch (error) {
216
+ console.error('Error stopping Voice:', error);
217
+ }
218
+
219
+ // Then force destroy
220
+ try {
221
+ await Voice.destroy();
222
+ await new Promise(resolve => setTimeout(resolve, 300));
223
+ } catch (error) {
224
+ console.error('Error destroying Voice:', error);
225
+ }
226
+
227
+ // Final cleanup
228
+ await cleanupVoiceSession();
229
+ } catch (error) {
230
+ console.error('Error in stopRecording:', error);
231
+ // Force cleanup on error
232
+ await cleanupVoiceSession();
48
233
  }
49
- const result = await audioRecorderPlayer.stopRecorder();
50
- console.log('Recording stopped:', result);
51
- return result;
234
+ }
235
+
236
+ export async function cancelRecording() {
237
+ try {
238
+ await Voice.cancel();
239
+ await cleanupVoiceSession();
240
+ } catch (error) {
241
+ console.error('Error canceling voice recognition:', error);
242
+ await cleanupVoiceSession();
243
+ }
244
+
52
245
  }
53
246
 
54
247
  export async function requestAudioPermission() {
@@ -57,16 +250,26 @@ export async function requestAudioPermission() {
57
250
  } else if (Platform.OS === 'ios') {
58
251
  return await requestIOSPermission();
59
252
  }
253
+
254
+ return false;
60
255
  }
61
256
 
62
- // ✅ Android: Request Microphone Permission
63
257
  async function requestAndroidPermission() {
64
258
  try {
259
+ // Check available speech recognition services on Android
260
+ const services = await Voice.getSpeechRecognitionServices();
261
+ if (!services || services.length === 0) {
262
+ console.error('No speech recognition services available');
263
+ return false;
264
+ }
265
+
65
266
  const granted = await PermissionsAndroid.request(
66
267
  PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
67
268
  {
68
269
  title: 'Microphone Permission',
69
- message: 'This app needs access to your microphone to record audio.',
270
+
271
+ message: 'This app needs access to your microphone for voice recognition.',
272
+
70
273
  buttonPositive: 'OK',
71
274
  buttonNegative: 'Cancel',
72
275
  }
@@ -74,26 +277,44 @@ async function requestAndroidPermission() {
74
277
 
75
278
  return granted === PermissionsAndroid.RESULTS.GRANTED;
76
279
  } catch (error) {
77
- console.error('Error requesting microphone permission:', error);
280
+ console.error('Error requesting Android permission:', error);
281
+
78
282
  return false;
79
283
  }
80
284
  }
81
285
 
82
- // ✅ iOS: Request Microphone Permission
286
+
83
287
  async function requestIOSPermission() {
84
288
  try {
85
- const { AVAudioSession } = NativeModules;
86
- if (AVAudioSession) {
87
- await AVAudioSession.requestRecordPermission((granted) => {
88
- console.log('iOS Microphone Permission:', granted);
89
- return granted;
90
- });
91
- } else {
92
- console.warn('AVAudioSession not available');
289
+ // Request microphone permission
290
+ const micPermission = await request(PERMISSIONS.IOS.MICROPHONE);
291
+ if (micPermission !== RESULTS.GRANTED) {
292
+ console.log('Microphone permission denied');
293
+ return false;
294
+ }
295
+
296
+ // Request speech recognition permission
297
+ const speechPermission = await request(PERMISSIONS.IOS.SPEECH_RECOGNITION);
298
+ if (speechPermission !== RESULTS.GRANTED) {
299
+ console.log('Speech recognition permission denied');
93
300
  return false;
94
301
  }
302
+
303
+ return true;
95
304
  } catch (error) {
96
- console.error('Error requesting microphone permission on iOS:', error);
305
+ console.error('Error requesting iOS permissions:', error);
97
306
  return false;
98
307
  }
99
308
  }
309
+
310
+ export function cleanup() {
311
+ Voice.destroy().then(() => {
312
+ Voice.removeAllListeners();
313
+ cleanupVoiceSession();
314
+ }).catch(error => {
315
+ console.error('Error in cleanup:', error);
316
+ // Try one more time
317
+ Voice.destroy().catch(e => console.error('Final cleanup attempt failed:', e));
318
+ });
319
+ }
320
+