Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5c4dd4644e | |||
| 9bbd172cfd | |||
| dbf9de77c3 | |||
| 8b790cd162 | |||
| 80219066e9 | |||
| 26fa5f098f | |||
| d75bb36131 | |||
| 30c5e8ca79 | |||
| c00e36fab6 | |||
| 80e60b9118 | |||
| e3a95a44bc | |||
| 86caf526f5 | |||
| e09f32b4b4 | |||
| 3803ab345d | |||
| 889b43136f | |||
| b517cf46af |
@@ -6,14 +6,14 @@
|
||||
|
||||
Vosk is a speech recognition toolkit. The best things in Vosk are:
|
||||
|
||||
1. Supports 8 languages - English, German, French, Spanish, Portuguese, Chinese, Russian, Vietnamese. More is coming.
|
||||
1. Works offline even on lightweight devices - Raspberry Pi, Android, iOS
|
||||
1. Supports 9 languages - English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish, Vietnamese. More to come.
|
||||
1. Works offline, even on lightweight devices - Raspberry Pi, Android, iOS
|
||||
1. Installs with simple `pip3 install vosk`
|
||||
1. Portable models per language is just only 50Mb but there are much bigger server models available.
|
||||
1. Provides streaming API for the best user experience (unlike popular speech-recognition python package)
|
||||
1. There bindings for different prograbmming languages too - java/csharp/javascript etc.
|
||||
1. Portable per-language models are only 50Mb each, but there are much bigger server models available.
|
||||
1. Provides streaming API for the best user experience (unlike popular speech-recognition python packages)
|
||||
1. There are bindings for different programming languages, too - java/csharp/javascript etc.
|
||||
1. Allows quick reconfiguration of vocabulary for best accuracy.
|
||||
1. Supports speaker identification beside simple speech recognition
|
||||
1. Supports speaker identification beside simple speech recognition.
|
||||
|
||||
## Android build
|
||||
|
||||
@@ -95,8 +95,8 @@ Run like this:
|
||||
|
||||
```
|
||||
cd vosk-api/python/example
|
||||
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
|
||||
tar xf alphacep-model-android-en-us-0.3.tar.gz
|
||||
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
|
||||
unzip alphacep-model-android-en-us-0.3.zip
|
||||
mv alphacep-model-android-en-us-0.3 model-en
|
||||
python3 ./test_simple.py test.wav
|
||||
```
|
||||
@@ -111,8 +111,8 @@ Or Java
|
||||
|
||||
```
|
||||
cd java && KALDI_ROOT=<KALDI_ROOT> make
|
||||
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
|
||||
tar xf alphacep-model-android-en-us-0.3.tar.gz
|
||||
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
|
||||
unzip alphacep-model-android-en-us-0.3.zip
|
||||
mv alphacep-model-android-en-us-0.3 model
|
||||
make run
|
||||
```
|
||||
@@ -123,8 +123,8 @@ Or C#
|
||||
|
||||
```
|
||||
cd csharp && KALDI_ROOT=<KALDI_ROOT> make
|
||||
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
|
||||
tar xf alphacep-model-android-en-us-0.3.tar.gz
|
||||
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
|
||||
unzip alphacep-model-android-en-us-0.3.zip
|
||||
mv alphacep-model-android-en-us-0.3 model
|
||||
mono test.exe
|
||||
```
|
||||
|
||||
+7
-7
@@ -6,7 +6,7 @@
|
||||
|
||||
Библитека для распознавания речи "Воск". Преимущества библиотеки:
|
||||
|
||||
1. Поддерживает 8 языков - русский, английский, немецкий, французский, португальский, испанский, китайский, вьетнамский. В скором времени будут добавлены и другие
|
||||
1. Поддерживает 9 языков - русский, английский, немецкий, французский, португальский, испанский, китайский, турецкий, вьетнамский. В скором времени будут добавлены и другие
|
||||
1. Работает без доступа к сети даже на мобильных устройствах - Raspberry Pi, Android, iOS
|
||||
1. Устанавливается с помощью простой команды `pip3 install vosk` без дополнительных шагов
|
||||
1. Модели для каждого языка занимают всего 50Мб, но есть и гораздо более точные большие модели для более точного распознавания
|
||||
@@ -100,8 +100,8 @@ python3 setup.py install
|
||||
|
||||
```
|
||||
cd vosk-api/python/example
|
||||
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
|
||||
tar xf alphacep-model-android-en-us-0.3.tar.gz
|
||||
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
|
||||
unzip alphacep-model-android-en-us-0.3.zip
|
||||
mv alphacep-model-android-en-us-0.3 model-en
|
||||
python3 ./test_simple.py test.wav
|
||||
```
|
||||
@@ -116,8 +116,8 @@ python3 ./test_simple.py test.wav
|
||||
|
||||
```
|
||||
cd java && KALDI_ROOT=<KALDI_ROOT> make
|
||||
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
|
||||
tar xf alphacep-model-android-en-us-0.3.tar.gz
|
||||
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
|
||||
unzip alphacep-model-android-en-us-0.3.zip
|
||||
mv alphacep-model-android-en-us-0.3 model
|
||||
make run
|
||||
```
|
||||
@@ -128,8 +128,8 @@ make run
|
||||
|
||||
```
|
||||
cd csharp && KALDI_ROOT=<KALDI_ROOT> make
|
||||
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
|
||||
tar xf alphacep-model-android-en-us-0.3.tar.gz
|
||||
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
|
||||
unzip alphacep-model-android-en-us-0.3.zip
|
||||
mv alphacep-model-android-en-us-0.3 model
|
||||
mono test.exe
|
||||
```
|
||||
|
||||
+5
-5
@@ -2,11 +2,11 @@
|
||||
|
||||
Vosk是言语识别工具包。Vosk最好的事情是:
|
||||
|
||||
1. 支持八种语言 - 中文, 英语,德语,法语,西班牙语,葡萄牙语,俄语,越南语。
|
||||
1. 移动设备上脱机工作-Raspberry Pi,Android,iOS。
|
||||
1. 支持九种语言 - 中文, 英语,德语,法语,西班牙语,葡萄牙语,俄语,土耳其语,越南语
|
||||
1. 移动设备上脱机工作-Raspberry Pi,Android,iOS
|
||||
1. 使用简单的 pip3 install vosk 安装
|
||||
1. 每种语言的手提式模型只有是50Mb, 但还有更大的服务器模型可用
|
||||
1. 提供流媒体API,以提供最佳用户体验(与流行的语音识别python包不同)
|
||||
1. 也有针对不同编程语言的绑定-java / csharp / javascript等。
|
||||
1. 允许快速重新配置词汇以获得最佳准确性。
|
||||
1. 除了简单的语音识别外,还支持说话人识别
|
||||
1. 还有用于不同编程语言的包装器-java / csharp / javascript等
|
||||
1. 可以快速重新配置词汇以实现最佳准确性
|
||||
1. 支持说话人识别
|
||||
|
||||
@@ -45,6 +45,7 @@ target_link_libraries( kaldi_jni
|
||||
${KALDI_ROOT}/src/tree/kaldi-tree.a
|
||||
${KALDI_ROOT}/src/feat/kaldi-feat.a
|
||||
${KALDI_ROOT}/src/lat/kaldi-lat.a
|
||||
${KALDI_ROOT}/src/lm/kaldi-lm.a
|
||||
${KALDI_ROOT}/src/hmm/kaldi-hmm.a
|
||||
${KALDI_ROOT}/src/transform/kaldi-transform.a
|
||||
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a
|
||||
|
||||
@@ -241,10 +241,6 @@ public class Assets {
|
||||
if (!items.get(path).equals(externalItems.get(path))
|
||||
|| !(new File(externalDir, path).exists()))
|
||||
newItems.add(path);
|
||||
else
|
||||
Log.i(TAG,
|
||||
String.format("Skipping asset %s: checksums are equal", path));
|
||||
|
||||
}
|
||||
|
||||
unusedItems.addAll(externalItems.keySet());
|
||||
@@ -252,13 +248,11 @@ public class Assets {
|
||||
|
||||
for (String path : newItems) {
|
||||
File file = copy(path);
|
||||
Log.i(TAG, String.format("Copying asset %s to %s", path, file));
|
||||
}
|
||||
|
||||
for (String path : unusedItems) {
|
||||
File file = new File(externalDir, path);
|
||||
file.delete();
|
||||
Log.i(TAG, String.format("Removing asset %s", file));
|
||||
}
|
||||
|
||||
updateItemList(items);
|
||||
|
||||
@@ -148,8 +148,7 @@ public class SpeechRecognizer {
|
||||
public boolean stop() {
|
||||
boolean result = stopRecognizerThread();
|
||||
if (result) {
|
||||
Log.i(TAG, "Stop recognition");
|
||||
mainHandler.post(new ResultEvent(recognizer.FinalResult(), true));
|
||||
mainHandler.post(new ResultEvent(recognizer.Result(), true));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -162,10 +161,7 @@ public class SpeechRecognizer {
|
||||
*/
|
||||
public boolean cancel() {
|
||||
boolean result = stopRecognizerThread();
|
||||
if (result) {
|
||||
Log.i(TAG, "Cancel recognition");
|
||||
}
|
||||
|
||||
recognizer.Result(); // Reset recognizer state
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -206,8 +202,6 @@ public class SpeechRecognizer {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Starting decoding");
|
||||
|
||||
short[] buffer = new short[bufferSize];
|
||||
|
||||
while (!interrupted()
|
||||
|
||||
+3
-2
@@ -11,6 +11,7 @@ KALDI_LIBS = \
|
||||
${KALDI_ROOT}/src/tree/kaldi-tree.a \
|
||||
${KALDI_ROOT}/src/feat/kaldi-feat.a \
|
||||
${KALDI_ROOT}/src/lat/kaldi-lat.a \
|
||||
${KALDI_ROOT}/src/lm/kaldi-lm.a \
|
||||
${KALDI_ROOT}/src/hmm/kaldi-hmm.a \
|
||||
${KALDI_ROOT}/src/transform/kaldi-transform.a \
|
||||
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a \
|
||||
@@ -43,10 +44,10 @@ libkaldiwrap.so: $(VOSK_SOURCES)
|
||||
$(CXX) -fpermissive $(CFLAGS) $(CPPFLAGS) -shared -o $@ $(VOSK_SOURCES) $(KALDI_LIBS)
|
||||
|
||||
vosk_wrap.c: ../src/vosk.i
|
||||
swig -csharp -DSWIG_CSHARP_NO_EXCEPTION_HELPER -dllimport "libkaldiwrap.so" \
|
||||
swig -csharp -DSWIG_CSHARP_NO_EXCEPTION_HELPER -dllimport "libkaldiwrap" \
|
||||
-namespace "Kaldi" -outdir gen -o vosk_wrap.c ../src/vosk.i
|
||||
|
||||
run:
|
||||
run: test.exe
|
||||
mono test.exe
|
||||
|
||||
clean:
|
||||
|
||||
@@ -7,6 +7,7 @@ public class Test
|
||||
public static void Main()
|
||||
{
|
||||
|
||||
Vosk.SetLogLevel(0);
|
||||
Model model = new Model("model");
|
||||
KaldiRecognizer rec = new KaldiRecognizer(model, 16000.0f);
|
||||
|
||||
|
||||
+62
-48
@@ -4,64 +4,78 @@ This is the list of models compatible with Vosk-API.
|
||||
|
||||
To add a new model here create an issue on Github.
|
||||
|
||||
### English
|
||||
|
||||
| Model | Size | Accuracy | Notes |
|
||||
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
|
||||
| [kaldi-en-us-aspire-0.1](http://alphacephei.com/kaldi/kaldi-en-us-aspire-0.1.tar.gz) | 363M | TBD | Trained on Fisher + more or less recent LM. Pretty outdated but still ok even even for calls |
|
||||
| [alphacep-model-android-en-us-0.3](http://alphacephei.com/kaldi/alphacep-model-android-en-us-0.3.tar.gz) | 36M | TBD | Lightweight wideband model for Android and RPi |
|
||||
|
||||
### Chinese
|
||||
|
||||
| Model | Size | Accuracy | Notes |
|
||||
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
|
||||
| [kaldi-cn-0.1.tar.gz](http://alphacephei.com/kaldi/kaldi-cn-0.1.tar.gz) | 195M | TBD | Big narrowband Chinese model for server processing |
|
||||
| [alphacep-model-android-cn-0.3](http://alphacephei.com/kaldi/alphacep-model-android-cn-0.3.tar.gz) | 32M | TBD | Lightweight wideband model for Android and RPi |
|
||||
|
||||
### Russian
|
||||
|
||||
| Model | Size | Accuracy | Notes |
|
||||
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
|
||||
| [kaldi-ru-0.9.tar.gz](http://alphacephei.com/kaldi/kaldi-ru-0.9.tar.gz) | 2.5G | TBD | Big narrowband Russian model for server processing |
|
||||
| [alphacep-model-android-ru-0.3](http://alphacephei.com/kaldi/alphacep-model-android-ru-0.3.tar.gz) | 39M | TBD | Lightweight wideband model for Android and RPi |
|
||||
|
||||
### French
|
||||
|
||||
| Model | Size | Accuracy | Notes |
|
||||
|-------------------------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
|
||||
| [alphacep-model-android-fr-pguyot-0.3](http://alphacephei.com/kaldi/alphacep-model-android-fr-pguyot-0.3.tar.gz) | 39M | TBD | Lightweight wideband model for Android and RPi trained by [Paul Guyot](https://github.com/pguyot/zamia-speech/releases) |
|
||||
| **English** | | | |
|
||||
| [vosk-model-en-us-aspire-0.2](http://alphacephei.com/kaldi/models/vosk-model-en-us-aspire-0.2.zip) | 1.4G | TBD | Trained on Fisher + more or less recent LM. Should be pretty good for generic US English transcription |
|
||||
| [vosk-model-small-en-us-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip) | 36M | TBD | Lightweight wideband model for Android and RPi |
|
||||
| **Chinese** | | | |
|
||||
| [vosk-model-cn-0.1.zip](http://alphacephei.com/kaldi/models/vosk-model-cn-0.1.zip) | 195M | TBD | Big narrowband Chinese model for server processing |
|
||||
| [vosk-model-small-cn-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-cn-0.3.zip) | 32M | TBD | Lightweight wideband model for Android and RPi |
|
||||
| **Russian** | | | |
|
||||
| [vosk-model-ru-0.10.zip](http://alphacephei.com/kaldi/models/vosk-model-ru-0.10.zip) | 2.5G | TBD | Big narrowband Russian model for server processing |
|
||||
| [vosk-model-small-ru-0.4](http://alphacephei.com/kaldi/models/vosk-model-small-ru-0.4.zip) | 39M | TBD | Lightweight wideband model for Android and RPi |
|
||||
| **French** | | | |
|
||||
| [vosk-model-small-fr-pguyot-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-fr-pguyot-0.3.zip) | 39M | TBD | Lightweight wideband model for Android and RPi trained by [Paul Guyot](https://github.com/pguyot/zamia-speech/releases) |
|
||||
| **German** | | | |
|
||||
| [tuda-de](http://ltdata1.informatik.uni-hamburg.de/kaldi_tuda_de/de_400k_nnet3chain_tdnn1f_2048_sp_bi.tar.bz2) | 566M | TBD | Wideband server model from [tuda-de](https://github.com/uhh-lt/vosk-model-tuda-de) |
|
||||
| [vosk-model-small-de-zamia-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-de-zamia-0.3.zip) | 49M | TBD | Lightweight wideband model for Android and RPi |
|
||||
| **Spanish** | | | |
|
||||
| [vosk-model-small-es-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-es-0.3.zip) | 33M | TBD | Lightweight wideband model for Android and RPi |
|
||||
| **Portuguese** | | | |
|
||||
| [vosk-model-small-pt-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-pt-0.3.zip) | 31M | TBD | Lightweight wideband model for Android and RPi |
|
||||
| **Greek** | | | |
|
||||
| [vosk-model-el-gr-0.6.zip](http://alphacephei.com/kaldi/models/vosk-model-el-gr-0.6.zip) | 1.1G | TBD | Big narrowband Greek model for server processing, not extremely accurate though |
|
||||
| **Turkish** | | | |
|
||||
| [vosk-model-small-tr-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-tr-0.3.zip) | 35M | TBD | Lightweight wideband model for Android and RPi |
|
||||
| **Vietnamese** | | | |
|
||||
| [vosk-model-small-vn-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-vn-0.3.zip) | 32M | TBD | Lightweight wideband model for Android and RPi |
|
||||
| **Speaker identification model** | | | |
|
||||
| [vosk-model-spk-0.3](http://alphacephei.com/kaldi/models/vosk-model-spk-0.3.zip) | 13M | TBD | Model for speaker identification, should work for all languages |
|
||||
|
||||
### German
|
||||
|
||||
| Model | Size | Accuracy | Notes |
|
||||
|-----------------------------------------------------------------------------------------------------------|-------|------------|------------------------------------------------------------------------------------------------------|
|
||||
| [tuda-de](http://ltdata1.informatik.uni-hamburg.de/kaldi_tuda_de/de_400k_nnet3chain_tdnn1f_2048_sp_bi.tar.bz2) | 566M | TBD | Wideband server model from [tuda-de](https://github.com/uhh-lt/kaldi-tuda-de) |
|
||||
| [alphacep-model-android-de-zamia-0.3](http://alphacephei.com/kaldi/alphacep-model-android-de-zamia-0.3.tar.gz) | 49M | TBD | Lightweight wideband model for Android and RPi |
|
||||
## Other models
|
||||
|
||||
### Spanish
|
||||
Other places where you can check for models which might be compatible:
|
||||
|
||||
| Model | Size | Accuracy | Notes |
|
||||
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
|
||||
| [alphacep-model-android-es-0.3](http://alphacephei.com/kaldi/alphacep-model-android-es-0.3.tar.gz) | 33M | TBD | Lightweight wideband model for Android and RPi |
|
||||
* http://kaldi-asr.org/models.html - variety of models from Kaldi - librispeech, aspire, chinese models
|
||||
* https://github.com/daanzu/kaldi-active-grammar/blob/master/docs/models.md - Big dictation models
|
||||
* http://zamia-speech.org/asr/ - German and English model from Zamia
|
||||
* https://github.com/pguyot/zamia-speech/releases - French models for Zamia
|
||||
* https://github.com/opensource-spraakherkenning-nl/Kaldi_NL - Dutch model
|
||||
* https://montreal-forced-aligner.readthedocs.io/en/latest/pretrained_models.html (GMM models, not compatible but might be still useful)
|
||||
* https://github.com/goodatlas/zeroth - Korean Kaldi (just a recipe and data to train)
|
||||
* https://github.com/undertheseanlp/automatic_speech_recognition - Vietnamese Kaldi project
|
||||
|
||||
### Portuguese
|
||||
## Training your own model
|
||||
|
||||
| Model | Size | Accuracy | Notes |
|
||||
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
|
||||
| [alphacep-model-android-pt-0.3](http://alphacephei.com/kaldi/alphacep-model-android-pt-0.3.tar.gz) | 31M | TBD | Lightweight wideband model for Android and RPi |
|
||||
You can train your model with Kaldi toolkit. The training is pretty standard - you need tdnn nnet3 model with ivectors. You can
|
||||
check mini_librispeech recipe for details. Some notes on training:
|
||||
|
||||
### Dutch
|
||||
* For smaller mobile models watch number of parameters
|
||||
* Train the model without pitch. It might be helpful for small amount of data, but for large database it doesn't give the advantage
|
||||
but complicates the processing and increases response time.
|
||||
* Train ivector of dim 30 instead of standard 100 to save memory of mobile models.
|
||||
|
||||
https://github.com/opensource-spraakherkenning-nl/Kaldi_NL
|
||||
## Model structure
|
||||
|
||||
### Greek
|
||||
Once you trained the model arrange the files according to the following layout (see en-us-aspire for details):
|
||||
|
||||
| Model | Size | Accuracy | Notes |
|
||||
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
|
||||
| [kaldi-el-gr-0.6.tar.gz](http://alphacephei.com/kaldi/kaldi-el-gr-0.6.tar.gz) | 1.1G | TBD | Big narrowband Greek model for server processing, not extremely accurate though |
|
||||
* `am/final.mdl` - acoustic model
|
||||
* `conf/mfcc.conf` - mfcc config file. Make sure you take mfcc_hires.conf version if you are using hires model (most external ones)
|
||||
* `conf/model.conf` - provide default decoding beams and silence phones. you have to create this file yourself, it is not present in kaldi model
|
||||
* `ivector/final.dubm` - take ivector files from ivector extractor
|
||||
* `ivector/final.ie`
|
||||
* `ivector/final.mat`
|
||||
* `ivector/splice.conf`
|
||||
* `ivector/global_cmvn.stats`
|
||||
* `ivector/online_cmvn.conf`
|
||||
* `graph/phones/word_boundary.int` - from the graph
|
||||
* `graph/HCLG.fst` - this is the decoding graph, if you are not using lookahead
|
||||
* `graph/HCLr.fst` - use Gr.fst and HCLr.fst instead of one big HCLG.fst if you want to run rescoring
|
||||
* `graph/Gr.fst`
|
||||
* `graph/phones.txt` - from the graph
|
||||
* `graph/words.txt` - from the graph
|
||||
* `rescore/G.carpa` - carpa rescoring is optional but helpful in big models. Usually located inside data/lang_test_rescore
|
||||
* `rescore/G.fst` - also optional if you want to use rescoring
|
||||
|
||||
### Vietnamese
|
||||
|
||||
| Model | Size | Accuracy | Notes |
|
||||
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
|
||||
| [alphacep-model-android-vn-0.3](http://alphacephei.com/kaldi/alphacep-model-android-vn-0.3.tar.gz) | 32M | TBD | Lightweight wideband model for Android and RPi |
|
||||
|
||||
+9
-8
@@ -11,6 +11,7 @@ KALDI_LIBS = \
|
||||
${KALDI_ROOT}/src/tree/kaldi-tree.a \
|
||||
${KALDI_ROOT}/src/feat/kaldi-feat.a \
|
||||
${KALDI_ROOT}/src/lat/kaldi-lat.a \
|
||||
${KALDI_ROOT}/src/lm/kaldi-lm.a \
|
||||
${KALDI_ROOT}/src/hmm/kaldi-hmm.a \
|
||||
${KALDI_ROOT}/src/transform/kaldi-transform.a \
|
||||
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a \
|
||||
@@ -49,16 +50,16 @@ clean:
|
||||
$(RM) *.so *_wrap.cc *_wrap.o test/*.class
|
||||
$(RM) -r org model-en
|
||||
|
||||
model-en:
|
||||
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
|
||||
tar xf alphacep-model-android-en-us-0.3.tar.gz && rm alphacep-model-android-en-us-0.3.tar.gz
|
||||
mv alphacep-model-android-en-us-0.3 model-en
|
||||
model:
|
||||
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
|
||||
unzip vosk-model-small-en-us-0.3.zip && rm vosk-model-small-en-us-0.3.zip
|
||||
mv vosk-model-small-en-us-0.3 model
|
||||
|
||||
model-spk:
|
||||
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-spk-model-0.3.tar.gz
|
||||
tar xf alphacep-spk-model-0.3.tar.gz && rm alphacep-spk-model-0.3.tar.gz
|
||||
mv alphacep-spk-model-0.3 model-spk
|
||||
wget https://alphacephei.com/kaldi/models/vosk-model-spk-0.3.zip
|
||||
unzip vosk-model-spk-0.3.zip && rm vosk-model-spk-0.3.zip
|
||||
mv vosk-model-spk-0.3 model-spk
|
||||
|
||||
run: model-en model-spk
|
||||
run: model model-spk
|
||||
javac test/*.java org/kaldi/*.java
|
||||
java -Djava.library.path=. -cp . test.DecoderTest
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.nio.*;
|
||||
import org.kaldi.KaldiRecognizer;
|
||||
import org.kaldi.Model;
|
||||
import org.kaldi.SpkModel;
|
||||
import org.kaldi.Vosk;
|
||||
|
||||
public class DecoderTest {
|
||||
static {
|
||||
@@ -18,8 +19,10 @@ public class DecoderTest {
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws IOException {
|
||||
Vosk.SetLogLevel(-10);
|
||||
|
||||
FileInputStream ais = new FileInputStream(new File("../python/example/test.wav"));
|
||||
Model model = new Model("model-en");
|
||||
Model model = new Model("model");
|
||||
SpkModel spkModel = new SpkModel("model-spk");
|
||||
KaldiRecognizer rec = new KaldiRecognizer(model, spkModel, 16000.0f);
|
||||
|
||||
|
||||
@@ -3,18 +3,18 @@ project(vosk)
|
||||
|
||||
set(TOP_SRCDIR "${CMAKE_SOURCE_DIR}/..")
|
||||
if("x$ENV{WHEEL_FLAGS}" STREQUAL "x")
|
||||
find_package (Python COMPONENTS Interpreter Development)
|
||||
find_package (Python3 COMPONENTS Interpreter Development)
|
||||
else()
|
||||
# docker case
|
||||
set(Python_INCLUDE_DIRS "")
|
||||
set(Python3_INCLUDE_DIRS "")
|
||||
set(TOP_SRCDIR "/io")
|
||||
endif()
|
||||
|
||||
set(KALDI_ROOT "$ENV{KALDI_ROOT}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -DFST_NO_DYNAMIC_LINKING")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFST_NO_DYNAMIC_LINKING")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} $ENV{WHEEL_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} -std=c++11")
|
||||
include_directories("${TOP_SRCDIR}/src" "${KALDI_ROOT}/src" "${KALDI_ROOT}/tools/openfst/include" ${Python_INCLUDE_DIRS})
|
||||
include_directories("${TOP_SRCDIR}/src" "${KALDI_ROOT}/src" "${KALDI_ROOT}/tools/openfst/include" ${Python3_INCLUDE_DIRS})
|
||||
|
||||
find_package(SWIG REQUIRED)
|
||||
include(${SWIG_USE_FILE})
|
||||
@@ -35,6 +35,7 @@ swig_link_libraries(vosk
|
||||
${KALDI_ROOT}/src/tree/kaldi-tree.a
|
||||
${KALDI_ROOT}/src/feat/kaldi-feat.a
|
||||
${KALDI_ROOT}/src/lat/kaldi-lat.a
|
||||
${KALDI_ROOT}/src/lm/kaldi-lm.a
|
||||
${KALDI_ROOT}/src/hmm/kaldi-hmm.a
|
||||
${KALDI_ROOT}/src/transform/kaldi-transform.a
|
||||
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a
|
||||
|
||||
@@ -4,7 +4,7 @@ from vosk import Model, KaldiRecognizer
|
||||
import sys
|
||||
import json
|
||||
|
||||
model = Model("model-en")
|
||||
model = Model("model")
|
||||
rec = KaldiRecognizer(model, 8000)
|
||||
|
||||
res = json.loads(rec.FinalResult())
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
from vosk import Model, KaldiRecognizer
|
||||
import os
|
||||
|
||||
if not os.path.exists("model-en"):
|
||||
print ("Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model-en' in the current folder.")
|
||||
if not os.path.exists("model"):
|
||||
print ("Please download the model from https://github.com/alphacep/vosk-api/blob/master/doc/models.md and unpack as 'model' in the current folder.")
|
||||
exit (1)
|
||||
|
||||
import pyaudio
|
||||
@@ -13,11 +13,11 @@ p = pyaudio.PyAudio()
|
||||
stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=8000)
|
||||
stream.start_stream()
|
||||
|
||||
model = Model("model-en")
|
||||
model = Model("model")
|
||||
rec = KaldiRecognizer(model, 16000)
|
||||
|
||||
while True:
|
||||
data = stream.read(2000)
|
||||
data = stream.read(4000)
|
||||
if len(data) == 0:
|
||||
break
|
||||
if rec.AcceptWaveform(data):
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from vosk import Model, KaldiRecognizer
|
||||
from vosk import Model, KaldiRecognizer, SetLogLevel
|
||||
import sys
|
||||
import os
|
||||
import wave
|
||||
|
||||
if not os.path.exists("model-en"):
|
||||
print ("Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model-en' in the current folder.")
|
||||
SetLogLevel(0)
|
||||
|
||||
if not os.path.exists("model"):
|
||||
print ("Please download the model from https://github.com/alphacep/vosk-api/blob/master/doc/models.md and unpack as 'model' in the current folder.")
|
||||
exit (1)
|
||||
|
||||
wf = wave.open(sys.argv[1], "rb")
|
||||
@@ -14,11 +16,11 @@ if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE
|
||||
print ("Audio file must be WAV format mono PCM.")
|
||||
exit (1)
|
||||
|
||||
model = Model("model-en")
|
||||
model = Model("model")
|
||||
rec = KaldiRecognizer(model, wf.getframerate())
|
||||
|
||||
while True:
|
||||
data = wf.readframes(1000)
|
||||
data = wf.readframes(4000)
|
||||
if len(data) == 0:
|
||||
break
|
||||
if rec.AcceptWaveform(data):
|
||||
|
||||
@@ -7,15 +7,15 @@ import json
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
model_path = "model-en"
|
||||
model_path = "model"
|
||||
spk_model_path = "model-spk"
|
||||
|
||||
if not os.path.exists(model_path):
|
||||
print ("Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as {} in the current folder.".format(model_path))
|
||||
print ("Please download the model from https://github.com/alphacep/vosk-api/blob/master/doc/models.md and unpack as {} in the current folder.".format(model_path))
|
||||
exit (1)
|
||||
|
||||
if not os.path.exists(spk_model_path):
|
||||
print ("Please download the speaker model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as {} in the current folder.".format(spk_model_path))
|
||||
print ("Please download the speaker model from https://github.com/alphacep/vosk-api/blob/master/doc/models.md and unpack as {} in the current folder.".format(spk_model_path))
|
||||
exit (1)
|
||||
|
||||
wf = wave.open(sys.argv[1], "rb")
|
||||
@@ -38,7 +38,7 @@ def cosine_dist(x, y):
|
||||
return 1 - np.dot(nx, ny) / np.linalg.norm(nx) / np.linalg.norm(ny)
|
||||
|
||||
while True:
|
||||
data = wf.readframes(1000)
|
||||
data = wf.readframes(4000)
|
||||
if len(data) == 0:
|
||||
break
|
||||
if rec.AcceptWaveform(data):
|
||||
|
||||
@@ -5,12 +5,12 @@ import sys
|
||||
import json
|
||||
import os
|
||||
|
||||
if not os.path.exists("model-en"):
|
||||
print ("Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model-en' in the current folder.")
|
||||
if not os.path.exists("model"):
|
||||
print ("Please download the model from https://github.com/alphacep/vosk-api/blob/master/doc/models.md and unpack as 'model' in the current folder.")
|
||||
exit (1)
|
||||
|
||||
|
||||
model = Model("model-en")
|
||||
model = Model("model")
|
||||
|
||||
# Large vocabulary free form recognition
|
||||
rec = KaldiRecognizer(model, 16000)
|
||||
@@ -22,7 +22,7 @@ wf = open(sys.argv[1], "rb")
|
||||
wf.read(44) # skip header
|
||||
|
||||
while True:
|
||||
data = wf.read(2000)
|
||||
data = wf.read(4000)
|
||||
if len(data) == 0:
|
||||
break
|
||||
if rec.AcceptWaveform(data):
|
||||
|
||||
@@ -5,8 +5,8 @@ import sys
|
||||
import os
|
||||
import wave
|
||||
|
||||
if not os.path.exists("model-en"):
|
||||
print ("Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model-en' in the current folder.")
|
||||
if not os.path.exists("model"):
|
||||
print ("Please download the model from https://github.com/alphacep/vosk-api/blob/master/doc/models.md and unpack as 'model' in the current folder.")
|
||||
exit (1)
|
||||
|
||||
wf = wave.open(sys.argv[1], "rb")
|
||||
@@ -14,12 +14,12 @@ if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE
|
||||
print ("Audio file must be WAV format mono PCM.")
|
||||
exit (1)
|
||||
|
||||
model = Model("model-en")
|
||||
model = Model("model")
|
||||
# You can also specify the possible word list
|
||||
rec = KaldiRecognizer(model, wf.getframerate(), "zero oh one two three four five six seven eight nine")
|
||||
|
||||
while True:
|
||||
data = wf.readframes(1000)
|
||||
data = wf.readframes(4000)
|
||||
if len(data) == 0:
|
||||
break
|
||||
if rec.AcceptWaveform(data):
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ with open("README.md", "r") as fh:
|
||||
|
||||
setuptools.setup(
|
||||
name="vosk", # Replace with your own username
|
||||
version="0.3.5",
|
||||
version="0.3.7",
|
||||
author="Alpha Cephei Inc",
|
||||
author_email="contact@alphacephei.com",
|
||||
description="API for Kaldi and Vosk",
|
||||
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from vosk import Model, KaldiRecognizer
|
||||
import sys
|
||||
import os
|
||||
import wave
|
||||
import json
|
||||
|
||||
model = Model("model")
|
||||
|
||||
for line in open(sys.argv[1]):
|
||||
uid, fn = line.split()
|
||||
wf = wave.open(fn, "rb")
|
||||
rec = KaldiRecognizer(model, wf.getframerate())
|
||||
|
||||
text = ""
|
||||
while True:
|
||||
data = wf.readframes(1000)
|
||||
if len(data) == 0:
|
||||
break
|
||||
if rec.AcceptWaveform(data):
|
||||
jres = json.loads(rec.Result())
|
||||
text = text + " " + jres['text']
|
||||
jres = json.loads(rec.FinalResult())
|
||||
text = text + " " + jres['text']
|
||||
print (uid + text)
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
from .vosk import KaldiRecognizer, Model, SpkModel
|
||||
from .vosk import KaldiRecognizer, Model, SpkModel, SetLogLevel
|
||||
|
||||
|
||||
+102
-52
@@ -20,40 +20,46 @@
|
||||
using namespace fst;
|
||||
using namespace kaldi::nnet3;
|
||||
|
||||
KaldiRecognizer::KaldiRecognizer(Model &model, float sample_frequency) : model_(model), spk_model_(0), sample_frequency_(sample_frequency) {
|
||||
KaldiRecognizer::KaldiRecognizer(Model *model, float sample_frequency) : model_(model), spk_model_(0), sample_frequency_(sample_frequency) {
|
||||
|
||||
feature_pipeline_ = new kaldi::OnlineNnet2FeaturePipeline (model_.feature_info_);
|
||||
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_.trans_model_, model_.feature_info_.silence_weighting_config, 3);
|
||||
model_->Ref();
|
||||
|
||||
feature_pipeline_ = new kaldi::OnlineNnet2FeaturePipeline (model_->feature_info_);
|
||||
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_->trans_model_, model_->feature_info_.silence_weighting_config, 3);
|
||||
|
||||
g_fst_ = NULL;
|
||||
decode_fst_ = NULL;
|
||||
|
||||
if (!model_.hclg_fst_) {
|
||||
if (model_.hcl_fst_ && model_.g_fst_) {
|
||||
decode_fst_ = LookaheadComposeFst(*model_.hcl_fst_, *model_.g_fst_, model_.disambig_);
|
||||
if (!model_->hclg_fst_) {
|
||||
if (model_->hcl_fst_ && model_->g_fst_) {
|
||||
decode_fst_ = LookaheadComposeFst(*model_->hcl_fst_, *model_->g_fst_, model_->disambig_);
|
||||
} else {
|
||||
KALDI_ERR << "Can't create decoding graph";
|
||||
}
|
||||
}
|
||||
|
||||
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_.nnet3_decoding_config_,
|
||||
*model_.trans_model_,
|
||||
*model_.decodable_info_,
|
||||
model_.hclg_fst_ ? *model.hclg_fst_ : *decode_fst_,
|
||||
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_->nnet3_decoding_config_,
|
||||
*model_->trans_model_,
|
||||
*model_->decodable_info_,
|
||||
model_->hclg_fst_ ? *model_->hclg_fst_ : *decode_fst_,
|
||||
feature_pipeline_);
|
||||
|
||||
frame_offset_ = 0;
|
||||
input_finalized_ = false;
|
||||
spk_feature_ = NULL;
|
||||
|
||||
InitRescoring();
|
||||
}
|
||||
|
||||
KaldiRecognizer::KaldiRecognizer(Model &model, float sample_frequency, char const *grammar) : model_(model), spk_model_(0), sample_frequency_(sample_frequency)
|
||||
KaldiRecognizer::KaldiRecognizer(Model *model, float sample_frequency, char const *grammar) : model_(model), spk_model_(0), sample_frequency_(sample_frequency)
|
||||
{
|
||||
feature_pipeline_ = new kaldi::OnlineNnet2FeaturePipeline (model_.feature_info_);
|
||||
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_.trans_model_, model_.feature_info_.silence_weighting_config, 3);
|
||||
model_->Ref();
|
||||
|
||||
feature_pipeline_ = new kaldi::OnlineNnet2FeaturePipeline (model_->feature_info_);
|
||||
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_->trans_model_, model_->feature_info_.silence_weighting_config, 3);
|
||||
|
||||
g_fst_ = new StdVectorFst();
|
||||
if (model_.hcl_fst_) {
|
||||
if (model_->hcl_fst_) {
|
||||
g_fst_->AddState();
|
||||
g_fst_->SetStart(0);
|
||||
g_fst_->AddState();
|
||||
@@ -61,58 +67,65 @@ KaldiRecognizer::KaldiRecognizer(Model &model, float sample_frequency, char cons
|
||||
g_fst_->AddArc(1, StdArc(0, 0, fst::TropicalWeight::One(), 0));
|
||||
|
||||
// Create simple word loop FST
|
||||
std::stringstream ss(grammar);
|
||||
std::string token;
|
||||
stringstream ss(grammar);
|
||||
string token;
|
||||
|
||||
while (std::getline(ss, token, ' ')) {
|
||||
int32 id = model_.word_syms_->Find(token);
|
||||
while (getline(ss, token, ' ')) {
|
||||
int32 id = model_->word_syms_->Find(token);
|
||||
g_fst_->AddArc(0, StdArc(id, id, fst::TropicalWeight::One(), 1));
|
||||
}
|
||||
ArcSort(g_fst_, ILabelCompare<StdArc>());
|
||||
|
||||
decode_fst_ = LookaheadComposeFst(*model_.hcl_fst_, *g_fst_, model_.disambig_);
|
||||
decode_fst_ = LookaheadComposeFst(*model_->hcl_fst_, *g_fst_, model_->disambig_);
|
||||
} else {
|
||||
decode_fst_ = NULL;
|
||||
KALDI_ERR << "Can't create decoding graph";
|
||||
}
|
||||
|
||||
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_.nnet3_decoding_config_,
|
||||
*model_.trans_model_,
|
||||
*model_.decodable_info_,
|
||||
model_.hclg_fst_ ? *model.hclg_fst_ : *decode_fst_,
|
||||
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_->nnet3_decoding_config_,
|
||||
*model_->trans_model_,
|
||||
*model_->decodable_info_,
|
||||
model_->hclg_fst_ ? *model_->hclg_fst_ : *decode_fst_,
|
||||
feature_pipeline_);
|
||||
|
||||
frame_offset_ = 0;
|
||||
input_finalized_ = false;
|
||||
spk_feature_ = NULL;
|
||||
|
||||
InitRescoring();
|
||||
}
|
||||
|
||||
KaldiRecognizer::KaldiRecognizer(Model *model, SpkModel *spk_model, float sample_frequency) : model_(model), spk_model_(spk_model), sample_frequency_(sample_frequency) {
|
||||
|
||||
KaldiRecognizer::KaldiRecognizer(Model &model, SpkModel *spk_model, float sample_frequency) : model_(model), spk_model_(spk_model), sample_frequency_(sample_frequency) {
|
||||
feature_pipeline_ = new kaldi::OnlineNnet2FeaturePipeline (model_.feature_info_);
|
||||
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_.trans_model_, model_.feature_info_.silence_weighting_config, 3);
|
||||
model_->Ref();
|
||||
spk_model->Ref();
|
||||
|
||||
feature_pipeline_ = new kaldi::OnlineNnet2FeaturePipeline (model_->feature_info_);
|
||||
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_->trans_model_, model_->feature_info_.silence_weighting_config, 3);
|
||||
|
||||
decode_fst_ = NULL;
|
||||
g_fst_ = NULL;
|
||||
|
||||
if (!model_.hclg_fst_) {
|
||||
if (model_.hcl_fst_ && model_.g_fst_) {
|
||||
decode_fst_ = LookaheadComposeFst(*model_.hcl_fst_, *model_.g_fst_, model_.disambig_);
|
||||
if (!model_->hclg_fst_) {
|
||||
if (model_->hcl_fst_ && model_->g_fst_) {
|
||||
decode_fst_ = LookaheadComposeFst(*model_->hcl_fst_, *model_->g_fst_, model_->disambig_);
|
||||
} else {
|
||||
KALDI_ERR << "Can't create decoding graph";
|
||||
}
|
||||
}
|
||||
|
||||
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_.nnet3_decoding_config_,
|
||||
*model_.trans_model_,
|
||||
*model_.decodable_info_,
|
||||
model_.hclg_fst_ ? *model.hclg_fst_ : *decode_fst_,
|
||||
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_->nnet3_decoding_config_,
|
||||
*model_->trans_model_,
|
||||
*model_->decodable_info_,
|
||||
model_->hclg_fst_ ? *model_->hclg_fst_ : *decode_fst_,
|
||||
feature_pipeline_);
|
||||
|
||||
frame_offset_ = 0;
|
||||
input_finalized_ = false;
|
||||
|
||||
spk_feature_ = new OnlineMfcc(spk_model_->spkvector_mfcc_opts);
|
||||
|
||||
InitRescoring();
|
||||
}
|
||||
|
||||
KaldiRecognizer::~KaldiRecognizer() {
|
||||
@@ -122,12 +135,29 @@ KaldiRecognizer::~KaldiRecognizer() {
|
||||
delete g_fst_;
|
||||
delete decode_fst_;
|
||||
delete spk_feature_;
|
||||
delete lm_fst_;
|
||||
|
||||
model_->Unref();
|
||||
if (spk_model_)
|
||||
spk_model_->Unref();
|
||||
}
|
||||
|
||||
void KaldiRecognizer::InitRescoring()
|
||||
{
|
||||
if (model_->std_lm_fst_) {
|
||||
fst::CacheOptions cache_opts(true, 50000);
|
||||
fst::MapFstOptions mapfst_opts(cache_opts);
|
||||
fst::StdToLatticeMapper<kaldi::BaseFloat> mapper;
|
||||
lm_fst_ = new fst::MapFst<fst::StdArc, kaldi::LatticeArc, fst::StdToLatticeMapper<kaldi::BaseFloat> >(*model_->std_lm_fst_, mapper, mapfst_opts);
|
||||
} else {
|
||||
lm_fst_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void KaldiRecognizer::CleanUp()
|
||||
{
|
||||
delete silence_weighting_;
|
||||
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_.trans_model_, model_.feature_info_.silence_weighting_config, 3);
|
||||
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_->trans_model_, model_->feature_info_.silence_weighting_config, 3);
|
||||
|
||||
frame_offset_ += decoder_->NumFramesDecoded();
|
||||
decoder_->InitDecoding(frame_offset_);
|
||||
@@ -137,7 +167,7 @@ void KaldiRecognizer::UpdateSilenceWeights()
|
||||
{
|
||||
if (silence_weighting_->Active() && feature_pipeline_->NumFramesReady() > 0 &&
|
||||
feature_pipeline_->IvectorFeature() != NULL) {
|
||||
std::vector<std::pair<int32, BaseFloat> > delta_weights;
|
||||
vector<pair<int32, BaseFloat> > delta_weights;
|
||||
silence_weighting_->ComputeCurrentTraceback(decoder_->Decoder());
|
||||
silence_weighting_->GetDeltaWeights(feature_pipeline_->NumFramesReady(),
|
||||
frame_offset_ * 3,
|
||||
@@ -188,14 +218,13 @@ bool KaldiRecognizer::AcceptWaveform(Vector<BaseFloat> &wdata)
|
||||
spk_feature_->AcceptWaveform(sample_frequency_, wdata);
|
||||
}
|
||||
|
||||
if (decoder_->EndpointDetected(model_.endpoint_config_)) {
|
||||
if (decoder_->EndpointDetected(model_->endpoint_config_)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Computes an xvector from a chunk of speech features.
|
||||
static void RunNnetComputation(const MatrixBase<BaseFloat> &features,
|
||||
const nnet3::Nnet &nnet, nnet3::CachingOptimizingCompiler *compiler,
|
||||
@@ -212,7 +241,7 @@ static void RunNnetComputation(const MatrixBase<BaseFloat> &features,
|
||||
output_spec.indexes.resize(1);
|
||||
request.outputs.resize(1);
|
||||
request.outputs[0].Swap(&output_spec);
|
||||
std::shared_ptr<const nnet3::NnetComputation> computation = compiler->Compile(request);
|
||||
shared_ptr<const nnet3::NnetComputation> computation = compiler->Compile(request);
|
||||
nnet3::Nnet *nnet_to_update = NULL; // we're not doing any update.
|
||||
nnet3::NnetComputer computer(nnet3::NnetComputeOptions(), *computation,
|
||||
nnet, nnet_to_update);
|
||||
@@ -225,7 +254,6 @@ static void RunNnetComputation(const MatrixBase<BaseFloat> &features,
|
||||
xvector->CopyFromVec(cu_output.Row(0));
|
||||
}
|
||||
|
||||
|
||||
void KaldiRecognizer::GetSpkVector(Vector<BaseFloat> &xvector)
|
||||
{
|
||||
int num_frames = spk_feature_->NumFramesReady() - frame_offset_ * 3;
|
||||
@@ -246,7 +274,6 @@ void KaldiRecognizer::GetSpkVector(Vector<BaseFloat> &xvector)
|
||||
RunNnetComputation(features, spk_model_->speaker_nnet, &compiler, &xvector);
|
||||
}
|
||||
|
||||
|
||||
const char* KaldiRecognizer::Result()
|
||||
{
|
||||
|
||||
@@ -262,30 +289,53 @@ const char* KaldiRecognizer::Result()
|
||||
|
||||
kaldi::CompactLattice clat;
|
||||
decoder_->GetLattice(true, &clat);
|
||||
fst::ScaleLattice(fst::LatticeScale(8.0, 10.0), &clat);
|
||||
|
||||
if (model_->std_lm_fst_) {
|
||||
Lattice lat1;
|
||||
|
||||
ConvertLattice(clat, &lat1);
|
||||
fst::ScaleLattice(fst::GraphLatticeScale(-1.0), &lat1);
|
||||
fst::ArcSort(&lat1, fst::OLabelCompare<kaldi::LatticeArc>());
|
||||
kaldi::Lattice composed_lat;
|
||||
fst::Compose(lat1, *lm_fst_, &composed_lat);
|
||||
fst::Invert(&composed_lat);
|
||||
kaldi::CompactLattice determinized_lat;
|
||||
DeterminizeLattice(composed_lat, &determinized_lat);
|
||||
fst::ScaleLattice(fst::GraphLatticeScale(-1), &determinized_lat);
|
||||
fst::ArcSort(&determinized_lat, fst::OLabelCompare<kaldi::CompactLatticeArc>());
|
||||
|
||||
kaldi::ConstArpaLmDeterministicFst const_arpa_fst(model_->const_arpa_);
|
||||
kaldi::CompactLattice composed_clat;
|
||||
kaldi::ComposeCompactLatticeDeterministic(determinized_lat, &const_arpa_fst, &composed_clat);
|
||||
kaldi::Lattice composed_lat1;
|
||||
ConvertLattice(composed_clat, &composed_lat1);
|
||||
fst::Invert(&composed_lat1);
|
||||
DeterminizeLattice(composed_lat1, &clat);
|
||||
}
|
||||
|
||||
fst::ScaleLattice(fst::LatticeScale(9.0, 10.0), &clat);
|
||||
CompactLattice aligned_lat;
|
||||
if (model_.winfo_) {
|
||||
WordAlignLattice(clat, *model_.trans_model_, *model_.winfo_, 0, &aligned_lat);
|
||||
if (model_->winfo_) {
|
||||
WordAlignLattice(clat, *model_->trans_model_, *model_->winfo_, 0, &aligned_lat);
|
||||
} else {
|
||||
aligned_lat = clat;
|
||||
}
|
||||
|
||||
MinimumBayesRisk mbr(aligned_lat);
|
||||
const std::vector<BaseFloat> &conf = mbr.GetOneBestConfidences();
|
||||
const std::vector<int32> &words = mbr.GetOneBest();
|
||||
const std::vector<std::pair<BaseFloat, BaseFloat> > × =
|
||||
const vector<BaseFloat> &conf = mbr.GetOneBestConfidences();
|
||||
const vector<int32> &words = mbr.GetOneBest();
|
||||
const vector<pair<BaseFloat, BaseFloat> > × =
|
||||
mbr.GetOneBestTimes();
|
||||
|
||||
int size = words.size();
|
||||
|
||||
json::JSON obj;
|
||||
std::stringstream text;
|
||||
stringstream text;
|
||||
|
||||
// Create JSON object
|
||||
for (int i = 0; i < size; i++) {
|
||||
json::JSON word;
|
||||
word["word"] = model_.word_syms_->Find(words[i]);
|
||||
word["word"] = model_->word_syms_->Find(words[i]);
|
||||
word["start"] = (frame_offset_ + times[i].first) * 0.03;
|
||||
word["end"] = (frame_offset_ + times[i].second) * 0.03;
|
||||
word["conf"] = conf[i];
|
||||
@@ -294,7 +344,7 @@ const char* KaldiRecognizer::Result()
|
||||
if (i) {
|
||||
text << " ";
|
||||
}
|
||||
text << model_.word_syms_->Find(words[i]);
|
||||
text << model_->word_syms_->Find(words[i]);
|
||||
}
|
||||
obj["text"] = text.str();
|
||||
|
||||
@@ -321,16 +371,16 @@ const char* KaldiRecognizer::PartialResult()
|
||||
|
||||
kaldi::Lattice lat;
|
||||
decoder_->GetBestPath(false, &lat);
|
||||
std::vector<kaldi::int32> alignment, words;
|
||||
vector<kaldi::int32> alignment, words;
|
||||
LatticeWeight weight;
|
||||
GetLinearSymbolSequence(lat, &alignment, &words, &weight);
|
||||
|
||||
std::ostringstream text;
|
||||
ostringstream text;
|
||||
for (size_t i = 0; i < words.size(); i++) {
|
||||
if (i) {
|
||||
text << " ";
|
||||
}
|
||||
text << model_.word_syms_->Find(words[i]);
|
||||
text << model_->word_syms_->Find(words[i]);
|
||||
}
|
||||
res["partial"] = text.str();
|
||||
|
||||
|
||||
@@ -31,9 +31,9 @@ using namespace kaldi;
|
||||
|
||||
class KaldiRecognizer {
|
||||
public:
|
||||
KaldiRecognizer(Model &model, float sample_frequency);
|
||||
KaldiRecognizer(Model &model, SpkModel *spk_model, float sample_frequency);
|
||||
KaldiRecognizer(Model &model, float sample_frequency, char const *grammar);
|
||||
KaldiRecognizer(Model *model, float sample_frequency);
|
||||
KaldiRecognizer(Model *model, SpkModel *spk_model, float sample_frequency);
|
||||
KaldiRecognizer(Model *model, float sample_frequency, char const *grammar);
|
||||
~KaldiRecognizer();
|
||||
bool AcceptWaveform(const char *data, int len);
|
||||
bool AcceptWaveform(const short *sdata, int len);
|
||||
@@ -43,12 +43,13 @@ class KaldiRecognizer {
|
||||
const char* PartialResult();
|
||||
|
||||
private:
|
||||
void InitRescoring();
|
||||
void CleanUp();
|
||||
void UpdateSilenceWeights();
|
||||
bool AcceptWaveform(Vector<BaseFloat> &wdata);
|
||||
void GetSpkVector(Vector<BaseFloat> &xvector);
|
||||
|
||||
Model &model_;
|
||||
Model *model_;
|
||||
SingleUtteranceNnet3Decoder *decoder_;
|
||||
fst::LookaheadFst<fst::StdArc, int32> *decode_fst_;
|
||||
fst::StdVectorFst *g_fst_; // dynamically constructed grammar
|
||||
@@ -58,8 +59,10 @@ class KaldiRecognizer {
|
||||
SpkModel *spk_model_;
|
||||
OnlineBaseFeature *spk_feature_;
|
||||
|
||||
fst::MapFst<fst::StdArc, kaldi::LatticeArc, fst::StdToLatticeMapper<kaldi::BaseFloat> > *lm_fst_;
|
||||
|
||||
float sample_frequency_;
|
||||
int32 frame_offset_;
|
||||
bool input_finalized_;
|
||||
std::string last_result_;
|
||||
string last_result_;
|
||||
};
|
||||
|
||||
+193
-43
@@ -45,19 +45,97 @@ static FstRegisterer<NGramFst<StdArc>> NGramFst_StdArc_registerer;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
static void AndroidLogHandler(const LogMessageEnvelope &env, const char *message)
|
||||
static void KaldiLogHandler(const LogMessageEnvelope &env, const char *message)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_VERBOSE, "KaldiDemo", message, 1);
|
||||
int priority;
|
||||
if (env.severity > GetVerboseLevel())
|
||||
return;
|
||||
|
||||
if (env.severity > LogMessageEnvelope::kInfo) {
|
||||
priority = ANDROID_LOG_VERBOSE;
|
||||
} else {
|
||||
switch (env.severity) {
|
||||
case LogMessageEnvelope::kInfo:
|
||||
priority = ANDROID_LOG_INFO;
|
||||
break;
|
||||
case LogMessageEnvelope::kWarning:
|
||||
priority = ANDROID_LOG_WARN;
|
||||
break;
|
||||
case LogMessageEnvelope::kAssertFailed:
|
||||
priority = ANDROID_LOG_FATAL;
|
||||
break;
|
||||
case LogMessageEnvelope::kError:
|
||||
default: // If not the ERROR, it still an error!
|
||||
priority = ANDROID_LOG_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream full_message;
|
||||
full_message << env.func << "():" << env.file << ':'
|
||||
<< env.line << ") " << message;
|
||||
|
||||
__android_log_print(priority, "VoskAPI", "%s", full_message.str().c_str());
|
||||
}
|
||||
#else
|
||||
static void KaldiLogHandler(const LogMessageEnvelope &env, const char *message)
|
||||
{
|
||||
if (env.severity > GetVerboseLevel())
|
||||
return;
|
||||
|
||||
// Modified default Kaldi logging so we can disable LOG messages.
|
||||
std::stringstream full_message;
|
||||
if (env.severity > LogMessageEnvelope::kInfo) {
|
||||
full_message << "VLOG[" << env.severity << "] (";
|
||||
} else {
|
||||
switch (env.severity) {
|
||||
case LogMessageEnvelope::kInfo:
|
||||
full_message << "LOG (";
|
||||
break;
|
||||
case LogMessageEnvelope::kWarning:
|
||||
full_message << "WARNING (";
|
||||
break;
|
||||
case LogMessageEnvelope::kAssertFailed:
|
||||
full_message << "ASSERTION_FAILED (";
|
||||
break;
|
||||
case LogMessageEnvelope::kError:
|
||||
default: // If not the ERROR, it still an error!
|
||||
full_message << "ERROR (";
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Add other info from the envelope and the message text.
|
||||
full_message << "VoskAPI" << ':'
|
||||
<< env.func << "():" << env.file << ':'
|
||||
<< env.line << ") " << message;
|
||||
|
||||
// Print the complete message to stderr.
|
||||
full_message << "\n";
|
||||
std::cerr << full_message.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
Model::Model(const char *model_path) {
|
||||
Model::Model(const char *model_path) : model_path_str_(model_path) {
|
||||
|
||||
#ifdef __ANDROID__
|
||||
SetLogHandler(AndroidLogHandler);
|
||||
#endif
|
||||
SetLogHandler(KaldiLogHandler);
|
||||
|
||||
const char *usage = "Read the docs";
|
||||
struct stat buffer;
|
||||
string am_path = model_path_str_ + "/am/final.mdl";
|
||||
if (stat(am_path.c_str(), &buffer) == 0) {
|
||||
ConfigureV2();
|
||||
} else {
|
||||
ConfigureV1();
|
||||
}
|
||||
|
||||
ReadDataFiles();
|
||||
|
||||
ref_cnt_ = 1;
|
||||
}
|
||||
|
||||
// Old model layout without model configuration file
|
||||
|
||||
void Model::ConfigureV1()
|
||||
{
|
||||
const char *extra_args[] = {
|
||||
"--min-active=200",
|
||||
"--max-active=3000",
|
||||
@@ -71,55 +149,98 @@ Model::Model(const char *model_path) {
|
||||
"--endpoint.rule2.min-trailing-silence=0.5",
|
||||
"--endpoint.rule3.min-trailing-silence=1.0",
|
||||
"--endpoint.rule4.min-trailing-silence=2.0",
|
||||
};
|
||||
std::string model_path_str(model_path);
|
||||
|
||||
kaldi::ParseOptions po(usage);
|
||||
"--print-args=false",
|
||||
};
|
||||
|
||||
kaldi::ParseOptions po("");
|
||||
nnet3_decoding_config_.Register(&po);
|
||||
endpoint_config_.Register(&po);
|
||||
decodable_opts_.Register(&po);
|
||||
|
||||
std::vector<const char*> args;
|
||||
vector<const char*> args;
|
||||
args.push_back("vosk");
|
||||
args.insert(args.end(), extra_args, extra_args + sizeof(extra_args) / sizeof(extra_args[0]));
|
||||
po.Read(args.size(), args.data());
|
||||
|
||||
feature_info_.feature_type = "mfcc";
|
||||
ReadConfigFromFile(model_path_str + "/mfcc.conf", &feature_info_.mfcc_opts);
|
||||
ReadConfigFromFile(model_path_str_ + "/mfcc.conf", &feature_info_.mfcc_opts);
|
||||
feature_info_.mfcc_opts.frame_opts.allow_downsample = true; // It is safe to downsample
|
||||
|
||||
feature_info_.silence_weighting_config.silence_weight = 1e-3;
|
||||
feature_info_.silence_weighting_config.silence_phones_str = "1:2:3:4:5:6:7:8:9:10";
|
||||
feature_info_.silence_weighting_config.silence_phones_str = endpoint_config_.silence_phones;
|
||||
|
||||
OnlineIvectorExtractionConfig ivector_extraction_opts;
|
||||
ivector_extraction_opts.splice_config_rxfilename = model_path_str + "/ivector/splice.conf";
|
||||
ivector_extraction_opts.cmvn_config_rxfilename = model_path_str + "/ivector/online_cmvn.conf";
|
||||
ivector_extraction_opts.lda_mat_rxfilename = model_path_str + "/ivector/final.mat";
|
||||
ivector_extraction_opts.global_cmvn_stats_rxfilename = model_path_str + "/ivector/global_cmvn.stats";
|
||||
ivector_extraction_opts.diag_ubm_rxfilename = model_path_str + "/ivector/final.dubm";
|
||||
ivector_extraction_opts.ivector_extractor_rxfilename = model_path_str + "/ivector/final.ie";
|
||||
ivector_extraction_opts.num_gselect = 5;
|
||||
ivector_extraction_opts.min_post = 0.025;
|
||||
ivector_extraction_opts.posterior_scale = 0.1;
|
||||
ivector_extraction_opts.max_remembered_frames = 1000;
|
||||
ivector_extraction_opts.max_count = 100;
|
||||
ivector_extraction_opts.ivector_period = 200;
|
||||
ivector_extraction_opts.splice_config_rxfilename = model_path_str_ + "/ivector/splice.conf";
|
||||
ivector_extraction_opts.cmvn_config_rxfilename = model_path_str_ + "/ivector/online_cmvn.conf";
|
||||
ivector_extraction_opts.lda_mat_rxfilename = model_path_str_ + "/ivector/final.mat";
|
||||
ivector_extraction_opts.global_cmvn_stats_rxfilename = model_path_str_ + "/ivector/global_cmvn.stats";
|
||||
ivector_extraction_opts.diag_ubm_rxfilename = model_path_str_ + "/ivector/final.dubm";
|
||||
ivector_extraction_opts.ivector_extractor_rxfilename = model_path_str_ + "/ivector/final.ie";
|
||||
feature_info_.use_ivectors = true;
|
||||
feature_info_.ivector_extractor_info.Init(ivector_extraction_opts);
|
||||
|
||||
std::string nnet3_rxfilename = model_path_str + "/final.mdl";
|
||||
std::string hclg_fst_rxfilename = model_path_str + "/HCLG.fst";
|
||||
std::string hcl_fst_rxfilename = model_path_str + "/HCLr.fst";
|
||||
std::string g_fst_rxfilename = model_path_str + "/Gr.fst";
|
||||
std::string disambig_rxfilename = model_path_str + "/disambig_tid.int";
|
||||
std::string word_syms_rxfilename = model_path_str + "/words.txt";
|
||||
std::string winfo_rxfilename = model_path_str + "/word_boundary.int";
|
||||
nnet3_rxfilename_ = model_path_str_ + "/final.mdl";
|
||||
hclg_fst_rxfilename_ = model_path_str_ + "/HCLG.fst";
|
||||
hcl_fst_rxfilename_ = model_path_str_ + "/HCLr.fst";
|
||||
g_fst_rxfilename_ = model_path_str_ + "/Gr.fst";
|
||||
disambig_rxfilename_ = model_path_str_ + "/disambig_tid.int";
|
||||
word_syms_rxfilename_ = model_path_str_ + "/words.txt";
|
||||
winfo_rxfilename_ = model_path_str_ + "/word_boundary.int";
|
||||
carpa_rxfilename_ = model_path_str_ + "/rescore/G.carpa";
|
||||
std_fst_rxfilename_ = model_path_str_ + "/rescore/G.fst";
|
||||
}
|
||||
|
||||
void Model::ConfigureV2()
|
||||
{
|
||||
kaldi::ParseOptions po("something");
|
||||
nnet3_decoding_config_.Register(&po);
|
||||
endpoint_config_.Register(&po);
|
||||
decodable_opts_.Register(&po);
|
||||
po.ReadConfigFile(model_path_str_ + "/conf/model.conf");
|
||||
|
||||
KALDI_LOG << "Decoding params beam=" << nnet3_decoding_config_.beam <<
|
||||
" max-active=" << nnet3_decoding_config_.max_active <<
|
||||
" lattice-beam=" << nnet3_decoding_config_.lattice_beam;
|
||||
KALDI_LOG << "Silence phones " << endpoint_config_.silence_phones;
|
||||
|
||||
feature_info_.feature_type = "mfcc";
|
||||
ReadConfigFromFile(model_path_str_ + "/conf/mfcc.conf", &feature_info_.mfcc_opts);
|
||||
feature_info_.mfcc_opts.frame_opts.allow_downsample = true; // It is safe to downsample
|
||||
|
||||
feature_info_.silence_weighting_config.silence_weight = 1e-3;
|
||||
feature_info_.silence_weighting_config.silence_phones_str = endpoint_config_.silence_phones;
|
||||
|
||||
OnlineIvectorExtractionConfig ivector_extraction_opts;
|
||||
ivector_extraction_opts.splice_config_rxfilename = model_path_str_ + "/ivector/splice.conf";
|
||||
ivector_extraction_opts.cmvn_config_rxfilename = model_path_str_ + "/ivector/online_cmvn.conf";
|
||||
ivector_extraction_opts.lda_mat_rxfilename = model_path_str_ + "/ivector/final.mat";
|
||||
ivector_extraction_opts.global_cmvn_stats_rxfilename = model_path_str_ + "/ivector/global_cmvn.stats";
|
||||
ivector_extraction_opts.diag_ubm_rxfilename = model_path_str_ + "/ivector/final.dubm";
|
||||
ivector_extraction_opts.ivector_extractor_rxfilename = model_path_str_ + "/ivector/final.ie";
|
||||
feature_info_.use_ivectors = true;
|
||||
feature_info_.ivector_extractor_info.Init(ivector_extraction_opts);
|
||||
|
||||
nnet3_rxfilename_ = model_path_str_ + "/am/final.mdl";
|
||||
hclg_fst_rxfilename_ = model_path_str_ + "/graph/HCLG.fst";
|
||||
hcl_fst_rxfilename_ = model_path_str_ + "/graph/HCLr.fst";
|
||||
g_fst_rxfilename_ = model_path_str_ + "/graph/Gr.fst";
|
||||
disambig_rxfilename_ = model_path_str_ + "/graph/disambig_tid.int";
|
||||
word_syms_rxfilename_ = model_path_str_ + "/graph/words.txt";
|
||||
winfo_rxfilename_ = model_path_str_ + "/graph/phones/word_boundary.int";
|
||||
carpa_rxfilename_ = model_path_str_ + "/rescore/G.carpa";
|
||||
std_fst_rxfilename_ = model_path_str_ + "/rescore/G.fst";
|
||||
}
|
||||
|
||||
void Model::ReadDataFiles()
|
||||
{
|
||||
struct stat buffer;
|
||||
|
||||
trans_model_ = new kaldi::TransitionModel();
|
||||
nnet_ = new kaldi::nnet3::AmNnetSimple();
|
||||
{
|
||||
bool binary;
|
||||
kaldi::Input ki(nnet3_rxfilename, &binary);
|
||||
kaldi::Input ki(nnet3_rxfilename_, &binary);
|
||||
trans_model_->Read(ki.Stream(), binary);
|
||||
nnet_->Read(ki.Stream(), binary);
|
||||
SetBatchnormTestMode(true, &(nnet_->GetNnet()));
|
||||
@@ -129,16 +250,17 @@ Model::Model(const char *model_path) {
|
||||
decodable_info_ = new nnet3::DecodableNnetSimpleLoopedInfo(decodable_opts_,
|
||||
nnet_);
|
||||
|
||||
struct stat buffer;
|
||||
if (stat(hclg_fst_rxfilename.c_str(), &buffer) == 0) {
|
||||
hclg_fst_ = fst::ReadFstKaldiGeneric(hclg_fst_rxfilename);
|
||||
if (stat(hclg_fst_rxfilename_.c_str(), &buffer) == 0) {
|
||||
KALDI_LOG << "Loading HCLG from " << hclg_fst_rxfilename_;
|
||||
hclg_fst_ = fst::ReadFstKaldiGeneric(hclg_fst_rxfilename_);
|
||||
hcl_fst_ = NULL;
|
||||
g_fst_ = NULL;
|
||||
} else {
|
||||
KALDI_LOG << "Loading HCL and G from " << hcl_fst_rxfilename_ << " " << g_fst_rxfilename_;
|
||||
hclg_fst_ = NULL;
|
||||
hcl_fst_ = fst::StdFst::Read(hcl_fst_rxfilename);
|
||||
g_fst_ = fst::StdFst::Read(g_fst_rxfilename);
|
||||
ReadIntegerVectorSimple(disambig_rxfilename, &disambig_);
|
||||
hcl_fst_ = fst::StdFst::Read(hcl_fst_rxfilename_);
|
||||
g_fst_ = fst::StdFst::Read(g_fst_rxfilename_);
|
||||
ReadIntegerVectorSimple(disambig_rxfilename_, &disambig_);
|
||||
}
|
||||
|
||||
word_syms_ = NULL;
|
||||
@@ -148,18 +270,46 @@ Model::Model(const char *model_path) {
|
||||
word_syms_ = g_fst_->OutputSymbols();
|
||||
}
|
||||
if (!word_syms_) {
|
||||
if (!(word_syms_ = fst::SymbolTable::ReadText(word_syms_rxfilename)))
|
||||
KALDI_LOG << "Loading words from " << word_syms_rxfilename_;
|
||||
if (!(word_syms_ = fst::SymbolTable::ReadText(word_syms_rxfilename_)))
|
||||
KALDI_ERR << "Could not read symbol table from file "
|
||||
<< word_syms_rxfilename;
|
||||
<< word_syms_rxfilename_;
|
||||
}
|
||||
KALDI_ASSERT(word_syms_);
|
||||
|
||||
if (stat(winfo_rxfilename.c_str(), &buffer) == 0) {
|
||||
if (stat(winfo_rxfilename_.c_str(), &buffer) == 0) {
|
||||
KALDI_LOG << "Loading winfo " << winfo_rxfilename_;
|
||||
kaldi::WordBoundaryInfoNewOpts opts;
|
||||
winfo_ = new kaldi::WordBoundaryInfo(opts, winfo_rxfilename);
|
||||
winfo_ = new kaldi::WordBoundaryInfo(opts, winfo_rxfilename_);
|
||||
} else {
|
||||
winfo_ = NULL;
|
||||
}
|
||||
|
||||
if (stat(carpa_rxfilename_.c_str(), &buffer) == 0) {
|
||||
KALDI_LOG << "Loading CARPA model from " << carpa_rxfilename_;
|
||||
std_lm_fst_ = fst::ReadFstKaldi(std_fst_rxfilename_);
|
||||
fst::Project(std_lm_fst_, fst::PROJECT_OUTPUT);
|
||||
if (std_lm_fst_->Properties(fst::kILabelSorted, true) == 0) {
|
||||
fst::ILabelCompare<fst::StdArc> ilabel_comp;
|
||||
fst::ArcSort(std_lm_fst_, ilabel_comp);
|
||||
}
|
||||
ReadKaldiObject(carpa_rxfilename_, &const_arpa_);
|
||||
} else {
|
||||
std_lm_fst_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Model::Ref()
|
||||
{
|
||||
ref_cnt_++;
|
||||
}
|
||||
|
||||
void Model::Unref()
|
||||
{
|
||||
ref_cnt_--;
|
||||
if (ref_cnt_ == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
Model::~Model() {
|
||||
|
||||
+25
-2
@@ -32,6 +32,7 @@
|
||||
#include "rnnlm/rnnlm-utils.h"
|
||||
|
||||
using namespace kaldi;
|
||||
using namespace std;
|
||||
|
||||
class KaldiRecognizer;
|
||||
|
||||
@@ -39,11 +40,28 @@ class Model {
|
||||
|
||||
public:
|
||||
Model(const char *model_path);
|
||||
~Model();
|
||||
void Ref();
|
||||
void Unref();
|
||||
|
||||
protected:
|
||||
~Model();
|
||||
void ConfigureV1();
|
||||
void ConfigureV2();
|
||||
void ReadDataFiles();
|
||||
|
||||
friend class KaldiRecognizer;
|
||||
|
||||
string model_path_str_;
|
||||
string nnet3_rxfilename_;
|
||||
string hclg_fst_rxfilename_;
|
||||
string hcl_fst_rxfilename_;
|
||||
string g_fst_rxfilename_;
|
||||
string disambig_rxfilename_;
|
||||
string word_syms_rxfilename_;
|
||||
string winfo_rxfilename_;
|
||||
string carpa_rxfilename_;
|
||||
string std_fst_rxfilename_;
|
||||
|
||||
kaldi::OnlineEndpointConfig endpoint_config_;
|
||||
kaldi::LatticeFasterDecoderConfig nnet3_decoding_config_;
|
||||
kaldi::nnet3::NnetSimpleLoopedComputationOptions decodable_opts_;
|
||||
@@ -54,11 +72,16 @@ protected:
|
||||
kaldi::nnet3::AmNnetSimple *nnet_;
|
||||
const fst::SymbolTable *word_syms_;
|
||||
kaldi::WordBoundaryInfo *winfo_;
|
||||
std::vector<int32> disambig_;
|
||||
vector<int32> disambig_;
|
||||
|
||||
fst::Fst<fst::StdArc> *hclg_fst_;
|
||||
fst::Fst<fst::StdArc> *hcl_fst_;
|
||||
fst::Fst<fst::StdArc> *g_fst_;
|
||||
|
||||
fst::VectorFst<fst::StdArc> *std_lm_fst_;
|
||||
kaldi::ConstArpaLm const_arpa_;
|
||||
|
||||
int ref_cnt_;
|
||||
};
|
||||
|
||||
#endif /* MODEL_H_ */
|
||||
|
||||
@@ -24,4 +24,19 @@ SpkModel::SpkModel(const char *speaker_path) {
|
||||
SetBatchnormTestMode(true, &speaker_nnet);
|
||||
SetDropoutTestMode(true, &speaker_nnet);
|
||||
CollapseModel(nnet3::CollapseModelConfig(), &speaker_nnet);
|
||||
|
||||
ref_cnt_ = 1;
|
||||
}
|
||||
|
||||
void SpkModel::Ref()
|
||||
{
|
||||
ref_cnt_++;
|
||||
}
|
||||
|
||||
void SpkModel::Unref()
|
||||
{
|
||||
ref_cnt_--;
|
||||
if (ref_cnt_ == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,12 +27,17 @@ class SpkModel {
|
||||
|
||||
public:
|
||||
SpkModel(const char *spk_path);
|
||||
void Ref();
|
||||
void Unref();
|
||||
|
||||
protected:
|
||||
friend class KaldiRecognizer;
|
||||
~SpkModel() {};
|
||||
|
||||
kaldi::nnet3::Nnet speaker_nnet;
|
||||
MfccOptions spkvector_mfcc_opts;
|
||||
|
||||
int ref_cnt_;
|
||||
};
|
||||
|
||||
#endif /* SPK_MODEL_H_ */
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#if SWIGPYTHON
|
||||
%module(package="vosk", "threads"=1) vosk
|
||||
#else
|
||||
%module Vosk
|
||||
#endif
|
||||
|
||||
%include <typemaps.i>
|
||||
|
||||
@@ -113,3 +117,6 @@ typedef struct {} KaldiRecognizer;
|
||||
return vosk_recognizer_final_result($self);
|
||||
}
|
||||
}
|
||||
|
||||
%rename(SetLogLevel) vosk_set_log_level;
|
||||
void vosk_set_log_level(int level);
|
||||
|
||||
+10
-5
@@ -28,7 +28,7 @@ VoskModel *vosk_model_new(const char *model_path)
|
||||
|
||||
void vosk_model_free(VoskModel *model)
|
||||
{
|
||||
delete (Model *)model;
|
||||
((Model *)model)->Unref();
|
||||
}
|
||||
|
||||
VoskSpkModel *vosk_spk_model_new(const char *model_path)
|
||||
@@ -38,22 +38,22 @@ VoskSpkModel *vosk_spk_model_new(const char *model_path)
|
||||
|
||||
void vosk_spk_model_free(VoskSpkModel *model)
|
||||
{
|
||||
delete (SpkModel *)model;
|
||||
((SpkModel *)model)->Unref();
|
||||
}
|
||||
|
||||
VoskRecognizer *vosk_recognizer_new(VoskModel *model, float sample_rate)
|
||||
{
|
||||
return (VoskRecognizer *)new KaldiRecognizer(*(Model *)model, sample_rate);
|
||||
return (VoskRecognizer *)new KaldiRecognizer((Model *)model, sample_rate);
|
||||
}
|
||||
|
||||
VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, VoskSpkModel *spk_model, float sample_rate)
|
||||
{
|
||||
return (VoskRecognizer *)new KaldiRecognizer(*(Model *)model, (SpkModel *)spk_model, sample_rate);
|
||||
return (VoskRecognizer *)new KaldiRecognizer((Model *)model, (SpkModel *)spk_model, sample_rate);
|
||||
}
|
||||
|
||||
VoskRecognizer *vosk_recognizer_new_grm(VoskModel *model, float sample_rate, const char *grammar)
|
||||
{
|
||||
return (VoskRecognizer *)new KaldiRecognizer(*(Model *)model, sample_rate, grammar);
|
||||
return (VoskRecognizer *)new KaldiRecognizer((Model *)model, sample_rate, grammar);
|
||||
}
|
||||
|
||||
int vosk_recognizer_accept_waveform(VoskRecognizer *recognizer, const char *data, int length)
|
||||
@@ -90,3 +90,8 @@ void vosk_recognizer_free(VoskRecognizer *recognizer)
|
||||
{
|
||||
delete (KaldiRecognizer *)(recognizer);
|
||||
}
|
||||
|
||||
void vosk_set_log_level(int log_level)
|
||||
{
|
||||
SetVerboseLevel(log_level);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,14 @@ const char *vosk_recognizer_partial_result(VoskRecognizer *recognizer);
|
||||
const char *vosk_recognizer_final_result(VoskRecognizer *recognizer);
|
||||
void vosk_recognizer_free(VoskRecognizer *recognizer);
|
||||
|
||||
/**
|
||||
* Set log level for Kaldi messages
|
||||
* 0 - default value to print info and error messages but no debug
|
||||
* less than 0 - don't print info messages
|
||||
* greather than 0 - more verbose mode
|
||||
*/
|
||||
void vosk_set_log_level(int log_level);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -35,7 +35,7 @@ RUN cd /opt \
|
||||
&& sed -i "s:-mfloat-abi=hard -mfpu=neon:${ARM_HARDWARE_OPTS}:g" makefiles/linux_openblas_arm.mk \
|
||||
&& sed -i "s: -O1 : -O3 :g" makefiles/linux_openblas_arm.mk \
|
||||
&& ./configure --mathlib=OPENBLAS --shared --use-cuda=no \
|
||||
&& make -j 10 online2 \
|
||||
&& make -j 10 online2 lm \
|
||||
&& find /opt/kaldi -name "*.o" -exec rm {} \;
|
||||
|
||||
RUN cd /opt \
|
||||
|
||||
@@ -27,7 +27,7 @@ RUN cd /opt \
|
||||
&& make -j 10 openfst \
|
||||
&& cd ../src \
|
||||
&& ./configure --mathlib=OPENBLAS --shared --use-cuda=no \
|
||||
&& make -j 10 online2 \
|
||||
&& make -j 10 online2 lm \
|
||||
&& find /opt/kaldi -name "*.o" -exec rm {} \;
|
||||
|
||||
RUN cd /opt \
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
set -e
|
||||
set -x
|
||||
|
||||
skip() {
|
||||
docker build --build-arg="DOCKCROSS_IMAGE=linux-armv7" --build-arg="OPENBLAS_ARCH=ARMV7" --file Dockerfile.dockcross --tag alphacep/kaldi-dockcross-armv7:latest .
|
||||
docker build --build-arg="DOCKCROSS_IMAGE=linux-armv6" --build-arg="OPENBLAS_ARCH=ARMV6" --build-arg="ARM_HARDWARE_OPTS=" --file Dockerfile.dockcross --tag alphacep/kaldi-dockcross-armv6:latest .
|
||||
docker build --build-arg="DOCKCROSS_IMAGE=linux-arm64" --build-arg="OPENBLAS_ARCH=ARMV8" --file Dockerfile.dockcross --tag alphacep/kaldi-dockcross-arm64:latest .
|
||||
}
|
||||
|
||||
docker run --rm -v /home/shmyrev/travis/vosk-api/:/io alphacep/kaldi-dockcross-armv6 /io/travis/build-wheels-dockcross.sh
|
||||
docker run --rm -v /home/shmyrev/travis/vosk-api/:/io alphacep/kaldi-dockcross-armv7 /io/travis/build-wheels-dockcross.sh
|
||||
|
||||
Reference in New Issue
Block a user