mirror of https://github.com/laurent22/joplin.git
Android: Add support for Voice Typing for most languages (#8309)
parent
377e35b1af
commit
5841596acb
|
@ -36,7 +36,7 @@ index 6afcbbf0cc8ca2d69dd78077d61e59a90b2136bb..9f8d72b4ec5b2b3d290975d6a255917c
|
||||||
def kotlin_version = getExtOrDefault('kotlinVersion')
|
def kotlin_version = getExtOrDefault('kotlinVersion')
|
||||||
|
|
||||||
diff --git a/android/src/main/java/com/reactnativevosk/VoskModule.kt b/android/src/main/java/com/reactnativevosk/VoskModule.kt
|
diff --git a/android/src/main/java/com/reactnativevosk/VoskModule.kt b/android/src/main/java/com/reactnativevosk/VoskModule.kt
|
||||||
index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..f3da440bc2863a59db6d2d1691c54d8d4870cb3f 100644
|
index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..5a8539b9cce8951967640dba755e29a4e3ff404a 100644
|
||||||
--- a/android/src/main/java/com/reactnativevosk/VoskModule.kt
|
--- a/android/src/main/java/com/reactnativevosk/VoskModule.kt
|
||||||
+++ b/android/src/main/java/com/reactnativevosk/VoskModule.kt
|
+++ b/android/src/main/java/com/reactnativevosk/VoskModule.kt
|
||||||
@@ -19,13 +19,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
@@ -19,13 +19,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
||||||
|
@ -66,7 +66,25 @@ index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..f3da440bc2863a59db6d2d1691c54d8d
|
||||||
sendEvent("onResult", text)
|
sendEvent("onResult", text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,6 +165,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
@@ -93,12 +105,11 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
||||||
|
@ReactMethod
|
||||||
|
fun loadModel(path: String, promise: Promise) {
|
||||||
|
cleanModel();
|
||||||
|
- StorageService.unpack(context, path, "models",
|
||||||
|
- { model: Model? ->
|
||||||
|
- this.model = model
|
||||||
|
- promise.resolve("Model successfully loaded")
|
||||||
|
- }
|
||||||
|
- ) { e: IOException ->
|
||||||
|
+
|
||||||
|
+ try {
|
||||||
|
+ this.model = Model(path);
|
||||||
|
+ promise.resolve("Model successfully loaded")
|
||||||
|
+ } catch (e: IOException) {
|
||||||
|
this.model = null
|
||||||
|
promise.reject(e)
|
||||||
|
}
|
||||||
|
@@ -153,6 +164,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
||||||
cleanRecognizer();
|
cleanRecognizer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
French small model for Vosk
|
|
||||||
|
|
||||||
WER
|
|
||||||
|
|
||||||
%WER 23.95 [ 37203 / 155330, 5373 ins, 4427 del, 27403 sub ] exp/chain_a/tdnn/decode_test_cv/wer_12_0.0
|
|
||||||
%WER 19.30 [ 2975 / 15412, 683 ins, 672 del, 1620 sub ] exp/chain_a/tdnn/decode_test_mtedx/wer_10_0.0
|
|
||||||
%WER 27.25 [ 20208 / 74145, 2647 ins, 5852 del, 11709 sub ] exp/chain_a/tdnn/decode_test_podcast_reseg/wer_10_0.0
|
|
Binary file not shown.
|
@ -1,8 +0,0 @@
|
||||||
--use-energy=false
|
|
||||||
--sample-frequency=16000
|
|
||||||
--num-mel-bins=40
|
|
||||||
--num-ceps=40
|
|
||||||
--low-freq=40
|
|
||||||
--high-freq=-200
|
|
||||||
--allow-upsample=true
|
|
||||||
--allow-downsample=true
|
|
|
@ -1,10 +0,0 @@
|
||||||
--min-active=200
|
|
||||||
--max-active=7000
|
|
||||||
--beam=13.0
|
|
||||||
--lattice-beam=4.0
|
|
||||||
--acoustic-scale=1.0
|
|
||||||
--frame-subsampling-factor=3
|
|
||||||
--endpoint.silence-phones=1:2:3:4:5:6:7:8:9:10
|
|
||||||
--endpoint.rule2.min-trailing-silence=0.5
|
|
||||||
--endpoint.rule3.min-trailing-silence=1.0
|
|
||||||
--endpoint.rule4.min-trailing-silence=2.0
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,76 +0,0 @@
|
||||||
9365
|
|
||||||
9366
|
|
||||||
9367
|
|
||||||
9368
|
|
||||||
9369
|
|
||||||
9370
|
|
||||||
9371
|
|
||||||
9372
|
|
||||||
9373
|
|
||||||
9374
|
|
||||||
9375
|
|
||||||
9376
|
|
||||||
9377
|
|
||||||
9378
|
|
||||||
9379
|
|
||||||
9380
|
|
||||||
9381
|
|
||||||
9382
|
|
||||||
9383
|
|
||||||
9384
|
|
||||||
9385
|
|
||||||
9386
|
|
||||||
9387
|
|
||||||
9388
|
|
||||||
9389
|
|
||||||
9390
|
|
||||||
9391
|
|
||||||
9392
|
|
||||||
9393
|
|
||||||
9394
|
|
||||||
9395
|
|
||||||
9396
|
|
||||||
9397
|
|
||||||
9398
|
|
||||||
9399
|
|
||||||
9400
|
|
||||||
9401
|
|
||||||
9402
|
|
||||||
9403
|
|
||||||
9404
|
|
||||||
9405
|
|
||||||
9406
|
|
||||||
9407
|
|
||||||
9408
|
|
||||||
9409
|
|
||||||
9410
|
|
||||||
9411
|
|
||||||
9412
|
|
||||||
9413
|
|
||||||
9414
|
|
||||||
9415
|
|
||||||
9416
|
|
||||||
9417
|
|
||||||
9418
|
|
||||||
9419
|
|
||||||
9420
|
|
||||||
9421
|
|
||||||
9422
|
|
||||||
9423
|
|
||||||
9424
|
|
||||||
9425
|
|
||||||
9426
|
|
||||||
9427
|
|
||||||
9428
|
|
||||||
9429
|
|
||||||
9430
|
|
||||||
9431
|
|
||||||
9432
|
|
||||||
9433
|
|
||||||
9434
|
|
||||||
9435
|
|
||||||
9436
|
|
||||||
9437
|
|
||||||
9438
|
|
||||||
9439
|
|
||||||
9440
|
|
|
@ -1,154 +0,0 @@
|
||||||
1 nonword
|
|
||||||
2 begin
|
|
||||||
3 end
|
|
||||||
4 internal
|
|
||||||
5 singleton
|
|
||||||
6 nonword
|
|
||||||
7 begin
|
|
||||||
8 end
|
|
||||||
9 internal
|
|
||||||
10 singleton
|
|
||||||
11 begin
|
|
||||||
12 end
|
|
||||||
13 internal
|
|
||||||
14 singleton
|
|
||||||
15 begin
|
|
||||||
16 end
|
|
||||||
17 internal
|
|
||||||
18 singleton
|
|
||||||
19 begin
|
|
||||||
20 end
|
|
||||||
21 internal
|
|
||||||
22 singleton
|
|
||||||
23 begin
|
|
||||||
24 end
|
|
||||||
25 internal
|
|
||||||
26 singleton
|
|
||||||
27 begin
|
|
||||||
28 end
|
|
||||||
29 internal
|
|
||||||
30 singleton
|
|
||||||
31 begin
|
|
||||||
32 end
|
|
||||||
33 internal
|
|
||||||
34 singleton
|
|
||||||
35 begin
|
|
||||||
36 end
|
|
||||||
37 internal
|
|
||||||
38 singleton
|
|
||||||
39 begin
|
|
||||||
40 end
|
|
||||||
41 internal
|
|
||||||
42 singleton
|
|
||||||
43 begin
|
|
||||||
44 end
|
|
||||||
45 internal
|
|
||||||
46 singleton
|
|
||||||
47 begin
|
|
||||||
48 end
|
|
||||||
49 internal
|
|
||||||
50 singleton
|
|
||||||
51 begin
|
|
||||||
52 end
|
|
||||||
53 internal
|
|
||||||
54 singleton
|
|
||||||
55 begin
|
|
||||||
56 end
|
|
||||||
57 internal
|
|
||||||
58 singleton
|
|
||||||
59 begin
|
|
||||||
60 end
|
|
||||||
61 internal
|
|
||||||
62 singleton
|
|
||||||
63 begin
|
|
||||||
64 end
|
|
||||||
65 internal
|
|
||||||
66 singleton
|
|
||||||
67 begin
|
|
||||||
68 end
|
|
||||||
69 internal
|
|
||||||
70 singleton
|
|
||||||
71 begin
|
|
||||||
72 end
|
|
||||||
73 internal
|
|
||||||
74 singleton
|
|
||||||
75 begin
|
|
||||||
76 end
|
|
||||||
77 internal
|
|
||||||
78 singleton
|
|
||||||
79 begin
|
|
||||||
80 end
|
|
||||||
81 internal
|
|
||||||
82 singleton
|
|
||||||
83 begin
|
|
||||||
84 end
|
|
||||||
85 internal
|
|
||||||
86 singleton
|
|
||||||
87 begin
|
|
||||||
88 end
|
|
||||||
89 internal
|
|
||||||
90 singleton
|
|
||||||
91 begin
|
|
||||||
92 end
|
|
||||||
93 internal
|
|
||||||
94 singleton
|
|
||||||
95 begin
|
|
||||||
96 end
|
|
||||||
97 internal
|
|
||||||
98 singleton
|
|
||||||
99 begin
|
|
||||||
100 end
|
|
||||||
101 internal
|
|
||||||
102 singleton
|
|
||||||
103 begin
|
|
||||||
104 end
|
|
||||||
105 internal
|
|
||||||
106 singleton
|
|
||||||
107 begin
|
|
||||||
108 end
|
|
||||||
109 internal
|
|
||||||
110 singleton
|
|
||||||
111 begin
|
|
||||||
112 end
|
|
||||||
113 internal
|
|
||||||
114 singleton
|
|
||||||
115 begin
|
|
||||||
116 end
|
|
||||||
117 internal
|
|
||||||
118 singleton
|
|
||||||
119 begin
|
|
||||||
120 end
|
|
||||||
121 internal
|
|
||||||
122 singleton
|
|
||||||
123 begin
|
|
||||||
124 end
|
|
||||||
125 internal
|
|
||||||
126 singleton
|
|
||||||
127 begin
|
|
||||||
128 end
|
|
||||||
129 internal
|
|
||||||
130 singleton
|
|
||||||
131 begin
|
|
||||||
132 end
|
|
||||||
133 internal
|
|
||||||
134 singleton
|
|
||||||
135 begin
|
|
||||||
136 end
|
|
||||||
137 internal
|
|
||||||
138 singleton
|
|
||||||
139 begin
|
|
||||||
140 end
|
|
||||||
141 internal
|
|
||||||
142 singleton
|
|
||||||
143 begin
|
|
||||||
144 end
|
|
||||||
145 internal
|
|
||||||
146 singleton
|
|
||||||
147 begin
|
|
||||||
148 end
|
|
||||||
149 internal
|
|
||||||
150 singleton
|
|
||||||
151 begin
|
|
||||||
152 end
|
|
||||||
153 internal
|
|
||||||
154 singleton
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,3 +0,0 @@
|
||||||
[
|
|
||||||
1.022245e+11 -6.33291e+09 -2.480997e+09 8.290258e+09 -9.084483e+09 -8.092173e+09 -1.4735e+10 -7.041795e+09 -1.171205e+10 -2.976464e+08 -1.009425e+10 -6765179 -7.821326e+09 1.449499e+09 -6.413975e+09 -5.303802e+08 -4.998635e+09 9.521598e+07 -3.073041e+09 1.56756e+08 -1.287956e+09 1.738752e+08 -2.382392e+08 -2.716675e+07 4.404485e+08 -1.913359e+08 7.780919e+08 -4.006922e+08 7.895809e+08 -5.401082e+08 5.17605e+08 -6.227134e+08 6.58271e+08 -6.204593e+07 5.187754e+08 -4.497048e+08 4.219366e+07 -2.78742e+08 -1.797385e+07 -3.604475e+07 1.053647e+09
|
|
||||||
1.040194e+13 6.245521e+11 4.223293e+11 6.831219e+11 6.078478e+11 6.3425e+11 7.943839e+11 6.013323e+11 6.781652e+11 5.272091e+11 5.810814e+11 4.353831e+11 4.473305e+11 3.42063e+11 3.083377e+11 2.14257e+11 1.892057e+11 1.163827e+11 8.367058e+10 4.203224e+10 2.297476e+10 7.596307e+09 1.099877e+09 2.886651e+08 3.797438e+09 9.372847e+09 1.629059e+10 2.196351e+10 2.747149e+10 3.072878e+10 3.238528e+10 3.330232e+10 3.407238e+10 3.230687e+10 2.676914e+10 2.252055e+10 1.914305e+10 1.565974e+10 1.224627e+10 8.415393e+09 0 ]
|
|
|
@ -1,2 +0,0 @@
|
||||||
--left-context=3
|
|
||||||
--right-context=3
|
|
|
@ -1 +0,0 @@
|
||||||
1b7180e6-e500-4818-adc8-a41fe97a84ce
|
|
|
@ -46,6 +46,7 @@ import { NoteEntity } from '@joplin/lib/services/database/types';
|
||||||
import Logger from '@joplin/lib/Logger';
|
import Logger from '@joplin/lib/Logger';
|
||||||
import VoiceTypingDialog from '../voiceTyping/VoiceTypingDialog';
|
import VoiceTypingDialog from '../voiceTyping/VoiceTypingDialog';
|
||||||
import { voskEnabled } from '../../services/voiceTyping/vosk';
|
import { voskEnabled } from '../../services/voiceTyping/vosk';
|
||||||
|
import { isSupportedLanguage } from '../../services/voiceTyping/vosk.android';
|
||||||
const urlUtils = require('@joplin/lib/urlUtils');
|
const urlUtils = require('@joplin/lib/urlUtils');
|
||||||
|
|
||||||
// import Vosk from 'react-native-vosk';
|
// import Vosk from 'react-native-vosk';
|
||||||
|
@ -988,7 +989,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Voice typing is enabled only for French language and on Android for now
|
// Voice typing is enabled only for French language and on Android for now
|
||||||
if (voskEnabled && shim.mobilePlatform() === 'android' && currentLocale() === 'fr_FR') {
|
if (voskEnabled && shim.mobilePlatform() === 'android' && isSupportedLanguage(currentLocale())) {
|
||||||
output.push({
|
output.push({
|
||||||
title: _('Voice typing...'),
|
title: _('Voice typing...'),
|
||||||
onPress: () => {
|
onPress: () => {
|
||||||
|
@ -1295,7 +1296,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||||
|
|
||||||
const renderVoiceTypingDialog = () => {
|
const renderVoiceTypingDialog = () => {
|
||||||
if (!this.state.voiceTypingDialogShown) return null;
|
if (!this.state.voiceTypingDialogShown) return null;
|
||||||
return <VoiceTypingDialog onText={this.voiceTypingDialog_onText} onDismiss={this.voiceTypingDialog_onDismiss}/>;
|
return <VoiceTypingDialog locale={currentLocale()} onText={this.voiceTypingDialog_onText} onDismiss={this.voiceTypingDialog_onDismiss}/>;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { Banner, ActivityIndicator } from 'react-native-paper';
|
import { Banner, ActivityIndicator, Modal } from 'react-native-paper';
|
||||||
import { _ } from '@joplin/lib/locale';
|
import { _, languageName } from '@joplin/lib/locale';
|
||||||
import useAsyncEffect, { AsyncEffectEvent } from '@joplin/lib/hooks/useAsyncEffect';
|
import useAsyncEffect, { AsyncEffectEvent } from '@joplin/lib/hooks/useAsyncEffect';
|
||||||
import { getVosk, Recorder, startRecording, Vosk } from '../../services/voiceTyping/vosk';
|
import { getVosk, Recorder, startRecording, Vosk } from '../../services/voiceTyping/vosk';
|
||||||
import { IconSource } from 'react-native-paper/lib/typescript/src/components/Icon';
|
import { IconSource } from 'react-native-paper/lib/typescript/src/components/Icon';
|
||||||
|
import { modelIsDownloaded } from '../../services/voiceTyping/vosk.android';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
locale: string;
|
||||||
onDismiss: ()=> void;
|
onDismiss: ()=> void;
|
||||||
onText: (text: string)=> void;
|
onText: (text: string)=> void;
|
||||||
}
|
}
|
||||||
|
@ -16,30 +18,39 @@ enum RecorderState {
|
||||||
Recording = 2,
|
Recording = 2,
|
||||||
Processing = 3,
|
Processing = 3,
|
||||||
Error = 4,
|
Error = 4,
|
||||||
|
Downloading = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
const useVosk = (): [Error | null, Vosk|null] => {
|
const useVosk = (locale: string): [Error | null, boolean, Vosk|null] => {
|
||||||
const [vosk, setVosk] = useState<Vosk>(null);
|
const [vosk, setVosk] = useState<Vosk>(null);
|
||||||
const [error, setError] = useState<Error>(null);
|
const [error, setError] = useState<Error>(null);
|
||||||
|
const [mustDownloadModel, setMustDownloadModel] = useState<boolean | null>(null);
|
||||||
|
|
||||||
useAsyncEffect(async (event: AsyncEffectEvent) => {
|
useAsyncEffect(async (event: AsyncEffectEvent) => {
|
||||||
|
if (mustDownloadModel === null) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const v = await getVosk();
|
const v = await getVosk(locale);
|
||||||
if (event.cancelled) return;
|
if (event.cancelled) return;
|
||||||
setVosk(v);
|
setVosk(v);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setError(error);
|
setError(error);
|
||||||
|
} finally {
|
||||||
|
setMustDownloadModel(false);
|
||||||
}
|
}
|
||||||
}, []);
|
}, [locale, mustDownloadModel]);
|
||||||
|
|
||||||
return [error, vosk];
|
useAsyncEffect(async (_event: AsyncEffectEvent) => {
|
||||||
|
setMustDownloadModel(!(await modelIsDownloaded(locale)));
|
||||||
|
}, [locale]);
|
||||||
|
|
||||||
|
return [error, mustDownloadModel, vosk];
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (props: Props) => {
|
export default (props: Props) => {
|
||||||
const [recorder, setRecorder] = useState<Recorder>(null);
|
const [recorder, setRecorder] = useState<Recorder>(null);
|
||||||
const [recorderState, setRecorderState] = useState<RecorderState>(RecorderState.Loading);
|
const [recorderState, setRecorderState] = useState<RecorderState>(RecorderState.Loading);
|
||||||
|
const [voskError, mustDownloadModel, vosk] = useVosk(props.locale);
|
||||||
const [voskError, vosk] = useVosk();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (voskError) {
|
if (voskError) {
|
||||||
|
@ -49,6 +60,12 @@ export default (props: Props) => {
|
||||||
}
|
}
|
||||||
}, [vosk, voskError]);
|
}, [vosk, voskError]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (mustDownloadModel) {
|
||||||
|
setRecorderState(RecorderState.Downloading);
|
||||||
|
}
|
||||||
|
}, [mustDownloadModel]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (recorderState === RecorderState.Recording) {
|
if (recorderState === RecorderState.Recording) {
|
||||||
setRecorder(startRecording(vosk, {
|
setRecorder(startRecording(vosk, {
|
||||||
|
@ -60,7 +77,7 @@ export default (props: Props) => {
|
||||||
}, [recorderState, vosk, props.onText]);
|
}, [recorderState, vosk, props.onText]);
|
||||||
|
|
||||||
const onDismiss = useCallback(() => {
|
const onDismiss = useCallback(() => {
|
||||||
recorder.cleanup();
|
if (recorder) recorder.cleanup();
|
||||||
props.onDismiss();
|
props.onDismiss();
|
||||||
}, [recorder, props.onDismiss]);
|
}, [recorder, props.onDismiss]);
|
||||||
|
|
||||||
|
@ -69,6 +86,7 @@ export default (props: Props) => {
|
||||||
[RecorderState.Loading]: () => _('Loading...'),
|
[RecorderState.Loading]: () => _('Loading...'),
|
||||||
[RecorderState.Recording]: () => _('Please record your voice...'),
|
[RecorderState.Recording]: () => _('Please record your voice...'),
|
||||||
[RecorderState.Processing]: () => _('Converting speech to text...'),
|
[RecorderState.Processing]: () => _('Converting speech to text...'),
|
||||||
|
[RecorderState.Downloading]: () => _('Downloading %s language files...', languageName(props.locale)),
|
||||||
[RecorderState.Error]: () => _('Error: %s', voskError.message),
|
[RecorderState.Error]: () => _('Error: %s', voskError.message),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,6 +98,7 @@ export default (props: Props) => {
|
||||||
[RecorderState.Loading]: ({ size }: { size: number }) => <ActivityIndicator animating={true} style={{ width: size, height: size }} />,
|
[RecorderState.Loading]: ({ size }: { size: number }) => <ActivityIndicator animating={true} style={{ width: size, height: size }} />,
|
||||||
[RecorderState.Recording]: 'microphone',
|
[RecorderState.Recording]: 'microphone',
|
||||||
[RecorderState.Processing]: 'microphone',
|
[RecorderState.Processing]: 'microphone',
|
||||||
|
[RecorderState.Downloading]: ({ size }: { size: number }) => <ActivityIndicator animating={true} style={{ width: size, height: size }} />,
|
||||||
[RecorderState.Error]: 'alert-circle-outline',
|
[RecorderState.Error]: 'alert-circle-outline',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,16 +106,18 @@ export default (props: Props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Banner
|
<Modal visible={true} style={{ display: 'flex', flexDirection: 'column', justifyContent: 'flex-end' }}>
|
||||||
visible={true}
|
<Banner
|
||||||
icon={renderIcon()}
|
visible={true}
|
||||||
actions={[
|
icon={renderIcon()}
|
||||||
{
|
actions={[
|
||||||
label: _('Done'),
|
{
|
||||||
onPress: onDismiss,
|
label: _('Done'),
|
||||||
},
|
onPress: onDismiss,
|
||||||
]}>
|
},
|
||||||
{`${_('Voice typing...')}\n${renderContent()}`}
|
]}>
|
||||||
</Banner>
|
{`${_('Voice typing...')}\n${renderContent()}`}
|
||||||
|
</Banner>
|
||||||
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -402,7 +402,7 @@ PODS:
|
||||||
- React-Core
|
- React-Core
|
||||||
- RNCPushNotificationIOS (1.11.0):
|
- RNCPushNotificationIOS (1.11.0):
|
||||||
- React-Core
|
- React-Core
|
||||||
- RNDateTimePicker (7.0.0):
|
- RNDateTimePicker (7.0.1):
|
||||||
- React-Core
|
- React-Core
|
||||||
- RNExitApp (1.1.0):
|
- RNExitApp (1.1.0):
|
||||||
- React
|
- React
|
||||||
|
@ -420,7 +420,15 @@ PODS:
|
||||||
- React-Core
|
- React-Core
|
||||||
- RNVectorIcons (9.2.0):
|
- RNVectorIcons (9.2.0):
|
||||||
- React-Core
|
- React-Core
|
||||||
|
- RNZipArchive (6.0.9):
|
||||||
|
- React-Core
|
||||||
|
- RNZipArchive/Core (= 6.0.9)
|
||||||
|
- SSZipArchive (~> 2.2)
|
||||||
|
- RNZipArchive/Core (6.0.9):
|
||||||
|
- React-Core
|
||||||
|
- SSZipArchive (~> 2.2)
|
||||||
- SocketRocket (0.6.0)
|
- SocketRocket (0.6.0)
|
||||||
|
- SSZipArchive (2.4.3)
|
||||||
- Yoga (1.14.0)
|
- Yoga (1.14.0)
|
||||||
- YogaKit (1.18.1):
|
- YogaKit (1.18.1):
|
||||||
- Yoga (~> 1.14)
|
- Yoga (~> 1.14)
|
||||||
|
@ -511,6 +519,7 @@ DEPENDENCIES:
|
||||||
- RNSecureRandom (from `../node_modules/react-native-securerandom`)
|
- RNSecureRandom (from `../node_modules/react-native-securerandom`)
|
||||||
- RNShare (from `../node_modules/react-native-share`)
|
- RNShare (from `../node_modules/react-native-share`)
|
||||||
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
|
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
|
||||||
|
- RNZipArchive (from `../node_modules/react-native-zip-archive`)
|
||||||
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
|
@ -529,6 +538,7 @@ SPEC REPOS:
|
||||||
- libevent
|
- libevent
|
||||||
- OpenSSL-Universal
|
- OpenSSL-Universal
|
||||||
- SocketRocket
|
- SocketRocket
|
||||||
|
- SSZipArchive
|
||||||
- YogaKit
|
- YogaKit
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
|
@ -654,6 +664,8 @@ EXTERNAL SOURCES:
|
||||||
:path: "../node_modules/react-native-share"
|
:path: "../node_modules/react-native-share"
|
||||||
RNVectorIcons:
|
RNVectorIcons:
|
||||||
:path: "../node_modules/react-native-vector-icons"
|
:path: "../node_modules/react-native-vector-icons"
|
||||||
|
RNZipArchive:
|
||||||
|
:path: "../node_modules/react-native-zip-archive"
|
||||||
Yoga:
|
Yoga:
|
||||||
:path: "../node_modules/react-native/ReactCommon/yoga"
|
:path: "../node_modules/react-native/ReactCommon/yoga"
|
||||||
|
|
||||||
|
@ -679,6 +691,7 @@ SPEC CHECKSUMS:
|
||||||
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
||||||
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
|
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
|
||||||
RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
|
RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
|
||||||
|
<<<<<<< HEAD
|
||||||
RCTRequired: e1866f61af7049eb3d8e08e8b133abd38bc1ca7a
|
RCTRequired: e1866f61af7049eb3d8e08e8b133abd38bc1ca7a
|
||||||
RCTTypeSafety: 27c2ac1b00609a432ced1ae701247593f07f901e
|
RCTTypeSafety: 27c2ac1b00609a432ced1ae701247593f07f901e
|
||||||
React: bb3e06418d2cc48a84f9666a576c7b38e89cd7db
|
React: bb3e06418d2cc48a84f9666a576c7b38e89cd7db
|
||||||
|
@ -692,6 +705,21 @@ SPEC CHECKSUMS:
|
||||||
React-jsiexecutor: b4a65947391c658450151275aa406f2b8263178f
|
React-jsiexecutor: b4a65947391c658450151275aa406f2b8263178f
|
||||||
React-jsinspector: 60769e5a0a6d4b32294a2456077f59d0266f9a8b
|
React-jsinspector: 60769e5a0a6d4b32294a2456077f59d0266f9a8b
|
||||||
React-logger: 1623c216abaa88974afce404dc8f479406bbc3a0
|
React-logger: 1623c216abaa88974afce404dc8f479406bbc3a0
|
||||||
|
=======
|
||||||
|
RCTRequired: 8ef706f91e2b643cd32c26a57700b5f24fab0585
|
||||||
|
RCTTypeSafety: 5fbddd8eb9242b91ac0d901c01da3673f358b1b7
|
||||||
|
React: e5d2d559e89d256a1d6da64d51adaecda9c8ddae
|
||||||
|
React-callinvoker: 352ecbafbdccca5fdf4aed99c98ae5b7fc28e39b
|
||||||
|
React-Codegen: fa660a71e24078b2e52a62ecc2f3048c2f8ae6d7
|
||||||
|
React-Core: 4ec45c2d537fe58e6d878bec6a13e3e2bed9c182
|
||||||
|
React-CoreModules: 63f7f9fda3d4b214040a80e3f47ab4fb9a3e88e6
|
||||||
|
React-cxxreact: 1a729807190ebf98ce5fb0c3d2ed211e8b5f2f87
|
||||||
|
React-hermes: eb93eb6e7921ecd4abcc6e741b327f40763e850f
|
||||||
|
React-jsi: 1995961abdff0c9af9aae8a6b24468f21811000e
|
||||||
|
React-jsiexecutor: 4bb480a183a354e4dbfb1012936b1a2bb9357de7
|
||||||
|
React-jsinspector: cdc854f8b13abd202afa54bc12578e5afb9cfae1
|
||||||
|
React-logger: ef2269b3afa6ba868da90496c3e17a4ec4f4cee0
|
||||||
|
>>>>>>> 13cda9a72 (Android: Add support for Voice Typing for most languages (#8309))
|
||||||
react-native-alarm-notification: 26527410a6162d07a9dc57f4bbc62e94ff48e65d
|
react-native-alarm-notification: 26527410a6162d07a9dc57f4bbc62e94ff48e65d
|
||||||
react-native-camera: 3eae183c1d111103963f3dd913b65d01aef8110f
|
react-native-camera: 3eae183c1d111103963f3dd913b65d01aef8110f
|
||||||
react-native-document-picker: 69ca2094d8780cfc1e7e613894d15290fdc54bba
|
react-native-document-picker: 69ca2094d8780cfc1e7e613894d15290fdc54bba
|
||||||
|
@ -723,7 +751,7 @@ SPEC CHECKSUMS:
|
||||||
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
|
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
|
||||||
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
|
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
|
||||||
RNCPushNotificationIOS: 64218f3c776c03d7408284a819b2abfda1834bc8
|
RNCPushNotificationIOS: 64218f3c776c03d7408284a819b2abfda1834bc8
|
||||||
RNDateTimePicker: 66cb21772d462d02efc6826adac37f1fd40984cf
|
RNDateTimePicker: e073697ac3e8a378968d68ab0581fef542b8af8a
|
||||||
RNExitApp: c4e052df2568b43bec8a37c7cd61194d4cfee2c3
|
RNExitApp: c4e052df2568b43bec8a37c7cd61194d4cfee2c3
|
||||||
RNFileViewer: ce7ca3ac370e18554d35d6355cffd7c30437c592
|
RNFileViewer: ce7ca3ac370e18554d35d6355cffd7c30437c592
|
||||||
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
|
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
|
||||||
|
@ -732,8 +760,14 @@ SPEC CHECKSUMS:
|
||||||
RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef
|
RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef
|
||||||
RNShare: d82e10f6b7677f4b0048c23709bd04098d5aee6c
|
RNShare: d82e10f6b7677f4b0048c23709bd04098d5aee6c
|
||||||
RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8
|
RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8
|
||||||
|
RNZipArchive: 68a0c6db4b1c103f846f1559622050df254a3ade
|
||||||
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
|
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
|
||||||
|
<<<<<<< HEAD
|
||||||
Yoga: 99caf8d5ab45e9d637ee6e0174ec16fbbb01bcfc
|
Yoga: 99caf8d5ab45e9d637ee6e0174ec16fbbb01bcfc
|
||||||
|
=======
|
||||||
|
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
|
||||||
|
Yoga: e7ea9e590e27460d28911403b894722354d73479
|
||||||
|
>>>>>>> 13cda9a72 (Android: Add support for Voice Typing for most languages (#8309))
|
||||||
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
||||||
|
|
||||||
PODFILE CHECKSUM: 0235ffbfa2e655de806a80d996148182dd493d8d
|
PODFILE CHECKSUM: 0235ffbfa2e655de806a80d996148182dd493d8d
|
||||||
|
|
|
@ -69,6 +69,7 @@
|
||||||
"react-native-version-info": "1.1.1",
|
"react-native-version-info": "1.1.1",
|
||||||
"react-native-vosk": "0.1.12",
|
"react-native-vosk": "0.1.12",
|
||||||
"react-native-webview": "11.26.1",
|
"react-native-webview": "11.26.1",
|
||||||
|
"react-native-zip-archive": "6.0.9",
|
||||||
"react-redux": "7.2.9",
|
"react-redux": "7.2.9",
|
||||||
"redux": "4.2.1",
|
"redux": "4.2.1",
|
||||||
"rn-fetch-blob": "0.12.0",
|
"rn-fetch-blob": "0.12.0",
|
||||||
|
|
|
@ -1,17 +1,25 @@
|
||||||
|
import { languageCodeOnly } from '@joplin/lib/locale';
|
||||||
import Logger from '@joplin/lib/Logger';
|
import Logger from '@joplin/lib/Logger';
|
||||||
|
import shim from '@joplin/lib/shim';
|
||||||
import Vosk from 'react-native-vosk';
|
import Vosk from 'react-native-vosk';
|
||||||
|
import { unzip } from 'react-native-zip-archive';
|
||||||
|
import RNFetchBlob from 'rn-fetch-blob';
|
||||||
|
const md5 = require('md5');
|
||||||
|
|
||||||
const logger = Logger.create('voiceTyping/vosk');
|
const logger = Logger.create('voiceTyping/vosk');
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
Idle = 0,
|
Idle = 0,
|
||||||
Recording,
|
Recording,
|
||||||
|
Completing,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StartOptions {
|
interface StartOptions {
|
||||||
onResult: (text: string)=> void;
|
onResult: (text: string)=> void;
|
||||||
}
|
}
|
||||||
|
|
||||||
let vosk_: Vosk|null = null;
|
let vosk_: Record<string, Vosk> = {};
|
||||||
|
|
||||||
let state_: State = State.Idle;
|
let state_: State = State.Idle;
|
||||||
|
|
||||||
export const voskEnabled = true;
|
export const voskEnabled = true;
|
||||||
|
@ -23,11 +31,113 @@ export interface Recorder {
|
||||||
cleanup: ()=> void;
|
cleanup: ()=> void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getVosk = async () => {
|
const supportedLanguages = {
|
||||||
if (vosk_) return vosk_;
|
'en': 'https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip',
|
||||||
vosk_ = new Vosk();
|
'cn': 'https://alphacephei.com/vosk/models/vosk-model-small-cn-0.22.zip',
|
||||||
await vosk_.loadModel('model-fr-fr');
|
'ru': 'https://alphacephei.com/vosk/models/vosk-model-small-ru-0.22.zip',
|
||||||
return vosk_;
|
'fr': 'https://alphacephei.com/vosk/models/vosk-model-small-fr-0.22.zip',
|
||||||
|
'de': 'https://alphacephei.com/vosk/models/vosk-model-small-de-0.15.zip',
|
||||||
|
'es': 'https://alphacephei.com/vosk/models/vosk-model-small-es-0.42.zip',
|
||||||
|
'pt': 'https://alphacephei.com/vosk/models/vosk-model-small-pt-0.3.zip',
|
||||||
|
'tr': 'https://alphacephei.com/vosk/models/vosk-model-small-tr-0.3.zip',
|
||||||
|
'vn': 'https://alphacephei.com/vosk/models/vosk-model-small-vn-0.4.zip',
|
||||||
|
'it': 'https://alphacephei.com/vosk/models/vosk-model-small-it-0.22.zip',
|
||||||
|
'nl': 'https://alphacephei.com/vosk/models/vosk-model-small-nl-0.22.zip',
|
||||||
|
'uk': 'https://alphacephei.com/vosk/models/vosk-model-small-uk-v3-small.zip',
|
||||||
|
'ja': 'https://alphacephei.com/vosk/models/vosk-model-small-ja-0.22.zip',
|
||||||
|
'hi': 'https://alphacephei.com/vosk/models/vosk-model-small-hi-0.22.zip',
|
||||||
|
'cs': 'https://alphacephei.com/vosk/models/vosk-model-small-cs-0.4-rhasspy.zip',
|
||||||
|
'pl': 'https://alphacephei.com/vosk/models/vosk-model-small-pl-0.22.zip',
|
||||||
|
'uz': 'https://alphacephei.com/vosk/models/vosk-model-small-uz-0.22.zip',
|
||||||
|
'ko': 'https://alphacephei.com/vosk/models/vosk-model-small-ko-0.22.zip',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isSupportedLanguage = (locale: string) => {
|
||||||
|
const l = languageCodeOnly(locale).toLowerCase();
|
||||||
|
return Object.keys(supportedLanguages).includes(l);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Where all the models files for all the languages are
|
||||||
|
const getModelRootDir = () => {
|
||||||
|
return `${RNFetchBlob.fs.dirs.DocumentDir}/vosk-models`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Where we unzip a model after downloading it
|
||||||
|
const getUnzipDir = (locale: string) => {
|
||||||
|
return `${getModelRootDir()}/${locale}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Where the model for a particular language is
|
||||||
|
const getModelDir = (locale: string) => {
|
||||||
|
return `${getUnzipDir(locale)}/model`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const languageModelUrl = (locale: string) => {
|
||||||
|
const l = languageCodeOnly(locale).toLowerCase();
|
||||||
|
if (!(l in supportedLanguages)) throw new Error(`No language file for: ${locale}`);
|
||||||
|
return (supportedLanguages as any)[l];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const modelIsDownloaded = async (locale: string) => {
|
||||||
|
const uuidFile = `${getModelDir(locale)}/uuid`;
|
||||||
|
return shim.fsDriver().exists(uuidFile);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getVosk = async (locale: string) => {
|
||||||
|
if (vosk_[locale]) return vosk_[locale];
|
||||||
|
|
||||||
|
const vosk = new Vosk();
|
||||||
|
const modelDir = await downloadModel(locale);
|
||||||
|
logger.info(`Loading model from ${modelDir}`);
|
||||||
|
await shim.fsDriver().readDirStats(modelDir);
|
||||||
|
const result = await vosk.loadModel(modelDir);
|
||||||
|
logger.info('getVosk:', result);
|
||||||
|
|
||||||
|
vosk_ = { [locale]: vosk };
|
||||||
|
|
||||||
|
return vosk;
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadModel = async (locale: string) => {
|
||||||
|
const modelUrl = languageModelUrl(locale);
|
||||||
|
const unzipDir = getUnzipDir(locale);
|
||||||
|
const zipFilePath = `${unzipDir}.zip`;
|
||||||
|
const modelDir = getModelDir(locale);
|
||||||
|
const uuidFile = `${modelDir}/uuid`;
|
||||||
|
|
||||||
|
if (await modelIsDownloaded(locale)) {
|
||||||
|
logger.info(`Model for ${locale} already exists at ${modelDir}`);
|
||||||
|
return modelDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
await shim.fsDriver().remove(unzipDir);
|
||||||
|
|
||||||
|
logger.info(`Downloading model from: ${modelUrl}`);
|
||||||
|
|
||||||
|
await shim.fetchBlob(languageModelUrl(locale), {
|
||||||
|
path: zipFilePath,
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info(`Unzipping ${zipFilePath} => ${unzipDir}`);
|
||||||
|
|
||||||
|
await unzip(zipFilePath, unzipDir);
|
||||||
|
|
||||||
|
const dirs = await shim.fsDriver().readDirStats(unzipDir);
|
||||||
|
if (dirs.length !== 1) {
|
||||||
|
logger.error('Expected 1 directory but got', dirs);
|
||||||
|
throw new Error(`Expected 1 directory, but got ${dirs.length}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fullUnzipPath = `${unzipDir}/${dirs[0].path}`;
|
||||||
|
|
||||||
|
logger.info(`Moving ${fullUnzipPath} => ${modelDir}`);
|
||||||
|
await shim.fsDriver().rename(fullUnzipPath, modelDir);
|
||||||
|
|
||||||
|
await shim.fsDriver().writeFile(uuidFile, md5(modelUrl));
|
||||||
|
|
||||||
|
await shim.fsDriver().remove(zipFilePath);
|
||||||
|
|
||||||
|
return modelDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const startRecording = (vosk: Vosk, options: StartOptions): Recorder => {
|
export const startRecording = (vosk: Vosk, options: StartOptions): Recorder => {
|
||||||
|
@ -109,8 +219,9 @@ export const startRecording = (vosk: Vosk, options: StartOptions): Recorder => {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
cleanup: () => {
|
cleanup: () => {
|
||||||
if (state_ !== State.Idle) {
|
if (state_ === State.Recording) {
|
||||||
logger.info('Cancelling...');
|
logger.info('Cancelling...');
|
||||||
|
state_ = State.Completing;
|
||||||
vosk.stopOnly();
|
vosk.stopOnly();
|
||||||
completeRecording('', null);
|
completeRecording('', null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,15 @@ export interface Recorder {
|
||||||
cleanup: ()=> void;
|
cleanup: ()=> void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getVosk = async () => {
|
export const isSupportedLanguage = (_locale: string) => {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const modelIsDownloaded = async (_locale: string) => {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getVosk = async (_locale: string) => {
|
||||||
return {} as any;
|
return {} as any;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,13 @@ export default class FsDriverRN extends FsDriverBase {
|
||||||
return RNFS.moveFile(source, dest);
|
return RNFS.moveFile(source, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async rename(source: string, dest: string) {
|
||||||
|
if (isScopedUri(source) || isScopedUri(dest)) {
|
||||||
|
await RNSAF.rename(source, dest);
|
||||||
|
}
|
||||||
|
return RNFS.moveFile(source, dest);
|
||||||
|
}
|
||||||
|
|
||||||
public async exists(path: string) {
|
public async exists(path: string) {
|
||||||
if (isScopedUri(path)) {
|
if (isScopedUri(path)) {
|
||||||
return RNSAF.exists(path);
|
return RNSAF.exists(path);
|
||||||
|
|
|
@ -508,7 +508,8 @@ function languageNameInEnglish(languageCode: string) {
|
||||||
return codeToLanguageE_[languageCode] ? codeToLanguageE_[languageCode] : '';
|
return codeToLanguageE_[languageCode] ? codeToLanguageE_[languageCode] : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function languageName(languageCode: string, defaultToEnglish: boolean = true) {
|
function languageName(canonicalName: string, defaultToEnglish: boolean = true) {
|
||||||
|
const languageCode = languageCodeOnly(canonicalName);
|
||||||
if (codeToLanguage_[languageCode]) return codeToLanguage_[languageCode];
|
if (codeToLanguage_[languageCode]) return codeToLanguage_[languageCode];
|
||||||
if (defaultToEnglish) return languageNameInEnglish(languageCode);
|
if (defaultToEnglish) return languageNameInEnglish(languageCode);
|
||||||
return '';
|
return '';
|
||||||
|
@ -603,4 +604,4 @@ const stringByLocale = (locale: string, s: string, ...args: any[]): string => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { _, _n, supportedLocales, currentLocale, localesFromLanguageCode, languageCodeOnly, countryDisplayName, localeStrings, setLocale, supportedLocalesToLanguages, defaultLocale, closestSupportedLocale, languageCode, countryCodeOnly };
|
export { _, _n, supportedLocales, languageName, currentLocale, localesFromLanguageCode, languageCodeOnly, countryDisplayName, localeStrings, setLocale, supportedLocalesToLanguages, defaultLocale, closestSupportedLocale, languageCode, countryCodeOnly };
|
||||||
|
|
|
@ -118,8 +118,6 @@ async function createRelease(projectName: string, name: string, tagName: string,
|
||||||
content = content.replace(/\s+"react-native-vosk": ".*",/, '');
|
content = content.replace(/\s+"react-native-vosk": ".*",/, '');
|
||||||
return content;
|
return content;
|
||||||
});
|
});
|
||||||
|
|
||||||
await patcher.removeFile(`${rnDir}/android/app/src/main/assets/model-fr-fr`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name === 'vosk') {
|
if (name === 'vosk') {
|
||||||
|
|
15
yarn.lock
15
yarn.lock
|
@ -4799,6 +4799,7 @@ __metadata:
|
||||||
react-native-version-info: 1.1.1
|
react-native-version-info: 1.1.1
|
||||||
react-native-vosk: 0.1.12
|
react-native-vosk: 0.1.12
|
||||||
react-native-webview: 11.26.1
|
react-native-webview: 11.26.1
|
||||||
|
react-native-zip-archive: 6.0.9
|
||||||
react-redux: 7.2.9
|
react-redux: 7.2.9
|
||||||
redux: 4.2.1
|
redux: 4.2.1
|
||||||
rn-fetch-blob: 0.12.0
|
rn-fetch-blob: 0.12.0
|
||||||
|
@ -27051,11 +27052,11 @@ __metadata:
|
||||||
|
|
||||||
"react-native-vosk@patch:react-native-vosk@npm%3A0.1.12#./.yarn/patches/react-native-vosk-npm-0.1.12-76b1caaae8.patch::locator=root%40workspace%3A.":
|
"react-native-vosk@patch:react-native-vosk@npm%3A0.1.12#./.yarn/patches/react-native-vosk-npm-0.1.12-76b1caaae8.patch::locator=root%40workspace%3A.":
|
||||||
version: 0.1.12
|
version: 0.1.12
|
||||||
resolution: "react-native-vosk@patch:react-native-vosk@npm%3A0.1.12#./.yarn/patches/react-native-vosk-npm-0.1.12-76b1caaae8.patch::version=0.1.12&hash=b82215&locator=root%40workspace%3A."
|
resolution: "react-native-vosk@patch:react-native-vosk@npm%3A0.1.12#./.yarn/patches/react-native-vosk-npm-0.1.12-76b1caaae8.patch::version=0.1.12&hash=5deb2c&locator=root%40workspace%3A."
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: "*"
|
react: "*"
|
||||||
react-native: "*"
|
react-native: "*"
|
||||||
checksum: 9451534de711f28274e117087a2c27266ee60ffc46723136841669c02345fd5644333a204c98c18d82e2c4221bb65906ac20529fd63fdcd5439c8aad86710e3b
|
checksum: ca31cf6345f422b778c18bc2365f5114ab2c3e20214e684bbb77220e6476cd877bb5c256d88070b2235f01714e8cd8e5bee999b854894b066d31834b9b17dca4
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -27072,6 +27073,16 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"react-native-zip-archive@npm:6.0.9":
|
||||||
|
version: 6.0.9
|
||||||
|
resolution: "react-native-zip-archive@npm:6.0.9"
|
||||||
|
peerDependencies:
|
||||||
|
react: ">=16.8.6"
|
||||||
|
react-native: ">=0.60.0"
|
||||||
|
checksum: 96c83864a596fcd8a82f55a01fa5e97822c9e80c7cf55de6b011a27cc436fbf58371207cb61c63b19dbd22b852ee62b95935358b4b9a73686695133dffdcfe27
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"react-native@npm:0.70.6":
|
"react-native@npm:0.70.6":
|
||||||
version: 0.70.6
|
version: 0.70.6
|
||||||
resolution: "react-native@npm:0.70.6"
|
resolution: "react-native@npm:0.70.6"
|
||||||
|
|
Loading…
Reference in New Issue