Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d497c3a0a5 | |||
| f37ee638a4 | |||
| e0b29bb17f | |||
| c3e3fc002f | |||
| 62fc308bdf | |||
| 60c0e33901 | |||
| 5d09ee8b2b | |||
| 12f29a3415 | |||
| d56221bcf2 | |||
| a2eb39d2d7 | |||
| 128c216c61 | |||
| da87d0dad3 | |||
| 9cee2899bb | |||
| a40742bbaf | |||
| d714dff8d3 | |||
| 790c564d14 | |||
| 988ba3f257 | |||
| 2796da0a50 | |||
| d9c6fc4958 | |||
| fff40ce1a1 | |||
| 2deb7de1dd | |||
| 7d87267c31 | |||
| 64d84b01b1 | |||
| cf2560c9f8 | |||
| 800d3d7089 | |||
| b471207f7a | |||
| 25c59b52e3 | |||
| 4c72097478 | |||
| 1053cfa0f8 | |||
| 21a42cb6cd | |||
| 16c4a0d985 | |||
| 298253401a | |||
| 32aa980069 | |||
| 7b4d396eb1 | |||
| 36968fbb30 | |||
| 7474888801 | |||
| d46b7a43eb | |||
| 2376b32a8a | |||
| b8a88cc30c | |||
| be0b117711 | |||
| 449c8ea5af | |||
| 900da76652 | |||
| df0ee24084 | |||
| d3d8f53156 | |||
| 6eee303d7e | |||
| 053d71f5aa | |||
| 4fbbf5882c | |||
| 7012103b3b | |||
| 967024d20a | |||
| b966a8078b | |||
| f63b015284 | |||
| 0a9672d910 | |||
| 4ccccd0cd2 | |||
| 354fb672a3 | |||
| 73abf0740a | |||
| 81c82935ac | |||
| ac3ec56584 | |||
| 2cbe12d4d0 | |||
| 1475b0e986 | |||
| 8ceab0b9b1 | |||
| 1496b597d3 | |||
| 983519e629 | |||
| 58fa98ccd7 | |||
| a7bc5a22d4 | |||
| 23bbff0b56 | |||
| a47b58e2f4 | |||
| 8cf64ee93e | |||
| 630edeb3d6 | |||
| b1b216d4c8 | |||
| 55dd29b0ff | |||
| ea0568a38d | |||
| 298c86d0d4 | |||
| 859420809b | |||
| 0fe3a89768 | |||
| 5b892fbfc5 | |||
| fb4ed21a7f | |||
| 4209f3a9fe | |||
| ff2c80d5f1 | |||
| 3a07a08121 | |||
| 592da81a8c | |||
| def8c93711 |
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(vosk-api CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
add_library(vosk
|
||||
src/language_model.cc
|
||||
src/model.cc
|
||||
src/recognizer.cc
|
||||
src/spk_model.cc
|
||||
src/vosk_api.cc
|
||||
)
|
||||
|
||||
find_package(kaldi REQUIRED)
|
||||
target_link_libraries(vosk PUBLIC kaldi-base kaldi-online2 kaldi-rnnlm fstngram)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS vosk DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(FILES src/vosk_api.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
@@ -4,14 +4,15 @@ Vosk is an offline open source speech recognition toolkit. It enables
|
||||
speech recognition for 20+ languages and dialects - English, Indian
|
||||
English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish,
|
||||
Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino,
|
||||
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech. More to come.
|
||||
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech, Polish.
|
||||
More to come.
|
||||
|
||||
Vosk models are small (50 Mb) but provide continuous large vocabulary
|
||||
transcription, zero-latency response with streaming API, reconfigurable
|
||||
vocabulary and speaker identification.
|
||||
|
||||
Speech recognition bindings implemented for various programming languages
|
||||
like Python, Java, Node.JS, C#, C++ and others.
|
||||
like Python, Java, Node.JS, C#, C++, Rust, Go and others.
|
||||
|
||||
Vosk supplies speech recognition for chatbots, smart home appliances,
|
||||
virtual assistants. It can also create subtitles for movies,
|
||||
|
||||
+26
-38
@@ -4,62 +4,50 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.2.0'
|
||||
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.18.0'
|
||||
classpath 'com.android.tools.build:gradle:7.4.0'
|
||||
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.24.0'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
version = '0.3.38'
|
||||
version = '0.3.47'
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'com.vanniktech.maven.publish'
|
||||
|
||||
plugins.withId('com.vanniktech.maven.publish') {
|
||||
mavenPublish {
|
||||
group = 'com.alphacephei'
|
||||
version = version
|
||||
sonatypeHost = 's01'
|
||||
androidVariantToPublish = 'release'
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
aar(MavenPublication) {
|
||||
groupId 'com.alphacephei'
|
||||
version version
|
||||
pom {
|
||||
url = 'http://www.alphacephei.com.com/vosk/'
|
||||
licenses {
|
||||
license {
|
||||
name = 'The Apache License, Version 2.0'
|
||||
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = 'com.alphacephei'
|
||||
name = 'Alpha Cephei Inc'
|
||||
email = 'contact@alphacephei.com'
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection = 'scm:git:git://github.com/alphacep/vosk-api.git'
|
||||
url = 'https://github.com/alphacep/vosk-api/'
|
||||
}
|
||||
mavenPublishing {
|
||||
publishToMavenCentral(com.vanniktech.maven.publish.SonatypeHost.S01, false)
|
||||
signAllPublications()
|
||||
}
|
||||
|
||||
mavenPublishing {
|
||||
pom {
|
||||
url = 'http://www.alphacephei.com.com/vosk/'
|
||||
licenses {
|
||||
license {
|
||||
name = 'The Apache License, Version 2.0'
|
||||
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = 'com.alphacephei'
|
||||
name = 'Alpha Cephei Inc'
|
||||
email = 'contact@alphacephei.com'
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection = 'scm:git:git://github.com/alphacep/vosk-api.git'
|
||||
url = 'https://github.com/alphacep/vosk-api/'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-27
@@ -3,14 +3,15 @@ def pomName = "Vosk Android"
|
||||
def pomDescription = "Vosk speech recognition library for Android"
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
namespace 'org.vosk'
|
||||
compileSdkVersion 33
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
versionCode 6
|
||||
targetSdkVersion 33
|
||||
versionCode 10
|
||||
versionName = version
|
||||
archivesBaseName = archiveName
|
||||
ndkVersion = "22.1.7171670"
|
||||
ndkVersion = "25.2.9519653"
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
@@ -24,32 +25,15 @@ task buildVosk(type: Exec) {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api 'net.java.dev.jna:jna:4.4.0@aar'
|
||||
api 'net.java.dev.jna:jna:5.13.0@aar'
|
||||
}
|
||||
|
||||
//preBuild.dependsOn buildVosk
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
aar(MavenPublication) {
|
||||
artifactId = archiveName
|
||||
artifact("$buildDir/outputs/aar/$archiveName-release.aar")
|
||||
pom {
|
||||
name = pomName
|
||||
description = pomDescription
|
||||
}
|
||||
//generate pom nodes for dependencies
|
||||
pom.withXml {
|
||||
def dependenciesNode = asNode().appendNode('dependencies')
|
||||
configurations.implementation.allDependencies.each { dependency ->
|
||||
if (dependency.name != 'unspecified') {
|
||||
def dependencyNode = dependenciesNode.appendNode('dependency')
|
||||
dependencyNode.appendNode('groupId', dependency.group)
|
||||
dependencyNode.appendNode('artifactId', dependency.name)
|
||||
dependencyNode.appendNode('version', dependency.version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mavenPublishing {
|
||||
coordinates("com.alphacephei", archiveName, version)
|
||||
pom {
|
||||
name = pomName
|
||||
description = pomDescription
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.vosk">
|
||||
<manifest>
|
||||
</manifest>
|
||||
@@ -52,10 +52,20 @@ public class LibVosk {
|
||||
|
||||
public static native String vosk_recognizer_partial_result(Pointer recognizer);
|
||||
|
||||
public static native void vosk_recognizer_set_grm(Pointer recognizer, String grammar);
|
||||
|
||||
public static native void vosk_recognizer_reset(Pointer recognizer);
|
||||
|
||||
public static native void vosk_recognizer_free(Pointer recognizer);
|
||||
|
||||
/**
|
||||
* Set log level for Kaldi messages.
|
||||
*
|
||||
* @param loglevel the level
|
||||
* 0 - default value to print info and error messages but no debug
|
||||
* less than 0 - don't print info messages
|
||||
* greater than 0 - more verbose mode
|
||||
*/
|
||||
public static void setLogLevel(LogLevel loglevel) {
|
||||
vosk_set_log_level(loglevel.getValue());
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
package org.vosk;
|
||||
|
||||
import java.io.IOException;
|
||||
import com.sun.jna.PointerType;
|
||||
|
||||
public class Model extends PointerType implements AutoCloseable {
|
||||
public Model() {
|
||||
}
|
||||
|
||||
public Model(String path) {
|
||||
public Model(String path) throws IOException {
|
||||
super(LibVosk.vosk_model_new(path));
|
||||
|
||||
if (getPointer() == null) {
|
||||
throw new IOException("Failed to create a model");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,36 +1,163 @@
|
||||
package org.vosk;
|
||||
|
||||
import com.sun.jna.PointerType;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Recognizer extends PointerType implements AutoCloseable {
|
||||
public Recognizer(Model model, float sampleRate) {
|
||||
/**
|
||||
* Creates the recognizer object.
|
||||
*
|
||||
* The recognizers process the speech and return text using shared model data
|
||||
* @param model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @throws IOException if the recognizer could not be created
|
||||
*/
|
||||
public Recognizer(Model model, float sampleRate) throws IOException {
|
||||
super(LibVosk.vosk_recognizer_new(model, sampleRate));
|
||||
|
||||
if (getPointer() == null) {
|
||||
throw new IOException("Failed to create a recognizer");
|
||||
}
|
||||
}
|
||||
|
||||
public Recognizer(Model model, float sampleRate, SpeakerModel spkModel) {
|
||||
/**
|
||||
* 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 model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @param spkModel speaker model for speaker identification
|
||||
* @throws IOException if the recognizer could not be created
|
||||
*/
|
||||
public Recognizer(Model model, float sampleRate, SpeakerModel spkModel) throws IOException {
|
||||
super(LibVosk.vosk_recognizer_new_spk(model.getPointer(), sampleRate, spkModel.getPointer()));
|
||||
|
||||
if (getPointer() == null) {
|
||||
throw new IOException("Failed to create a recognizer");
|
||||
}
|
||||
}
|
||||
|
||||
public Recognizer(Model model, float sampleRate, String 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 phrases 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 model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
|
||||
* for example "["one two three four five", "[unk]"]".
|
||||
* @throws IOException if the recognizer could not be created
|
||||
*/
|
||||
public Recognizer(Model model, float sampleRate, String grammar) throws IOException {
|
||||
super(LibVosk.vosk_recognizer_new_grm(model.getPointer(), sampleRate, grammar));
|
||||
|
||||
if (getPointer() == null) {
|
||||
throw new IOException("Failed to create a recognizer");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures recognizer to output n-best results.
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "alternatives": [
|
||||
* { "text": "one two three four five", "confidence": 0.97 },
|
||||
* { "text": "one two three for five", "confidence": 0.03 },
|
||||
* ]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param maxAlternatives - maximum alternatives to return from recognition results
|
||||
*/
|
||||
public void setMaxAlternatives(int maxAlternatives) {
|
||||
LibVosk.vosk_recognizer_set_max_alternatives(this.getPointer(), maxAlternatives);
|
||||
}
|
||||
|
||||
/** Enables words with times in the output
|
||||
*
|
||||
* <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"
|
||||
* }],
|
||||
* </pre>
|
||||
*
|
||||
* @param words - boolean value
|
||||
*/
|
||||
public void setWords(boolean words) {
|
||||
LibVosk.vosk_recognizer_set_words(this.getPointer(), words);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like above return words and confidences in partial results.
|
||||
*
|
||||
* @param partial_words - boolean value
|
||||
*/
|
||||
public void setPartialWords(boolean partial_words) {
|
||||
LibVosk.vosk_recognizer_set_partial_words(this.getPointer(), partial_words);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds speaker model to already initialized recognizer.
|
||||
*
|
||||
* Can add speaker recognition model to already created recognizer.
|
||||
* Helps to initialize speaker recognition for grammar-based recognizer.
|
||||
*
|
||||
* @param spkModel Speaker recognition model
|
||||
*/
|
||||
public void setSpeakerModel(SpeakerModel spkModel) {
|
||||
LibVosk.vosk_recognizer_set_spk_model(this.getPointer(), spkModel.getPointer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept and process new chunk of voice data.
|
||||
*
|
||||
* @param data - audio data in PCM 16-bit mono format
|
||||
* @param len - length of the audio data
|
||||
* @return 1 if silence is occurred and you can retrieve a new utterance with result method
|
||||
* 0 if decoding continues
|
||||
* -1 if exception occurred
|
||||
*/
|
||||
public boolean acceptWaveForm(byte[] data, int len) {
|
||||
return LibVosk.vosk_recognizer_accept_waveform(this.getPointer(), data, len);
|
||||
}
|
||||
@@ -43,22 +170,76 @@ public class Recognizer extends PointerType implements AutoCloseable {
|
||||
return LibVosk.vosk_recognizer_accept_waveform_f(this.getPointer(), data, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns speech recognition result
|
||||
*
|
||||
* @return 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>
|
||||
* {
|
||||
* "text" : "what zero zero zero one"
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* If alternatives enabled it returns result with alternatives, see also #setMaxAlternatives().
|
||||
*
|
||||
* If word times enabled returns word time, see also #setWordTimes().
|
||||
*/
|
||||
public String getResult() {
|
||||
return LibVosk.vosk_recognizer_result(this.getPointer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns partial speech recognition.
|
||||
*
|
||||
* @return partial speech recognition text which is not yet finalized.
|
||||
* result may change as recognizer process more data.
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "partial" : "cyril one eight zero"
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public String getPartialResult() {
|
||||
return LibVosk.vosk_recognizer_partial_result(this.getPointer());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return speech result in JSON format.
|
||||
*/
|
||||
public String getFinalResult() {
|
||||
return LibVosk.vosk_recognizer_final_result(this.getPointer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconfigures recognizer to use grammar.
|
||||
*
|
||||
* @param grammar Set of phrases in JSON array of strings or "[]" to use default model graph.
|
||||
* @see #Recognizer(Model, float, String)
|
||||
*/
|
||||
public void setGrammar(String grammar) {
|
||||
LibVosk.vosk_recognizer_set_grm(this.getPointer(), grammar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the recognizer.
|
||||
* Resets current results so the recognition can continue from scratch.
|
||||
*/
|
||||
public void reset() {
|
||||
LibVosk.vosk_recognizer_reset(this.getPointer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases recognizer object.
|
||||
* Underlying model is also unreferenced and if needed, released.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
LibVosk.vosk_recognizer_free(this.getPointer());
|
||||
|
||||
@@ -1,13 +1,36 @@
|
||||
package org.vosk;
|
||||
|
||||
import com.sun.jna.PointerType;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Helps to initialize speaker recognition for grammar-based recognizer.
|
||||
*/
|
||||
public class SpeakerModel extends PointerType implements AutoCloseable {
|
||||
public SpeakerModel() {
|
||||
}
|
||||
|
||||
public SpeakerModel(String path) {
|
||||
/**
|
||||
* Loads speaker model data from the file.
|
||||
*
|
||||
* The path must contain:
|
||||
* - a config file: mfcc.conf
|
||||
* - kaldi nnet: final.ext.raw
|
||||
* - mean.vec
|
||||
* - transform.mat
|
||||
*
|
||||
* @param path the path of the model on the filesystem
|
||||
* @throws IOException if the model could not be created
|
||||
*
|
||||
* @see <a href="http://kaldi-asr.org/doc/structkaldi_1_1MfccOptions.html">Kaldi MfccOptions</a>
|
||||
* @see <a href="http://kaldi-asr.org/doc/classkaldi_1_1nnet3_1_1Nnet.html">Kaldi Nnet</a>
|
||||
*/
|
||||
public SpeakerModel(String path) throws IOException {
|
||||
super(LibVosk.vosk_spk_model_new(path));
|
||||
|
||||
if (getPointer() == null) {
|
||||
throw new IOException("Failed to create a speaker model");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,9 +19,9 @@ import android.media.AudioRecord;
|
||||
import android.media.MediaRecorder.AudioSource;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import org.vosk.Recognizer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@@ -48,6 +48,7 @@ public class SpeechService {
|
||||
*
|
||||
* @throws IOException thrown if audio recorder can not be created for some reason.
|
||||
*/
|
||||
@SuppressLint("MissingPermission")
|
||||
public SpeechService(Recognizer recognizer, float sampleRate) throws IOException {
|
||||
this.recognizer = recognizer;
|
||||
this.sampleRate = (int) sampleRate;
|
||||
|
||||
@@ -3,11 +3,12 @@ def pomName = "Vosk English Model"
|
||||
def pomDescription = "Small English model for Android"
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
namespace "org.vosk"
|
||||
compileSdkVersion 33
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
versionCode 6
|
||||
targetSdkVersion 33
|
||||
versionCode 10
|
||||
versionName = version
|
||||
archivesBaseName = archiveName
|
||||
}
|
||||
@@ -33,15 +34,10 @@ tasks.register('genUUID') {
|
||||
|
||||
preBuild.dependsOn(genUUID)
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
aar(MavenPublication) {
|
||||
artifactId = archiveName
|
||||
artifact("$buildDir/outputs/aar/$archiveName-release.aar")
|
||||
pom {
|
||||
name = pomName
|
||||
description = pomDescription
|
||||
}
|
||||
}
|
||||
mavenPublishing {
|
||||
coordinates("com.alphacephei", archiveName, version)
|
||||
pom {
|
||||
name = pomName
|
||||
description = pomDescription
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.vosk.model.en">
|
||||
<manifest>
|
||||
</manifest>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Vosk" Version="0.3.31" />
|
||||
<PackageReference Include="Vosk" Version="0.3.45" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
<package>
|
||||
<metadata>
|
||||
<id>Vosk</id>
|
||||
<version>0.3.38</version>
|
||||
<version>0.3.45</version>
|
||||
<authors>Alpha Cephei Inc</authors>
|
||||
<owners>Alpha Cephei Inc</owners>
|
||||
<license type="expression">Apache-2.0</license>
|
||||
<projectUrl>https://alphacephei.com/vosk/</projectUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>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.
|
||||
<title>Vosk Speech Recognition Toolkit</title>
|
||||
<description>Vosk is an offline open source speech recognition toolkit. It enables speech recognition models for 20+ languages and dialects - English, Indian English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish, Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino, Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech. More to come.
|
||||
|
||||
Vosk models are small (50 Mb) but provide continuous large vocabulary transcription, zero-latency response with streaming API, reconfigurable vocabulary and speaker identification.
|
||||
|
||||
@@ -18,7 +19,8 @@ Vosk supplies speech recognition for chatbots, smart home appliances, virtual as
|
||||
|
||||
Vosk scales from small devices like Raspberry Pi or Android smartphone to big clusters.</description>
|
||||
<releaseNotes>See for details https://github.com/alphacep/vosk-api/releases</releaseNotes>
|
||||
<copyright>Copyright 2020 Alpha Cephei Inc</copyright>
|
||||
<repository type="git" url="https://github.com/alphacep/vosk-api.git" branch="master"/>
|
||||
<copyright>Copyright 2020-2050 Alpha Cephei Inc</copyright>
|
||||
<tags>speech recognition voice stt asr speech-to-text ai offline privacy</tags>
|
||||
<dependencies>
|
||||
<group targetFramework=".NETStandard2.0"/>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<ItemGroup>
|
||||
<NativeLibs Include="$(MSBuildThisFileDirectory)\lib\linux-x64\*.so" Condition="'$([MSBuild]::IsOsPlatform(Linux))'" />
|
||||
<NativeLibs Include="$(MSBuildThisFileDirectory)\lib\win-x64\*.dll" Condition="'$([MSBuild]::IsOsPlatform(Windows))'" />
|
||||
<NativeLibs Include="$(MSBuildThisFileDirectory)\lib\osx-x64\*.dylib" Condition="'$([MSBuild]::IsOsPlatform(OSX))'" />
|
||||
<NativeLibs Include="$(MSBuildThisFileDirectory)\lib\osx-universal\*.dylib" Condition="'$([MSBuild]::IsOsPlatform(OSX))'" />
|
||||
<None Include="@(NativeLibs)">
|
||||
<Link>%(FileName)%(Extension)</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
|
||||
namespace Vosk
|
||||
{
|
||||
public class BatchModel : global::System.IDisposable
|
||||
{
|
||||
private global::System.Runtime.InteropServices.HandleRef handle;
|
||||
|
||||
internal BatchModel(global::System.IntPtr cPtr)
|
||||
{
|
||||
handle = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
|
||||
}
|
||||
|
||||
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(BatchModel obj)
|
||||
{
|
||||
return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.handle;
|
||||
}
|
||||
|
||||
~BatchModel()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
global::System.GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (handle.Handle != global::System.IntPtr.Zero)
|
||||
{
|
||||
VoskPINVOKE.delete_BatchModel(handle);
|
||||
handle = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BatchModel(string model_path) : this(VoskPINVOKE.new_BatchModel(model_path))
|
||||
{
|
||||
}
|
||||
|
||||
public void WaitForCompletion()
|
||||
{
|
||||
if (handle.Handle != global::System.IntPtr.Zero)
|
||||
{
|
||||
VoskPINVOKE.wait_BatchModel(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
|
||||
namespace Vosk
|
||||
{
|
||||
public class VoskBatchRecognizer : System.IDisposable
|
||||
{
|
||||
private System.Runtime.InteropServices.HandleRef handle;
|
||||
|
||||
internal VoskBatchRecognizer(System.IntPtr cPtr)
|
||||
{
|
||||
handle = new System.Runtime.InteropServices.HandleRef(this, cPtr);
|
||||
}
|
||||
|
||||
internal static System.Runtime.InteropServices.HandleRef getCPtr(VoskBatchRecognizer obj)
|
||||
{
|
||||
return (obj == null) ? new System.Runtime.InteropServices.HandleRef(null, System.IntPtr.Zero) : obj.handle;
|
||||
}
|
||||
|
||||
~VoskBatchRecognizer()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
System.GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (handle.Handle != System.IntPtr.Zero)
|
||||
{
|
||||
VoskPINVOKE.delete_VoskBatchRecognizer(handle);
|
||||
handle = new System.Runtime.InteropServices.HandleRef(null, System.IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public VoskBatchRecognizer(BatchModel model, float sample_rate) : this(VoskPINVOKE.new_VoskBatchRecognizer(BatchModel.getCPtr(model), sample_rate))
|
||||
{
|
||||
}
|
||||
|
||||
public bool AcceptWaveform(byte[] data, int len)
|
||||
{
|
||||
return VoskPINVOKE.VoskBatchRecognizer_AcceptWaveform(handle, data, len);
|
||||
}
|
||||
|
||||
private static string PtrToStringUTF8(System.IntPtr ptr)
|
||||
{
|
||||
int len = 0;
|
||||
while (System.Runtime.InteropServices.Marshal.ReadByte(ptr, len) != 0)
|
||||
len++;
|
||||
byte[] array = new byte[len];
|
||||
System.Runtime.InteropServices.Marshal.Copy(ptr, array, 0, len);
|
||||
return System.Text.Encoding.UTF8.GetString(array);
|
||||
}
|
||||
|
||||
public string FrontResult()
|
||||
{
|
||||
return PtrToStringUTF8(VoskPINVOKE.VoskBatchRecognizer_FrontResult(handle));
|
||||
}
|
||||
|
||||
public string Result()
|
||||
{
|
||||
string result = PtrToStringUTF8(VoskPINVOKE.VoskBatchRecognizer_FrontResult(handle));
|
||||
VoskPINVOKE.VoskBatchRecognizer_Pop(handle);
|
||||
return result;
|
||||
}
|
||||
|
||||
public int GetNumPendingChunks()
|
||||
{
|
||||
return VoskPINVOKE.VoskBatchRecognizer_GetPendingChunks(handle);
|
||||
}
|
||||
|
||||
public void FinishStream()
|
||||
{
|
||||
VoskPINVOKE.VoskBatchRecognizer_FinishStream(handle);
|
||||
}
|
||||
|
||||
public void SetNLSML(bool nlsml)
|
||||
{
|
||||
VoskPINVOKE.VoskBatchRecognizer_SetNLSML(handle, Convert.ToInt32(nlsml));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,41 @@ class VoskPINVOKE {
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_gpu_thread_init")]
|
||||
public static extern void GpuThreadInit();
|
||||
}
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_model_new")]
|
||||
public static extern global::System.IntPtr new_BatchModel(string jarg1);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_model_free")]
|
||||
public static extern void delete_BatchModel(global::System.Runtime.InteropServices.HandleRef jarg1);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_model_wait")]
|
||||
public static extern void wait_BatchModel(global::System.Runtime.InteropServices.HandleRef jarg1);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_new")]
|
||||
public static extern global::System.IntPtr new_VoskBatchRecognizer(global::System.Runtime.InteropServices.HandleRef jarg1, float jarg2);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_free")]
|
||||
public static extern void delete_VoskBatchRecognizer(global::System.Runtime.InteropServices.HandleRef jarg1);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_accept_waveform")]
|
||||
public static extern bool VoskBatchRecognizer_AcceptWaveform(global::System.Runtime.InteropServices.HandleRef jarg1, [global::System.Runtime.InteropServices.In, global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPArray)] byte[] jarg2, int jarg3);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_set_nlsml")]
|
||||
public static extern void VoskBatchRecognizer_SetNLSML(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_finish_stream")]
|
||||
public static extern void VoskBatchRecognizer_FinishStream(global::System.Runtime.InteropServices.HandleRef jarg1);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_front_result")]
|
||||
public static extern global::System.IntPtr VoskBatchRecognizer_FrontResult(global::System.Runtime.InteropServices.HandleRef jarg1);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_pop")]
|
||||
public static extern void VoskBatchRecognizer_Pop(global::System.Runtime.InteropServices.HandleRef jarg1);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_get_pending_chunks")]
|
||||
public static extern int VoskBatchRecognizer_GetPendingChunks(global::System.Runtime.InteropServices.HandleRef jarg1);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
See example subfolder for instructions how to use the module
|
||||
@@ -0,0 +1,31 @@
|
||||
To try this package do the following steps:
|
||||
|
||||
On Linux (we download library and set LD_LIBRARY_PATH)
|
||||
|
||||
```
|
||||
git clone https://github.com/alphacep/vosk-api
|
||||
cd vosk-api/go/example
|
||||
wget https://github.com/alphacep/vosk-api/releases/download/v0.3.45/vosk-linux-x86_64-0.3.45.zip
|
||||
unzip vosk-linux-x86_64-0.3.45.zip
|
||||
wget https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip
|
||||
unzip vosk-model-small-en-us-0.15.zip
|
||||
mv vosk-model-small-en-us-0.15 model
|
||||
cp ../../python/example/test.wav .
|
||||
VOSK_PATH=`pwd`/vosk-linux-x86_64-0.3.45 LD_LIBRARY_PATH=$VOSK_PATH CGO_CPPFLAGS="-I $VOSK_PATH" CGO_LDFLAGS="-L $VOSK_PATH" go run . -f test.wav
|
||||
```
|
||||
|
||||
for Windows (we place DLLs in current folder where linker finds them):
|
||||
|
||||
```
|
||||
git clone https://github.com/alphacep/vosk-api
|
||||
cd vosk-api/go/example
|
||||
wget https://github.com/alphacep/vosk-api/releases/download/v0.3.45/vosk-linux-x86_64-0.3.45.zip
|
||||
unzip vosk-linux-x86_64-0.3.45.zip
|
||||
cp vosk-linux-x86_64-0.3.45/*.dll .
|
||||
cp vosk-linux-x86_64-0.3.45/*.h .
|
||||
wget https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip
|
||||
unzip vosk-model-small-en-us-0.15.zip
|
||||
mv vosk-model-small-en-us-0.15 model
|
||||
cp ../../python/example/test.wav .
|
||||
VOSK_PATH=`pwd` LD_LIBRARY_PATH=$VOSK_PATH CGO_CPPFLAGS="-I $VOSK_PATH" CGO_LDFLAGS="-L $VOSK_PATH -lvosk -lpthread -dl" go run . -f test.wav
|
||||
```
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
// Example package for Vosk Go bindings.
|
||||
package test_simple
|
||||
package main
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -21,6 +21,9 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// we can check if word is in the vocabulary
|
||||
// fmt.Println(model.FindWord("air"))
|
||||
|
||||
sampleRate := 16000.0
|
||||
rec, err := vosk.NewRecognizer(model, sampleRate)
|
||||
if err != nil {
|
||||
@@ -34,11 +37,10 @@ func main() {
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
reader := bufio.NewReader(file)
|
||||
buf := make([]byte, 4096)
|
||||
|
||||
for {
|
||||
_, err := reader.Read(buf)
|
||||
_, err := file.Read(buf)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
log.Fatal(err)
|
||||
@@ -48,9 +50,12 @@ func main() {
|
||||
}
|
||||
|
||||
if rec.AcceptWaveform(buf) != 0 {
|
||||
fmt.Println(string(rec.Result()))
|
||||
fmt.Println(rec.Result())
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(string(rec.FinalResult()))
|
||||
// Unmarshal example for final result
|
||||
var jres map[string]interface{}
|
||||
json.Unmarshal([]byte(rec.FinalResult()), &jres)
|
||||
fmt.Println(jres["text"])
|
||||
}
|
||||
|
||||
+33
-16
@@ -5,6 +5,7 @@ package vosk
|
||||
// #include <stdlib.h>
|
||||
// #include <vosk_api.h>
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
// VoskModel contains a reference to the C VoskModel
|
||||
type VoskModel struct {
|
||||
@@ -13,7 +14,9 @@ type VoskModel struct {
|
||||
|
||||
// NewModel creates a new VoskModel instance
|
||||
func NewModel(modelPath string) (*VoskModel, error) {
|
||||
internal := C.vosk_model_new(C.CString(modelPath))
|
||||
cmodelPath := C.CString(modelPath)
|
||||
defer C.free(unsafe.Pointer(cmodelPath))
|
||||
internal := C.vosk_model_new(cmodelPath)
|
||||
model := &VoskModel{model: internal}
|
||||
return model, nil
|
||||
}
|
||||
@@ -29,10 +32,10 @@ func freeModel(model *VoskModel) {
|
||||
// FindWord checks if a word can be recognized by the model.
|
||||
// Returns the word symbol if the word exists inside the model or
|
||||
// -1 otherwise.
|
||||
func (m *VoskModel) FindWord(word []byte) int {
|
||||
cbuf := C.CBytes(word)
|
||||
defer C.free(cbuf)
|
||||
i := C.vosk_model_find_word(m.model, (*C.char)(cbuf))
|
||||
func (m *VoskModel) FindWord(word string) int {
|
||||
cstr := C.CString(word)
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
i := C.vosk_model_find_word(m.model, cstr)
|
||||
return int(i)
|
||||
}
|
||||
|
||||
@@ -43,7 +46,9 @@ type VoskSpkModel struct {
|
||||
|
||||
// NewSpkModel creates a new VoskSpkModel instance
|
||||
func NewSpkModel(spkModelPath string) (*VoskSpkModel, error) {
|
||||
internal := C.vosk_spk_model_new(C.CString(spkModelPath))
|
||||
cspkModelPath := C.CString(spkModelPath)
|
||||
defer C.free(unsafe.Pointer(cspkModelPath))
|
||||
internal := C.vosk_spk_model_new(cspkModelPath)
|
||||
spkModel := &VoskSpkModel{spkModel: internal}
|
||||
return spkModel, nil
|
||||
}
|
||||
@@ -84,10 +89,10 @@ func NewRecognizerSpk(model *VoskModel, sampleRate float64, spkModel *VoskSpkMod
|
||||
}
|
||||
|
||||
// NewRecognizerGrm creates a new VoskRecognizer instance with the phrase list.
|
||||
func NewRecognizerGrm(model *VoskModel, sampleRate float64, grammer []byte) (*VoskRecognizer, error) {
|
||||
cbuf := C.CBytes(grammer)
|
||||
defer C.free(cbuf)
|
||||
internal := C.vosk_recognizer_new_grm(model.model, C.float(sampleRate), (*C.char)(cbuf))
|
||||
func NewRecognizerGrm(model *VoskModel, sampleRate float64, grammar string) (*VoskRecognizer, error) {
|
||||
cgrammar := C.CString(grammar)
|
||||
defer C.free(unsafe.Pointer(cgrammar))
|
||||
internal := C.vosk_recognizer_new_grm(model.model, C.float(sampleRate), cgrammar)
|
||||
rec := &VoskRecognizer{rec: internal}
|
||||
return rec, nil
|
||||
}
|
||||
@@ -97,6 +102,13 @@ func (r *VoskRecognizer) SetSpkModel(spkModel *VoskSpkModel) {
|
||||
C.vosk_recognizer_set_spk_model(r.rec, spkModel.spkModel)
|
||||
}
|
||||
|
||||
// SetGrm sets which phrases to recognize on an already initialized recognizer.
|
||||
func (r *VoskRecognizer) SetGrm(grammar string) {
|
||||
cgrammar := C.CString(grammar)
|
||||
defer C.free(unsafe.Pointer(cgrammar))
|
||||
C.vosk_recognizer_set_grm(r.rec, cgrammar)
|
||||
}
|
||||
|
||||
// SetMaxAlternatives configures the recognizer to output n-best results.
|
||||
func (r *VoskRecognizer) SetMaxAlternatives(maxAlternatives int) {
|
||||
C.vosk_recognizer_set_max_alternatives(r.rec, C.int(maxAlternatives))
|
||||
@@ -107,6 +119,11 @@ func (r *VoskRecognizer) SetWords(words int) {
|
||||
C.vosk_recognizer_set_words(r.rec, C.int(words))
|
||||
}
|
||||
|
||||
// SetPartialWords enables words with times in the partial ouput.
|
||||
func (r *VoskRecognizer) SetPartialWords(words int) {
|
||||
C.vosk_recognizer_set_partial_words(r.rec, C.int(words))
|
||||
}
|
||||
|
||||
// AcceptWaveform accepts and processes a new chunk of the voice data.
|
||||
func (r *VoskRecognizer) AcceptWaveform(buffer []byte) int {
|
||||
cbuf := C.CBytes(buffer)
|
||||
@@ -116,19 +133,19 @@ func (r *VoskRecognizer) AcceptWaveform(buffer []byte) int {
|
||||
}
|
||||
|
||||
// Result returns a speech recognition result.
|
||||
func (r *VoskRecognizer) Result() []byte {
|
||||
return []byte(C.GoString(C.vosk_recognizer_result(r.rec)))
|
||||
func (r *VoskRecognizer) Result() string {
|
||||
return C.GoString(C.vosk_recognizer_result(r.rec))
|
||||
}
|
||||
|
||||
// PartialResult returns a partial speech recognition result.
|
||||
func (r *VoskRecognizer) PartialResult() []byte {
|
||||
return []byte(C.GoString(C.vosk_recognizer_partial_result(r.rec)))
|
||||
func (r *VoskRecognizer) PartialResult() string {
|
||||
return C.GoString(C.vosk_recognizer_partial_result(r.rec))
|
||||
}
|
||||
|
||||
// FinalResult returns a speech recognition result. Same as result, but doesn't wait
|
||||
// for silence.
|
||||
func (r *VoskRecognizer) FinalResult() []byte {
|
||||
return []byte(C.GoString(C.vosk_recognizer_final_result(r.rec)))
|
||||
func (r *VoskRecognizer) FinalResult() string {
|
||||
return C.GoString(C.vosk_recognizer_final_result(r.rec))
|
||||
}
|
||||
|
||||
// Reset resets the recognizer.
|
||||
|
||||
@@ -11,6 +11,5 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation group: 'net.java.dev.jna', name: 'jna', version: '5.7.0'
|
||||
implementation group: 'com.alphacephei', name: 'vosk', version: '0.3.38+'
|
||||
implementation group: 'com.alphacephei', name: 'vosk', version: '0.3.45'
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ repositories {
|
||||
|
||||
archivesBaseName = 'vosk'
|
||||
group = 'com.alphacephei'
|
||||
version = '0.3.38'
|
||||
version = '0.3.45'
|
||||
|
||||
mavenPublish {
|
||||
group = 'com.alphacephei'
|
||||
@@ -25,7 +25,7 @@ mavenPublish {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api group: 'net.java.dev.jna', name: 'jna', version: '5.7.0'
|
||||
api group: 'net.java.dev.jna', name: 'jna', version: '5.13.0'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.vosk;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Platform;
|
||||
import com.sun.jna.Pointer;
|
||||
import java.io.File;
|
||||
@@ -13,8 +12,9 @@ import java.nio.file.StandardCopyOption;
|
||||
public class LibVosk {
|
||||
|
||||
private static void unpackDll(File targetDir, String lib) throws IOException {
|
||||
InputStream source = LibVosk.class.getResourceAsStream("/win32-x86-64/" + lib + ".dll");
|
||||
Files.copy(source, new File(targetDir, lib + ".dll").toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
try (InputStream source = LibVosk.class.getResourceAsStream("/win32-x86-64/" + lib + ".dll")) {
|
||||
Files.copy(source, new File(targetDir, lib + ".dll").toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
@@ -23,7 +23,7 @@ public class LibVosk {
|
||||
// We have to unpack dependencies
|
||||
try {
|
||||
// To get a tmp folder we unpack small library and mark it for deletion
|
||||
File tmpFile = Native.extractFromResourcePath("/win32-x86-64/empty");
|
||||
File tmpFile = Native.extractFromResourcePath("/win32-x86-64/empty", LibVosk.class.getClassLoader());
|
||||
File tmpDir = tmpFile.getParentFile();
|
||||
new File(tmpDir, tmpFile.getName() + ".x").createNewFile();
|
||||
|
||||
@@ -78,10 +78,20 @@ public class LibVosk {
|
||||
|
||||
public static native String vosk_recognizer_partial_result(Pointer recognizer);
|
||||
|
||||
public static native void vosk_recognizer_set_grm(Pointer recognizer, String grammar);
|
||||
|
||||
public static native void vosk_recognizer_reset(Pointer recognizer);
|
||||
|
||||
public static native void vosk_recognizer_free(Pointer recognizer);
|
||||
|
||||
/**
|
||||
* Set log level for Kaldi messages.
|
||||
*
|
||||
* @param loglevel the level
|
||||
* 0 - default value to print info and error messages but no debug
|
||||
* less than 0 - don't print info messages
|
||||
* greater than 0 - more verbose mode
|
||||
*/
|
||||
public static void setLogLevel(LogLevel loglevel) {
|
||||
vosk_set_log_level(loglevel.getValue());
|
||||
}
|
||||
|
||||
@@ -4,6 +4,17 @@ import com.sun.jna.PointerType;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Recognizer extends PointerType implements AutoCloseable {
|
||||
/**
|
||||
* Creates the recognizer object.
|
||||
*
|
||||
* The recognizers process the speech and return text using shared model data
|
||||
* @param model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @throws IOException if the recognizer could not be created
|
||||
*/
|
||||
public Recognizer(Model model, float sampleRate) throws IOException {
|
||||
super(LibVosk.vosk_recognizer_new(model, sampleRate));
|
||||
|
||||
@@ -12,30 +23,141 @@ public class Recognizer extends PointerType implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
public Recognizer(Model model, float sampleRate, SpeakerModel spkModel) {
|
||||
/**
|
||||
* 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 model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @param spkModel speaker model for speaker identification
|
||||
* @throws IOException if the recognizer could not be created
|
||||
*/
|
||||
public Recognizer(Model model, float sampleRate, SpeakerModel spkModel) throws IOException {
|
||||
super(LibVosk.vosk_recognizer_new_spk(model.getPointer(), sampleRate, spkModel.getPointer()));
|
||||
|
||||
if (getPointer() == null) {
|
||||
throw new IOException("Failed to create a recognizer");
|
||||
}
|
||||
}
|
||||
|
||||
public Recognizer(Model model, float sampleRate, String 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 phrases 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 model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
|
||||
* for example "["one two three four five", "[unk]"]".
|
||||
* @throws IOException if the recognizer could not be created
|
||||
*/
|
||||
public Recognizer(Model model, float sampleRate, String grammar) throws IOException {
|
||||
super(LibVosk.vosk_recognizer_new_grm(model.getPointer(), sampleRate, grammar));
|
||||
|
||||
if (getPointer() == null) {
|
||||
throw new IOException("Failed to create a recognizer");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures recognizer to output n-best results.
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "alternatives": [
|
||||
* { "text": "one two three four five", "confidence": 0.97 },
|
||||
* { "text": "one two three for five", "confidence": 0.03 },
|
||||
* ]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param maxAlternatives - maximum alternatives to return from recognition results
|
||||
*/
|
||||
public void setMaxAlternatives(int maxAlternatives) {
|
||||
LibVosk.vosk_recognizer_set_max_alternatives(this.getPointer(), maxAlternatives);
|
||||
}
|
||||
|
||||
/** Enables words with times in the output
|
||||
*
|
||||
* <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"
|
||||
* }],
|
||||
* </pre>
|
||||
*
|
||||
* @param words - boolean value
|
||||
*/
|
||||
public void setWords(boolean words) {
|
||||
LibVosk.vosk_recognizer_set_words(this.getPointer(), words);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like above return words and confidences in partial results.
|
||||
*
|
||||
* @param partial_words - boolean value
|
||||
*/
|
||||
public void setPartialWords(boolean partial_words) {
|
||||
LibVosk.vosk_recognizer_set_partial_words(this.getPointer(), partial_words);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds speaker model to already initialized recognizer.
|
||||
*
|
||||
* Can add speaker recognition model to already created recognizer.
|
||||
* Helps to initialize speaker recognition for grammar-based recognizer.
|
||||
*
|
||||
* @param spkModel Speaker recognition model
|
||||
*/
|
||||
public void setSpeakerModel(SpeakerModel spkModel) {
|
||||
LibVosk.vosk_recognizer_set_spk_model(this.getPointer(), spkModel.getPointer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept and process new chunk of voice data.
|
||||
*
|
||||
* @param data - audio data in PCM 16-bit mono format
|
||||
* @param len - length of the audio data
|
||||
* @return 1 if silence is occurred and you can retrieve a new utterance with result method
|
||||
* 0 if decoding continues
|
||||
* -1 if exception occurred
|
||||
*/
|
||||
public boolean acceptWaveForm(byte[] data, int len) {
|
||||
return LibVosk.vosk_recognizer_accept_waveform(this.getPointer(), data, len);
|
||||
}
|
||||
@@ -48,22 +170,76 @@ public class Recognizer extends PointerType implements AutoCloseable {
|
||||
return LibVosk.vosk_recognizer_accept_waveform_f(this.getPointer(), data, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns speech recognition result
|
||||
*
|
||||
* @return 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>
|
||||
* {
|
||||
* "text" : "what zero zero zero one"
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* If alternatives enabled it returns result with alternatives, see also #setMaxAlternatives().
|
||||
*
|
||||
* If word times enabled returns word time, see also #setWordTimes().
|
||||
*/
|
||||
public String getResult() {
|
||||
return LibVosk.vosk_recognizer_result(this.getPointer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns partial speech recognition.
|
||||
*
|
||||
* @return partial speech recognition text which is not yet finalized.
|
||||
* result may change as recognizer process more data.
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "partial" : "cyril one eight zero"
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public String getPartialResult() {
|
||||
return LibVosk.vosk_recognizer_partial_result(this.getPointer());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return speech result in JSON format.
|
||||
*/
|
||||
public String getFinalResult() {
|
||||
return LibVosk.vosk_recognizer_final_result(this.getPointer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconfigures recognizer to use grammar.
|
||||
*
|
||||
* @param grammar Set of phrases in JSON array of strings or "[]" to use default model graph.
|
||||
* @see #Recognizer(Model, float, String)
|
||||
*/
|
||||
public void setGrammar(String grammar) {
|
||||
LibVosk.vosk_recognizer_set_grm(this.getPointer(), grammar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the recognizer.
|
||||
* Resets current results so the recognition can continue from scratch.
|
||||
*/
|
||||
public void reset() {
|
||||
LibVosk.vosk_recognizer_reset(this.getPointer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases recognizer object.
|
||||
* Underlying model is also unreferenced and if needed, released.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
LibVosk.vosk_recognizer_free(this.getPointer());
|
||||
|
||||
@@ -3,10 +3,28 @@ package org.vosk;
|
||||
import com.sun.jna.PointerType;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Helps to initialize speaker recognition for grammar-based recognizer.
|
||||
*/
|
||||
public class SpeakerModel extends PointerType implements AutoCloseable {
|
||||
public SpeakerModel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads speaker model data from the file.
|
||||
*
|
||||
* The path must contain:
|
||||
* - a config file: mfcc.conf
|
||||
* - kaldi nnet: final.ext.raw
|
||||
* - mean.vec
|
||||
* - transform.mat
|
||||
*
|
||||
* @param path the path of the model on the filesystem
|
||||
* @throws IOException if the model could not be created
|
||||
*
|
||||
* @see <a href="http://kaldi-asr.org/doc/structkaldi_1_1MfccOptions.html">Kaldi MfccOptions</a>
|
||||
* @see <a href="http://kaldi-asr.org/doc/classkaldi_1_1nnet3_1_1Nnet.html">Kaldi Nnet</a>
|
||||
*/
|
||||
public SpeakerModel(String path) throws IOException {
|
||||
super(LibVosk.vosk_spk_model_new(path));
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.gradle/
|
||||
.idea/
|
||||
build/
|
||||
Generated
+3
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
Generated
+1
@@ -0,0 +1 @@
|
||||
vosk-api-kotlin
|
||||
Generated
+127
@@ -0,0 +1,127 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
<option name="SMART_TABS" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="11" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<component name="CopyrightManager">
|
||||
<copyright>
|
||||
<option name="notice" value="Copyright &#36;today.year Alpha Cephei Inc. 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 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License." />
|
||||
<option name="myName" value="Apache-2.0" />
|
||||
</copyright>
|
||||
</component>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings default="Apache-2.0">
|
||||
<module2copyright>
|
||||
<element module="All" copyright="Apache-2.0" />
|
||||
</module2copyright>
|
||||
</settings>
|
||||
</component>
|
||||
Generated
+18
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+25
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Google" />
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Embedded JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
Doomsdayrs doomsdayrs@gmail.com
|
||||
@@ -0,0 +1,8 @@
|
||||
# Maintenance
|
||||
|
||||
To maintain this module, please ensure the following.
|
||||
1. Kotlin version is kept up to date.
|
||||
This will be found in the plugins block of the [build.gradle.kts](./build.gradle.kts).
|
||||
Ensure both multiplatform and serialization have the same value.
|
||||
2. Ensure dependencies are up to date
|
||||
3. Ensure that the android min & target sdks are up to date.
|
||||
@@ -0,0 +1,63 @@
|
||||
# vosk-api-kotlin
|
||||
|
||||
The vosk-api wrapped using Kotlin Multiplatform.
|
||||
|
||||
## Usage
|
||||
|
||||
The following are ways to use this wrapper.
|
||||
|
||||
### JVM
|
||||
|
||||
For Java & Android targets.
|
||||
|
||||
```kotlin
|
||||
dependencoes {
|
||||
val voskVersion = "0.4.0-alpha0"
|
||||
|
||||
// Generic
|
||||
implementation("com.alphacephei:vosk-api-kotlin:$voskVersion")
|
||||
|
||||
// Android
|
||||
implementation("com.alphacephei:vosk-api-kotlin-android:$voskVersion")
|
||||
}
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To build this project, follow the following steps.
|
||||
|
||||
1. Install `libvosk`.
|
||||
This can be done from [source][source install] (parent monorepo)
|
||||
or [downloaded][download].
|
||||
2. Download a [Vosk model](https://alphacephei.com/vosk/models) to use.
|
||||
- It is suggested to use a small model to speed up tests.
|
||||
3. Once both are downloaded and placed into a proper location (hopefully following UNIX specification).
|
||||
Set the following environment variables:
|
||||
- `VOSK_MODEL` to the path of the model.
|
||||
- `VOSK_PATH` to the path of `libvosk`.
|
||||
These are used by the various tests to operate.
|
||||
4. Now that the required steps are complete, one can run `./gradlew build`.
|
||||
|
||||
## Kotlin/Native
|
||||
|
||||
Currently, the native target is disabled due to a lack of vosk-api packaging on platforms.
|
||||
Further worsened by the fact that installing the vosk-api on Linux systems is a chore.
|
||||
|
||||
First, either install from [source][source install]
|
||||
or [download][download] and install into the proper unix directories as expected in
|
||||
[libvosk.def](./src/nativeInterop/cinterop/libvosk.def).
|
||||
|
||||
To enable development for Kotlin/Native, do either for the following.
|
||||
- Add `NATIVE_EXPERIMENT=true` to your environment.
|
||||
- Go into [build.gradle.kts](./build.gradle.kts) & find `enableNative` & set the right side to true.
|
||||
|
||||
Afterwards, when syncing the project, the native source sets will become available to work on.
|
||||
It is suggested to run `cinteropLibvoskNative` to generate the Kotlin C bindings to work with.
|
||||
|
||||
## Future
|
||||
|
||||
- Possibly target Kotlin/JS
|
||||
- Possibly target Kotlin/Objective-C (?)
|
||||
|
||||
[source install]: https://alphacephei.com/vosk/install
|
||||
[download]: https://github.com/alphacep/vosk-api/releases/latest
|
||||
@@ -0,0 +1,190 @@
|
||||
import org.jetbrains.dokka.gradle.DokkaTask
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
|
||||
/*
|
||||
* Copyright 2020 Alpha Cephei Inc. & Doomsdayrs
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform") version "1.8.10"
|
||||
id("com.android.library")
|
||||
`maven-publish`
|
||||
id("org.jetbrains.dokka") version "1.7.20"
|
||||
kotlin("plugin.serialization") version "1.8.10"
|
||||
}
|
||||
|
||||
group = "com.alphacephei"
|
||||
version = "0.4.0-alpha0"
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
val dokkaOutputDir = "$buildDir/dokka"
|
||||
|
||||
tasks.getByName<DokkaTask>("dokkaHtml") {
|
||||
outputDirectory.set(file(dokkaOutputDir))
|
||||
}
|
||||
|
||||
val deleteDokkaOutputDir by tasks.register<Delete>("deleteDokkaOutputDirectory") {
|
||||
delete(dokkaOutputDir)
|
||||
}
|
||||
|
||||
val javadocJar = tasks.register<Jar>("javadocJar") {
|
||||
dependsOn(deleteDokkaOutputDir, tasks.dokkaHtml)
|
||||
archiveClassifier.set("javadoc")
|
||||
from(dokkaOutputDir)
|
||||
}
|
||||
|
||||
fun org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension.native(
|
||||
configure: org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithHostTests.() -> Unit = {}
|
||||
) {
|
||||
when {
|
||||
org.jetbrains.kotlin.konan.target.HostManager.hostIsMingw -> mingwX64("native")
|
||||
org.jetbrains.kotlin.konan.target.HostManager.hostIsLinux -> linuxX64("native")
|
||||
org.jetbrains.kotlin.konan.target.HostManager.hostIsMac -> if (org.jetbrains.kotlin.konan.target.HostManager.hostArch() == "arm64") {
|
||||
macosArm64("native")
|
||||
} else {
|
||||
macosX64("native")
|
||||
}
|
||||
|
||||
else -> error("Unsupported Host OS: ${org.jetbrains.kotlin.konan.target.HostManager.hostOs()}")
|
||||
}.apply(configure)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
compilations.all {
|
||||
kotlinOptions.jvmTarget = JvmTarget.JVM_11.description
|
||||
}
|
||||
testRuns["test"].executionTask.configure {
|
||||
useJUnitPlatform()
|
||||
environment("MODEL", "VOSK_MODEL")
|
||||
//environment("MODEL", "/home/doomsdayrs/Downloads/vosk-model-small-en-us-0.15/")
|
||||
environment("LIBRARY", "VOSK_PATH")
|
||||
//environment("LIBRARY", "/usr/local/lib64/libvosk/libvosk.so")
|
||||
environment("AUDIO", "$projectDir/../python/example/test.wav")
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
publishAllLibraryVariants()
|
||||
}
|
||||
|
||||
/**
|
||||
* If native target should be enabled or not.
|
||||
*
|
||||
* Currently disabled as there is no proper packaging distribution currently.
|
||||
*/
|
||||
@Suppress("SimplifyBooleanWithConstants") // Ignore, the false is for overrides
|
||||
val enableNative = System.getenv("NATIVE_EXPERIMENT") == "true" || false
|
||||
|
||||
if (enableNative)
|
||||
native {
|
||||
val main by compilations.getting
|
||||
val libvosk by main.cinterops.creating
|
||||
|
||||
binaries {
|
||||
sharedLib()
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
withType<MavenPublication> {
|
||||
artifact(javadocJar)
|
||||
pom {
|
||||
url.set("http://www.alphacephei.com.com/vosk/")
|
||||
licenses {
|
||||
license {
|
||||
name.set("The Apache License, Version 2.0")
|
||||
url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id.set("com.alphacephei")
|
||||
name.set("Alpha Cephei Inc")
|
||||
email.set("contact@alphacephei.com")
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection.set("scm:git:git://github.com/alphacep/vosk-api.git")
|
||||
url.set("https://github.com/alphacep/vosk-api/")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val jna_version = "5.13.0"
|
||||
val coroutines_version = "1.6.4"
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1")
|
||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
|
||||
}
|
||||
}
|
||||
val commonTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version")
|
||||
}
|
||||
}
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
api("net.java.dev.jna:jna:$jna_version")
|
||||
}
|
||||
}
|
||||
val jvmTest by getting
|
||||
if (enableNative) {
|
||||
val nativeMain by getting
|
||||
}
|
||||
val androidMain by getting {
|
||||
dependsOn(jvmMain)
|
||||
dependencies {
|
||||
api("net.java.dev.jna:jna:$jna_version@aar")
|
||||
}
|
||||
}
|
||||
val androidTest by getting {
|
||||
dependencies {
|
||||
implementation("junit:junit:4.13.2")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = 33
|
||||
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
targetSdk = 33
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
publishing {
|
||||
multipleVariants {
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
allVariants()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2020 Alpha Cephei Inc. & Doomsdayrs
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
google()
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
}
|
||||
resolutionStrategy {
|
||||
eachPlugin {
|
||||
if (requested.id.namespace == "com.android") {
|
||||
useModule("com.android.tools.build:gradle:7.3.0")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rootProject.name = "vosk-api-kotlin"
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.alphacephei.library">
|
||||
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
</manifest>
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.vosk.android
|
||||
|
||||
/**
|
||||
* Interface to receive recognition results
|
||||
*/
|
||||
interface RecognitionListener {
|
||||
/**
|
||||
* Called when partial recognition result is available.
|
||||
*/
|
||||
fun onPartialResult(hypothesis: String)
|
||||
|
||||
/**
|
||||
* Called after silence occured.
|
||||
*/
|
||||
fun onResult(hypothesis: String)
|
||||
|
||||
/**
|
||||
* Called after stream end.
|
||||
*/
|
||||
fun onFinalResult(hypothesis: String)
|
||||
|
||||
/**
|
||||
* Called when an error occurs.
|
||||
*/
|
||||
fun onError(exception: Exception)
|
||||
|
||||
/**
|
||||
* Called after timeout expired
|
||||
*/
|
||||
fun onTimeout()
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.vosk.android
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.media.AudioFormat
|
||||
import android.media.AudioRecord
|
||||
import android.media.MediaRecorder.AudioSource
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import org.vosk.Recognizer
|
||||
import java.io.IOException
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* Service that records audio in a thread, passes it to a recognizer and emits
|
||||
* recognition results. Recognition events are passed to a client using
|
||||
* [RecognitionListener]
|
||||
*/
|
||||
class SpeechService @Throws(IOException::class) constructor(
|
||||
private val recognizer: Recognizer,
|
||||
sampleRate: Float
|
||||
) {
|
||||
private val sampleRate: Int
|
||||
private val bufferSize: Int
|
||||
private val recorder: AudioRecord
|
||||
private var recognizerThread: RecognizerThread? = null
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
/**
|
||||
* Creates speech service. Service holds the AudioRecord object, so you
|
||||
* need to call [.shutdown] in order to properly finalize it.
|
||||
*
|
||||
* @throws IOException thrown if audio recorder can not be created for some reason.
|
||||
*/
|
||||
init {
|
||||
this.sampleRate = sampleRate.toInt()
|
||||
bufferSize = (this.sampleRate * BUFFER_SIZE_SECONDS).roundToInt()
|
||||
@SuppressLint("MissingPermission")
|
||||
recorder = AudioRecord(
|
||||
AudioSource.VOICE_RECOGNITION, this.sampleRate,
|
||||
AudioFormat.CHANNEL_IN_MONO,
|
||||
AudioFormat.ENCODING_PCM_16BIT, bufferSize * 2
|
||||
)
|
||||
if (recorder.state == AudioRecord.STATE_UNINITIALIZED) {
|
||||
recorder.release()
|
||||
throw IOException(
|
||||
"Failed to initialize recorder. Microphone might be already in use."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts recognition. Does nothing if recognition is active.
|
||||
*
|
||||
* @return true if recognition was actually started
|
||||
*/
|
||||
fun startListening(listener: RecognitionListener): Boolean {
|
||||
if (null != recognizerThread) return false
|
||||
recognizerThread = RecognizerThread(listener)
|
||||
recognizerThread!!.start()
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts recognition. After specified timeout listening stops and the
|
||||
* endOfSpeech signals about that. Does nothing if recognition is active.
|
||||
*
|
||||
*
|
||||
* timeout - timeout in milliseconds to listen.
|
||||
*
|
||||
* @return true if recognition was actually started
|
||||
*/
|
||||
fun startListening(listener: RecognitionListener, timeout: Int): Boolean {
|
||||
if (null != recognizerThread) return false
|
||||
recognizerThread = RecognizerThread(listener, timeout)
|
||||
recognizerThread!!.start()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun stopRecognizerThread(): Boolean {
|
||||
if (null == recognizerThread) return false
|
||||
try {
|
||||
recognizerThread!!.interrupt()
|
||||
recognizerThread!!.join()
|
||||
} catch (e: InterruptedException) {
|
||||
// Restore the interrupted status.
|
||||
Thread.currentThread().interrupt()
|
||||
}
|
||||
recognizerThread = null
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops recognition. Listener should receive final result if there is
|
||||
* any. Does nothing if recognition is not active.
|
||||
*
|
||||
* @return true if recognition was actually stopped
|
||||
*/
|
||||
fun stop(): Boolean {
|
||||
return stopRecognizerThread()
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel recognition. Do not post any new events, simply cancel processing.
|
||||
* Does nothing if recognition is not active.
|
||||
*
|
||||
* @return true if recognition was actually stopped
|
||||
*/
|
||||
fun cancel(): Boolean {
|
||||
if (recognizerThread != null) {
|
||||
recognizerThread!!.setPause(true)
|
||||
}
|
||||
return stopRecognizerThread()
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the recognizer and release the recorder
|
||||
*/
|
||||
fun shutdown() {
|
||||
recorder.release()
|
||||
}
|
||||
|
||||
fun setPause(paused: Boolean) {
|
||||
if (recognizerThread != null) {
|
||||
recognizerThread!!.setPause(paused)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets recognizer in a thread, starts recognition over again
|
||||
*/
|
||||
fun reset() {
|
||||
if (recognizerThread != null) {
|
||||
recognizerThread!!.reset()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class RecognizerThread @JvmOverloads constructor(
|
||||
var listener: RecognitionListener,
|
||||
timeout: Int = Companion.NO_TIMEOUT
|
||||
) : Thread() {
|
||||
private var remainingSamples: Int
|
||||
private val timeoutSamples: Int
|
||||
|
||||
@Volatile
|
||||
private var paused = false
|
||||
|
||||
@Volatile
|
||||
private var reset = false
|
||||
|
||||
init {
|
||||
timeoutSamples = if (timeout != Companion.NO_TIMEOUT) {
|
||||
timeout * sampleRate / 1000
|
||||
} else {
|
||||
Companion.NO_TIMEOUT
|
||||
}
|
||||
remainingSamples = timeoutSamples
|
||||
}
|
||||
|
||||
/**
|
||||
* When we are paused, don't process audio by the recognizer and don't emit
|
||||
* any listener results
|
||||
*
|
||||
* @param paused the status of pause
|
||||
*/
|
||||
fun setPause(paused: Boolean) {
|
||||
this.paused = paused
|
||||
}
|
||||
|
||||
/**
|
||||
* Set reset state to signal reset of the recognizer and start over
|
||||
*/
|
||||
fun reset() {
|
||||
reset = true
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
recorder.startRecording()
|
||||
if (recorder.recordingState == AudioRecord.RECORDSTATE_STOPPED) {
|
||||
recorder.stop()
|
||||
val ioe = IOException(
|
||||
"Failed to start recording. Microphone might be already in use."
|
||||
)
|
||||
mainHandler.post { listener.onError(ioe) }
|
||||
}
|
||||
val buffer = ShortArray(bufferSize)
|
||||
while (!interrupted()
|
||||
&& (timeoutSamples == Companion.NO_TIMEOUT || remainingSamples > 0)
|
||||
) {
|
||||
val nread = recorder.read(buffer, 0, buffer.size)
|
||||
if (paused) {
|
||||
continue
|
||||
}
|
||||
if (reset) {
|
||||
recognizer.reset()
|
||||
reset = false
|
||||
}
|
||||
if (nread < 0) throw RuntimeException("error reading audio buffer")
|
||||
if (recognizer.acceptWaveform(buffer)) {
|
||||
val result = recognizer.result
|
||||
mainHandler.post { listener.onResult(result) }
|
||||
} else {
|
||||
val partialResult = recognizer.partialResult
|
||||
mainHandler.post { listener.onPartialResult(partialResult) }
|
||||
}
|
||||
if (timeoutSamples != NO_TIMEOUT) {
|
||||
remainingSamples -= nread
|
||||
}
|
||||
}
|
||||
recorder.stop()
|
||||
if (!paused) {
|
||||
// If we met timeout signal that speech ended
|
||||
if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) {
|
||||
mainHandler.post { listener.onTimeout() }
|
||||
} else {
|
||||
val finalResult = recognizer.finalResult
|
||||
mainHandler.post { listener.onFinalResult(finalResult) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val NO_TIMEOUT = -1
|
||||
private const val BUFFER_SIZE_SECONDS = 0.2f
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.vosk.android
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import org.vosk.Recognizer
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* Service that recognizes stream audio in a thread, passes it to a recognizer and emits
|
||||
* recognition results. Recognition events are passed to a client using
|
||||
* [RecognitionListener]
|
||||
*/
|
||||
class SpeechStreamService(
|
||||
private val recognizer: Recognizer,
|
||||
inputStream: InputStream,
|
||||
sampleRate: Float
|
||||
) {
|
||||
private val inputStream: InputStream
|
||||
private val sampleRate: Int
|
||||
private val bufferSize: Int
|
||||
private var recognizerThread: Thread? = null
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
/**
|
||||
* Creates speech service.
|
||||
*/
|
||||
init {
|
||||
this.sampleRate = sampleRate.toInt()
|
||||
this.inputStream = inputStream
|
||||
bufferSize = (this.sampleRate * BUFFER_SIZE_SECONDS * 2).roundToInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts recognition. Does nothing if recognition is active.
|
||||
*
|
||||
* @return true if recognition was actually started
|
||||
*/
|
||||
fun start(listener: RecognitionListener): Boolean {
|
||||
if (null != recognizerThread) return false
|
||||
recognizerThread = RecognizerThread(listener)
|
||||
recognizerThread!!.start()
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts recognition. After specified timeout listening stops and the
|
||||
* endOfSpeech signals about that. Does nothing if recognition is active.
|
||||
*
|
||||
*
|
||||
* timeout - timeout in milliseconds to listen.
|
||||
*
|
||||
* @return true if recognition was actually started
|
||||
*/
|
||||
fun start(listener: RecognitionListener, timeout: Int): Boolean {
|
||||
if (null != recognizerThread) return false
|
||||
recognizerThread = RecognizerThread(listener, timeout)
|
||||
recognizerThread!!.start()
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops recognition. All listeners should receive final result if there is
|
||||
* any. Does nothing if recognition is not active.
|
||||
*
|
||||
* @return true if recognition was actually stopped
|
||||
*/
|
||||
fun stop(): Boolean {
|
||||
if (null == recognizerThread) return false
|
||||
try {
|
||||
recognizerThread!!.interrupt()
|
||||
recognizerThread!!.join()
|
||||
} catch (e: InterruptedException) {
|
||||
// Restore the interrupted status.
|
||||
Thread.currentThread().interrupt()
|
||||
}
|
||||
recognizerThread = null
|
||||
return true
|
||||
}
|
||||
|
||||
private inner class RecognizerThread @JvmOverloads constructor(
|
||||
var listener: RecognitionListener,
|
||||
timeout: Int = Companion.NO_TIMEOUT
|
||||
) : Thread() {
|
||||
private var remainingSamples: Int
|
||||
private val timeoutSamples: Int
|
||||
|
||||
init {
|
||||
if (timeout != Companion.NO_TIMEOUT) timeoutSamples =
|
||||
timeout * sampleRate / 1000 else timeoutSamples = Companion.NO_TIMEOUT
|
||||
remainingSamples = timeoutSamples
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
val buffer = ByteArray(bufferSize)
|
||||
while (!interrupted()
|
||||
&& (timeoutSamples == Companion.NO_TIMEOUT || remainingSamples > 0)
|
||||
) {
|
||||
try {
|
||||
val nread = inputStream.read(buffer, 0, buffer.size)
|
||||
if (nread < 0) {
|
||||
break
|
||||
} else {
|
||||
val isSilence: Boolean = recognizer.acceptWaveform(buffer)
|
||||
if (isSilence) {
|
||||
val result = recognizer.result
|
||||
mainHandler.post { listener.onResult(result) }
|
||||
} else {
|
||||
val partialResult = recognizer.partialResult
|
||||
mainHandler.post { listener.onPartialResult(partialResult) }
|
||||
}
|
||||
}
|
||||
if (timeoutSamples != NO_TIMEOUT) {
|
||||
remainingSamples -= nread
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
mainHandler.post { listener.onError(e) }
|
||||
}
|
||||
}
|
||||
|
||||
// If we met timeout signal that speech ended
|
||||
if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) {
|
||||
mainHandler.post { listener.onTimeout() }
|
||||
} else {
|
||||
val finalResult = recognizer.finalResult
|
||||
mainHandler.post { listener.onFinalResult(finalResult) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val NO_TIMEOUT = -1
|
||||
private const val BUFFER_SIZE_SECONDS = 0.2f
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.vosk.android
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.AssetManager
|
||||
import android.os.Environment
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import org.vosk.Model
|
||||
import java.io.*
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.function.Consumer
|
||||
|
||||
/**
|
||||
* Provides utility methods to sync model files to external storage to allow
|
||||
* C++ code access them. Relies on file named "uuid" to track updates.
|
||||
*/
|
||||
object StorageService {
|
||||
private val TAG = StorageService::class.simpleName
|
||||
|
||||
@JvmStatic
|
||||
fun unpack(
|
||||
context: Context,
|
||||
sourcePath: String,
|
||||
targetPath: String,
|
||||
completeCallback: Consumer<Model>,
|
||||
errorCallback: Consumer<IOException>
|
||||
) {
|
||||
val executor: Executor =
|
||||
Executors.newSingleThreadExecutor() // change according to your requirements
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
executor.execute {
|
||||
try {
|
||||
val outputPath = sync(context, sourcePath, targetPath)
|
||||
val model = Model(outputPath)
|
||||
handler.post { completeCallback.accept(model) }
|
||||
} catch (e: IOException) {
|
||||
handler.post { errorCallback.accept(e) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun sync(context: Context, sourcePath: String, targetPath: String): String {
|
||||
val assetManager = context.assets
|
||||
val externalFilesDir = context.getExternalFilesDir(null)
|
||||
?: throw IOException(
|
||||
"cannot get external files dir, "
|
||||
+ "external storage state is " + Environment.getExternalStorageState()
|
||||
)
|
||||
val targetDir = File(externalFilesDir, targetPath)
|
||||
val resultPath = File(targetDir, sourcePath).absolutePath
|
||||
val sourceUUID = readLine(assetManager.open("$sourcePath/uuid"))
|
||||
try {
|
||||
val targetUUID = readLine(FileInputStream(File(targetDir, "$sourcePath/uuid")))
|
||||
if (targetUUID == sourceUUID) return resultPath
|
||||
} catch (e: FileNotFoundException) {
|
||||
// ignore
|
||||
}
|
||||
deleteContents(targetDir)
|
||||
copyAssets(assetManager, sourcePath, targetDir)
|
||||
|
||||
// Copy uuid
|
||||
copyFile(assetManager, "$sourcePath/uuid", targetDir)
|
||||
return resultPath
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun readLine(inputStream: InputStream): String {
|
||||
return BufferedReader(InputStreamReader(inputStream)).use { it.readLine() }
|
||||
}
|
||||
|
||||
private fun deleteContents(dir: File): Boolean {
|
||||
val files = dir.listFiles()
|
||||
var success = true
|
||||
if (files != null) {
|
||||
for (file in files) {
|
||||
if (file.isDirectory) {
|
||||
success = success and deleteContents(file)
|
||||
}
|
||||
if (!file.delete()) {
|
||||
success = false
|
||||
}
|
||||
}
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun copyAssets(assetManager: AssetManager, path: String, outPath: File) {
|
||||
val assets = assetManager.list(path) ?: return
|
||||
if (assets.isEmpty()) {
|
||||
if (!path.endsWith("uuid")) copyFile(assetManager, path, outPath)
|
||||
} else {
|
||||
val dir = File(outPath, path)
|
||||
if (!dir.exists()) {
|
||||
Log.v(TAG, "Making directory " + dir.absolutePath)
|
||||
if (!dir.mkdirs()) {
|
||||
Log.v(TAG, "Failed to create directory " + dir.absolutePath)
|
||||
}
|
||||
}
|
||||
for (asset in assets) {
|
||||
copyAssets(assetManager, "$path/$asset", outPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun copyFile(assetManager: AssetManager, fileName: String, outPath: File) {
|
||||
Log.v(TAG, "Copy $fileName to $outPath")
|
||||
assetManager.open(fileName).use { inputStream ->
|
||||
FileOutputStream("$outPath/$fileName").use { out ->
|
||||
val buffer = ByteArray(4000)
|
||||
var read: Int
|
||||
while (inputStream.read(buffer).also { read = it } != -1) {
|
||||
out.write(buffer, 0, read)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
/**
|
||||
* Thrown when a [Recognizer] cannot accept a given waveform
|
||||
*/
|
||||
class AcceptWaveformException(data: Any) : Exception("Could not accept waveform: $data")
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import org.vosk.exception.ModelException
|
||||
|
||||
/**
|
||||
* Batch model object
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
* @constructor Creates the batch recognizer object
|
||||
*/
|
||||
expect class BatchModel @Throws(ModelException::class) constructor(path: String) : Freeable {
|
||||
|
||||
/**
|
||||
* Releases batch model object
|
||||
*/
|
||||
override fun free()
|
||||
|
||||
/**
|
||||
* Wait for the processing
|
||||
*/
|
||||
fun await()
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
/**
|
||||
* Batch recognizer object
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
* @constructor Creates batch recognizer object
|
||||
*/
|
||||
expect class BatchRecognizer constructor(model: BatchModel, sampleRate: Float) : Freeable {
|
||||
|
||||
/**
|
||||
* Releases batch recognizer object
|
||||
*/
|
||||
override fun free()
|
||||
|
||||
/**
|
||||
* Accept batch voice data
|
||||
*/
|
||||
fun acceptWaveform(data: ByteArray)
|
||||
|
||||
/**
|
||||
* Set NLSML output
|
||||
* @param nlsml - boolean value
|
||||
*/
|
||||
fun setNLSML(nlsml: Boolean)
|
||||
|
||||
/**
|
||||
* Closes the stream
|
||||
*/
|
||||
fun finishStream()
|
||||
|
||||
/**
|
||||
* Return results
|
||||
*/
|
||||
val frontResult: String
|
||||
|
||||
/**
|
||||
* Release and free first retrieved result
|
||||
*/
|
||||
fun pop()
|
||||
|
||||
/**
|
||||
* Get amount of pending chunks for more intelligent waiting
|
||||
*/
|
||||
val pendingChunks: Int
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
/**
|
||||
* Denotes an object that must be freed afterwards.
|
||||
*
|
||||
* On JVM, This is done via AutoClosable.
|
||||
*/
|
||||
@Suppress("SpellCheckingInspection")
|
||||
interface Freeable {
|
||||
|
||||
/**
|
||||
* Dereference the related object
|
||||
*/
|
||||
fun free()
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
/**
|
||||
* Log level for Kaldi messages.
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
*/
|
||||
enum class LogLevel(val value: Int) {
|
||||
|
||||
/**
|
||||
* Don't print info messages
|
||||
*/
|
||||
WARNINGS(-1),
|
||||
|
||||
/**
|
||||
* Default value to print info and error messages but no debug
|
||||
*/
|
||||
INFO(0),
|
||||
|
||||
/**
|
||||
* More verbose mode
|
||||
*/
|
||||
DEBUG(1);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import org.vosk.exception.IOException
|
||||
|
||||
|
||||
/**
|
||||
* Model stores all the data required for recognition
|
||||
*
|
||||
* It contains static data and can be shared across processing
|
||||
* threads.
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
* @constructor Loads model data from the file and returns the model object
|
||||
* @param path the path of the model on the filesystem
|
||||
* @throws IOException if the path provided is invalid
|
||||
*/
|
||||
expect class Model @Throws(IOException::class) constructor(path: String) : Freeable {
|
||||
|
||||
/**
|
||||
* Check if a word can be recognized by the model
|
||||
* @param word: the word
|
||||
* @returns the word symbol if @param word exists inside the model
|
||||
* or -1 otherwise.
|
||||
* Reminding that word symbol 0 is for <epsilon>
|
||||
*/
|
||||
fun findWord(word: String): Int
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
override fun free()
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import org.vosk.exception.RecognizerException
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
*/
|
||||
expect class Recognizer : Freeable {
|
||||
/**
|
||||
* Creates the recognizer object
|
||||
*
|
||||
* The recognizers process the speech and return text using shared model data
|
||||
* @param model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @throws RecognizerException if a problem occurred
|
||||
*/
|
||||
@Throws(RecognizerException::class)
|
||||
constructor(model: Model, sampleRate: Float)
|
||||
|
||||
/**
|
||||
* 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 model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @param speakerModel speaker model for speaker identification
|
||||
* @throws RecognizerException if a problem occurred
|
||||
*/
|
||||
@Throws(RecognizerException::class)
|
||||
constructor(model: Model, sampleRate: Float, speakerModel: SpeakerModel)
|
||||
|
||||
/**
|
||||
* 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 phrases 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 model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The valuesample rate of the audio you going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
|
||||
* for example "["one two three four five", "[unk]"]".
|
||||
*
|
||||
* @throws RecognizerException if a problem occurred
|
||||
*/
|
||||
@Throws(RecognizerException::class)
|
||||
constructor(model: Model, sampleRate: Float, grammar: String)
|
||||
|
||||
/**
|
||||
* Adds speaker model to already initialized recognizer
|
||||
*
|
||||
* Can add speaker recognition model to already created recognizer. Helps to initialize
|
||||
* speaker recognition for grammar-based recognizer.
|
||||
*
|
||||
* @param speakerModel Speaker recognition model
|
||||
*/
|
||||
fun setSpeakerModel(speakerModel: SpeakerModel)
|
||||
|
||||
|
||||
/**
|
||||
* Reconfigures recognizer to use grammar
|
||||
*
|
||||
* @param grammar Set of phrases in JSON array of strings or "[]" to use default model graph.
|
||||
* See also vosk_recognizer_new_grm
|
||||
*/
|
||||
fun setGrammar(grammar: String)
|
||||
|
||||
/**
|
||||
* Configures recognizer to output n-best results
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "alternatives": [
|
||||
* { "text": "one two three four five", "confidence": 0.97 },
|
||||
* { "text": "one two three for five", "confidence": 0.03 },
|
||||
* ]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param maxAlternatives - maximum alternatives to return from recognition results
|
||||
*/
|
||||
fun setMaxAlternatives(maxAlternatives: Int)
|
||||
|
||||
/**
|
||||
* Enables words with times in the output
|
||||
*
|
||||
* <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"
|
||||
* }],
|
||||
* </pre>
|
||||
*
|
||||
* @param words - boolean value
|
||||
*/
|
||||
fun setOutputWordTimes(words: Boolean)
|
||||
|
||||
/**
|
||||
* Like [setOutputWordTimes] return words and confidences in partial results
|
||||
*
|
||||
* @param partialWords - boolean value
|
||||
*/
|
||||
fun setPartialWords(partialWords: Boolean)
|
||||
|
||||
/**
|
||||
* Set NLSML output
|
||||
* @param nlsml - boolean value
|
||||
*/
|
||||
fun setNLSML(nlsml: Boolean)
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 1 - If silence is occurred and you can retrieve a new utterance with result method
|
||||
* 0 - If decoding continues
|
||||
* -1 - If exception occurred
|
||||
*/
|
||||
@Throws(AcceptWaveformException::class)
|
||||
fun acceptWaveform(data: ByteArray): Boolean
|
||||
|
||||
/**
|
||||
* Same as [acceptWaveform] but the version with the short data for language bindings where you have
|
||||
* audio as array of shorts
|
||||
*/
|
||||
@Throws(AcceptWaveformException::class)
|
||||
fun acceptWaveform(data: ShortArray): Boolean
|
||||
|
||||
/**
|
||||
* Same as [acceptWaveform] but the version with the float data for language bindings where you have
|
||||
* audio as array of floats
|
||||
*/
|
||||
@Throws(AcceptWaveformException::class)
|
||||
fun acceptWaveform(data: FloatArray): Boolean
|
||||
|
||||
/**
|
||||
* 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>
|
||||
* {
|
||||
* "text" : "what zero zero zero one"
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* If alternatives enabled it returns result with alternatives, see also [setMaxAlternatives].
|
||||
*
|
||||
* If word times enabled returns word time, see also [setOutputWordTimes].
|
||||
*/
|
||||
val result: String
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*/
|
||||
val finalResult: String
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
val partialResult: String
|
||||
|
||||
/**
|
||||
* Resets the recognizer
|
||||
*
|
||||
* Resets current results so the recognition can continue from scratch
|
||||
*/
|
||||
fun reset()
|
||||
|
||||
/**
|
||||
* Releases recognizer object
|
||||
*
|
||||
* Underlying model is also unreferenced and if needed released
|
||||
*/
|
||||
override fun free()
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import org.vosk.exception.ModelException
|
||||
|
||||
/**
|
||||
* Speaker model is the same as model but contains the data
|
||||
* for speaker identification.
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
* @constructor Loads speaker model data from the file and returns the model object
|
||||
* @param path the path of the model on the filesystem
|
||||
* @throws ModelException if the path provided is invalid
|
||||
*/
|
||||
expect class SpeakerModel @Throws(ModelException::class) constructor(path: String) : Freeable {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
override fun free()
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
/**
|
||||
* 26 / 12 / 2022
|
||||
*
|
||||
* Control overarching features of libvosk.
|
||||
*/
|
||||
expect object Vosk {
|
||||
/**
|
||||
* Set log level for Kaldi messages
|
||||
*
|
||||
* @param logLevel the level
|
||||
*/
|
||||
fun setLogLevel(logLevel: LogLevel)
|
||||
|
||||
/**
|
||||
* Init, automatically select a CUDA device and allow multithreading.
|
||||
* Must be called once from the main thread.
|
||||
* Has no effect if HAVE_CUDA flag is not set.
|
||||
*/
|
||||
fun gpuInit()
|
||||
|
||||
|
||||
/**
|
||||
* Init CUDA device in a multi-threaded environment.
|
||||
* Must be called for each thread.
|
||||
* Has no effect if HAVE_CUDA flag is not set.
|
||||
*/
|
||||
fun gpuThreadInit()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk.exception
|
||||
|
||||
/**
|
||||
* Internal common IO exception. On JVM this is just a type alias.
|
||||
*/
|
||||
expect open class IOException(message: String? = null) : Exception
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk.exception
|
||||
|
||||
/**
|
||||
* Thrown when there is an exception creating a model.
|
||||
*/
|
||||
class ModelException(path: String): IOException("Failed to find model: $path")
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk.exception
|
||||
|
||||
/**
|
||||
* Thrown when the recognizer fails to be created
|
||||
*/
|
||||
class RecognizerException: IOException("Failed to create recognizer.")
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk.json
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Represents an alternative result.
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
*/
|
||||
@Serializable
|
||||
data class Alternative(
|
||||
val confidence: Double,
|
||||
val result: List<Result> = emptyList(),
|
||||
val text: String
|
||||
)
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk.json
|
||||
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.encodeToJsonElement
|
||||
import org.vosk.Recognizer
|
||||
import org.vosk.Model
|
||||
import org.vosk.exception.RecognizerException
|
||||
|
||||
/*
|
||||
* 26 / 12 / 2022
|
||||
*/
|
||||
|
||||
/**
|
||||
* Vosk JSON encoder
|
||||
*/
|
||||
val voskJson = Json { encodeDefaults = true }
|
||||
|
||||
/**
|
||||
* Get the result as a JSON object
|
||||
*/
|
||||
fun Recognizer.resultAsJson(): ResultOutput =
|
||||
voskJson.decodeFromString(result)
|
||||
|
||||
/**
|
||||
* Get the final result as a JSON object
|
||||
*/
|
||||
fun Recognizer.finalResultAsJson(): ResultOutput =
|
||||
voskJson.decodeFromString(finalResult)
|
||||
|
||||
/**
|
||||
* Get the partial result as a JSON object
|
||||
*/
|
||||
fun Recognizer.partialResultAsJson(): PartialResultOutput =
|
||||
voskJson.decodeFromString(partialResult)
|
||||
|
||||
|
||||
/**
|
||||
* Create a [Recognizer], but using a list for grammar instead.
|
||||
*
|
||||
* The grammar list is converted into a JSON array
|
||||
*/
|
||||
@Throws(RecognizerException::class)
|
||||
fun Recognizer(model: Model, sampleRate: Float, grammar: List<String>) =
|
||||
Recognizer(model, sampleRate, voskJson.encodeToJsonElement(grammar).toString())
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk.json
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Represents a partial result
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
*/
|
||||
@Serializable
|
||||
data class PartialResultOutput(
|
||||
val partial: String,
|
||||
@SerialName("partial_result")
|
||||
val partialResult: List<Result> = emptyList(),
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk.json
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Represents a result for any given word.
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
*/
|
||||
@Serializable
|
||||
data class Result(
|
||||
val conf: Double? = null,
|
||||
val end: Double,
|
||||
val start: Double,
|
||||
val word: String,
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk.json
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Result output
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
*/
|
||||
@Serializable
|
||||
data class ResultOutput(
|
||||
val alternatives: List<Alternative> = emptyList(),
|
||||
val result: List<Result> = emptyList(),
|
||||
val text: String? = null
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk.json
|
||||
|
||||
/**
|
||||
* For extension functions transforming (input streams->recognizers) into flows.
|
||||
*/
|
||||
sealed interface WaveformResult {
|
||||
|
||||
/**
|
||||
* A result made after a period of silence.
|
||||
*/
|
||||
data class Result(val result: ResultOutput) : WaveformResult
|
||||
|
||||
/**
|
||||
* A partial result that is being made in progress.
|
||||
*/
|
||||
data class PartialResult(val result: PartialResultOutput) : WaveformResult
|
||||
|
||||
/**
|
||||
* A final result made after there is no more content to feed.
|
||||
*/
|
||||
data class FinalResult(val result: ResultOutput) : WaveformResult
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import com.sun.jna.PointerType
|
||||
import org.vosk.exception.ModelException
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.absolutePathString
|
||||
|
||||
|
||||
/**
|
||||
* Batch model object
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
*/
|
||||
actual class BatchModel : Freeable, PointerType, AutoCloseable {
|
||||
|
||||
/**
|
||||
* Empty constructor for JNA
|
||||
*/
|
||||
constructor()
|
||||
|
||||
/**
|
||||
* Creates the batch recognizer object
|
||||
*/
|
||||
@Throws(ModelException::class)
|
||||
actual constructor(path: String) : super(
|
||||
LibVosk.vosk_batch_model_new(path) ?: throw ModelException(path)
|
||||
)
|
||||
|
||||
/**
|
||||
* Constructor using a Path, will retrieve absolutePath
|
||||
*
|
||||
* @param path to batch model
|
||||
*/
|
||||
@Throws(ModelException::class)
|
||||
constructor(path: Path) : this(path.absolutePathString())
|
||||
|
||||
/**
|
||||
* Constructor using a File, will retrieve absolutePath
|
||||
*
|
||||
* @param file to batch model
|
||||
*/
|
||||
@Throws(ModelException::class)
|
||||
constructor(file: File) : this(file.absolutePath)
|
||||
|
||||
/**
|
||||
* Releases batch model object
|
||||
*/
|
||||
actual override fun free() {
|
||||
LibVosk.vosk_batch_model_free(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the processing
|
||||
*/
|
||||
actual fun await() {
|
||||
LibVosk.vosk_batch_model_wait(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see free
|
||||
*/
|
||||
override fun close() {
|
||||
free()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import com.sun.jna.PointerType
|
||||
|
||||
|
||||
/**
|
||||
* Batch recognizer object
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
* @constructor Creates batch recognizer object
|
||||
*/
|
||||
actual class BatchRecognizer : Freeable, PointerType, AutoCloseable {
|
||||
|
||||
/**
|
||||
* Empty constructor for JNA
|
||||
*/
|
||||
constructor()
|
||||
|
||||
/**
|
||||
* Creates batch recognizer object
|
||||
*/
|
||||
actual constructor(model: BatchModel, sampleRate: Float) :
|
||||
super(LibVosk.vosk_batch_recognizer_new(model, sampleRate))
|
||||
|
||||
/**
|
||||
* Releases batch recognizer object
|
||||
*/
|
||||
actual override fun free() {
|
||||
LibVosk.vosk_batch_recognizer_free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept batch voice data
|
||||
*/
|
||||
actual fun acceptWaveform(data: ByteArray) {
|
||||
LibVosk.vosk_batch_recognizer_accept_waveform(this, data, data.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set NLSML output
|
||||
* @param nlsml - boolean value
|
||||
*/
|
||||
actual fun setNLSML(nlsml: Boolean) {
|
||||
LibVosk.vosk_batch_recognizer_set_nlsml(this, nlsml)
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream
|
||||
*/
|
||||
actual fun finishStream() {
|
||||
LibVosk.vosk_batch_recognizer_finish_stream(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return results
|
||||
*/
|
||||
actual val frontResult: String
|
||||
get() = LibVosk.vosk_batch_recognizer_front_result(this)
|
||||
|
||||
/**
|
||||
* Release and free first retrieved result
|
||||
*/
|
||||
actual fun pop() {
|
||||
LibVosk.vosk_batch_recognizer_pop(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get amount of pending chunks for more intelligent waiting
|
||||
*/
|
||||
actual val pendingChunks: Int
|
||||
get() = LibVosk.vosk_batch_recognizer_get_pending_chunks(this)
|
||||
|
||||
/**
|
||||
* @see free
|
||||
*/
|
||||
override fun close() {
|
||||
free()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import com.sun.jna.Native
|
||||
import com.sun.jna.Platform
|
||||
import com.sun.jna.Pointer
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
/**
|
||||
* 26 / 12 / 2022
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
internal object LibVosk {
|
||||
|
||||
@JvmStatic
|
||||
@Deprecated(
|
||||
"LibVosk is now for internal JNA, use Vosk instead",
|
||||
ReplaceWith("Vosk.setLogLevel(logLevel)", "org.vosk.Vosk")
|
||||
)
|
||||
fun setLogLevel(logLevel: LogLevel) {
|
||||
Vosk.setLogLevel(logLevel)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun unpackDll(targetDir: File, lib: String) {
|
||||
val source: InputStream =
|
||||
Vosk::class.java.getResourceAsStream("/win32-x86-64/$lib.dll")!!
|
||||
|
||||
Files.copy(
|
||||
source,
|
||||
File(targetDir, "$lib.dll").toPath(),
|
||||
StandardCopyOption.REPLACE_EXISTING
|
||||
)
|
||||
}
|
||||
|
||||
init {
|
||||
when {
|
||||
Platform.isAndroid() -> {
|
||||
Native.register(LibVosk::class.java, "vosk")
|
||||
}
|
||||
Platform.isWindows() -> {
|
||||
// We have to unpack dependencies
|
||||
try {
|
||||
// To get a tmp folder we unpack small library and mark it for deletion
|
||||
val tmpFile: File = Native.extractFromResourcePath(
|
||||
"/win32-x86-64/empty",
|
||||
LibVosk::class.java.classLoader
|
||||
)
|
||||
val tmpDir = tmpFile.parentFile!!
|
||||
File(tmpDir, tmpFile.name + ".x").createNewFile()
|
||||
|
||||
// Now unpack dependencies
|
||||
unpackDll(tmpDir, "libwinpthread-1");
|
||||
unpackDll(tmpDir, "libgcc_s_seh-1");
|
||||
unpackDll(tmpDir, "libstdc++-6");
|
||||
|
||||
} catch (e: IOException) {
|
||||
// Nothing for now, it will fail on next step
|
||||
} finally {
|
||||
Native.register(LibVosk::class.java, "libvosk");
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
Native.register(LibVosk::class.java, "vosk");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
external fun vosk_model_new(path: String): Pointer?
|
||||
|
||||
external fun vosk_model_free(model: Model)
|
||||
|
||||
external fun vosk_model_find_word(model: Model, word: String): Int
|
||||
|
||||
|
||||
external fun vosk_spk_model_new(path: String): Pointer?
|
||||
|
||||
external fun vosk_spk_model_free(model: SpeakerModel)
|
||||
|
||||
|
||||
external fun vosk_recognizer_new(model: Model, sampleRate: Float): Pointer?
|
||||
|
||||
external fun vosk_recognizer_new_spk(
|
||||
model: Model,
|
||||
sampleRate: Float,
|
||||
spkModel: SpeakerModel
|
||||
): Pointer?
|
||||
|
||||
external fun vosk_recognizer_new_grm(
|
||||
model: Model,
|
||||
sampleRate: Float,
|
||||
grammar: String?
|
||||
): Pointer?
|
||||
|
||||
external fun vosk_recognizer_set_spk_model(recognizer: Recognizer, spk_model: SpeakerModel)
|
||||
|
||||
external fun vosk_recognizer_set_grm(recognizer: Recognizer, grammar: String)
|
||||
|
||||
external fun vosk_recognizer_set_max_alternatives(recognizer: Recognizer, maxAlternatives: Int)
|
||||
|
||||
external fun vosk_recognizer_set_words(recognizer: Recognizer, words: Boolean)
|
||||
|
||||
external fun vosk_recognizer_set_partial_words(recognizer: Recognizer, partial_words: Boolean)
|
||||
|
||||
external fun vosk_recognizer_set_nlsml(recognizer: Recognizer, nlsml: Boolean)
|
||||
|
||||
|
||||
external fun vosk_recognizer_accept_waveform(
|
||||
recognizer: Recognizer,
|
||||
data: ByteArray?,
|
||||
len: Int
|
||||
): Int
|
||||
|
||||
external fun vosk_recognizer_accept_waveform_s(
|
||||
recognizer: Recognizer,
|
||||
data: ShortArray?,
|
||||
len: Int
|
||||
): Int
|
||||
|
||||
external fun vosk_recognizer_accept_waveform_f(
|
||||
recognizer: Recognizer,
|
||||
data: FloatArray?,
|
||||
len: Int
|
||||
): Int
|
||||
|
||||
|
||||
external fun vosk_recognizer_result(recognizer: Recognizer): String
|
||||
|
||||
external fun vosk_recognizer_final_result(recognizer: Recognizer): String
|
||||
|
||||
external fun vosk_recognizer_partial_result(recognizer: Recognizer): String
|
||||
|
||||
|
||||
external fun vosk_recognizer_reset(recognizer: Recognizer)
|
||||
|
||||
external fun vosk_recognizer_free(recognizer: Recognizer)
|
||||
|
||||
external fun vosk_set_log_level(level: Int)
|
||||
|
||||
external fun vosk_gpu_init()
|
||||
|
||||
external fun vosk_gpu_thread_init()
|
||||
|
||||
|
||||
external fun vosk_batch_model_new(path: String): Pointer?
|
||||
|
||||
external fun vosk_batch_model_free(model: BatchModel)
|
||||
|
||||
external fun vosk_batch_model_wait(model: BatchModel)
|
||||
|
||||
external fun vosk_batch_recognizer_new(batchModel: BatchModel, sampleRate: Float): Pointer
|
||||
|
||||
external fun vosk_batch_recognizer_free(recognizer: BatchRecognizer)
|
||||
|
||||
external fun vosk_batch_recognizer_accept_waveform(
|
||||
recognizer: BatchRecognizer,
|
||||
data: ByteArray?,
|
||||
length: Int
|
||||
)
|
||||
|
||||
external fun vosk_batch_recognizer_set_nlsml(
|
||||
recognizer: BatchRecognizer,
|
||||
nlsml: Boolean
|
||||
)
|
||||
|
||||
external fun vosk_batch_recognizer_finish_stream(
|
||||
recognizer: BatchRecognizer
|
||||
)
|
||||
|
||||
external fun vosk_batch_recognizer_front_result(
|
||||
recognizer: BatchRecognizer
|
||||
): String
|
||||
|
||||
external fun vosk_batch_recognizer_pop(recognizer: BatchRecognizer)
|
||||
|
||||
external fun vosk_batch_recognizer_get_pending_chunks(recognizer: BatchRecognizer): Int
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import com.sun.jna.PointerType
|
||||
import org.vosk.exception.IOException
|
||||
import org.vosk.exception.ModelException
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.absolutePathString
|
||||
|
||||
|
||||
/**
|
||||
* Model stores all the data required for recognition
|
||||
*
|
||||
* It contains static data and can be shared across processing
|
||||
* threads.
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
* @constructor Loads model data from the file and returns the model object
|
||||
* @throws IOException if the path provided is invalid
|
||||
*/
|
||||
actual class Model : Freeable, PointerType, AutoCloseable {
|
||||
|
||||
/**
|
||||
* Empty constructor for JNA
|
||||
*/
|
||||
constructor()
|
||||
|
||||
/**
|
||||
* Loads model data from the file and returns the model object
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
actual constructor(path: String) : super(
|
||||
LibVosk.vosk_model_new(path) ?: throw ModelException(path)
|
||||
)
|
||||
|
||||
/**
|
||||
* Constructor using a Path, will retrieve absolutePath
|
||||
*
|
||||
* @param path to batch model
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
constructor(path: Path) : this(path.absolutePathString())
|
||||
|
||||
/**
|
||||
* Constructor using a File, will retrieve absolutePath
|
||||
*
|
||||
* @param file to batch model
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
constructor(file: File) : this(file.absolutePath)
|
||||
|
||||
/**
|
||||
* Check if a word can be recognized by the model
|
||||
* @param word: the word
|
||||
* @returns the word symbol if @param word exists inside the model
|
||||
* or -1 otherwise.
|
||||
* Reminding that word symbol 0 is for <epsilon>
|
||||
*/
|
||||
actual fun findWord(word: String): Int =
|
||||
LibVosk.vosk_model_find_word(this, word)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
actual override fun free() {
|
||||
LibVosk.vosk_model_free(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see free
|
||||
*/
|
||||
override fun close() {
|
||||
free()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import com.sun.jna.PointerType
|
||||
import org.vosk.exception.RecognizerException
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
*/
|
||||
actual class Recognizer : Freeable, PointerType, AutoCloseable {
|
||||
|
||||
/**
|
||||
* Empty constructor for JNA
|
||||
*/
|
||||
constructor()
|
||||
|
||||
/**
|
||||
* Creates the recognizer object
|
||||
*
|
||||
* The recognizers process the speech and return text using shared model data
|
||||
* @param model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @throws RecognizerException if a problem occurred
|
||||
*/
|
||||
@Throws(RecognizerException::class)
|
||||
actual constructor(model: Model, sampleRate: Float) :
|
||||
super(LibVosk.vosk_recognizer_new(model, sampleRate) ?: throw RecognizerException())
|
||||
|
||||
/**
|
||||
* 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 model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @param speakerModel speaker model for speaker identification
|
||||
* @throws RecognizerException if a problem occurred
|
||||
*/
|
||||
@Throws(RecognizerException::class)
|
||||
actual constructor(
|
||||
model: Model,
|
||||
sampleRate: Float,
|
||||
speakerModel: SpeakerModel
|
||||
) : super(
|
||||
LibVosk.vosk_recognizer_new_spk(model, sampleRate, speakerModel)
|
||||
?: throw RecognizerException()
|
||||
)
|
||||
|
||||
/**
|
||||
* 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 phrases 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 model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The valuesample rate of the audio you going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
|
||||
* for example "["one two three four five", "[unk]"]".
|
||||
*
|
||||
* @throws RecognizerException if a problem occurred
|
||||
*/
|
||||
@Throws(RecognizerException::class)
|
||||
actual constructor(
|
||||
model: Model,
|
||||
sampleRate: Float,
|
||||
grammar: String
|
||||
) : super(
|
||||
LibVosk.vosk_recognizer_new_grm(model, sampleRate, grammar) ?: throw RecognizerException()
|
||||
)
|
||||
|
||||
/**
|
||||
* JVM analog of Kotlin extension
|
||||
* @see [org.vosk.json.Recognizer]
|
||||
*/
|
||||
@Throws(RecognizerException::class)
|
||||
constructor(
|
||||
model: Model,
|
||||
sampleRate: Float,
|
||||
grammar: List<String>
|
||||
) : super(
|
||||
// We need the full qualifer to avoid any build issues
|
||||
@Suppress("RemoveRedundantQualifierName")
|
||||
org.vosk.json.Recognizer(model, sampleRate, grammar).pointer
|
||||
)
|
||||
|
||||
/**
|
||||
* Adds speaker model to already initialized recognizer
|
||||
*
|
||||
* Can add speaker recognition model to already created recognizer. Helps to initialize
|
||||
* speaker recognition for grammar-based recognizer.
|
||||
*
|
||||
* @param speakerModel Speaker recognition model
|
||||
*/
|
||||
actual fun setSpeakerModel(speakerModel: SpeakerModel) {
|
||||
LibVosk.vosk_recognizer_set_spk_model(this, speakerModel)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconfigures recognizer to use grammar
|
||||
*
|
||||
* @param grammar Set of phrases in JSON array of strings or "[]" to use default model graph.
|
||||
* See also vosk_recognizer_new_grm
|
||||
*/
|
||||
actual fun setGrammar(grammar: String) {
|
||||
LibVosk.vosk_recognizer_set_grm(this, grammar)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures recognizer to output n-best results
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "alternatives": [
|
||||
* { "text": "one two three four five", "confidence": 0.97 },
|
||||
* { "text": "one two three for five", "confidence": 0.03 },
|
||||
* ]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param maxAlternatives - maximum alternatives to return from recognition results
|
||||
*/
|
||||
actual fun setMaxAlternatives(maxAlternatives: Int) {
|
||||
LibVosk.vosk_recognizer_set_max_alternatives(this, maxAlternatives)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables words with times in the output
|
||||
*
|
||||
* <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"
|
||||
* }],
|
||||
* </pre>
|
||||
*
|
||||
* @param words - boolean value
|
||||
*/
|
||||
actual fun setOutputWordTimes(words: Boolean) {
|
||||
LibVosk.vosk_recognizer_set_words(this, words)
|
||||
}
|
||||
|
||||
/**
|
||||
* Like [setOutputWordTimes] return words and confidences in partial results
|
||||
*
|
||||
* @param partialWords - boolean value
|
||||
*/
|
||||
actual fun setPartialWords(partialWords: Boolean) {
|
||||
LibVosk.vosk_recognizer_set_partial_words(this, partialWords)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set NLSML output
|
||||
* @param nlsml - boolean value
|
||||
*/
|
||||
actual fun setNLSML(nlsml: Boolean) {
|
||||
LibVosk.vosk_recognizer_set_nlsml(this, nlsml)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 1 - If silence is occurred and you can retrieve a new utterance with result method
|
||||
* 0 - If decoding continues
|
||||
* -1 - If exception occurred
|
||||
*/
|
||||
@Throws(AcceptWaveformException::class)
|
||||
actual fun acceptWaveform(data: ByteArray): Boolean {
|
||||
val result = LibVosk.vosk_recognizer_accept_waveform(this, data, data.size)
|
||||
if (result == -1) throw AcceptWaveformException(data)
|
||||
return result == 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as [acceptWaveform] but the version with the short data for language bindings where you have
|
||||
* audio as array of shorts
|
||||
*/
|
||||
@Throws(AcceptWaveformException::class)
|
||||
actual fun acceptWaveform(data: ShortArray): Boolean {
|
||||
val result = LibVosk.vosk_recognizer_accept_waveform_s(this, data, data.size)
|
||||
if (result == -1) throw AcceptWaveformException(data)
|
||||
return result == 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as [acceptWaveform] but the version with the float data for language bindings where you have
|
||||
* audio as array of floats
|
||||
*/
|
||||
@Throws(AcceptWaveformException::class)
|
||||
actual fun acceptWaveform(data: FloatArray): Boolean {
|
||||
val result = LibVosk.vosk_recognizer_accept_waveform_f(this, data, data.size)
|
||||
if (result == -1) throw AcceptWaveformException(data)
|
||||
return result == 1
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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>
|
||||
* {
|
||||
* "text" : "what zero zero zero one"
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* If alternatives enabled it returns result with alternatives, see also [setMaxAlternatives].
|
||||
*
|
||||
* If word times enabled returns word time, see also [setOutputWordTimes].
|
||||
*/
|
||||
actual val result: String
|
||||
get() = LibVosk.vosk_recognizer_result(this)
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*/
|
||||
actual val finalResult: String
|
||||
get() = LibVosk.vosk_recognizer_final_result(this)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
actual val partialResult: String
|
||||
get() = LibVosk.vosk_recognizer_partial_result(this)
|
||||
|
||||
/**
|
||||
* Resets the recognizer
|
||||
*
|
||||
* Resets current results so the recognition can continue from scratch
|
||||
*/
|
||||
actual fun reset() {
|
||||
LibVosk.vosk_recognizer_reset(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases recognizer object
|
||||
*
|
||||
* Underlying model is also unreferenced and if needed released
|
||||
*/
|
||||
actual override fun free() {
|
||||
LibVosk.vosk_recognizer_free(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see free
|
||||
*/
|
||||
override fun close() {
|
||||
free()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import com.sun.jna.PointerType
|
||||
import org.vosk.exception.ModelException
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.absolutePathString
|
||||
|
||||
/**
|
||||
* Speaker model is the same as model but contains the data
|
||||
* for speaker identification.
|
||||
*
|
||||
* @since 26 / 12 / 2022
|
||||
* @constructor Loads speaker model data from the file and returns the model object
|
||||
* @throws ModelException if the path provided is invalid
|
||||
*/
|
||||
actual class SpeakerModel : Freeable, PointerType, AutoCloseable {
|
||||
|
||||
/**
|
||||
* Empty constructor for JNA
|
||||
*/
|
||||
constructor()
|
||||
|
||||
/**
|
||||
* Loads speaker model data from the file and returns the model object
|
||||
*
|
||||
* @param path the path of the model on the filesystem
|
||||
*/
|
||||
@Throws(ModelException::class)
|
||||
actual constructor(path: String) : super(
|
||||
LibVosk.vosk_spk_model_new(path) ?: throw ModelException(path)
|
||||
)
|
||||
|
||||
/**
|
||||
* Constructor using a Path, will retrieve absolutePath
|
||||
*
|
||||
* @param path to batch model
|
||||
*/
|
||||
@Throws(ModelException::class)
|
||||
constructor(path: Path) : this(path.absolutePathString())
|
||||
|
||||
/**
|
||||
* Constructor using a File, will retrieve absolutePath
|
||||
*
|
||||
* @param file to batch model
|
||||
*/
|
||||
@Throws(ModelException::class)
|
||||
constructor(file: File) : this(file.absolutePath)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
actual override fun free() {
|
||||
LibVosk.vosk_spk_model_free(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see free
|
||||
*/
|
||||
override fun close() {
|
||||
free()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
|
||||
/**
|
||||
* 26 / 12 / 2022
|
||||
*
|
||||
* Control overarching features of libvosk.
|
||||
*/
|
||||
actual object Vosk {
|
||||
/**
|
||||
* Set log level for Kaldi messages
|
||||
*
|
||||
* @param logLevel the level
|
||||
*/
|
||||
@JvmStatic
|
||||
actual fun setLogLevel(logLevel: LogLevel) {
|
||||
LibVosk.vosk_set_log_level(logLevel.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Init, automatically select a CUDA device and allow multithreading.
|
||||
* Must be called once from the main thread.
|
||||
* Has no effect if HAVE_CUDA flag is not set.
|
||||
*/
|
||||
@JvmStatic
|
||||
actual fun gpuInit() {
|
||||
LibVosk.vosk_gpu_init()
|
||||
}
|
||||
|
||||
/**
|
||||
* Init CUDA device in a multi-threaded environment.
|
||||
* Must be called for each thread.
|
||||
* Has no effect if HAVE_CUDA flag is not set.
|
||||
*/
|
||||
@JvmStatic
|
||||
actual fun gpuThreadInit() {
|
||||
LibVosk.vosk_gpu_thread_init()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.vosk.json.WaveformResult
|
||||
import org.vosk.json.finalResultAsJson
|
||||
import org.vosk.json.partialResultAsJson
|
||||
import org.vosk.json.resultAsJson
|
||||
|
||||
/**
|
||||
* Feed an [Flow] of [ByteArray] into a [Recognizer].
|
||||
*
|
||||
* The returned flow will emit an [WaveformResult] for each result parsed.
|
||||
*
|
||||
* This expects a null terminator to signify the end of a stream.
|
||||
*
|
||||
* This will not close the [recognizer] at the end of reading.
|
||||
*
|
||||
* Any exceptions will be fed into the flow,
|
||||
* and should be collected via [kotlinx.coroutines.flow.catch].
|
||||
*
|
||||
* Flows on [Dispatchers.IO] to prevent blocking the main thread.
|
||||
*
|
||||
* @see [Recognizer.acceptWaveform]
|
||||
*/
|
||||
fun Flow<ByteArray?>.feed(recognizer: Recognizer): Flow<WaveformResult> =
|
||||
map {
|
||||
if (it != null) {
|
||||
if (recognizer.acceptWaveform(it)) {
|
||||
WaveformResult.Result(recognizer.resultAsJson())
|
||||
} else {
|
||||
WaveformResult.PartialResult(recognizer.partialResultAsJson())
|
||||
}
|
||||
} else {
|
||||
WaveformResult.FinalResult(recognizer.finalResultAsJson())
|
||||
}
|
||||
}.flowOn(Dispatchers.IO)
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk.exception
|
||||
|
||||
/**
|
||||
* Analog of [java.io.IOException]
|
||||
*/
|
||||
actual typealias IOException = java.io.IOException
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright 2023 Alpha Cephei Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.vosk.*
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.FileInputStream
|
||||
import java.io.IOException
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import javax.sound.sampled.AudioSystem
|
||||
import javax.sound.sampled.UnsupportedAudioFileException
|
||||
import kotlin.test.Test
|
||||
|
||||
class DecoderTest {
|
||||
val modelPath = System.getenv("MODEL")
|
||||
val testFile = System.getenv("AUDIO")
|
||||
|
||||
init {
|
||||
System.load(System.getenv("LIBRARY"))
|
||||
Vosk.setLogLevel(LogLevel.DEBUG)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun grammarList() {
|
||||
Model(modelPath).use { model ->
|
||||
Recognizer(model, 16000f, listOf("one")).apply {
|
||||
setMaxAlternatives(10)
|
||||
setOutputWordTimes(true)
|
||||
setPartialWords(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(IOException::class, UnsupportedAudioFileException::class)
|
||||
fun decoderTest() {
|
||||
Model(modelPath).use { model ->
|
||||
AudioSystem.getAudioInputStream(BufferedInputStream(FileInputStream(testFile)))
|
||||
.use { ais ->
|
||||
Recognizer(model, 16000f).apply {
|
||||
setMaxAlternatives(10)
|
||||
setOutputWordTimes(true)
|
||||
setPartialWords(true)
|
||||
}.use { recognizer ->
|
||||
val b = ByteArray(4096)
|
||||
while (ais.read(b) >= 0) {
|
||||
if (recognizer.acceptWaveform(b)) {
|
||||
println(recognizer.result)
|
||||
} else {
|
||||
println(recognizer.partialResult)
|
||||
}
|
||||
}
|
||||
println(recognizer.finalResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
@Throws(IOException::class, UnsupportedAudioFileException::class)
|
||||
fun decoderTestFlow() = runTest {
|
||||
Model(modelPath).use { model ->
|
||||
Recognizer(model, 16000f).apply {
|
||||
setMaxAlternatives(10)
|
||||
setOutputWordTimes(true)
|
||||
setPartialWords(true)
|
||||
}.use { recognizer ->
|
||||
AudioSystem.getAudioInputStream(BufferedInputStream(FileInputStream(testFile)))
|
||||
.use { ais ->
|
||||
flow {
|
||||
val b = ByteArray(4096)
|
||||
while (ais.read(b) >= 0) {
|
||||
emit(b)
|
||||
}
|
||||
emit(null)
|
||||
}.flowOn(Dispatchers.IO)
|
||||
.feed(recognizer)
|
||||
.collect {
|
||||
println(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This test aims to simulate the situation for Dicio,
|
||||
* In which we can receive the audio input stream before the recognizer is setup.
|
||||
*
|
||||
* It is recommended to use a large model on desktop to properly see how long it takes to load up.
|
||||
*/
|
||||
@Test
|
||||
@Throws(IOException::class, UnsupportedAudioFileException::class)
|
||||
fun decoderTestFlowBuffered() {
|
||||
// Scope to buffer into
|
||||
val scope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
AudioSystem.getAudioInputStream(BufferedInputStream(FileInputStream(testFile))).use { ais ->
|
||||
val byteFlow = flow {
|
||||
val b = ByteArray(4096)
|
||||
while (ais.read(b) >= 0) {
|
||||
emit(b)
|
||||
}
|
||||
emit(null)
|
||||
}.flowOn(Dispatchers.IO)
|
||||
.shareIn(scope, SharingStarted.Eagerly, 100)
|
||||
|
||||
// Tell us the current buffer size
|
||||
println("Buffered size:" + byteFlow.replayCache.size)
|
||||
|
||||
var startTime = System.currentTimeMillis()
|
||||
|
||||
Model(modelPath).use { model ->
|
||||
var resultTime = System.currentTimeMillis() - startTime
|
||||
println("Model initialized in: $resultTime")
|
||||
startTime = System.currentTimeMillis()
|
||||
|
||||
Recognizer(model, 16000f).apply {
|
||||
setMaxAlternatives(10)
|
||||
setOutputWordTimes(true)
|
||||
setPartialWords(true)
|
||||
}.use { recognizer ->
|
||||
resultTime = System.currentTimeMillis() - startTime
|
||||
println("Recognizer initialized in: $resultTime")
|
||||
println("Buffered size:" + byteFlow.replayCache.size)
|
||||
|
||||
runBlocking {
|
||||
byteFlow
|
||||
.feed(recognizer)
|
||||
.take(byteFlow.replayCache.size)
|
||||
.collect {
|
||||
println(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(IOException::class, UnsupportedAudioFileException::class)
|
||||
fun decoderTestShort() {
|
||||
Model(modelPath).use { model ->
|
||||
AudioSystem.getAudioInputStream(BufferedInputStream(FileInputStream(testFile)))
|
||||
.use { ais ->
|
||||
Recognizer(model, 16000f).use { recognizer ->
|
||||
val b = ByteArray(4096)
|
||||
val s = ShortArray(2048)
|
||||
while (ais.read(b) >= 0) {
|
||||
ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(s)
|
||||
if (recognizer.acceptWaveform(s)) {
|
||||
println(recognizer.result)
|
||||
} else {
|
||||
println(recognizer.partialResult)
|
||||
}
|
||||
}
|
||||
println(recognizer.finalResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(IOException::class, UnsupportedAudioFileException::class)
|
||||
fun decoderTestGrammar() {
|
||||
Model(modelPath).use { model ->
|
||||
AudioSystem.getAudioInputStream(BufferedInputStream(FileInputStream(testFile)))
|
||||
.use { ais ->
|
||||
Recognizer(
|
||||
model, 16000f, "[\"one two three four five six seven eight nine zero oh\"]"
|
||||
).use { recognizer ->
|
||||
val b = ByteArray(4096)
|
||||
while (ais.read(b) >= 0) {
|
||||
if (recognizer.acceptWaveform(b)) {
|
||||
println(recognizer.result)
|
||||
} else {
|
||||
println(recognizer.partialResult)
|
||||
}
|
||||
}
|
||||
println(recognizer.finalResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun decoderTestException() {
|
||||
try {
|
||||
val model = Model("model_missing")
|
||||
assert(false)
|
||||
} catch (e: IOException) {
|
||||
assert(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
headers = libvosk/vosk_api.h
|
||||
package = libvosk
|
||||
|
||||
noStringConversion = \
|
||||
vosk_batch_recognizer_accept_waveform \
|
||||
vosk_recognizer_accept_waveform
|
||||
|
||||
compilerOpts.linux = \
|
||||
-I/usr/include/libvosk/ \
|
||||
-I/usr/local/include/libvosk/ \
|
||||
-I/usr/include/ \
|
||||
-I/usr/local/include/
|
||||
|
||||
compilerOpts.linux_x64 = \
|
||||
-I/usr/lib64/libvosk/ \
|
||||
-I/usr/local/lib64/libvosk/
|
||||
|
||||
linkerOpts.linux = \
|
||||
-L/usr/lib/ \
|
||||
-L/usr/local/lib/ \
|
||||
-llibvosk
|
||||
|
||||
linkerOpts.linux_x64 = \
|
||||
-L/usr/lib64/ \
|
||||
-L/usr/local/lib64/
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2020 Alpha Cephei Inc. & Doomsdayrs
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import cnames.structs.VoskBatchModel
|
||||
import kotlinx.cinterop.CPointer
|
||||
import libvosk.vosk_batch_model_free
|
||||
import libvosk.vosk_batch_model_new
|
||||
import libvosk.vosk_batch_model_wait
|
||||
|
||||
/**
|
||||
* Batch model object
|
||||
*
|
||||
* 26 / 12 / 2022
|
||||
*/
|
||||
actual class BatchModel(val pointer: CPointer<VoskBatchModel>) : Freeable {
|
||||
/**
|
||||
* Creates the batch recognizer object
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
actual constructor(path: String) : this(vosk_batch_model_new(path) ?: throw ioException(path))
|
||||
|
||||
/**
|
||||
* Releases batch model object
|
||||
*/
|
||||
actual override fun free() {
|
||||
vosk_batch_model_free(pointer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the processing
|
||||
*/
|
||||
actual fun await() {
|
||||
vosk_batch_model_wait(pointer)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2020 Alpha Cephei Inc. & Doomsdayrs
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import cnames.structs.VoskBatchRecognizer
|
||||
import kotlinx.cinterop.CPointer
|
||||
import kotlinx.cinterop.toCValues
|
||||
import kotlinx.cinterop.toKString
|
||||
import libvosk.*
|
||||
|
||||
/**
|
||||
* Batch recognizer object
|
||||
*
|
||||
* 26 / 12 / 2022
|
||||
*/
|
||||
actual class BatchRecognizer(val pointer: CPointer<VoskBatchRecognizer>) : Freeable {
|
||||
/**
|
||||
* Creates batch recognizer object
|
||||
*/
|
||||
actual constructor(
|
||||
model: BatchModel,
|
||||
sampleRate: Float
|
||||
) : this(vosk_batch_recognizer_new(model.pointer, sampleRate)!!)
|
||||
|
||||
/**
|
||||
* Releases batch recognizer object
|
||||
*/
|
||||
actual override fun free() {
|
||||
vosk_batch_recognizer_free(pointer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept batch voice data
|
||||
*/
|
||||
actual fun acceptWaveform(data: ByteArray) {
|
||||
vosk_batch_recognizer_accept_waveform(pointer, data.toCValues(), data.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set NLSML output
|
||||
* @param nlsml - boolean value
|
||||
*/
|
||||
actual fun setNLSML(nlsml: Boolean) {
|
||||
vosk_batch_recognizer_set_nlsml(pointer, nlsml.toInt())
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream
|
||||
*/
|
||||
actual fun finishStream() {
|
||||
vosk_batch_recognizer_finish_stream(pointer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return results
|
||||
*/
|
||||
actual val frontResult: String
|
||||
get() = vosk_batch_recognizer_front_result(pointer)!!.toKString()
|
||||
|
||||
/**
|
||||
* Release and free first retrieved result
|
||||
*/
|
||||
actual fun pop() {
|
||||
vosk_batch_recognizer_pop(pointer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get amount of pending chunks for more intelligent waiting
|
||||
*/
|
||||
actual val pendingChunks: Int
|
||||
get() = vosk_batch_recognizer_get_pending_chunks(pointer)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2020 Alpha Cephei Inc. & Doomsdayrs
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
/**
|
||||
* Use a [Freeable], then immediately free it and return any values.
|
||||
*/
|
||||
fun <T : Freeable, R> T.use(block: (T) -> R): R =
|
||||
block(this).also { free() }
|
||||
@@ -0,0 +1,3 @@
|
||||
package org.vosk
|
||||
|
||||
actual class IOException actual constructor(message: String?) : Exception()
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2020 Alpha Cephei Inc. & Doomsdayrs
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import cnames.structs.VoskModel
|
||||
import kotlinx.cinterop.CPointer
|
||||
import libvosk.vosk_model_find_word
|
||||
import libvosk.vosk_model_free
|
||||
import libvosk.vosk_model_new
|
||||
|
||||
/**
|
||||
* Model stores all the data required for recognition
|
||||
*
|
||||
* It contains static data and can be shared across processing
|
||||
* threads.
|
||||
*
|
||||
* 26 / 12 / 2022
|
||||
*/
|
||||
actual class Model(val pointer: CPointer<VoskModel>) : Freeable {
|
||||
/**
|
||||
* Loads model data from the file and returns the model object
|
||||
*
|
||||
* @param path: the path of the model on the filesystem
|
||||
* @returns model object or NULL if problem occured
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
actual constructor(path: String) : this(vosk_model_new(path) ?: throw ioException(path))
|
||||
|
||||
/**
|
||||
* Check if a word can be recognized by the model
|
||||
* @param word: the word
|
||||
* @returns the word symbol if @param word exists inside the model
|
||||
* or -1 otherwise.
|
||||
* Reminding that word symbol 0 is for <epsilon>
|
||||
*/
|
||||
actual fun findWord(word: String): Int =
|
||||
vosk_model_find_word(pointer, word)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
actual override fun free() {
|
||||
vosk_model_free(pointer)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright 2020 Alpha Cephei Inc. & Doomsdayrs
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import kotlinx.cinterop.CPointer
|
||||
import kotlinx.cinterop.toCValues
|
||||
import kotlinx.cinterop.toKString
|
||||
import libvosk.*
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* 26 / 12 / 2022
|
||||
*/
|
||||
actual class Recognizer(val pointer: CPointer<VoskRecognizer>) : Freeable {
|
||||
/**
|
||||
* Creates the recognizer object
|
||||
*
|
||||
* The recognizers process the speech and return text using shared model data
|
||||
* @param model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @returns recognizer object or NULL if problem occured
|
||||
*/
|
||||
actual constructor(
|
||||
model: Model,
|
||||
sampleRate: Float
|
||||
) : this(
|
||||
vosk_recognizer_new(
|
||||
model.pointer,
|
||||
sampleRate
|
||||
)!!
|
||||
)
|
||||
|
||||
/**
|
||||
* 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 model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @param speakerModel speaker model for speaker identification
|
||||
* @returns recognizer object or NULL if problem occured
|
||||
*/
|
||||
actual constructor(
|
||||
model: Model,
|
||||
sampleRate: Float,
|
||||
speakerModel: SpeakerModel
|
||||
) : this(
|
||||
vosk_recognizer_new_spk(
|
||||
model.pointer,
|
||||
sampleRate,
|
||||
speakerModel.pointer
|
||||
)!!
|
||||
)
|
||||
|
||||
/**
|
||||
* 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 phrases 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 model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sampleRate The sample rate of the audio you going to feed into the recognizer.
|
||||
* Make sure this rate matches the audio content, it is a common
|
||||
* issue causing accuracy problems.
|
||||
* @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 or NULL if problem occured
|
||||
*/
|
||||
actual constructor(
|
||||
model: Model,
|
||||
sampleRate: Float,
|
||||
grammar: String
|
||||
) : this(
|
||||
vosk_recognizer_new_grm(
|
||||
model.pointer,
|
||||
sampleRate,
|
||||
grammar
|
||||
)!!
|
||||
)
|
||||
|
||||
/**
|
||||
* Adds speaker model to already initialized recognizer
|
||||
*
|
||||
* Can add speaker recognition model to already created recognizer. Helps to initialize
|
||||
* speaker recognition for grammar-based recognizer.
|
||||
*
|
||||
* @param speakerModel Speaker recognition model
|
||||
*/
|
||||
actual fun setSpeakerModel(speakerModel: SpeakerModel) {
|
||||
vosk_recognizer_set_spk_model(pointer, speakerModel.pointer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconfigures recognizer to use grammar
|
||||
*
|
||||
* @param grammar Set of phrases in JSON array of strings or "[]" to use default model graph.
|
||||
* See also vosk_recognizer_new_grm
|
||||
*/
|
||||
actual fun setGrammar(grammar: String) {
|
||||
vosk_recognizer_set_grm(pointer, grammar)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures recognizer to output n-best results
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "alternatives": [
|
||||
* { "text": "one two three four five", "confidence": 0.97 },
|
||||
* { "text": "one two three for five", "confidence": 0.03 },
|
||||
* ]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param maxAlternatives - maximum alternatives to return from recognition results
|
||||
*/
|
||||
actual fun setMaxAlternatives(maxAlternatives: Int) {
|
||||
vosk_recognizer_set_max_alternatives(pointer, maxAlternatives)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables words with times in the output
|
||||
*
|
||||
* <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"
|
||||
* }],
|
||||
* </pre>
|
||||
*
|
||||
* @param words - boolean value
|
||||
*/
|
||||
actual fun setWords(words: Boolean) {
|
||||
vosk_recognizer_set_words(pointer, words.toInt())
|
||||
}
|
||||
|
||||
/**
|
||||
* Like above return words and confidences in partial results
|
||||
*
|
||||
* @param partialWords - boolean value
|
||||
*/
|
||||
actual fun setPartialWords(partialWords: Boolean) {
|
||||
vosk_recognizer_set_partial_words(pointer, partialWords.toInt())
|
||||
}
|
||||
|
||||
/**
|
||||
* Set NLSML output
|
||||
* @param nlsml - boolean value
|
||||
*/
|
||||
actual fun setNLSML(nlsml: Boolean) {
|
||||
vosk_recognizer_set_nlsml(pointer, nlsml.toInt())
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 1 if silence is occured and you can retrieve a new utterance with result method
|
||||
* 0 if decoding continues
|
||||
* -1 if exception occured
|
||||
*/
|
||||
@Throws(AcceptWaveformException::class)
|
||||
actual fun acceptWaveform(data: ByteArray): Boolean {
|
||||
val result = vosk_recognizer_accept_waveform(pointer, data.toCValues(), data.size)
|
||||
if (result == -1) throw AcceptWaveformException(data)
|
||||
return result == 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above but the version with the short data for language bindings where you have
|
||||
* audio as array of shorts
|
||||
*/
|
||||
@Throws(AcceptWaveformException::class)
|
||||
actual fun acceptWaveform(data: ShortArray): Boolean {
|
||||
val result = vosk_recognizer_accept_waveform_s(pointer, data.toCValues(), data.size)
|
||||
if (result == -1) throw AcceptWaveformException(data)
|
||||
return result == 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above but the version with the float data for language bindings where you have
|
||||
* audio as array of floats
|
||||
*/
|
||||
@Throws(AcceptWaveformException::class)
|
||||
actual fun acceptWaveform(data: FloatArray): Boolean {
|
||||
val result = vosk_recognizer_accept_waveform_f(pointer, data.toCValues(), data.size)
|
||||
if (result == -1) throw AcceptWaveformException(data)
|
||||
return result == 1
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>
|
||||
* {
|
||||
* "text" : "what zero zero zero one"
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* If alternatives enabled it returns result with alternatives, see also vosk_recognizer_set_max_alternatives().
|
||||
*
|
||||
* If word times enabled returns word time, see also vosk_recognizer_set_word_times().
|
||||
*/
|
||||
actual val result: String
|
||||
get() = vosk_recognizer_result(pointer)!!.toKString()
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*/
|
||||
actual val finalResult: String
|
||||
get() = vosk_recognizer_result(pointer)!!.toKString()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
actual val partialResult: String
|
||||
get() = vosk_recognizer_partial_result(pointer)!!.toKString()
|
||||
|
||||
/**
|
||||
* Resets the recognizer
|
||||
*
|
||||
* Resets current results so the recognition can continue from scratch */
|
||||
actual fun reset() {
|
||||
vosk_recognizer_reset(pointer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases recognizer object
|
||||
*
|
||||
* Underlying model is also unreferenced and if needed released */
|
||||
actual override fun free() {
|
||||
vosk_recognizer_free(pointer)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2020 Alpha Cephei Inc. & Doomsdayrs
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import cnames.structs.VoskSpkModel
|
||||
import kotlinx.cinterop.CPointer
|
||||
import libvosk.vosk_spk_model_free
|
||||
import libvosk.vosk_spk_model_new
|
||||
|
||||
/**
|
||||
* Speaker model is the same as model but contains the data
|
||||
* for speaker identification.
|
||||
*
|
||||
* 26 / 12 / 2022
|
||||
*/
|
||||
actual class SpeakerModel(val pointer: CPointer<VoskSpkModel>) : Freeable {
|
||||
/**
|
||||
* Loads speaker model data from the file and returns the model object
|
||||
*
|
||||
* @param path: the path of the model on the filesystem
|
||||
* @returns model object or NULL if problem occurred
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
actual constructor(path: String) : this(vosk_spk_model_new(path) ?: throw ioException(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.
|
||||
*/
|
||||
actual override fun free() {
|
||||
vosk_spk_model_free(pointer)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2020 Alpha Cephei Inc. & Doomsdayrs
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
/*
|
||||
* 26 / 12 / 2022
|
||||
*/
|
||||
|
||||
/**
|
||||
* Converts a boolean to an int
|
||||
*/
|
||||
internal inline fun Boolean.toInt() = if (this) 1 else 0
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2020 Alpha Cephei Inc. & Doomsdayrs
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.vosk
|
||||
|
||||
import libvosk.vosk_set_log_level
|
||||
import libvosk.vosk_gpu_init
|
||||
import libvosk.vosk_gpu_thread_init
|
||||
|
||||
/**
|
||||
* 26 / 12 / 2022
|
||||
*/
|
||||
actual object Vosk {
|
||||
/** Set log level for Kaldi messages
|
||||
*
|
||||
* @param logLevel the level
|
||||
*/
|
||||
actual fun setLogLevel(logLevel: LogLevel) {
|
||||
vosk_set_log_level(logLevel.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Init, automatically select a CUDA device and allow multithreading.
|
||||
* Must be called once from the main thread.
|
||||
* Has no effect if HAVE_CUDA flag is not set.
|
||||
*/
|
||||
actual fun gpuInit() {
|
||||
vosk_gpu_init()
|
||||
}
|
||||
|
||||
/**
|
||||
* Init CUDA device in a multi-threaded environment.
|
||||
* Must be called for each thread.
|
||||
* Has no effect if HAVE_CUDA flag is not set.
|
||||
*/
|
||||
actual fun gpuThreadInit() {
|
||||
vosk_gpu_thread_init()
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -13,7 +13,8 @@ Vosk is an offline open source speech recognition toolkit. It enables
|
||||
speech recognition for 20+ languages and dialects - English, Indian
|
||||
English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish,
|
||||
Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino,
|
||||
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech. More to come.
|
||||
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech, Polish.
|
||||
More to come.
|
||||
|
||||
Vosk models are small (50 Mb) but provide continuous large vocabulary
|
||||
transcription, zero-latency response with streaming API, reconfigurable
|
||||
|
||||
@@ -18,11 +18,11 @@ const rec = new vosk.Recognizer({model: model, sampleRate: SAMPLE_RATE});
|
||||
var micInstance = mic({
|
||||
rate: String(SAMPLE_RATE),
|
||||
channels: '1',
|
||||
debug: false
|
||||
debug: false,
|
||||
device: 'default',
|
||||
});
|
||||
|
||||
var micInputStream = micInstance.getAudioStream();
|
||||
micInstance.start();
|
||||
|
||||
micInputStream.on('data', data => {
|
||||
if (rec.acceptWaveform(data))
|
||||
@@ -31,9 +31,16 @@ micInputStream.on('data', data => {
|
||||
console.log(rec.partialResult());
|
||||
});
|
||||
|
||||
process.on('SIGINT', function() {
|
||||
micInputStream.on('audioProcessExitComplete', function() {
|
||||
console.log("Cleaning up");
|
||||
console.log(rec.finalResult());
|
||||
console.log("\nDone");
|
||||
rec.free();
|
||||
model.free();
|
||||
});
|
||||
|
||||
process.on('SIGINT', function() {
|
||||
console.log("\nStopping");
|
||||
micInstance.stop();
|
||||
});
|
||||
|
||||
micInstance.start();
|
||||
|
||||
+2
-2
@@ -72,11 +72,11 @@ if (os.platform() == 'win32') {
|
||||
// Update path to load dependent dlls
|
||||
let currentPath = process.env.Path;
|
||||
let dllDirectory = path.resolve(path.join(__dirname, "lib", "win-x86_64"));
|
||||
process.env.Path = currentPath + path.delimiter + dllDirectory;
|
||||
process.env.Path = dllDirectory + path.delimiter + currentPath;
|
||||
|
||||
soname = path.join(__dirname, "lib", "win-x86_64", "libvosk.dll")
|
||||
} else if (os.platform() == 'darwin') {
|
||||
soname = path.join(__dirname, "lib", "osx-x86_64", "libvosk.dylib")
|
||||
soname = path.join(__dirname, "lib", "osx-universal", "libvosk.dylib")
|
||||
} else {
|
||||
soname = path.join(__dirname, "lib", "linux-x86_64", "libvosk.so")
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vosk",
|
||||
"version": "0.3.38",
|
||||
"version": "0.3.45",
|
||||
"description": "Node binding for continuous offline voice recoginition with Vosk library.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -0,0 +1,639 @@
|
||||
[MAIN]
|
||||
|
||||
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
||||
# 3 compatible code, which means that the block might have code that exists
|
||||
# only in one or another interpreter, leading to false positives when analysed.
|
||||
analyse-fallback-blocks=no
|
||||
|
||||
# Load and enable all available extensions. Use --list-extensions to see a list
|
||||
# all available extensions.
|
||||
#enable-all-extensions=
|
||||
|
||||
# In error mode, messages with a category besides ERROR or FATAL are
|
||||
# suppressed, and no reports are done by default. Error mode is compatible with
|
||||
# disabling specific errors.
|
||||
#errors-only=
|
||||
|
||||
# Always return a 0 (non-error) status code, even if lint errors are found.
|
||||
# This is primarily useful in continuous integration scripts.
|
||||
#exit-zero=
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code.
|
||||
extension-pkg-allow-list=
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
|
||||
# for backward compatibility.)
|
||||
extension-pkg-whitelist=
|
||||
|
||||
# Return non-zero exit code if any of these messages/categories are detected,
|
||||
# even if score is above --fail-under value. Syntax same as enable. Messages
|
||||
# specified are enabled, while categories only check already-enabled messages.
|
||||
fail-on=
|
||||
|
||||
# Specify a score threshold under which the program will exit with error.
|
||||
fail-under=10
|
||||
|
||||
# Interpret the stdin as a python script, whose filename needs to be passed as
|
||||
# the module_or_package argument.
|
||||
#from-stdin=
|
||||
|
||||
# Files or directories to be skipped. They should be base names, not paths.
|
||||
ignore=CVS
|
||||
|
||||
# Add files or directories matching the regular expressions patterns to the
|
||||
# ignore-list. The regex matches against paths and can be in Posix or Windows
|
||||
# format. Because '\' represents the directory delimiter on Windows systems, it
|
||||
# can't be used as an escape character.
|
||||
ignore-paths=
|
||||
|
||||
# Files or directories matching the regular expression patterns are skipped.
|
||||
# The regex matches against base names, not paths. The default value ignores
|
||||
# Emacs file locks
|
||||
ignore-patterns=^\.#
|
||||
|
||||
# List of module names for which member attributes should not be checked
|
||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||
# and thus existing member attributes cannot be deduced by static analysis). It
|
||||
# supports qualified module names, as well as Unix pattern matching.
|
||||
ignored-modules=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
|
||||
# number of processors available to use, and will cap the count on Windows to
|
||||
# avoid hangs.
|
||||
jobs=1
|
||||
|
||||
# Control the amount of potential inferred values when inferring a single
|
||||
# object. This can help the performance when dealing with large functions or
|
||||
# complex, nested conditions.
|
||||
limit-inference-results=100
|
||||
|
||||
# List of plugins (as comma separated values of python module names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# Minimum Python version to use for version dependent checks. Will default to
|
||||
# the version used to run pylint.
|
||||
py-version=3.7
|
||||
|
||||
# Discover python modules and packages in the file system subtree.
|
||||
recursive=no
|
||||
|
||||
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
||||
# user-friendly hints instead of false-positive error messages.
|
||||
suggestion-mode=yes
|
||||
|
||||
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
||||
# active Python interpreter and may run arbitrary code.
|
||||
unsafe-load-any-extension=no
|
||||
|
||||
# In verbose mode, extra non-checker-related info will be displayed.
|
||||
#verbose=
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Python expression which should return a score less than or equal to 10. You
|
||||
# have access to the variables 'fatal', 'error', 'warning', 'refactor',
|
||||
# 'convention', and 'info' which contain the number of messages in each
|
||||
# category, as well as 'statement' which is the total number of statements
|
||||
# analyzed. This score is used by the global evaluation report (RP0004).
|
||||
evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
|
||||
|
||||
# Template used to display messages. This is a python new-style format string
|
||||
# used to format the message information. See doc for all details.
|
||||
msg-template=
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, json
|
||||
# and msvs (visual studio). You can also give a reporter class, e.g.
|
||||
# mypackage.mymodule.MyReporterClass.
|
||||
#output-format=
|
||||
|
||||
# Tells whether to display a full report or only the messages.
|
||||
reports=no
|
||||
|
||||
# Activate the evaluation score.
|
||||
score=yes
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||
# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE,
|
||||
# UNDEFINED.
|
||||
confidence=HIGH,
|
||||
CONTROL_FLOW,
|
||||
INFERENCE,
|
||||
INFERENCE_FAILURE,
|
||||
UNDEFINED
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifiers separated by comma (,) or put this
|
||||
# option multiple times (only on the command line, not in the configuration
|
||||
# file where it should appear only once). You can also use "--disable=all" to
|
||||
# disable everything first and then re-enable specific checks. For example, if
|
||||
# you want to run only the similarities checker, you can use "--disable=all
|
||||
# --enable=similarities". If you want to run only the classes checker, but have
|
||||
# no Warning level messages displayed, use "--disable=all --enable=classes
|
||||
# --disable=W".
|
||||
disable=raw-checker-failed,
|
||||
bad-inline-option,
|
||||
locally-disabled,
|
||||
file-ignored,
|
||||
suppressed-message,
|
||||
useless-suppression,
|
||||
deprecated-pragma,
|
||||
use-symbolic-message-instead,
|
||||
missing-module-docstring, # added
|
||||
missing-class-docstring, # added
|
||||
missing-function-docstring, # added
|
||||
invalid-name, # added
|
||||
broad-except, # added
|
||||
wrong-import-order, # added
|
||||
consider-using-f-string, # added
|
||||
logging-format-interpolation, # added
|
||||
no-member, # added
|
||||
consider-using-with, # added
|
||||
unused-argument,
|
||||
no-else-return, # added
|
||||
too-few-public-methods, # added
|
||||
import-error, # added
|
||||
protected-access, # added
|
||||
unused-variable, # added
|
||||
R0801 # added (similarity of two scripts)
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time (only on the command line, not in the configuration file where
|
||||
# it should appear only once). See also the "--disable" option for examples.
|
||||
enable=c-extension-no-member
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Naming style matching correct argument names.
|
||||
argument-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct argument names. Overrides argument-
|
||||
# naming-style. If left empty, argument names will be checked with the set
|
||||
# naming style.
|
||||
#argument-rgx=
|
||||
|
||||
# Naming style matching correct attribute names.
|
||||
attr-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct attribute names. Overrides attr-naming-
|
||||
# style. If left empty, attribute names will be checked with the set naming
|
||||
# style.
|
||||
#attr-rgx=
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma.
|
||||
bad-names=foo,
|
||||
bar,
|
||||
baz,
|
||||
toto,
|
||||
tutu,
|
||||
tata
|
||||
|
||||
# Bad variable names regexes, separated by a comma. If names match any regex,
|
||||
# they will always be refused
|
||||
bad-names-rgxs=
|
||||
|
||||
# Naming style matching correct class attribute names.
|
||||
class-attribute-naming-style=any
|
||||
|
||||
# Regular expression matching correct class attribute names. Overrides class-
|
||||
# attribute-naming-style. If left empty, class attribute names will be checked
|
||||
# with the set naming style.
|
||||
#class-attribute-rgx=
|
||||
|
||||
# Naming style matching correct class constant names.
|
||||
class-const-naming-style=UPPER_CASE
|
||||
|
||||
# Regular expression matching correct class constant names. Overrides class-
|
||||
# const-naming-style. If left empty, class constant names will be checked with
|
||||
# the set naming style.
|
||||
#class-const-rgx=
|
||||
|
||||
# Naming style matching correct class names.
|
||||
class-naming-style=PascalCase
|
||||
|
||||
# Regular expression matching correct class names. Overrides class-naming-
|
||||
# style. If left empty, class names will be checked with the set naming style.
|
||||
#class-rgx=
|
||||
|
||||
# Naming style matching correct constant names.
|
||||
const-naming-style=UPPER_CASE
|
||||
|
||||
# Regular expression matching correct constant names. Overrides const-naming-
|
||||
# style. If left empty, constant names will be checked with the set naming
|
||||
# style.
|
||||
#const-rgx=
|
||||
|
||||
# Minimum line length for functions/classes that require docstrings, shorter
|
||||
# ones are exempt.
|
||||
docstring-min-length=-1
|
||||
|
||||
# Naming style matching correct function names.
|
||||
function-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct function names. Overrides function-
|
||||
# naming-style. If left empty, function names will be checked with the set
|
||||
# naming style.
|
||||
#function-rgx=
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma.
|
||||
good-names=i,
|
||||
j,
|
||||
k,
|
||||
ex,
|
||||
Run,
|
||||
_,
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny
|
||||
|
||||
# Good variable names regexes, separated by a comma. If names match any regex,
|
||||
# they will always be accepted
|
||||
good-names-rgxs=
|
||||
|
||||
# Include a hint for the correct naming format with invalid-name.
|
||||
include-naming-hint=no
|
||||
|
||||
# Naming style matching correct inline iteration names.
|
||||
inlinevar-naming-style=any
|
||||
|
||||
# Regular expression matching correct inline iteration names. Overrides
|
||||
# inlinevar-naming-style. If left empty, inline iteration names will be checked
|
||||
# with the set naming style.
|
||||
#inlinevar-rgx=
|
||||
|
||||
# Naming style matching correct method names.
|
||||
method-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct method names. Overrides method-naming-
|
||||
# style. If left empty, method names will be checked with the set naming style.
|
||||
#method-rgx=
|
||||
|
||||
# Naming style matching correct module names.
|
||||
module-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct module names. Overrides module-naming-
|
||||
# style. If left empty, module names will be checked with the set naming style.
|
||||
#module-rgx=
|
||||
|
||||
# Colon-delimited sets of names that determine each other's naming style when
|
||||
# the name regexes allow several styles.
|
||||
name-group=
|
||||
|
||||
# Regular expression which should only match function or class names that do
|
||||
# not require a docstring.
|
||||
no-docstring-rgx=^_
|
||||
|
||||
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
||||
# to this list to register other decorators that produce valid properties.
|
||||
# These decorators are taken in consideration only for invalid-name.
|
||||
property-classes=abc.abstractproperty
|
||||
|
||||
# Regular expression matching correct type variable names. If left empty, type
|
||||
# variable names will be checked with the set naming style.
|
||||
#typevar-rgx=
|
||||
|
||||
# Naming style matching correct variable names.
|
||||
variable-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct variable names. Overrides variable-
|
||||
# naming-style. If left empty, variable names will be checked with the set
|
||||
# naming style.
|
||||
#variable-rgx=
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid defining new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
# Tells whether unused global variables should be treated as a violation.
|
||||
allow-global-unused-variables=yes
|
||||
|
||||
# List of names allowed to shadow builtins
|
||||
allowed-redefined-builtins=
|
||||
|
||||
# List of strings which can identify a callback function by name. A callback
|
||||
# name must start or end with one of those strings.
|
||||
callbacks=cb_,
|
||||
_cb
|
||||
|
||||
# A regular expression matching the name of dummy variables (i.e. expected to
|
||||
# not be used).
|
||||
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||
|
||||
# Argument names that match this expression will be ignored.
|
||||
ignored-argument-names=_.*|^ignored_|^unused_
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# List of qualified module names which can have objects that can redefine
|
||||
# builtins.
|
||||
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Comments are removed from the similarity computation
|
||||
ignore-comments=yes
|
||||
|
||||
# Docstrings are removed from the similarity computation
|
||||
ignore-docstrings=yes
|
||||
|
||||
# Imports are removed from the similarity computation
|
||||
ignore-imports=yes
|
||||
|
||||
# Signatures are removed from the similarity computation
|
||||
ignore-signatures=yes
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,
|
||||
XXX,
|
||||
TODO
|
||||
|
||||
# Regular expression of note tags to take in consideration.
|
||||
notes-rgx=
|
||||
|
||||
|
||||
[STRING]
|
||||
|
||||
# This flag controls whether inconsistent-quotes generates a warning when the
|
||||
# character used as a quote delimiter is used inconsistently within a module.
|
||||
check-quote-consistency=no
|
||||
|
||||
# This flag controls whether the implicit-str-concat should generate a warning
|
||||
# on implicit string concatenation in sequences defined over several lines.
|
||||
check-str-concat-over-line-jumps=no
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# List of modules that can be imported at any level, not just the top level
|
||||
# one.
|
||||
allow-any-import-level=
|
||||
|
||||
# Allow wildcard imports from modules that define __all__.
|
||||
allow-wildcard-with-all=no
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma.
|
||||
deprecated-modules=
|
||||
|
||||
# Output a graph (.gv or any supported image format) of external dependencies
|
||||
# to the given file (report RP0402 must not be disabled).
|
||||
ext-import-graph=
|
||||
|
||||
# Output a graph (.gv or any supported image format) of all (i.e. internal and
|
||||
# external) dependencies to the given file (report RP0402 must not be
|
||||
# disabled).
|
||||
import-graph=
|
||||
|
||||
# Output a graph (.gv or any supported image format) of internal dependencies
|
||||
# to the given file (report RP0402 must not be disabled).
|
||||
int-import-graph=
|
||||
|
||||
# Force import order to recognize a module as part of the standard
|
||||
# compatibility libraries.
|
||||
known-standard-library=
|
||||
|
||||
# Force import order to recognize a module as part of a third party library.
|
||||
known-third-party=enchant
|
||||
|
||||
# Couples of modules and preferred modules, separated by a comma.
|
||||
preferred-modules=
|
||||
|
||||
|
||||
[EXCEPTIONS]
|
||||
|
||||
# Exceptions that will emit a warning when caught.
|
||||
overgeneral-exceptions=BaseException,
|
||||
Exception
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# List of regular expressions of class ancestor names to ignore when counting
|
||||
# public methods (see R0903)
|
||||
exclude-too-few-public-methods=
|
||||
|
||||
# List of qualified class names to ignore when counting class parents (see
|
||||
# R0901)
|
||||
ignored-parents=
|
||||
|
||||
# Maximum number of arguments for function / method.
|
||||
max-args=5
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=7
|
||||
|
||||
# Maximum number of boolean expressions in an if statement (see R0916).
|
||||
max-bool-expr=5
|
||||
|
||||
# Maximum number of branch for function / method body.
|
||||
max-branches=12
|
||||
|
||||
# Maximum number of locals for function / method body.
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
# Maximum number of return / yield for function / method body.
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of statements in function / method body.
|
||||
max-statements=50
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=2
|
||||
|
||||
|
||||
[METHOD_ARGS]
|
||||
|
||||
# List of qualified names (i.e., library.method) which require a timeout
|
||||
# parameter e.g. 'requests.api.get,requests.api.post'
|
||||
timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request
|
||||
|
||||
|
||||
[LOGGING]
|
||||
|
||||
# The type of string formatting that logging methods do. `old` means using %
|
||||
# formatting, `new` is for `{}` formatting.
|
||||
logging-format-style=old
|
||||
|
||||
# Logging modules to check that the string format arguments are in logging
|
||||
# function parameter format.
|
||||
logging-modules=logging
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||
expected-line-ending-format=
|
||||
|
||||
# Regexp for a line that is allowed to be longer than the limit.
|
||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||
|
||||
# Number of spaces of indent required inside a hanging or continued line.
|
||||
indent-after-paren=4
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=100
|
||||
|
||||
# Maximum number of lines in a module.
|
||||
max-module-lines=1000
|
||||
|
||||
# Allow the body of a class to be on the same line as the declaration if body
|
||||
# contains single statement.
|
||||
single-line-class-stmt=no
|
||||
|
||||
# Allow the body of an if to be on the same line as the test if there is no
|
||||
# else.
|
||||
single-line-if-stmt=no
|
||||
|
||||
|
||||
[REFACTORING]
|
||||
|
||||
# Maximum number of nested blocks for function / method body
|
||||
max-nested-blocks=5
|
||||
|
||||
# Complete name of functions that never returns. When checking for
|
||||
# inconsistent-return-statements if a never returning function is called then
|
||||
# it will be considered as an explicit return statement and no message will be
|
||||
# printed.
|
||||
never-returning-functions=sys.exit,argparse.parse_error
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# List of decorators that produce context managers, such as
|
||||
# contextlib.contextmanager. Add to this list to register other decorators that
|
||||
# produce valid context managers.
|
||||
contextmanager-decorators=contextlib.contextmanager
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=
|
||||
|
||||
# Tells whether to warn about missing members when the owner of the attribute
|
||||
# is inferred to be None.
|
||||
ignore-none=yes
|
||||
|
||||
# This flag controls whether pylint should warn about no-member and similar
|
||||
# checks whenever an opaque object is returned when inferring. The inference
|
||||
# can return multiple potential results while evaluating a Python object, but
|
||||
# some branches might not be evaluated, which results in partial inference. In
|
||||
# that case, it might be useful to still emit no-member and other checks for
|
||||
# the rest of the inferred objects.
|
||||
ignore-on-opaque-inference=yes
|
||||
|
||||
# List of symbolic message names to ignore for Mixin members.
|
||||
ignored-checks-for-mixins=no-member,
|
||||
not-async-context-manager,
|
||||
not-context-manager,
|
||||
attribute-defined-outside-init
|
||||
|
||||
# List of class names for which member attributes should not be checked (useful
|
||||
# for classes with dynamically set attributes). This supports the use of
|
||||
# qualified names.
|
||||
ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace
|
||||
|
||||
# Show a hint with possible names when a member name was not found. The aspect
|
||||
# of finding the hint is based on edit distance.
|
||||
missing-member-hint=yes
|
||||
|
||||
# The minimum edit distance a name should have in order to be considered a
|
||||
# similar match for a missing member name.
|
||||
missing-member-hint-distance=1
|
||||
|
||||
# The total number of similar names that should be taken in consideration when
|
||||
# showing a hint for a missing member.
|
||||
missing-member-max-choices=1
|
||||
|
||||
# Regex pattern to define which classes are considered mixins.
|
||||
mixin-class-rgx=.*[Mm]ixin
|
||||
|
||||
# List of decorators that change the signature of a decorated function.
|
||||
signature-mutators=
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# Warn about protected attribute access inside special methods
|
||||
check-protected-access-in-special-methods=no
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,
|
||||
__new__,
|
||||
setUp,
|
||||
__post_init__
|
||||
|
||||
# List of member names, which should be excluded from the protected access
|
||||
# warning.
|
||||
exclude-protected=_asdict,
|
||||
_fields,
|
||||
_replace,
|
||||
_source,
|
||||
_make
|
||||
|
||||
# List of valid names for the first argument in a class method.
|
||||
valid-classmethod-first-arg=cls
|
||||
|
||||
# List of valid names for the first argument in a metaclass class method.
|
||||
valid-metaclass-classmethod-first-arg=cls
|
||||
|
||||
|
||||
[SPELLING]
|
||||
|
||||
# Limits count of emitted suggestions for spelling mistakes.
|
||||
max-spelling-suggestions=4
|
||||
|
||||
# Spelling dictionary name. Available dictionaries: none. To make it work,
|
||||
# install the 'python-enchant' package.
|
||||
spelling-dict=
|
||||
|
||||
# List of comma separated words that should be considered directives if they
|
||||
# appear at the beginning of a comment and should not be checked.
|
||||
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
|
||||
|
||||
# List of comma separated words that should not be checked.
|
||||
spelling-ignore-words=
|
||||
|
||||
# A path to a file that contains the private dictionary; one word per line.
|
||||
spelling-private-dict-file=
|
||||
|
||||
# Tells whether to store unknown words to the private dictionary (see the
|
||||
# --spelling-private-dict-file option) instead of raising a message.
|
||||
spelling-store-unknown-words=no
|
||||
+2
-1
@@ -4,7 +4,8 @@ Vosk is an offline open source speech recognition toolkit. It enables
|
||||
speech recognition for 20+ languages and dialects - English, Indian
|
||||
English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish,
|
||||
Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino,
|
||||
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech. More to come.
|
||||
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech, Polish.
|
||||
More to come.
|
||||
|
||||
Vosk models are small (50 Mb) but provide continuous large vocabulary
|
||||
transcription, zero-latency response with streaming API, reconfigurable
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,558 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "Vosk Adaptation",
|
||||
"provenance": [],
|
||||
"collapsed_sections": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
},
|
||||
"accelerator": "GPU",
|
||||
"gpuClass": "standard"
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "URzWMmv50-Ba",
|
||||
"outputId": "0e096a99-74dd-42e2-efb1-9cba784c3664"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"/content\n",
|
||||
"--2022-08-17 09:48:52-- https://alphacephei.com/vosk-colab/kaldi.tar.gz\n",
|
||||
"Resolving alphacephei.com (alphacephei.com)... 188.40.21.16, 2a01:4f8:13a:279f::2\n",
|
||||
"Connecting to alphacephei.com (alphacephei.com)|188.40.21.16|:443... connected.\n",
|
||||
"HTTP request sent, awaiting response... 200 OK\n",
|
||||
"Length: 809174554 (772M) [application/octet-stream]\n",
|
||||
"Saving to: ‘kaldi.tar.gz’\n",
|
||||
"\n",
|
||||
"kaldi.tar.gz 100%[===================>] 771.69M 20.3MB/s in 40s \n",
|
||||
"\n",
|
||||
"2022-08-17 09:49:33 (19.4 MB/s) - ‘kaldi.tar.gz’ saved [809174554/809174554]\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%cd /content\n",
|
||||
"!wget -c https://alphacephei.com/vosk-colab/kaldi.tar.gz\n",
|
||||
"!tar xzf kaldi.tar.gz"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"%cd /content/kaldi/egs/ac\n",
|
||||
"!wget -c https://alphacephei.com/vosk-colab/vosk-model-small-en-us-0.15-compile-colab.tar.gz\n",
|
||||
"!rm -rf vosk-model-small-en-us-0.15-compile-colab\n",
|
||||
"!tar xf vosk-model-small-en-us-0.15-compile-colab.tar.gz"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "-065p7WC2SHh",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"outputId": "241c7473-7464-48d5-b48d-dc6e3bf4971d"
|
||||
},
|
||||
"execution_count": 8,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"/content/kaldi/egs/ac\n",
|
||||
"--2022-08-17 10:28:26-- https://alphacephei.com/vosk-colab/vosk-model-small-en-us-0.15-compile-colab.tar.gz\n",
|
||||
"Resolving alphacephei.com (alphacephei.com)... 188.40.21.16, 2a01:4f8:13a:279f::2\n",
|
||||
"Connecting to alphacephei.com (alphacephei.com)|188.40.21.16|:443... connected.\n",
|
||||
"HTTP request sent, awaiting response... 200 OK\n",
|
||||
"Length: 59618100 (57M) [application/octet-stream]\n",
|
||||
"Saving to: ‘vosk-model-small-en-us-0.15-compile-colab.tar.gz’\n",
|
||||
"\n",
|
||||
"vosk-model-small-en 100%[===================>] 56.86M 18.6MB/s in 3.6s \n",
|
||||
"\n",
|
||||
"2022-08-17 10:28:30 (15.7 MB/s) - ‘vosk-model-small-en-us-0.15-compile-colab.tar.gz’ saved [59618100/59618100]\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"%cd /content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab\n",
|
||||
"!ls\n",
|
||||
"!cat compile-graph.sh\n",
|
||||
"!bash compile-graph.sh"
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "wuDjvNbd2sf9",
|
||||
"outputId": "34a1d2fe-d443-4574-e25d-824e38eb3a78"
|
||||
},
|
||||
"execution_count": 9,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab\n",
|
||||
"compile-graph.sh data_test decode.sh\texp\t local path.sh steps\n",
|
||||
"conf\t\t db\t dict.py\tget_vocab.py mfcc RESULTS utils\n",
|
||||
"#!/bin/bash\n",
|
||||
"\n",
|
||||
"set -x\n",
|
||||
"\n",
|
||||
". path.sh\n",
|
||||
"\n",
|
||||
"pip3 install phonetisaurus\n",
|
||||
"\n",
|
||||
"rm -rf data\n",
|
||||
"rm -rf exp/tdnn/lgraph\n",
|
||||
"rm -rf exp/tdnn/lgraph_orig\n",
|
||||
"\n",
|
||||
"mkdir -p data/dict\n",
|
||||
"cp db/phone/* data/dict\n",
|
||||
"./dict.py > data/dict/lexicon.txt\n",
|
||||
"\n",
|
||||
"python3 ./get_vocab.py > data/mix.vocab\n",
|
||||
"ngramsymbols data/mix.vocab data/mix.syms\n",
|
||||
"farcompilestrings --fst_type=compact --symbols=data/mix.syms --keep_symbols --unknown_symbol=\"[unk]\" db/extra.txt data/extra.far\n",
|
||||
"ngramcount --order=3 data/extra.far - |\n",
|
||||
" ngramprint --integers | grep -v \"<unk>\" | ngramread |\n",
|
||||
" ngramshrink --method=count_prune --count_pattern=\"3+:3\" |\n",
|
||||
" ngrammake --method=witten_bell - data/extra.mod\n",
|
||||
"gunzip -c db/en-50k-0.4-android.lm.gz | ngramread --renormalize_arpa --ARPA --symbols=data/mix.syms - data/en-us.mod\n",
|
||||
"ngrammerge --method=\"bayes_model_merge\" --normalize --alpha=0.95 --beta=0.05 data/en-us.mod data/extra.mod data/en-us-mix.mod\n",
|
||||
"ngramprint --ARPA data/en-us-mix.mod | gzip -c > data/en-us-mix.lm.gz\n",
|
||||
"\n",
|
||||
"# Prune for the first stage if needed\n",
|
||||
"# ngramshrink --method=relative_entropy --theta=2e-8 data/en-us-mix.mod data/en-us-mix-prune.mod\n",
|
||||
"# ngramprint --ARPA data/en-us-mix-prune.mod | gzip -c > data/en-us-mix-small.lm.gz\n",
|
||||
"\n",
|
||||
"utils/prepare_lang.sh data/dict \"[unk]\" data/lang_local data/lang\n",
|
||||
"utils/format_lm.sh data/lang db/en-50k-0.4-android.lm.gz data/dict/lexicon.txt data/lang_test\n",
|
||||
"utils/format_lm.sh data/lang data/en-us-mix.lm.gz data/dict/lexicon.txt data/lang_test_adapt\n",
|
||||
"\n",
|
||||
"utils/mkgraph.sh --self-loop-scale 1.0 data/lang_test exp/tdnn exp/tdnn/graph\n",
|
||||
"utils/mkgraph.sh --self-loop-scale 1.0 data/lang_test_adapt exp/tdnn exp/tdnn/graph_adapt\n",
|
||||
"\n",
|
||||
"# Lookahead part goes OOM\n",
|
||||
"#utils/mkgraph_lookahead.sh \\\n",
|
||||
"# --self-loop-scale 1.0 data/lang \\\n",
|
||||
"# exp/tdnn data/en-us-mix.lm.gz exp/tdnn/lgraph\n",
|
||||
"#utils/mkgraph_lookahead.sh \\\n",
|
||||
"# --self-loop-scale 1.0 data/lang \\\n",
|
||||
"# exp/tdnn db/en-50k-0.4-android.lm.gz exp/tdnn/lgraph_orig\n",
|
||||
"+ . path.sh\n",
|
||||
"+++ pwd\n",
|
||||
"++ export KALDI_ROOT=/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../..\n",
|
||||
"++ KALDI_ROOT=/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../..\n",
|
||||
"++ export PATH=/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/utils:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../tools/openfst/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/fstbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/gmmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/featbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/lm:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/sgmmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/sgmm2bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/fgmmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/latbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/nnetbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/nnet2bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/online2bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/ivectorbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/lmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/chainbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/nnet3bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab:/opt/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/tools/node/bin:/tools/google-cloud-sdk/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../tools/sph2pipe_v2.5\n",
|
||||
"++ PATH=/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/utils:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../tools/openfst/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/fstbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/gmmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/featbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/lm:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/sgmmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/sgmm2bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/fgmmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/latbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/nnetbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/nnet2bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/online2bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/ivectorbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/lmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/chainbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/nnet3bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab:/opt/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/tools/node/bin:/tools/google-cloud-sdk/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../tools/sph2pipe_v2.5\n",
|
||||
"++ export PATH=/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../tools/ngram-1.3.7/src/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/utils:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../tools/openfst/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/fstbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/gmmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/featbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/lm:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/sgmmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/sgmm2bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/fgmmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/latbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/nnetbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/nnet2bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/online2bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/ivectorbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/lmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/chainbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/nnet3bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab:/opt/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/tools/node/bin:/tools/google-cloud-sdk/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../tools/sph2pipe_v2.5\n",
|
||||
"++ PATH=/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../tools/ngram-1.3.7/src/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/utils:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../tools/openfst/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/fstbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/gmmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/featbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/lm:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/sgmmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/sgmm2bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/fgmmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/latbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/nnetbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/nnet2bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/online2bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/ivectorbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/lmbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/chainbin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../src/nnet3bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab:/opt/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/tools/node/bin:/tools/google-cloud-sdk/bin:/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../tools/sph2pipe_v2.5\n",
|
||||
"++ export LD_LIBRARY_PATH=/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../tools/openfst/lib/fst/\n",
|
||||
"++ LD_LIBRARY_PATH=/content/kaldi/egs/ac/vosk-model-small-en-us-0.15-compile-colab/../../../tools/openfst/lib/fst/\n",
|
||||
"++ export LC_ALL=C\n",
|
||||
"++ LC_ALL=C\n",
|
||||
"+ pip3 install phonetisaurus\n",
|
||||
"Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n",
|
||||
"Requirement already satisfied: phonetisaurus in /usr/local/lib/python3.7/dist-packages (0.3.0)\n",
|
||||
"+ rm -rf data\n",
|
||||
"+ rm -rf exp/tdnn/lgraph\n",
|
||||
"+ rm -rf exp/tdnn/lgraph_orig\n",
|
||||
"+ mkdir -p data/dict\n",
|
||||
"+ cp db/phone/extra_questions.txt db/phone/nonsilence_phones.txt db/phone/optional_silence.txt db/phone/silence_phones.txt data/dict\n",
|
||||
"+ ./dict.py\n",
|
||||
"+ python3 ./get_vocab.py\n",
|
||||
"+ ngramsymbols data/mix.vocab data/mix.syms\n",
|
||||
"+ farcompilestrings --fst_type=compact --symbols=data/mix.syms --keep_symbols '--unknown_symbol=[unk]' db/extra.txt data/extra.far\n",
|
||||
"+ ngramcount --order=3 data/extra.far -\n",
|
||||
"+ ngrammake --method=witten_bell - data/extra.mod\n",
|
||||
"+ ngramshrink --method=count_prune --count_pattern=3+:3\n",
|
||||
"+ ngramread\n",
|
||||
"+ ngramprint --integers\n",
|
||||
"+ grep -v '<unk>'\n",
|
||||
"+ ngramread --renormalize_arpa --ARPA --symbols=data/mix.syms - data/en-us.mod\n",
|
||||
"+ gunzip -c db/en-50k-0.4-android.lm.gz\n",
|
||||
"+ ngrammerge --method=bayes_model_merge --normalize --alpha=0.95 --beta=0.05 data/en-us.mod data/extra.mod data/en-us-mix.mod\n",
|
||||
"+ ngramprint --ARPA data/en-us-mix.mod\n",
|
||||
"+ gzip -c\n",
|
||||
"+ utils/prepare_lang.sh data/dict '[unk]' data/lang_local data/lang\n",
|
||||
"utils/prepare_lang.sh data/dict [unk] data/lang_local data/lang\n",
|
||||
"Checking data/dict/silence_phones.txt ...\n",
|
||||
"--> reading data/dict/silence_phones.txt\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> data/dict/silence_phones.txt is OK\n",
|
||||
"\n",
|
||||
"Checking data/dict/optional_silence.txt ...\n",
|
||||
"--> reading data/dict/optional_silence.txt\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> data/dict/optional_silence.txt is OK\n",
|
||||
"\n",
|
||||
"Checking data/dict/nonsilence_phones.txt ...\n",
|
||||
"--> reading data/dict/nonsilence_phones.txt\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> data/dict/nonsilence_phones.txt is OK\n",
|
||||
"\n",
|
||||
"Checking disjoint: silence_phones.txt, nonsilence_phones.txt\n",
|
||||
"--> disjoint property is OK.\n",
|
||||
"\n",
|
||||
"Checking data/dict/lexicon.txt\n",
|
||||
"--> reading data/dict/lexicon.txt\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> data/dict/lexicon.txt is OK\n",
|
||||
"\n",
|
||||
"Checking data/dict/extra_questions.txt ...\n",
|
||||
"--> data/dict/extra_questions.txt is empty (this is OK)\n",
|
||||
"--> SUCCESS [validating dictionary directory data/dict]\n",
|
||||
"\n",
|
||||
"**Creating data/dict/lexiconp.txt from data/dict/lexicon.txt\n",
|
||||
"fstaddselfloops data/lang/phones/wdisambig_phones.int data/lang/phones/wdisambig_words.int \n",
|
||||
"prepare_lang.sh: validating output directory\n",
|
||||
"utils/validate_lang.pl data/lang\n",
|
||||
"Checking existence of separator file\n",
|
||||
"separator file data/lang/subword_separator.txt is empty or does not exist, deal in word case.\n",
|
||||
"Checking data/lang/phones.txt ...\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> data/lang/phones.txt is OK\n",
|
||||
"\n",
|
||||
"Checking words.txt: #0 ...\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> data/lang/words.txt is OK\n",
|
||||
"\n",
|
||||
"Checking disjoint: silence.txt, nonsilence.txt, disambig.txt ...\n",
|
||||
"--> silence.txt and nonsilence.txt are disjoint\n",
|
||||
"--> silence.txt and disambig.txt are disjoint\n",
|
||||
"--> disambig.txt and nonsilence.txt are disjoint\n",
|
||||
"--> disjoint property is OK\n",
|
||||
"\n",
|
||||
"Checking sumation: silence.txt, nonsilence.txt, disambig.txt ...\n",
|
||||
"--> found no unexplainable phones in phones.txt\n",
|
||||
"\n",
|
||||
"Checking data/lang/phones/context_indep.{txt, int, csl} ...\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> 10 entry/entries in data/lang/phones/context_indep.txt\n",
|
||||
"--> data/lang/phones/context_indep.int corresponds to data/lang/phones/context_indep.txt\n",
|
||||
"--> data/lang/phones/context_indep.csl corresponds to data/lang/phones/context_indep.txt\n",
|
||||
"--> data/lang/phones/context_indep.{txt, int, csl} are OK\n",
|
||||
"\n",
|
||||
"Checking data/lang/phones/nonsilence.{txt, int, csl} ...\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> 156 entry/entries in data/lang/phones/nonsilence.txt\n",
|
||||
"--> data/lang/phones/nonsilence.int corresponds to data/lang/phones/nonsilence.txt\n",
|
||||
"--> data/lang/phones/nonsilence.csl corresponds to data/lang/phones/nonsilence.txt\n",
|
||||
"--> data/lang/phones/nonsilence.{txt, int, csl} are OK\n",
|
||||
"\n",
|
||||
"Checking data/lang/phones/silence.{txt, int, csl} ...\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> 10 entry/entries in data/lang/phones/silence.txt\n",
|
||||
"--> data/lang/phones/silence.int corresponds to data/lang/phones/silence.txt\n",
|
||||
"--> data/lang/phones/silence.csl corresponds to data/lang/phones/silence.txt\n",
|
||||
"--> data/lang/phones/silence.{txt, int, csl} are OK\n",
|
||||
"\n",
|
||||
"Checking data/lang/phones/optional_silence.{txt, int, csl} ...\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> 1 entry/entries in data/lang/phones/optional_silence.txt\n",
|
||||
"--> data/lang/phones/optional_silence.int corresponds to data/lang/phones/optional_silence.txt\n",
|
||||
"--> data/lang/phones/optional_silence.csl corresponds to data/lang/phones/optional_silence.txt\n",
|
||||
"--> data/lang/phones/optional_silence.{txt, int, csl} are OK\n",
|
||||
"\n",
|
||||
"Checking data/lang/phones/disambig.{txt, int, csl} ...\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> 14 entry/entries in data/lang/phones/disambig.txt\n",
|
||||
"--> data/lang/phones/disambig.int corresponds to data/lang/phones/disambig.txt\n",
|
||||
"--> data/lang/phones/disambig.csl corresponds to data/lang/phones/disambig.txt\n",
|
||||
"--> data/lang/phones/disambig.{txt, int, csl} are OK\n",
|
||||
"\n",
|
||||
"Checking data/lang/phones/roots.{txt, int} ...\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> 41 entry/entries in data/lang/phones/roots.txt\n",
|
||||
"--> data/lang/phones/roots.int corresponds to data/lang/phones/roots.txt\n",
|
||||
"--> data/lang/phones/roots.{txt, int} are OK\n",
|
||||
"\n",
|
||||
"Checking data/lang/phones/sets.{txt, int} ...\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> 41 entry/entries in data/lang/phones/sets.txt\n",
|
||||
"--> data/lang/phones/sets.int corresponds to data/lang/phones/sets.txt\n",
|
||||
"--> data/lang/phones/sets.{txt, int} are OK\n",
|
||||
"\n",
|
||||
"Checking data/lang/phones/extra_questions.{txt, int} ...\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> 9 entry/entries in data/lang/phones/extra_questions.txt\n",
|
||||
"--> data/lang/phones/extra_questions.int corresponds to data/lang/phones/extra_questions.txt\n",
|
||||
"--> data/lang/phones/extra_questions.{txt, int} are OK\n",
|
||||
"\n",
|
||||
"Checking data/lang/phones/word_boundary.{txt, int} ...\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> 166 entry/entries in data/lang/phones/word_boundary.txt\n",
|
||||
"--> data/lang/phones/word_boundary.int corresponds to data/lang/phones/word_boundary.txt\n",
|
||||
"--> data/lang/phones/word_boundary.{txt, int} are OK\n",
|
||||
"\n",
|
||||
"Checking optional_silence.txt ...\n",
|
||||
"--> reading data/lang/phones/optional_silence.txt\n",
|
||||
"--> data/lang/phones/optional_silence.txt is OK\n",
|
||||
"\n",
|
||||
"Checking disambiguation symbols: #0 and #1\n",
|
||||
"--> data/lang/phones/disambig.txt has \"#0\" and \"#1\"\n",
|
||||
"--> data/lang/phones/disambig.txt is OK\n",
|
||||
"\n",
|
||||
"Checking topo ...\n",
|
||||
"\n",
|
||||
"Checking word_boundary.txt: silence.txt, nonsilence.txt, disambig.txt ...\n",
|
||||
"--> data/lang/phones/word_boundary.txt doesn't include disambiguation symbols\n",
|
||||
"--> data/lang/phones/word_boundary.txt is the union of nonsilence.txt and silence.txt\n",
|
||||
"--> data/lang/phones/word_boundary.txt is OK\n",
|
||||
"\n",
|
||||
"Checking word-level disambiguation symbols...\n",
|
||||
"--> data/lang/phones/wdisambig.txt exists (newer prepare_lang.sh)\n",
|
||||
"Checking word_boundary.int and disambig.int\n",
|
||||
"--> generating a 98 word/subword sequence\n",
|
||||
"--> resulting phone sequence from L.fst corresponds to the word sequence\n",
|
||||
"--> L.fst is OK\n",
|
||||
"--> generating a 49 word/subword sequence\n",
|
||||
"--> resulting phone sequence from L_disambig.fst corresponds to the word sequence\n",
|
||||
"--> L_disambig.fst is OK\n",
|
||||
"\n",
|
||||
"Checking data/lang/oov.{txt, int} ...\n",
|
||||
"--> text seems to be UTF-8 or ASCII, checking whitespaces\n",
|
||||
"--> text contains only allowed whitespaces\n",
|
||||
"--> 1 entry/entries in data/lang/oov.txt\n",
|
||||
"--> data/lang/oov.int corresponds to data/lang/oov.txt\n",
|
||||
"--> data/lang/oov.{txt, int} are OK\n",
|
||||
"\n",
|
||||
"--> data/lang/L.fst is olabel sorted\n",
|
||||
"--> data/lang/L_disambig.fst is olabel sorted\n",
|
||||
"--> SUCCESS [validating lang directory data/lang]\n",
|
||||
"+ utils/format_lm.sh data/lang db/en-50k-0.4-android.lm.gz data/dict/lexicon.txt data/lang_test\n",
|
||||
"Converting 'db/en-50k-0.4-android.lm.gz' to FST\n",
|
||||
"arpa2fst --disambig-symbol=#0 --read-symbol-table=data/lang_test/words.txt - data/lang_test/G.fst \n",
|
||||
"LOG (arpa2fst[5.5.1046~1-76cd5]:Read():arpa-file-parser.cc:94) Reading \\data\\ section.\n",
|
||||
"LOG (arpa2fst[5.5.1046~1-76cd5]:Read():arpa-file-parser.cc:149) Reading \\1-grams: section.\n",
|
||||
"LOG (arpa2fst[5.5.1046~1-76cd5]:Read():arpa-file-parser.cc:149) Reading \\2-grams: section.\n",
|
||||
"LOG (arpa2fst[5.5.1046~1-76cd5]:Read():arpa-file-parser.cc:149) Reading \\3-grams: section.\n",
|
||||
"LOG (arpa2fst[5.5.1046~1-76cd5]:RemoveRedundantStates():arpa-lm-compiler.cc:359) Reduced num-states from 1217362 to 185036\n",
|
||||
"fstisstochastic data/lang_test/G.fst \n",
|
||||
"0.476411 -3.03779\n",
|
||||
"Succeeded in formatting LM: 'db/en-50k-0.4-android.lm.gz'\n",
|
||||
"+ utils/format_lm.sh data/lang data/en-us-mix.lm.gz data/dict/lexicon.txt data/lang_test_adapt\n",
|
||||
"Converting 'data/en-us-mix.lm.gz' to FST\n",
|
||||
"arpa2fst --disambig-symbol=#0 --read-symbol-table=data/lang_test_adapt/words.txt - data/lang_test_adapt/G.fst \n",
|
||||
"LOG (arpa2fst[5.5.1046~1-76cd5]:Read():arpa-file-parser.cc:94) Reading \\data\\ section.\n",
|
||||
"LOG (arpa2fst[5.5.1046~1-76cd5]:Read():arpa-file-parser.cc:149) Reading \\1-grams: section.\n",
|
||||
"LOG (arpa2fst[5.5.1046~1-76cd5]:Read():arpa-file-parser.cc:149) Reading \\2-grams: section.\n",
|
||||
"LOG (arpa2fst[5.5.1046~1-76cd5]:Read():arpa-file-parser.cc:149) Reading \\3-grams: section.\n",
|
||||
"LOG (arpa2fst[5.5.1046~1-76cd5]:RemoveRedundantStates():arpa-lm-compiler.cc:359) Reduced num-states from 1217646 to 185095\n",
|
||||
"fstisstochastic data/lang_test_adapt/G.fst \n",
|
||||
"6.81902e-07 -3.03779\n",
|
||||
"Succeeded in formatting LM: 'data/en-us-mix.lm.gz'\n",
|
||||
"+ utils/mkgraph.sh --self-loop-scale 1.0 data/lang_test exp/tdnn exp/tdnn/graph\n",
|
||||
"tree-info exp/tdnn/tree \n",
|
||||
"tree-info exp/tdnn/tree \n",
|
||||
"fstdeterminizestar --use-log=true \n",
|
||||
"fsttablecompose data/lang_test/L_disambig.fst data/lang_test/G.fst \n",
|
||||
"fstminimizeencoded \n",
|
||||
"fstpushspecial \n",
|
||||
"fstisstochastic data/lang_test/tmp/LG.fst \n",
|
||||
"-0.145498 -0.146281\n",
|
||||
"[info]: LG not stochastic.\n",
|
||||
"fstcomposecontext --context-size=2 --central-position=1 --read-disambig-syms=data/lang_test/phones/disambig.int --write-disambig-syms=data/lang_test/tmp/disambig_ilabels_2_1.int data/lang_test/tmp/ilabels_2_1.905 data/lang_test/tmp/LG.fst \n",
|
||||
"fstisstochastic data/lang_test/tmp/CLG_2_1.fst \n",
|
||||
"-0.145498 -0.146281\n",
|
||||
"[info]: CLG not stochastic.\n",
|
||||
"make-h-transducer --disambig-syms-out=exp/tdnn/graph/disambig_tid.int --transition-scale=1.0 data/lang_test/tmp/ilabels_2_1 exp/tdnn/tree exp/tdnn/final.mdl \n",
|
||||
"fstrmepslocal \n",
|
||||
"fsttablecompose exp/tdnn/graph/Ha.fst data/lang_test/tmp/CLG_2_1.fst \n",
|
||||
"fstdeterminizestar --use-log=true \n",
|
||||
"fstminimizeencoded \n",
|
||||
"fstrmsymbols exp/tdnn/graph/disambig_tid.int \n",
|
||||
"fstisstochastic exp/tdnn/graph/HCLGa.fst \n",
|
||||
"-0.109817 -0.571742\n",
|
||||
"HCLGa is not stochastic\n",
|
||||
"add-self-loops --self-loop-scale=1.0 --reorder=true exp/tdnn/final.mdl exp/tdnn/graph/HCLGa.fst \n",
|
||||
"fstisstochastic exp/tdnn/graph/HCLG.fst \n",
|
||||
"1.90465e-09 -0.415046\n",
|
||||
"[info]: final HCLG is not stochastic.\n",
|
||||
"+ utils/mkgraph.sh --self-loop-scale 1.0 data/lang_test_adapt exp/tdnn exp/tdnn/graph_adapt\n",
|
||||
"tree-info exp/tdnn/tree \n",
|
||||
"tree-info exp/tdnn/tree \n",
|
||||
"fstdeterminizestar --use-log=true \n",
|
||||
"fsttablecompose data/lang_test_adapt/L_disambig.fst data/lang_test_adapt/G.fst \n",
|
||||
"fstminimizeencoded \n",
|
||||
"fstpushspecial \n",
|
||||
"fstisstochastic data/lang_test_adapt/tmp/LG.fst \n",
|
||||
"-0.148474 -0.149181\n",
|
||||
"[info]: LG not stochastic.\n",
|
||||
"fstcomposecontext --context-size=2 --central-position=1 --read-disambig-syms=data/lang_test_adapt/phones/disambig.int --write-disambig-syms=data/lang_test_adapt/tmp/disambig_ilabels_2_1.int data/lang_test_adapt/tmp/ilabels_2_1.979 data/lang_test_adapt/tmp/LG.fst \n",
|
||||
"fstisstochastic data/lang_test_adapt/tmp/CLG_2_1.fst \n",
|
||||
"-0.148474 -0.149181\n",
|
||||
"[info]: CLG not stochastic.\n",
|
||||
"make-h-transducer --disambig-syms-out=exp/tdnn/graph_adapt/disambig_tid.int --transition-scale=1.0 data/lang_test_adapt/tmp/ilabels_2_1 exp/tdnn/tree exp/tdnn/final.mdl \n",
|
||||
"fstrmepslocal \n",
|
||||
"fsttablecompose exp/tdnn/graph_adapt/Ha.fst data/lang_test_adapt/tmp/CLG_2_1.fst \n",
|
||||
"fstdeterminizestar --use-log=true \n",
|
||||
"fstminimizeencoded \n",
|
||||
"fstrmsymbols exp/tdnn/graph_adapt/disambig_tid.int \n",
|
||||
"fstisstochastic exp/tdnn/graph_adapt/HCLGa.fst \n",
|
||||
"-0.113907 -0.5857\n",
|
||||
"HCLGa is not stochastic\n",
|
||||
"add-self-loops --self-loop-scale=1.0 --reorder=true exp/tdnn/final.mdl exp/tdnn/graph_adapt/HCLGa.fst \n",
|
||||
"fstisstochastic exp/tdnn/graph_adapt/HCLG.fst \n",
|
||||
"1.90465e-09 -0.423618\n",
|
||||
"[info]: final HCLG is not stochastic.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"!cat decode.sh\n",
|
||||
"!bash decode.sh"
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "Sl3QBI1MXpc-",
|
||||
"outputId": "affac8a3-782f-4000-e31f-81bfed47a37a"
|
||||
},
|
||||
"execution_count": 10,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"#!/bin/bash\n",
|
||||
"\n",
|
||||
". path.sh\n",
|
||||
"\n",
|
||||
"steps/make_mfcc.sh --nj 10 data_test/test_small exp/make_mfcc/test mfcc\n",
|
||||
"steps/compute_cmvn_stats.sh data_test/test_small exp/make_mfcc/test mfcc\n",
|
||||
"utils/fix_data_dir.sh data_test/test_small\n",
|
||||
"\n",
|
||||
"steps/online/nnet2/extract_ivectors_online.sh --nj 4 \\\n",
|
||||
" data_test/test_small exp/extractor \\\n",
|
||||
" exp/ivectors_test\n",
|
||||
"\n",
|
||||
"steps/nnet3/decode.sh --nj 4 \\\n",
|
||||
" --acwt 1.0 --post-decode-acwt 10.0 \\\n",
|
||||
" --online-ivector-dir exp/ivectors_test \\\n",
|
||||
" exp/tdnn/graph_adapt data_test/test_small exp/tdnn/decode_test_adapt\n",
|
||||
"\n",
|
||||
"steps/nnet3/decode.sh --nj 4 \\\n",
|
||||
" --acwt 1.0 --post-decode-acwt 10.0 \\\n",
|
||||
" --online-ivector-dir exp/ivectors_test \\\n",
|
||||
" exp/tdnn/graph data_test/test_small exp/tdnn/decode_test\n",
|
||||
"\n",
|
||||
"#steps/nnet3/decode_lookahead.sh --nj 4 \\\n",
|
||||
"# --acwt 1.0 --post-decode-acwt 10.0 \\\n",
|
||||
"# --online-ivector-dir exp/ivectors_test \\\n",
|
||||
"# exp/tdnn/lgraph data_test/test_small exp/tdnn/decode_test_adapt\n",
|
||||
"#steps/nnet3/decode_lookahead.sh --nj 4 \\\n",
|
||||
"# --acwt 1.0 --post-decode-acwt 10.0 \\\n",
|
||||
"# --online-ivector-dir exp/ivectors_test \\\n",
|
||||
"# exp/tdnn/lgraph_orig data_test/test_small exp/tdnn/decode_test\n",
|
||||
"steps/make_mfcc.sh --nj 10 data_test/test_small exp/make_mfcc/test mfcc\n",
|
||||
"steps/make_mfcc.sh: moving data_test/test_small/feats.scp to data_test/test_small/.backup\n",
|
||||
"utils/validate_data_dir.sh: Successfully validated data-directory data_test/test_small\n",
|
||||
"steps/make_mfcc.sh: [info]: no segments file exists: assuming wav.scp indexed by utterance.\n",
|
||||
"steps/make_mfcc.sh: Succeeded creating MFCC features for test_small\n",
|
||||
"steps/compute_cmvn_stats.sh data_test/test_small exp/make_mfcc/test mfcc\n",
|
||||
"Succeeded creating CMVN stats for test_small\n",
|
||||
"fix_data_dir.sh: kept all 50 utterances.\n",
|
||||
"fix_data_dir.sh: old files are kept in data_test/test_small/.backup\n",
|
||||
"steps/online/nnet2/extract_ivectors_online.sh --nj 4 data_test/test_small exp/extractor exp/ivectors_test\n",
|
||||
"steps/online/nnet2/extract_ivectors_online.sh: extracting iVectors\n",
|
||||
"steps/online/nnet2/extract_ivectors_online.sh: combining iVectors across jobs\n",
|
||||
"steps/online/nnet2/extract_ivectors_online.sh: done extracting (online) iVectors to exp/ivectors_test using the extractor in exp/extractor.\n",
|
||||
"steps/nnet3/decode.sh --nj 4 --acwt 1.0 --post-decode-acwt 10.0 --online-ivector-dir exp/ivectors_test exp/tdnn/graph_adapt data_test/test_small exp/tdnn/decode_test_adapt\n",
|
||||
"steps/nnet2/check_ivectors_compatible.sh: WARNING: One of the directories do not contain iVector ID.\n",
|
||||
"steps/nnet2/check_ivectors_compatible.sh: WARNING: That means it's you who's reponsible for keeping \n",
|
||||
"steps/nnet2/check_ivectors_compatible.sh: WARNING: the directories compatible\n",
|
||||
"steps/nnet3/decode.sh: feature type is raw\n",
|
||||
"steps/diagnostic/analyze_lats.sh --cmd run.pl --iter final exp/tdnn/graph_adapt exp/tdnn/decode_test_adapt\n",
|
||||
"steps/diagnostic/analyze_lats.sh: see stats in exp/tdnn/decode_test_adapt/log/analyze_alignments.log\n",
|
||||
"Overall, lattice depth (10,50,90-percentile)=(1,1,4) and mean=2.4\n",
|
||||
"steps/diagnostic/analyze_lats.sh: see stats in exp/tdnn/decode_test_adapt/log/analyze_lattice_depth_stats.log\n",
|
||||
"score best paths\n",
|
||||
"local/score.sh --cmd run.pl data_test/test_small exp/tdnn/graph_adapt exp/tdnn/decode_test_adapt\n",
|
||||
"local/score.sh: scoring with word insertion penalty=0.0,0.5,1.0\n",
|
||||
"score confidence and timing with sclite\n",
|
||||
"Decoding done.\n",
|
||||
"steps/nnet3/decode.sh --nj 4 --acwt 1.0 --post-decode-acwt 10.0 --online-ivector-dir exp/ivectors_test exp/tdnn/graph data_test/test_small exp/tdnn/decode_test\n",
|
||||
"steps/nnet2/check_ivectors_compatible.sh: WARNING: One of the directories do not contain iVector ID.\n",
|
||||
"steps/nnet2/check_ivectors_compatible.sh: WARNING: That means it's you who's reponsible for keeping \n",
|
||||
"steps/nnet2/check_ivectors_compatible.sh: WARNING: the directories compatible\n",
|
||||
"steps/nnet3/decode.sh: feature type is raw\n",
|
||||
"steps/diagnostic/analyze_lats.sh --cmd run.pl --iter final exp/tdnn/graph exp/tdnn/decode_test\n",
|
||||
"steps/diagnostic/analyze_lats.sh: see stats in exp/tdnn/decode_test/log/analyze_alignments.log\n",
|
||||
"Overall, lattice depth (10,50,90-percentile)=(1,5,23) and mean=10.4\n",
|
||||
"steps/diagnostic/analyze_lats.sh: see stats in exp/tdnn/decode_test/log/analyze_lattice_depth_stats.log\n",
|
||||
"score best paths\n",
|
||||
"local/score.sh --cmd run.pl data_test/test_small exp/tdnn/graph exp/tdnn/decode_test\n",
|
||||
"local/score.sh: scoring with word insertion penalty=0.0,0.5,1.0\n",
|
||||
"score confidence and timing with sclite\n",
|
||||
"Decoding done.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"!bash RESULTS"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "ABtcNyUDX4S8",
|
||||
"outputId": "d5e50be7-3293-4a59-94b8-9bfa46736481",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
}
|
||||
},
|
||||
"execution_count": 11,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"%WER 11.77 [ 107 / 909, 13 ins, 7 del, 87 sub ] exp/tdnn/decode_test/wer_7_1.0\n",
|
||||
"%WER 0.22 [ 2 / 909, 0 ins, 1 del, 1 sub ] exp/tdnn/decode_test_adapt/wer_10_1.0\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,23 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from vosk import Model, KaldiRecognizer, SetLogLevel
|
||||
import sys
|
||||
import os
|
||||
import wave
|
||||
import sys
|
||||
import json
|
||||
|
||||
from vosk import Model, KaldiRecognizer, SetLogLevel
|
||||
|
||||
SetLogLevel(0)
|
||||
|
||||
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)
|
||||
|
||||
wf = wave.open(sys.argv[1], "rb")
|
||||
if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE":
|
||||
print ("Audio file must be WAV format mono PCM.")
|
||||
exit (1)
|
||||
print("Audio file must be WAV format mono PCM.")
|
||||
sys.exit(1)
|
||||
|
||||
model = Model("model")
|
||||
model = Model(lang="en-us")
|
||||
rec = KaldiRecognizer(model, wf.getframerate())
|
||||
rec.SetMaxAlternatives(10)
|
||||
rec.SetWords(True)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user