Compare commits

..

40 Commits

Author SHA1 Message Date
Nickolay Shmyrev 0269a10833 Critical ivector bugfix and version 0.3.15 2020-10-13 01:28:46 +02:00
Nickolay Shmyrev 7af3e9a334 Add srt example 2020-10-07 13:43:09 +02:00
Nickolay Shmyrev d666876be1 Revert compile flags 2020-10-05 01:24:32 +02:00
Nickolay Shmyrev 564fab7ec1 Update documentation 2020-10-05 00:16:15 +02:00
Nickolay Shmyrev 155c6c2a2a Don't crash with grammar and static graphs 2020-10-05 00:13:25 +02:00
Nickolay Shmyrev d43cbe9344 Add 0.3.14 2020-10-04 23:45:34 +02:00
Nickolay Shmyrev 57cc474c9f Build bigram language model from grammars 2020-10-04 23:42:50 +02:00
Nickolay Shmyrev 586603f8e1 Add Farsi 2020-10-03 12:42:54 +02:00
Nickolay Shmyrev d57887d22a Add Greek 2020-09-30 13:42:20 +02:00
Nickolay Shmyrev 6183bcfc5f Add Arabic model 2020-09-30 13:29:43 +02:00
Nickolay Shmyrev 65f6113b4d Add Catalan 2020-09-27 11:57:20 +02:00
Nickolay Shmyrev 8d88b89db1 Fix reserved identifier violation. Closes issue #226
Thanks to Markus Elfring
2020-09-23 21:16:34 +02:00
Nickolay Shmyrev 62885e8963 Update descriptions 2020-09-22 11:30:27 +02:00
qo6xup6 9fc094a5da Update kaldi_recognizer.h 2020-09-22 10:11:29 +08:00
Nickolay Shmyrev f97383c17f Update models location 2020-09-22 00:00:24 +02:00
Nickolay Shmyrev 4b892ec5e7 Bump version 2020-09-21 23:49:55 +02:00
Nickolay Shmyrev 41035485db Fix x-vectors, now they actually work. Requires new version spk-model-0.4 with whitening transform matrix 2020-09-21 23:31:30 +02:00
Nickolay Shmyrev 9696f4c917 Mention Dutch 2020-09-18 17:31:17 +02:00
Nickolay Shmyrev 55abf5f5ac Dynamic arch in pip module 2020-09-13 22:08:36 +02:00
Nickolay Shmyrev a1b2e41710 Mention we support Indian English 2020-09-09 23:28:55 +02:00
Nickolay Shmyrev dff4ab26e4 Library is now vosk_jni 2020-09-01 18:27:54 +02:00
Nickolay Shmyrev 83b6e1cdf7 Speech service for more flexible recognizer initialization
Publish repo on jcenter
2020-09-01 16:32:15 +02:00
Nickolay Shmyrev 38dbaa15ea Load JNI inside library itself 2020-09-01 12:44:44 +02:00
Nickolay Shmyrev 0e531b6061 Organize Makefile 2020-08-23 20:10:48 +02:00
Nickolay Shmyrev de94ef5537 Add speaker C demo 2020-08-14 11:33:41 +02:00
Nickolay Shmyrev 6ef9d13877 Add Italian 2020-08-03 01:31:30 +02:00
Nickolay Shmyrev 1c7b94757d Don't attempt to resize to empty matrix 2020-07-31 16:45:05 +02:00
Nickolay Shmyrev 83486e0bef Spk vector fix 2020-07-31 12:58:23 +02:00
Nickolay Shmyrev 9787e8a53f No .html in links 2020-07-21 10:15:27 +02:00
Nickolay Shmyrev f59d6685ad Fix confidences 2020-07-15 10:24:08 +02:00
Nickolay Shmyrev 8a986ef384 Require KALDI_MKL to be 1 2020-07-12 11:03:22 +02:00
Nickolay Shmyrev 78f9f55e14 Fixes description 2020-07-12 10:37:56 +02:00
Nickolay Shmyrev c2e006f664 Some probably helpful flags for npm on osx 2020-07-11 20:54:13 +02:00
Nickolay V. Shmyrev 4b8e9737a5 Update README.md 2020-07-08 01:38:03 +02:00
Nickolay Shmyrev 722b09eaa4 Ignore words missing in the vocabulary 2020-07-08 01:35:50 +02:00
Nickolay Shmyrev f5b4f5a1f2 Added C test 2020-07-08 01:35:50 +02:00
Nickolay Shmyrev 4407d8da55 Another timestamp bugfix 2020-07-08 01:35:50 +02:00
Nickolay Shmyrev 73b73527cd Release memory when final result is received to reduce memory pressure. 2020-07-08 01:35:50 +02:00
Nickolay Shmyrev 4df0e3a741 Actually show the distance 2020-07-08 01:35:49 +02:00
He1nr1chK 1a771e0172 Added cosine distance function 2020-06-23 20:10:14 +02:00
40 changed files with 1073 additions and 184 deletions
+3
View File
@@ -5,6 +5,9 @@
# Java class files
*.class
# Object files
*.o
# Gradle files
.gradle/
build/
+19 -20
View File
@@ -1,26 +1,25 @@
Vosk is an open source speech recognition toolkit which supports 9
languages - English, German, French, Spanish, Portuguese, Chinese,
Russian, Turkish, Vietnamese. Vosk works offline with small (50 Mb), but
accurate model, zero-latency response with streaming API, reconfigurable
# About
Vosk is an offline open source speech recognition toolkit. It enables
speech recognition models for 16 languages and dialects - English, Indian
English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish,
Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi.
Vosk models are small (50 Mb) but provide continuous large vocabulary
transcription, zero-latency response with streaming API, reconfigurable
vocabulary and speaker identification.
### Installation and usage
Speech recognition bindings implemented for various programming languages
like Python, Java, Node.JS, C#, C++ and others.
For Vosk installation instructions, examples and turorial and documentation visit https://alphacephei.com/vosk
Vosk supplies speech recognition for chatbots, smart home appliances,
virtual assistants. It can also create subtitles for movies,
transcription for lectures and interviews.
### Build
Vosk scales from small devices like Raspberry Pi or Android smartphone to
big clusters.
[![Build Status](https://travis-ci.com/alphacep/vosk-api.svg?branch=master)](https://travis-ci.com/alphacep/vosk-api)
# Documentation
### Models for different languages
For information about models see [the documentation on available models](https://alphacephei.com/vosk/models.html).
### Contact Us
If you have any questions, feel free to:
* Post an issue here on github
* Send us an e-mail at [contact@alphacephei.com](mailto:contact@alphacephei.com)
* Join our group dedicated to speech recognition on Telegram [@speech_recognition](https://t.me/speech_recognition)
* We have a Wechat group which is pretty big, so it is invitation-only. Mail us to join the group and provide some information about yourself.
For installation instructions, examples and documentation visit [Vosk
Website](https://alphacephei.com/vosk).
+4 -2
View File
@@ -22,6 +22,8 @@ set(LIB_ROOT "${PROJECT_SOURCE_DIR}/build/kaldi_${KALDI_SUFFIX}/local")
set(API_SOURCES
"${PROJECT_SOURCE_DIR}/../src/kaldi_recognizer.cc"
"${PROJECT_SOURCE_DIR}/../src/kaldi_recognizer.h"
"${PROJECT_SOURCE_DIR}/../src/language_model.cc"
"${PROJECT_SOURCE_DIR}/../src/language_model.h"
"${PROJECT_SOURCE_DIR}/../src/model.cc"
"${PROJECT_SOURCE_DIR}/../src/model.h"
"${PROJECT_SOURCE_DIR}/../src/spk_model.cc"
@@ -32,14 +34,14 @@ set(API_SOURCES
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DFST_NO_DYNAMIC_LINKING")
add_library( kaldi_jni SHARED
add_library( vosk_jni SHARED
build/generated-src/cpp/vosk_wrap.cc
${API_SOURCES}
)
include_directories("${PROJECT_SOURCE_DIR}/../src" "build/kaldi_${KALDI_SUFFIX}/kaldi/src" "build/kaldi_${KALDI_SUFFIX}/local/include")
target_link_libraries( kaldi_jni
target_link_libraries( vosk_jni
${KALDI_ROOT}/src/online2/kaldi-online2.a
${KALDI_ROOT}/src/decoder/kaldi-decoder.a
${KALDI_ROOT}/src/ivector/kaldi-ivector.a
+45 -3
View File
@@ -5,9 +5,17 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
}
}
plugins {
id "com.jfrog.bintray" version "1.8.5"
}
def archiveName = "vosk-android"
def libVersion = "0.3.15"
allprojects {
repositories {
google()
@@ -16,15 +24,16 @@ allprojects {
}
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 21
targetSdkVersion 29
versionCode 5
versionName "5.2"
setProperty("archivesBaseName", "kaldi-android-$versionName")
versionCode 6
versionName = libVersion
archivesBaseName = archiveName
externalNativeBuild {
cmake {
arguments "-DCMAKE_VERBOSE_MAKEFILE=ON", "-DANDROID_ARM_NEON=TRUE", "-DCMAKE_CXX_FLAGS_RELEASE=-O3"
@@ -46,6 +55,39 @@ android {
}
}
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
bintray {
user = properties.getProperty("bintray.user")
key = properties.getProperty("bintray.apikey")
pkg {
repo = 'vosk'
name = 'vosk-android'
userOrg = "alphacep"
licenses = ['Apache2.0']
websiteUrl = 'https://github.com/alphacep/vosk-api'
issueTrackerUrl = 'https://github.com/alphacep/vosk-api/issues'
vcsUrl = 'https://github.com/alphacep/vosk-api'
version {
name = libVersion
vcsTag = libVersion
}
}
publications = ['aar']
}
publishing {
publications {
aar(MavenPublication) {
groupId 'com.alphacep'
artifactId archiveName
version libVersion
artifact("$buildDir/outputs/aar/$archiveName-release.aar")
}
}
}
task swig {
doLast {
mkdir 'build/generated-src/java'
@@ -29,19 +29,18 @@ import android.os.Looper;
import android.util.Log;
/**
* Main class to access recognizer functions. After configuration this class
* starts a listener thread which records the data and recognizes it using
* VOSK engine. Recognition events are passed to a client using
* Service that records audio in a thread, passes it to a recognizer and emits
* recognition results. Recognition events are passed to a client using
* {@link RecognitionListener}
*
*
*/
public class SpeechRecognizer {
public class SpeechService {
protected static final String TAG = SpeechRecognizer.class.getSimpleName();
protected static final String TAG = SpeechService.class.getSimpleName();
private final KaldiRecognizer recognizer;
private final int sampleRate;
private final int sampleRate;
private final static float BUFFER_SIZE_SECONDS = 0.4f;
private int bufferSize;
private final AudioRecord recorder;
@@ -53,33 +52,18 @@ public class SpeechRecognizer {
private final Collection<RecognitionListener> listeners = new HashSet<RecognitionListener>();
/**
* Creates speech recognizer. Recognizer holds the AudioRecord object, so you
* Creates speech service. Service holds the AudioRecord object, so you
* need to call {@link release} in order to properly finalize it.
*
* @throws IOException thrown if audio recorder can not be created for some reason.
*/
public SpeechRecognizer(Model model) throws IOException {
recognizer = new KaldiRecognizer(model, 16000.0f);
sampleRate = 16000;
bufferSize = Math.round(sampleRate * BUFFER_SIZE_SECONDS);
recorder = new AudioRecord(
AudioSource.VOICE_RECOGNITION, sampleRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize * 2);
public SpeechService(KaldiRecognizer recognizer, float sampleRate) throws IOException {
this.recognizer = recognizer;
this.sampleRate = (int)sampleRate;
if (recorder.getState() == AudioRecord.STATE_UNINITIALIZED) {
recorder.release();
throw new IOException(
"Failed to initialize recorder. Microphone might be already in use.");
}
}
public SpeechRecognizer(Model model, SpkModel spkModel) throws IOException {
recognizer = new KaldiRecognizer(model, spkModel, 16000.0f);
sampleRate = 16000;
bufferSize = Math.round(sampleRate * BUFFER_SIZE_SECONDS);
bufferSize = Math.round(this.sampleRate * BUFFER_SIZE_SECONDS);
recorder = new AudioRecord(
AudioSource.VOICE_RECOGNITION, sampleRate,
AudioSource.VOICE_RECOGNITION, this.sampleRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize * 2);
@@ -187,9 +171,9 @@ public class SpeechRecognizer {
public void shutdown() {
recorder.release();
}
private final class RecognizerThread extends Thread {
private int remainingSamples;
private int timeoutSamples;
private final static int NO_TIMEOUT = -1;
+50
View File
@@ -0,0 +1,50 @@
KALDI_ROOT=$(HOME)/travis/kaldi
VOSK_SOURCES= \
../src/kaldi_recognizer.cc \
../src/language_model.cc \
../src/model.cc \
../src/spk_model.cc \
../src/vosk_api.cc
CFLAGS=-g -O2 -DFST_NO_DYNAMIC_LINKING -I../src -I$(KALDI_ROOT)/src -I$(KALDI_ROOT)/tools/openfst/include
LIBS= \
$(KALDI_ROOT)/src/online2/kaldi-online2.a \
$(KALDI_ROOT)/src/decoder/kaldi-decoder.a \
$(KALDI_ROOT)/src/ivector/kaldi-ivector.a \
$(KALDI_ROOT)/src/gmm/kaldi-gmm.a \
$(KALDI_ROOT)/src/nnet3/kaldi-nnet3.a \
$(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 \
$(KALDI_ROOT)/src/matrix/kaldi-matrix.a \
$(KALDI_ROOT)/src/fstext/kaldi-fstext.a \
$(KALDI_ROOT)/src/util/kaldi-util.a \
$(KALDI_ROOT)/src/base/kaldi-base.a \
$(KALDI_ROOT)/tools/OpenBLAS/libopenblas.a \
$(KALDI_ROOT)/tools/openfst/lib/libfst.a \
$(KALDI_ROOT)/tools/openfst/lib/libfstngram.a
all: test_vosk test_vosk_speaker
test_vosk: test_vosk.o libvosk.a
g++ $^ -o $@ $(LIBS) -lgfortran -lpthread
test_vosk_speaker: test_vosk_speaker.o libvosk.a
g++ $^ -o $@ $(LIBS) -lgfortran -lpthread
libvosk.a: $(VOSK_SOURCES:.cc=.o)
ar rcs $@ $^
%.o: %.c
g++ $(CFLAGS) -c -o $@ $<
%.o: %.cc
g++ -std=c++11 $(CFLAGS) -c -o $@ $<
clean:
rm -f *.o *.a test_vosk
+28
View File
@@ -0,0 +1,28 @@
#include <vosk_api.h>
#include <stdio.h>
int main() {
FILE *wavin;
char buf[3200];
int nread, final;
VoskModel *model = vosk_model_new("model");
VoskRecognizer *recognizer = vosk_recognizer_new(model, 16000.0);
wavin = fopen("test.wav", "rb");
fseek(wavin, 44, SEEK_SET);
while (!feof(wavin)) {
nread = fread(buf, 1, sizeof(buf), wavin);
final = vosk_recognizer_accept_waveform(recognizer, buf, nread);
if (final) {
printf("%s\n", vosk_recognizer_result(recognizer));
} else {
printf("%s\n", vosk_recognizer_partial_result(recognizer));
}
}
printf("%s\n", vosk_recognizer_final_result(recognizer));
vosk_recognizer_free(recognizer);
vosk_model_free(model);
return 0;
}
+30
View File
@@ -0,0 +1,30 @@
#include <vosk_api.h>
#include <stdio.h>
int main() {
FILE *wavin;
char buf[3200];
int nread, final;
VoskModel *model = vosk_model_new("model");
VoskSpkModel *spk_model = vosk_spk_model_new("spk-model");
VoskRecognizer *recognizer = vosk_recognizer_new_spk(model, spk_model, 16000.0);
wavin = fopen("test.wav", "rb");
fseek(wavin, 44, SEEK_SET);
while (!feof(wavin)) {
nread = fread(buf, 1, sizeof(buf), wavin);
final = vosk_recognizer_accept_waveform(recognizer, buf, nread);
if (final) {
printf("%s\n", vosk_recognizer_result(recognizer));
} else {
printf("%s\n", vosk_recognizer_partial_result(recognizer));
}
}
printf("%s\n", vosk_recognizer_final_result(recognizer));
vosk_recognizer_free(recognizer);
vosk_spk_model_free(spk_model);
vosk_model_free(model);
return 0;
}
+17 -10
View File
@@ -20,9 +20,12 @@ KALDI_LIBS = \
${KALDI_ROOT}/src/util/kaldi-util.a \
${KALDI_ROOT}/src/base/kaldi-base.a \
${KALDI_ROOT}/tools/openfst/lib/libfst.a \
${KALDI_ROOT}/tools/openfst/lib/libfstngram.a \
${KALDI_ROOT}/tools/OpenBLAS/libopenblas.a \
-lgfortran -lstdc++
${KALDI_ROOT}/tools/openfst/lib/libfstngram.a
# On Linux
MATH_LIBS = ${KALDI_ROOT}/tools/OpenBLAS/libopenblas.a -lgfortran
# On OSX
# MATH_LIBS = -framework Accelerate
all: test.exe
@@ -32,16 +35,20 @@ test.exe: libkaldiwrap.so test.cs
VOSK_SOURCES = \
vosk_wrap.c \
../src/kaldi_recognizer.cc \
../src/kaldi_recognizer.h \
../src/language_model.cc \
../src/model.cc \
../src/model.h \
../src/spk_model.cc \
../src/spk_model.h \
../src/vosk_api.cc \
../src/vosk_api.h
../src/vosk_api.cc
libkaldiwrap.so: $(VOSK_SOURCES)
$(CXX) -fpermissive $(CFLAGS) $(CPPFLAGS) -shared -o $@ $(VOSK_SOURCES) $(KALDI_LIBS)
VOSK_HEADERS = \
../src/kaldi_recognizer.h \
../src/language_model.h \
../src/model.h \
../src/vosk_api.h \
../src/spk_model.h
libkaldiwrap.so: $(VOSK_SOURCES) $(VOSK_HEADERS)
$(CXX) -fpermissive $(CFLAGS) $(CPPFLAGS) -shared -o $@ $(VOSK_SOURCES) $(KALDI_LIBS) $(MATH_LIBS)
vosk_wrap.c: ../src/vosk.i
mkdir -p gen
+1 -1
View File
@@ -1 +1 @@
See https://alphacephei.com/vosk/accuracy.html
See https://alphacephei.com/vosk/accuracy
+1 -1
View File
@@ -1 +1 @@
See https://alphacephei.com/vosk/adaptation.html
See https://alphacephei.com/vosk/adaptation
+1 -1
View File
@@ -1 +1 @@
See https://alphacephei.com/vosk/models.html
See https://alphacephei.com/vosk/models
+165 -3
View File
@@ -12,37 +12,199 @@
// See the License for the specific language governing permissions and
// limitations under the License.
/* This header contains the C API for Vosk speech recognition system */
#ifndef _VOSK_API_H_
#define _VOSK_API_H_
#ifndef VOSK_API_H
#define VOSK_API_H
#ifdef __cplusplus
extern "C" {
#endif
/** Model stores all the data required for recognition
* it contains static data and can be shared across processing
* threads. */
typedef struct VoskModel VoskModel;
/** Speaker model is the same as model but contains the data
* for speaker identification. */
typedef struct VoskSpkModel VoskSpkModel;
/** Recognizer object is the main object which processes data.
* Each recognizer usually runs in own thread and takes audio as input.
* Once audio is processed recognizer returns JSON object as a string
* which represent decoded information - words, confidences, times, n-best lists,
* speaker information and so on */
typedef struct VoskRecognizer VoskRecognizer;
/** Loads model data from the file and returns the model object
*
* @param model_path: the path of the model on the filesystem
@ @returns model object */
VoskModel *vosk_model_new(const char *model_path);
/** Releases the model memory
*
* The model object is reference-counted so if some recognizer
* depends on this model, model might still stay alive. When
* last recognizer is released, model will be released too. */
void vosk_model_free(VoskModel *model);
/** Loads speaker model data from the file and returns the model object
*
* @param model_path: the path of the model on the filesystem
* @returns model object */
VoskSpkModel *vosk_spk_model_new(const char *model_path);
/** Releases the model memory
*
* The model object is reference-counted so if some recognizer
* depends on this model, model might still stay alive. When
* last recognizer is released, model will be released too. */
void vosk_spk_model_free(VoskSpkModel *model);
/** Creates the recognizer object
*
* The recognizers process the speech and return text using shared model data
* @param sample_rate The sample rate of the audio you going to feed into the recognizer
* @returns recognizer object */
VoskRecognizer *vosk_recognizer_new(VoskModel *model, float sample_rate);
/** Creates the recognizer object with speaker recognition
*
* With the speaker recognition mode the recognizer not just recognize
* text but also return speaker vectors one can use for speaker identification
*
* @param spk_model speaker model for speaker identification
* @param sample_rate The sample rate of the audio you going to feed into the recognizer
* @returns recognizer object */
VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, VoskSpkModel *spk_model, float sample_rate);
/** Creates the recognizer object with the grammar
*
* Sometimes when you want to improve recognition accuracy and when you don't need
* to recognize large vocabulary you can specify a list of words to recognize. This
* will improve recognizer speed and accuracy but might return [unk] if user said
* something different.
*
* Only recognizers with lookahead models support this type of quick configuration.
* Precompiled HCLG graph models are not supported.
*
* @param sample_rate The sample rate of the audio you going to feed into the recognizer
* @param grammar The string with the list of words to recognize, for example "one two three four five [unk]"
*
* @returns recognizer object */
VoskRecognizer *vosk_recognizer_new_grm(VoskModel *model, float sample_rate, const char *grammar);
/** Accept voice data
*
* accept and process new chunk of voice data
*
* @param data - audio data in PCM 16-bit mono format
* @param length - length of the audio data
* @returns true if silence is occured and you can retrieve a new utterance with result method */
int vosk_recognizer_accept_waveform(VoskRecognizer *recognizer, const char *data, int length);
/** Same as above but the version with the short data for language bindings where you have
* audio as array of shorts */
int vosk_recognizer_accept_waveform_s(VoskRecognizer *recognizer, const short *data, int length);
/** Same as above but the version with the float data for language bindings where you have
* audio as array of floats */
int vosk_recognizer_accept_waveform_f(VoskRecognizer *recognizer, const float *data, int length);
/** Returns speech recognition result
*
* @returns the result in JSON format which contains decoded line, decoded
* words, times in seconds and confidences. You can parse this result
* with any json parser
*
* <pre>
* {
* "result" : [{
* "conf" : 1.000000,
* "end" : 1.110000,
* "start" : 0.870000,
* "word" : "what"
* }, {
* "conf" : 1.000000,
* "end" : 1.530000,
* "start" : 1.110000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 1.950000,
* "start" : 1.530000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.340000,
* "start" : 1.950000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.610000,
* "start" : 2.340000,
* "word" : "one"
* }],
* "text" : "what zero zero zero one"
* }
* </pre>
*/
const char *vosk_recognizer_result(VoskRecognizer *recognizer);
/** Returns partial speech recognition
*
* @returns partial speech recognition text which is not yet finalized.
* result may change as recognizer process more data.
*
* <pre>
* {
* "partial" : "cyril one eight zero"
* }
* </pre>
*/
const char *vosk_recognizer_partial_result(VoskRecognizer *recognizer);
/** Returns speech recognition result. Same as result, but doesn't wait for silence
* You usually call it in the end of the stream to get final bits of audio. It
* flushes the feature pipeline, so all remaining audio chunks got processed.
*
* @returns speech result in JSON format.
*/
const char *vosk_recognizer_final_result(VoskRecognizer *recognizer);
/** Releases recognizer object
*
* Underlying model is also unreferenced and if needed released */
void vosk_recognizer_free(VoskRecognizer *recognizer);
/** Set log level for Kaldi messages
*
* @param log_level the level
* 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
#endif /* _VOSK_API_H_ */
#endif /* VOSK_API_H */
+2
View File
@@ -30,6 +30,8 @@ VOSK_SOURCES = \
vosk_wrap.cc \
../src/kaldi_recognizer.cc \
../src/kaldi_recognizer.h \
../src/language_model.cc \
../src/language_model.h \
../src/model.cc \
../src/model.h \
../src/spk_model.cc \
-3
View File
@@ -14,9 +14,6 @@ import org.kaldi.SpkModel;
import org.kaldi.Vosk;
public class DecoderTest {
static {
System.loadLibrary("vosk_jni");
}
public static void main(String args[]) throws IOException {
Vosk.SetLogLevel(-10);
+1 -1
View File
@@ -9,7 +9,7 @@ Still, you need swig of newest version 4.0.1
Build like this
```
npm install --kaldi_root=/home/suser/kaldi
npm install --kaldi_root=/home/user/kaldi
```
Then test with
+19 -9
View File
@@ -5,22 +5,32 @@
'sources': [
'../src/kaldi_recognizer.cc',
'../src/model.cc',
'../src/language_model.cc',
'../src/spk_model.cc',
'../src/vosk_api.cc',
'vosk_wrap.cc',
],
'cflags': [
'-std=c++11',
'-DFST_NO_DYNAMIC_LINKING',
'-Wno-deprecated-declarations',
'-Wno-sign-compare',
'-Wno-unused-local-typedefs',
'-Wno-ignored-quaifiers',
'-Wno-extra',
'-std=c++11',
'-DFST_NO_DYNAMIC_LINKING',
'-Wno-deprecated-declarations',
'-Wno-sign-compare',
'-Wno-unused-local-typedefs',
'-Wno-ignored-quaifiers',
'-Wno-extra',
],
'cflags_cc!' : [
'-fno-rtti',
'-fno-exceptions',
'-fno-rtti',
'-fno-exceptions',
],
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
'GCC_ENABLE_CPP_RTTI': 'YES',
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11'
}
}]
],
'actions': [
{
+71 -28
View File
@@ -1,47 +1,90 @@
#!/usr/bin/env node
const wav = require('wav')
const fs = require('fs')
const fs = require("fs");
const { Readable } = require("stream");
const wav = require("wav");
const { Model, KaldiRecognizer, SpkModel } = require("..");
const {Readable} = require('stream')
const {Model, KaldiRecognizer, SpkModel} = require('..')
try {
fs.accessSync("model", fs.constants.R_OK);
} catch(err) {
console.error("Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model' in the current folder.");
process.exit(1);
fs.accessSync('model', fs.constants.R_OK)
} catch (err) {
console.error("Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model' in the current folder.")
process.exit(1)
}
try {
fs.accessSync("model-spk", fs.constants.R_OK);
} catch(err) {
console.error("Please download the speaker model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model-spk' in the current folder.");
process.exit(1);
fs.accessSync('model-spk', fs.constants.R_OK)
} catch (err) {
console.error("Please download the speaker model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model-spk' in the current folder.")
process.exit(1)
}
const wfStream = fs.createReadStream('test.wav', { highWaterMark: 4096 })
const wfReader = new wav.Reader()
const wfStream = fs.createReadStream("test.wav", {'highWaterMark': 4096});
const wfReader = new wav.Reader();
const model = new Model('model')
const spkModel = new SpkModel('model-spk')
const model = new Model("model");
const spkModel = new SpkModel("model-spk");
const spk_sig = [-0.56648, 0.030579, 1.730239, 0.239899, -1.194183,
0.251954, 0.540388, -0.971872, -0.020963, 0.085036, 0.563973, -0.019682,
-0.597381, 1.094719, -0.566738, 0.29819, 0.171165, 0.370341, -0.033539,
-0.09757, 1.228286, 0.485949, 0.427826, 0.147762, -0.015112, 0.599513,
-2.040655, -0.490882, 0.440161, -0.072991, 0.835955, -0.496124, 0.952978,
0.85356, -1.096116, 0.107764, -0.385486, 1.410305, 0.609147, -0.457014,
-1.542864, 0.343669, 0.171913, -0.627281, -1.281781, -1.134276,
-0.639895, 1.190183, -0.700537, 1.063457, 0.206946, 0.342198, -1.165625,
1.475955, -0.089007, -2.555155, 0.551438, -0.212736, 1.025625, -1.631965,
-0.716256, -1.295995, 1.554956, -1.866009, -1.010782, -1.43231, 0.109027,
2.123925, 1.703283, -0.784997, 2.730568, 0.755113, 0.0617, 0.128955,
-0.054047, 1.359119, -0.611666, -1.105754, -0.631353, 0.052109, 0.729386,
-0.769876, 1.250235, -1.463298, 0.648176, -0.73239, -0.385239,
-1.661856, 0.602106, -0.45567, -1.438431, -0.836673, 0.033557, 0.373597,
-1.343341, -0.181095, 0.237287, -0.522005, -1.722836, 0.932333,
-0.092861, -0.219254, 0.476182, 1.033803, -1.633563, -0.874341, 1.039064,
-1.758573, -0.838422, -0.324336, -0.924634, 1.962594, 2.152814, 1.2521,
-0.46172, -1.50271, 1.685691, 0.403097, -0.819042, 0.866403, -0.591716,
-0.578645, -0.553839, 0.381861, -1.051647, -1.477578, 0.524005, 0.925245]
function dotp(x, y) {
function dotp_sum(a, b) {
return a + b
}
function dotp_times(a, i) {
return x[i] * y[i]
}
return x.map(dotp_times).reduce(dotp_sum, 0)
}
function cosineSimilarity(A, B) {
var similarity =
dotp(A, B) / (Math.sqrt(dotp(A, A)) * Math.sqrt(dotp(B, B)))
return similarity
}
function cosine_dist(x, y) {
return 1 - cosineSimilarity(x, y)
}
wfReader.on('format', async ({ audioFormat, sampleRate, channels }) => {
if (audioFormat != 1 || channels != 1) {
console.error("Audio file must be WAV format mono PCM.");
process.exit(1);
console.error('Audio file must be WAV format mono PCM.')
process.exit(1)
}
const rec = new KaldiRecognizer(model, spkModel, sampleRate);
const rec = new KaldiRecognizer(model, spkModel, sampleRate)
for await (const data of new Readable().wrap(wfReader)) {
const result = await rec.AcceptWaveform(data);
if (result != 0) {
console.log(await rec.Result());
const endOfSpeech = await rec.AcceptWaveform(data)
if (endOfSpeech) {
res = await JSON.parse(rec.Result());
console.log(res)
console.log('X-vector:', JSON.stringify(res['spk']))
console.log('Speaker distance:', cosine_dist(spk_sig, res['spk']))
} else {
console.log(await rec.PartialResult());
console.log(await rec.PartialResult())
}
}
console.log(await rec.FinalResult());
});
res = await JSON.parse(rec.FinalResult());
console.log(res)
console.log('X-vector:', JSON.stringify(res['spk']))
console.log('Speaker distance:', cosine_dist(spk_sig, res['spk']))
})
wfStream.pipe(wfReader);
wfStream.pipe(wfReader)
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "vosk",
"version": "0.3.8",
"description": "Node binding for continuous voice recoginition through pocketsphinx.",
"version": "0.3.15",
"description": "Node binding for continuous offline voice recoginition with Vosk library.",
"repository": {
"type": "git",
"url": "git://github.com/alphacep/vosk-api.git"
+22 -2
View File
@@ -1,3 +1,23 @@
Python module for vosk-api
This is a Python module for Vosk.
See for details https://github.com/alphacep/vosk-api
Vosk is an offline open source speech recognition toolkit. It enables
speech recognition models for 16 languages and dialects - English, Indian
English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish,
Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi.
Vosk models are small (50 Mb) but provide continuous large vocabulary
transcription, zero-latency response with streaming API, reconfigurable
vocabulary and speaker identification.
Vosk supplies speech recognition for chatbots, smart home appliances,
virtual assistants. It can also create subtitles for movies,
transcription for lectures and interviews.
Vosk scales from small devices like Raspberry Pi or Android smartphone to
big clusters.
# Documentation
For installation instructions, examples and documentation visit [Vosk
Website](https://alphacephei.com/vosk). See also our project on
[Github](https://github.com/alphacep/vosk-api).
+1 -1
View File
@@ -9,7 +9,7 @@ import subprocess
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.")
print ("Please download the model from https://alphacephei.com/vosk/models and unpack as 'model' in the current folder.")
exit (1)
sample_rate=16000
+1 -1
View File
@@ -4,7 +4,7 @@ from vosk import Model, KaldiRecognizer
import os
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.")
print ("Please download the model from https://alphacephei.com/vosk/models and unpack as 'model' in the current folder.")
exit (1)
import pyaudio
+1 -1
View File
@@ -8,7 +8,7 @@ import wave
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.")
print ("Please download the model from https://alphacephei.com/vosk/models and unpack as 'model' in the current folder.")
exit (1)
wf = wave.open(sys.argv[1], "rb")
+8 -5
View File
@@ -11,11 +11,11 @@ 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/vosk-api/blob/master/doc/models.md and unpack as {} in the current folder.".format(model_path))
print ("Please download the model from https://alphacephei.com/vosk/models 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/vosk-api/blob/master/doc/models.md and unpack as {} in the current folder.".format(spk_model_path))
print ("Please download the speaker model from https://alphacephei.com/vosk/models and unpack as {} in the current folder.".format(spk_model_path))
exit (1)
wf = wave.open(sys.argv[1], "rb")
@@ -30,7 +30,7 @@ rec = KaldiRecognizer(model, spk_model, wf.getframerate())
# We compare speakers with cosine distance. We can keep one or several fingerprints for the speaker in a database
# to distingusih among users.
spk_sig = [4.658117, 1.277387, 3.346158, -1.473036, -2.15727, 2.461757, 3.76756, -1.241252, 2.333765, 0.642588, -2.848165, 1.229534, 3.907015, 1.726496, -1.188692, 1.16322, -0.668811, -0.623309, 4.628018, 0.407197, 0.089955, 0.920438, 1.47237, -0.311365, -0.437051, -0.531738, -1.591781, 3.095415, 0.439524, -0.274787, 4.03165, 2.665864, 4.815553, 1.581063, 1.078242, 5.017717, -0.089395, -3.123428, 5.34038, 0.456982, 2.465727, 2.131833, 4.056272, 1.178392, -2.075712, -1.568503, 0.847139, 0.409214, 1.84727, 0.986758, 4.222116, 2.235512, 1.369377, 4.283126, 2.278125, -1.467577, -0.999971, 3.070041, 1.462214, 0.423204, 2.143578, 0.567174, -2.294655, 1.864723, 4.307356, 2.610872, -1.238721, 0.551861, 2.861954, 0.59613, -0.715396, -1.395357, 2.706177, -2.004444, 2.055255, 0.458283, 1.231968, 3.48234, 2.993858, 0.402819, 0.940885, 0.360162, -2.173674, -2.504609, 0.329541, 3.653913, 3.638025, -1.406409, 2.14059, 1.662765, -0.991323, 0.770921, 0.010094, 3.775469, 1.847511, 2.074432, -1.928593, 0.807414, 2.964505, 0.128597, 1.297962, 2.645227, 0.136405, -2.543087, 0.932246, 2.405783, -2.122267, 3.044013, 0.486728, 4.395338, 0.474267, 0.781297, 1.694144, -0.831078, -0.462362, -0.964715, 3.187863, 6.008708, 1.725954, 3.667886, -1.467623, 3.370667, 2.72555, -0.796541, 2.416543, 0.675401, -0.737634, -1.709676]
spk_sig = [-1.110417,0.09703002,1.35658,0.7798632,-0.305457,-0.339204,0.6186931,-0.4521213,0.3982236,-0.004530723,0.7651616,0.6500852,-0.6664245,0.1361499,0.1358056,-0.2887807,-0.1280468,-0.8208137,-1.620276,-0.4628615,0.7870904,-0.105754,0.9739769,-0.3258137,-0.7322628,-0.6212429,-0.5531687,-0.7796484,0.7035915,1.056094,-0.4941756,-0.6521456,-0.2238328,-0.003737517,0.2165709,1.200186,-0.7737719,0.492015,1.16058,0.6135428,-0.7183084,0.3153541,0.3458071,-1.418189,-0.9624157,0.4168292,-1.627305,0.2742135,-0.6166027,0.1962581,-0.6406527,0.4372789,-0.4296024,0.4898657,-0.9531326,-0.2945702,0.7879696,-1.517101,-0.9344181,-0.5049928,-0.005040941,-0.4637912,0.8223695,-1.079849,0.8871287,-0.9732434,-0.5548235,1.879138,-1.452064,-0.1975368,1.55047,0.5941782,-0.52897,1.368219,0.6782904,1.202505,-0.9256122,-0.9718158,-0.9570228,-0.5563112,-1.19049,-1.167985,2.606804,-2.261825,0.01340385,0.2526799,-1.125458,-1.575991,-0.363153,0.3270262,1.485984,-1.769565,1.541829,0.7293826,0.1743717,-0.4759418,1.523451,-2.487134,-1.824067,-0.626367,0.7448186,-1.425648,0.3524166,-0.9903384,3.339342,0.4563958,-0.2876643,1.521635,0.9508078,-0.1398541,0.3867955,-0.7550205,0.6568405,0.09419366,-1.583935,1.306094,-0.3501927,0.1794427,-0.3768163,0.9683866,-0.2442541,-1.696921,-1.8056,-0.6803037,-1.842043,0.3069353,0.9070363,-0.486526]
def cosine_dist(x, y):
nx = np.array(x)
@@ -45,9 +45,12 @@ while True:
res = json.loads(rec.Result())
print ("Text:", res['text'])
print ("X-vector:", res['spk'])
print ("Speaker distance:", cosine_dist(spk_sig, res['spk']))
print ("Speaker distance:", cosine_dist(spk_sig, res['spk']), "based on", res['spk_frames'], "frames")
print ("Note that second distance is not very reliable because utterance is too short. Utterances longer than 4 seconds give better xvector")
res = json.loads(rec.FinalResult())
print ("Text:", res['text'])
print ("Speaker distance:", cosine_dist(spk_sig, res['spk']))
print ("X-vector:", res['spk'])
print ("Speaker distance:", cosine_dist(spk_sig, res['spk']), "based on", res['spk_frames'], "frames")
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env python3
from vosk import Model, KaldiRecognizer, SetLogLevel
import sys
import os
import wave
import subprocess
import srt
import json
import datetime
SetLogLevel(-1)
if not os.path.exists("model"):
print ("Please download the model from https://alphacephei.com/vosk/models and unpack as 'model' in the current folder.")
exit (1)
sample_rate=16000
model = Model("model")
rec = KaldiRecognizer(model, sample_rate)
process = subprocess.Popen(['ffmpeg', '-loglevel', 'quiet', '-i',
sys.argv[1],
'-ar', str(sample_rate) , '-ac', '1', '-f', 's16le', '-'],
stdout=subprocess.PIPE)
def transcribe():
results = []
subs = []
while True:
data = process.stdout.read(4000)
if len(data) == 0:
break
if rec.AcceptWaveform(data):
results.append(rec.Result())
results.append(rec.FinalResult())
for i, res in enumerate(results):
jres = json.loads(res)
s = srt.Subtitle(index=i,
content=jres['text'],
start=datetime.timedelta(seconds=jres['result'][0]['start']),
end=datetime.timedelta(seconds=jres['result'][-1]['end']))
subs.append(s)
return subs
print (srt.compose(transcribe()))
+1 -1
View File
@@ -6,7 +6,7 @@ import json
import os
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.")
print ("Please download the model from https://alphacephei.com/vosk/models and unpack as 'model' in the current folder.")
exit (1)
+4 -3
View File
@@ -6,7 +6,7 @@ import os
import wave
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.")
print ("Please download the model from https://alphacephei.com/vosk/models and unpack as 'model' in the current folder.")
exit (1)
wf = wave.open(sys.argv[1], "rb")
@@ -15,8 +15,9 @@ if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE
exit (1)
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")
# You can also specify the possible word or phrase list as JSON list, the order doesn't have to be strict
rec = KaldiRecognizer(model, wf.getframerate(), '["oh one two three four five six seven eight nine zero", "[unk]"]')
while True:
data = wf.readframes(4000)
+5 -5
View File
@@ -52,14 +52,14 @@ kaldi_libraries = []
if sys.platform.startswith('darwin'):
kaldi_link_args.extend(['-Wl,-undefined,dynamic_lookup', '-framework', 'Accelerate'])
elif kaldi_mkl != None:
elif kaldi_mkl == "1":
kaldi_link_args.extend(['-L/opt/intel/mkl/lib/intel64', '-Wl,-rpath=/opt/intel/mkl/lib/intel64'])
kaldi_libraries.extend(['mkl_rt', 'mkl_intel_lp64', 'mkl_core', 'mkl_sequential'])
else:
kaldi_static_libs.append('tools/OpenBLAS/libopenblas.a')
kaldi_libraries.append('gfortran')
sources = ['kaldi_recognizer.cc', 'model.cc', 'spk_model.cc', 'vosk_api.cc', 'vosk.i']
sources = ['kaldi_recognizer.cc', 'model.cc', 'spk_model.cc', 'vosk_api.cc', 'language_model.cc', 'vosk.i']
vosk_ext = Extension('vosk._vosk',
define_macros = [('FST_NO_DYNAMIC_LINKING', '1')],
@@ -72,11 +72,11 @@ vosk_ext = Extension('vosk._vosk',
extra_compile_args = ['-std=c++11', '-Wno-sign-compare', '-Wno-unused-variable', '-Wno-unused-local-typedefs'])
setuptools.setup(
name="vosk", # Replace with your own username
version="0.3.9",
name="vosk",
version="0.3.15",
author="Alpha Cephei Inc",
author_email="contact@alphacephei.com",
description="API for Kaldi and Vosk",
description="Offline open source speech recognition API based on Kaldi and Vosk",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/alphacep/vosk-api",
+112 -35
View File
@@ -16,6 +16,7 @@
#include "json.h"
#include "fstext/fstext-utils.h"
#include "lat/sausages.h"
#include "language_model.h"
using namespace fst;
using namespace kaldi::nnet3;
@@ -57,28 +58,49 @@ KaldiRecognizer::KaldiRecognizer(Model *model, float sample_frequency, char cons
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_) {
g_fst_->AddState();
g_fst_->SetStart(0);
g_fst_->AddState();
g_fst_->SetFinal(1, fst::TropicalWeight::One());
g_fst_->AddArc(1, StdArc(0, 0, fst::TropicalWeight::One(), 0));
json::JSON obj;
obj = json::JSON::Load(grammar);
// Create simple word loop FST
stringstream ss(grammar);
string token;
if (obj.length() <= 0) {
KALDI_WARN << "Expecting array of strings, got: '" << grammar << "'";
} else {
KALDI_LOG << obj;
while (getline(ss, token, ' ')) {
int32 id = model_->word_syms_->Find(token);
g_fst_->AddArc(0, StdArc(id, id, fst::TropicalWeight::One(), 1));
LanguageModelOptions opts;
opts.ngram_order = 2;
opts.discount = 0.5;
LanguageModelEstimator estimator(opts);
for (int i = 0; i < obj.length(); i++) {
bool ok;
string line = obj[i].ToString(ok);
if (!ok) {
KALDI_ERR << "Expecting array of strings, got: '" << obj << "'";
}
std::vector<int32> sentence;
stringstream ss(line);
string token;
while (getline(ss, token, ' ')) {
int32 id = model_->word_syms_->Find(token);
if (id == kNoSymbol) {
KALDI_WARN << "Ignoring word missing in vocabulary: '" << token << "'";
} else {
sentence.push_back(id);
}
}
estimator.AddCounts(sentence);
}
g_fst_ = new StdVectorFst();
estimator.Estimate(g_fst_);
decode_fst_ = LookaheadComposeFst(*model_->hcl_fst_, *g_fst_, model_->disambig_);
}
ArcSort(g_fst_, ILabelCompare<StdArc>());
decode_fst_ = LookaheadComposeFst(*model_->hcl_fst_, *g_fst_, model_->disambig_);
} else {
decode_fst_ = NULL;
KALDI_ERR << "Can't create decoding graph";
KALDI_WARN << "Runtime graphs are not supported by this model";
}
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_->nnet3_decoding_config_,
@@ -125,9 +147,9 @@ KaldiRecognizer::KaldiRecognizer(Model *model, SpkModel *spk_model, float sample
}
KaldiRecognizer::~KaldiRecognizer() {
delete decoder_;
delete feature_pipeline_;
delete silence_weighting_;
delete decoder_;
delete g_fst_;
delete decode_fst_;
delete spk_feature_;
@@ -164,12 +186,8 @@ void KaldiRecognizer::CleanUp()
delete silence_weighting_;
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_->trans_model_, model_->feature_info_.silence_weighting_config, 3);
if (spk_feature_) {
delete spk_feature_;
spk_feature_ = new OnlineMfcc(spk_model_->spkvector_mfcc_opts);
}
frame_offset_ += decoder_->NumFramesDecoded();
if (decoder_)
frame_offset_ += decoder_->NumFramesDecoded();
// Each 10 minutes we drop the pipeline to save frontend memory in continuous processing
// here we drop few frames remaining in the feature pipeline but hope it will not
@@ -177,8 +195,9 @@ void KaldiRecognizer::CleanUp()
// Also restart if we retrieved final result already
if (frame_offset_ > 20000 || state_ == RECOGNIZER_FINALIZED) {
if (decoder_ == NULL || state_ == RECOGNIZER_FINALIZED || frame_offset_ > 20000) {
samples_round_start_ += samples_processed_;
samples_processed_ = 0;
frame_offset_ = 0;
delete decoder_;
@@ -190,6 +209,11 @@ void KaldiRecognizer::CleanUp()
*model_->decodable_info_,
model_->hclg_fst_ ? *model_->hclg_fst_ : *decode_fst_,
feature_pipeline_);
if (spk_model_) {
delete spk_feature_;
spk_feature_ = new OnlineMfcc(spk_model_->spkvector_mfcc_opts);
}
} else {
decoder_->InitDecoding(frame_offset_);
}
@@ -292,7 +316,9 @@ static void RunNnetComputation(const MatrixBase<BaseFloat> &features,
xvector->CopyFromVec(cu_output.Row(0));
}
void KaldiRecognizer::GetSpkVector(Vector<BaseFloat> &xvector)
#define MIN_SPK_FEATS 50
bool KaldiRecognizer::GetSpkVector(Vector<BaseFloat> &out_xvector, int *num_spk_frames)
{
vector<int32> nonsilence_frames;
if (silence_weighting_->Active() && feature_pipeline_->NumFramesReady() > 0) {
@@ -302,17 +328,36 @@ void KaldiRecognizer::GetSpkVector(Vector<BaseFloat> &xvector)
&nonsilence_frames);
}
int num_frames = spk_feature_->NumFramesReady();
int num_frames = spk_feature_->NumFramesReady() - frame_offset_ * 3;
Matrix<BaseFloat> mfcc(num_frames, spk_feature_->Dim());
// Not very efficient, would be nice to have faster search
int num_nonsilence_frames = 0;
Vector<BaseFloat> feat(spk_feature_->Dim());
for (int i = 0; i < num_frames; ++i) {
if (std::find(nonsilence_frames.begin(),
nonsilence_frames.end(), i % 3) == nonsilence_frames.end())
nonsilence_frames.end(), i / 3) == nonsilence_frames.end()) {
continue;
Vector<BaseFloat> feat(spk_feature_->Dim());
spk_feature_->GetFrame(i, &feat);
mfcc.CopyRowFromVec(feat, i);
}
spk_feature_->GetFrame(i + frame_offset_ * 3, &feat);
mfcc.CopyRowFromVec(feat, num_nonsilence_frames);
num_nonsilence_frames++;
}
*num_spk_frames = num_nonsilence_frames;
// Don't extract vector if not enough data
if (num_nonsilence_frames < MIN_SPK_FEATS) {
return false;
}
mfcc.Resize(num_nonsilence_frames, spk_feature_->Dim(), kCopyData);
SlidingWindowCmnOptions cmvn_opts;
cmvn_opts.center = true;
cmvn_opts.cmn_window = 300;
Matrix<BaseFloat> features(mfcc.NumRows(), mfcc.NumCols(), kUndefined);
SlidingWindowCmn(cmvn_opts, mfcc, &features);
@@ -320,7 +365,22 @@ void KaldiRecognizer::GetSpkVector(Vector<BaseFloat> &xvector)
nnet3::CachingOptimizingCompilerOptions compiler_config;
nnet3::CachingOptimizingCompiler compiler(spk_model_->speaker_nnet, opts.optimize_config, compiler_config);
Vector<BaseFloat> xvector;
RunNnetComputation(features, spk_model_->speaker_nnet, &compiler, &xvector);
// Whiten the vector with global mean and transform and normalize mean
xvector.AddVec(-1.0, spk_model_->mean);
out_xvector.Resize(spk_model_->transform.NumRows(), kSetZero);
out_xvector.AddMatVec(1.0, spk_model_->transform, kNoTrans, xvector, 0.0);
BaseFloat norm = out_xvector.Norm(2.0);
BaseFloat ratio = norm / sqrt(out_xvector.Dim()); // how much larger it is
// than it would be, in
// expectation, if normally
out_xvector.Scale(1.0 / ratio);
return true;
}
const char* KaldiRecognizer::GetResult()
@@ -355,7 +415,7 @@ const char* KaldiRecognizer::GetResult()
DeterminizeLattice(composed_lat1, &clat);
}
fst::ScaleLattice(fst::LatticeScale(9.0, 10.0), &clat);
fst::ScaleLattice(fst::GraphLatticeScale(0.9), &clat); // Apply rescoring weight
CompactLattice aligned_lat;
if (model_->winfo_) {
WordAlignLattice(clat, *model_->trans_model_, *model_->winfo_, 0, &aligned_lat);
@@ -392,9 +452,12 @@ const char* KaldiRecognizer::GetResult()
if (spk_model_) {
Vector<BaseFloat> xvector;
GetSpkVector(xvector);
for (int i = 0; i < xvector.Dim(); i++) {
obj["spk"].append(xvector(i));
int num_spk_frames;
if (GetSpkVector(xvector, &num_spk_frames)) {
for (int i = 0; i < xvector.Dim(); i++) {
obj["spk"].append(xvector(i));
}
obj["spk_frames"] = num_spk_frames;
}
}
@@ -454,7 +517,21 @@ const char* KaldiRecognizer::FinalResult()
decoder_->AdvanceDecoding();
decoder_->FinalizeDecoding();
state_ = RECOGNIZER_FINALIZED;
return GetResult();
GetResult();
// Free some memory while we are finalized, next
// iteration will reinitialize them anyway
delete decoder_;
delete feature_pipeline_;
delete silence_weighting_;
delete spk_feature_;
feature_pipeline_ = NULL;
silence_weighting_ = NULL;
decoder_ = NULL;
spk_feature_ = NULL;
return last_result_.c_str();
}
// Store result in recognizer and return as const string
+6 -1
View File
@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef VOSK_KALDI_RECOGNIZER_H
#define VOSK_KALDI_RECOGNIZER_H
#include "base/kaldi-common.h"
#include "util/common-utils.h"
#include "fstext/fstext-lib.h"
@@ -55,7 +58,7 @@ class KaldiRecognizer {
void CleanUp();
void UpdateSilenceWeights();
bool AcceptWaveform(Vector<BaseFloat> &wdata);
void GetSpkVector(Vector<BaseFloat> &xvector);
bool GetSpkVector(Vector<BaseFloat> &out_xvector, int *frames);
const char *GetResult();
const char *StoreReturn(const string &res);
@@ -80,3 +83,5 @@ class KaldiRecognizer {
KaldiRecognizerState state_;
string last_result_;
};
#endif /* VOSK_KALDI_RECOGNIZER_H */
+211
View File
@@ -0,0 +1,211 @@
// Copyright 2015 Johns Hopkins University (author: Daniel Povey)
// See ../../COPYING for clarification regarding multiple authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
// MERCHANTABLITY OR NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing permissions and
// limitations under the License.
// A modified version from chain/language-model.cc for static backoff
#include <algorithm>
#include <numeric>
#include "language_model.h"
using namespace kaldi;
void LanguageModelEstimator::AddCounts(const std::vector<int32> &sentence) {
KALDI_ASSERT(opts_.ngram_order >= 2 && "--ngram-order must be >= 2");
int32 order = opts_.ngram_order;
// 0 is used for left-context at the beginning of the file.. treat it as BOS.
std::vector<int32> history(0);
std::vector<int32>::const_iterator iter = sentence.begin(),
end = sentence.end();
for (; iter != end; ++iter) {
KALDI_ASSERT(*iter != 0);
IncrementCount(history, *iter);
history.push_back(*iter);
if (history.size() >= order)
history.erase(history.begin());
}
// Probability of end of sentence. This will end up getting ignored later, but
// it still makes a difference for probability-normalization reasons.
IncrementCount(history, 0);
}
void LanguageModelEstimator::IncrementCount(const std::vector<int32> &history,
int32 next_phone) {
int32 lm_state_index = FindOrCreateLmStateIndexForHistory(history);
if (lm_states_[lm_state_index].tot_count == 0) {
num_active_lm_states_++;
}
lm_states_[lm_state_index].AddCount(next_phone, 1);
}
void LanguageModelEstimator::SetParentCounts() {
int32 num_lm_states = lm_states_.size();
for (int32 l = 0; l < num_lm_states; l++) {
int32 l_iter = lm_states_[l].backoff_lmstate_index;
while (l_iter != -1) {
lm_states_[l_iter].Add(lm_states_[l]);
l_iter = lm_states_[l_iter].backoff_lmstate_index;
}
}
}
int32 LanguageModelEstimator::FindLmStateIndexForHistory(
const std::vector<int32> &hist) const {
MapType::const_iterator iter = hist_to_lmstate_index_.find(hist);
if (iter == hist_to_lmstate_index_.end())
return -1;
else
return iter->second;
}
int32 LanguageModelEstimator::FindNonzeroLmStateIndexForHistory(
std::vector<int32> hist) const {
while (1) {
int32 l = FindLmStateIndexForHistory(hist);
if (l == -1 || lm_states_[l].tot_count == 0) {
// no such state or state has zero count.
if (hist.empty())
KALDI_ERR << "Error looking up LM state index for history "
<< "(likely code bug)";
hist.erase(hist.begin()); // back off.
} else {
return l;
}
}
}
int32 LanguageModelEstimator::FindOrCreateLmStateIndexForHistory(
const std::vector<int32> &hist) {
MapType::const_iterator iter = hist_to_lmstate_index_.find(hist);
if (iter != hist_to_lmstate_index_.end())
return iter->second;
int32 ans = lm_states_.size(); // index of next element
// next statement relies on default construct of LmState.
lm_states_.resize(lm_states_.size() + 1);
lm_states_.back().history = hist;
hist_to_lmstate_index_[hist] = ans;
// make sure backoff_lmstate_index is set
if (hist.size() > 0) {
std::vector<int32> backoff_hist(hist.begin() + 1,
hist.end());
int32 backoff_lm_state = FindOrCreateLmStateIndexForHistory(backoff_hist);
lm_states_[ans].backoff_lmstate_index = backoff_lm_state;
}
return ans;
}
void LanguageModelEstimator::LmState::AddCount(int32 phone, int32 count) {
std::map<int32, int32>::iterator iter = phone_to_count.find(phone);
if (iter == phone_to_count.end())
phone_to_count[phone] = count;
else
iter->second += count;
tot_count += count;
}
void LanguageModelEstimator::LmState::Add(const LmState &other) {
KALDI_ASSERT(&other != this);
std::map<int32, int32>::const_iterator iter = other.phone_to_count.begin(),
end = other.phone_to_count.end();
for (; iter != end; ++iter)
AddCount(iter->first, iter->second);
}
int32 LanguageModelEstimator::AssignFstStates() {
int32 num_lm_states = lm_states_.size();
int32 current_fst_state = 0;
for (int32 l = 0; l < num_lm_states; l++) {
if (lm_states_[l].tot_count != 0) {
lm_states_[l].fst_state = current_fst_state++;
}
}
KALDI_ASSERT(current_fst_state == num_active_lm_states_);
return current_fst_state;
}
void LanguageModelEstimator::Estimate(fst::StdVectorFst *fst) {
KALDI_LOG << "Estimating language model with ngram-order="
<< opts_.ngram_order << ", discount="
<< opts_.discount;
SetParentCounts();
int32 num_fst_states = AssignFstStates();
OutputToFst(num_fst_states, fst);
}
int32 LanguageModelEstimator::FindInitialFstState() const {
std::vector<int32> history(0);
int32 l = FindNonzeroLmStateIndexForHistory(history);
KALDI_ASSERT(l != -1 && lm_states_[l].fst_state != -1);
return lm_states_[l].fst_state;
}
void LanguageModelEstimator::OutputToFst(
int32 num_states,
fst::StdVectorFst *fst) const {
KALDI_ASSERT(num_states == num_active_lm_states_);
fst->DeleteStates();
for (int32 i = 0; i < num_states; i++)
fst->AddState();
fst->SetStart(FindInitialFstState());
int64 tot_count = 0;
double tot_logprob = 0.0;
int32 num_lm_states = lm_states_.size();
// note: not all lm-states end up being 'active'.
for (int32 l = 0; l < num_lm_states; l++) {
const LmState &lm_state = lm_states_[l];
if (lm_state.fst_state == -1) {
continue;
}
int32 state_count = lm_state.tot_count;
KALDI_ASSERT(state_count != 0);
std::map<int32, int32>::const_iterator
iter = lm_state.phone_to_count.begin(),
end = lm_state.phone_to_count.end();
for (; iter != end; ++iter) {
int32 phone = iter->first, count = iter->second;
BaseFloat logprob = log(count * opts_.discount / state_count);
tot_count += count;
tot_logprob += logprob * count;
if (phone == 0) { // Go to final state
fst->SetFinal(lm_state.fst_state, fst::TropicalWeight(-logprob));
} else { // It becomes a transition.
std::vector<int32> next_history(lm_state.history);
next_history.push_back(phone);
int32 dest_lm_state = FindNonzeroLmStateIndexForHistory(next_history),
dest_fst_state = lm_states_[dest_lm_state].fst_state;
KALDI_ASSERT(dest_fst_state != -1);
fst->AddArc(lm_state.fst_state,
fst::StdArc(phone, phone, fst::TropicalWeight(-logprob),
dest_fst_state));
}
}
if (lm_state.backoff_lmstate_index >= 0) {
fst->AddArc(lm_state.fst_state, fst::StdArc(0, 0, fst::TropicalWeight(-log(1 - opts_.discount)), lm_states_[lm_state.backoff_lmstate_index].fst_state));
}
}
fst::Connect(fst);
// Make sure that Connect does not delete any states.
int32 num_states_connected = fst->NumStates();
KALDI_ASSERT(num_states_connected == num_states);
// arc-sort. ilabel or olabel doesn't matter, it's an acceptor.
fst::ArcSort(fst, fst::ILabelCompare<fst::StdArc>());
KALDI_LOG << "Created language model with " << num_states
<< " states and " << fst::NumArcs(*fst) << " arcs.";
}
+150
View File
@@ -0,0 +1,150 @@
// Copyright 2015 Johns Hopkins University (Author: Daniel Povey)
// See ../../COPYING for clarification regarding multiple authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
// MERCHANTABLITY OR NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing permissions and
// limitations under the License.
#ifndef VOSK_LANGUAGE_MODEL_H
#define VOSK_LANGUAGE_MODEL_H
#include <vector>
#include <map>
#include "base/kaldi-common.h"
#include "util/common-utils.h"
#include "fstext/fstext-lib.h"
#include "lat/kaldi-lattice.h"
using namespace kaldi;
// Very simply lm construction with absolute discounting
struct LanguageModelOptions {
int32 ngram_order; // you might want to tune this
BaseFloat discount; // discount for backoff
LanguageModelOptions():
ngram_order(3),
discount(0.5)
{ }
void Register(OptionsItf *opts) {
opts->Register("ngram-order", &ngram_order, "n-gram order for the phone "
"language model used for the 'denominator model'");
opts->Register("discount", &discount, "Discount for backoff");
}
};
class LanguageModelEstimator {
public:
LanguageModelEstimator(LanguageModelOptions &opts): opts_(opts),
num_active_lm_states_(0) {
KALDI_ASSERT(opts.ngram_order >= 1);
}
// Adds counts for this sentence. Basically does: for each n-gram in the
// sentence, count[n-gram] += 1. The only constraint on 'sentence' is that it
// should contain no zeros.
void AddCounts(const std::vector<int32> &sentence);
// Estimates the LM and outputs it as an FST. Note: there is
// no concept here of backoff arcs.
void Estimate(fst::StdVectorFst *fst);
protected:
struct LmState {
// the phone history associated with this state (length can vary).
std::vector<int32> history;
// maps from
std::map<int32, int32> phone_to_count;
// total count of this state. As we back off states to lower-order states
// (and note that this is a hard backoff where we completely remove un-needed
// states) this tot_count may become zero.
int32 tot_count;
// LM-state index of the backoff LM state (if it exists, else -1)...
// provided for convenience.
int32 backoff_lmstate_index;
// this is only set after we decide on the FST state numbering (at the end).
// If not set, it's -1.
int32 fst_state;
void AddCount(int32 phone, int32 count);
// Add the contents of another LmState.
void Add(const LmState &other);
LmState(): tot_count(0), backoff_lmstate_index(-1),
fst_state(-1) { }
LmState(const LmState &other):
history(other.history), phone_to_count(other.phone_to_count),
tot_count(other.tot_count),
backoff_lmstate_index(other.backoff_lmstate_index),
fst_state(other.fst_state) { }
};
// maps from history to int32
typedef unordered_map<std::vector<int32>, int32, VectorHasher<int32> > MapType;
LanguageModelOptions opts_;
MapType hist_to_lmstate_index_;
std::vector<LmState> lm_states_; // indexed by lmstate_index, the LmStates.
// Keeps track of the number of lm states that have nonzero counts.
int32 num_active_lm_states_;
// adds the counts for this ngram (called from AddCounts()).
inline void IncrementCount(const std::vector<int32> &history,
int32 next_phone);
// sets up tot_count_with_parents in all the lm-states
void SetParentCounts();
// Finds and returns an LM-state index for a history -- or -1 if it doesn't
// exist. No backoff is done.
int32 FindLmStateIndexForHistory(const std::vector<int32> &hist) const;
// Finds and returns an LM-state index for a history -- and creates one if
// it doesn't exist -- and also creates any backoff states needed, down
// to history-length no_prune_ngram_order - 1.
int32 FindOrCreateLmStateIndexForHistory(const std::vector<int32> &hist);
// Finds and returns the most specific LM-state index for a history or
// backed-off versions of it, that exists and has nonzero count. Will die if
// there is no such history. [e.g. if there is no unigram backoff state,
// which generally speaking there won't be.]
int32 FindNonzeroLmStateIndexForHistory(std::vector<int32> hist) const;
// after all backoff has been done, assigns FST state indexes to all states
// that exist and have nonzero count. Returns the number of states.
int32 AssignFstStates();
// find the FST index of the initial-state, and returns it.
int32 FindInitialFstState() const;
// Write to an FST
void OutputToFst(
int32 num_fst_states,
fst::StdVectorFst *fst) const;
};
#endif
+2
View File
@@ -225,6 +225,8 @@ void Model::ReadDataFiles()
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.max_count = 100;
feature_info_.use_ivectors = true;
feature_info_.ivector_extractor_info.Init(ivector_extraction_opts);
} else {
+3 -3
View File
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MODEL_H_
#define MODEL_H_
#ifndef VOSK_MODEL_H
#define VOSK_MODEL_H
#include "base/kaldi-common.h"
#include "fstext/fstext-lib.h"
@@ -86,4 +86,4 @@ protected:
int ref_cnt_;
};
#endif /* MODEL_H_ */
#endif /* VOSK_MODEL_H */
+3
View File
@@ -25,6 +25,9 @@ SpkModel::SpkModel(const char *speaker_path) {
SetDropoutTestMode(true, &speaker_nnet);
CollapseModel(nnet3::CollapseModelConfig(), &speaker_nnet);
ReadKaldiObject(speaker_path_str + "/mean.vec", &mean);
ReadKaldiObject(speaker_path_str + "/transform.mat", &transform);
ref_cnt_ = 1;
}
+6 -3
View File
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SPK_MODEL_H_
#define SPK_MODEL_H_
#ifndef VOSK_SPK_MODEL_H
#define VOSK_SPK_MODEL_H
#include "base/kaldi-common.h"
#include "online2/online-feature-pipeline.h"
@@ -35,9 +35,12 @@ protected:
~SpkModel() {};
kaldi::nnet3::Nnet speaker_nnet;
kaldi::Vector<BaseFloat> mean;
kaldi::Matrix<BaseFloat> transform;
MfccOptions spkvector_mfcc_opts;
int ref_cnt_;
};
#endif /* SPK_MODEL_H_ */
#endif /* VOSK_SPK_MODEL_H */
+5
View File
@@ -34,6 +34,11 @@ import java.nio.ByteOrder;
return AcceptWaveform(bdata, bdata.length);
}
%}
%pragma(java) jniclasscode=%{
static {
System.loadLibrary("vosk_jni");
}
%}
#endif
#if SWIGCSHARP
+7 -6
View File
@@ -14,8 +14,8 @@
/* This header contains the C API for Vosk speech recognition system */
#ifndef _VOSK_API_H_
#define _VOSK_API_H_
#ifndef VOSK_API_H
#define VOSK_API_H
#ifdef __cplusplus
extern "C" {
@@ -88,10 +88,10 @@ VoskRecognizer *vosk_recognizer_new(VoskModel *model, float sample_rate);
VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, VoskSpkModel *spk_model, float sample_rate);
/** Creates the recognizer object with the grammar
/** Creates the recognizer object with the phrase list
*
* Sometimes when you want to improve recognition accuracy and when you don't need
* to recognize large vocabulary you can specify a list of words to recognize. This
* to recognize large vocabulary you can specify a list of phrases to recognize. This
* will improve recognizer speed and accuracy but might return [unk] if user said
* something different.
*
@@ -99,7 +99,8 @@ VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, VoskSpkModel *spk_mode
* Precompiled HCLG graph models are not supported.
*
* @param sample_rate The sample rate of the audio you going to feed into the recognizer
* @param grammar The string with the list of words to recognize, for example "one two three four five [unk]"
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
* for example "["one two three four five", "[unk]"]".
*
* @returns recognizer object */
VoskRecognizer *vosk_recognizer_new_grm(VoskModel *model, float sample_rate, const char *grammar);
@@ -207,4 +208,4 @@ void vosk_set_log_level(int log_level);
}
#endif
#endif /* _VOSK_API_H_ */
#endif /* VOSK_API_H */
+1 -1
View File
@@ -90,7 +90,7 @@ RUN cd /opt \
&& cd kaldi/tools \
&& git clone -b v0.3.7 --single-branch https://github.com/xianyi/OpenBLAS \
&& make PREFIX=$(pwd)/OpenBLAS/install TARGET="${OPENBLAS_ARCH}" HOSTCC=gcc USE_LOCKING=1 USE_THREAD=0 -C OpenBLAS all install \
&& git clone https://github.com/alphacep/openfst openfst \
&& git clone -b old-gcc --single-branch https://github.com/alphacep/openfst openfst \
&& cd openfst \
&& autoreconf -i \
&& ./configure --prefix=/opt/kaldi/tools/openfst --enable-static --enable-shared --enable-far --enable-ngram-fsts --enable-lookahead-fsts --with-pic --disable-bin --host=${CROSS_TRIPLE} --build=x86-linux-gnu \
+2 -2
View File
@@ -24,7 +24,7 @@ RUN cd /opt \
&& git clone -b lookahead --single-branch https://github.com/alphacep/kaldi \
&& cd kaldi/tools \
&& git clone -b v0.3.7 --single-branch https://github.com/xianyi/OpenBLAS \
&& make PREFIX=$(pwd)/OpenBLAS/install TARGET=NEHALEM USE_LOCKING=1 USE_THREAD=0 -C OpenBLAS all install \
&& make PREFIX=$(pwd)/OpenBLAS/install DYNAMIC_ARCH=1 USE_LOCKING=1 USE_THREAD=0 -C OpenBLAS all install \
&& git clone https://github.com/alphacep/openfst openfst \
&& cd openfst \
&& autoreconf -i \
@@ -32,5 +32,5 @@ RUN cd /opt \
&& make -j 10 && make install \
&& cd /opt/kaldi/src \
&& ./configure --mathlib=OPENBLAS --shared --use-cuda=no \
&& make -j 10 online2 lm \
&& make -j 10 online2 lm rnnlm \
&& find /opt/kaldi -name "*.o" -exec rm {} \;