chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:45:58 +08:00
commit 2dd9ea9aee
261 changed files with 32719 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
Java bindings for Vosk API using jnr-ffi
See demo project for details, build it with Gradle.
Download model and unpack as "model" folder in the demo project.
Make sure you are using recent JDK and Gradle.
+15
View File
@@ -0,0 +1,15 @@
plugins {
id 'application'
}
application {
mainClass = 'org.vosk.demo.DecoderDemo'
}
repositories {
mavenCentral()
}
dependencies {
implementation group: 'com.alphacephei', name: 'vosk', version: '0.3.75'
}
@@ -0,0 +1,38 @@
package org.vosk.demo;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.vosk.LogLevel;
import org.vosk.Recognizer;
import org.vosk.LibVosk;
import org.vosk.Model;
public class DecoderDemo {
public static void main(String[] argv) throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream("../../python/example/test.wav")));
Recognizer recognizer = new Recognizer(model, 16000)) {
int nbytes;
byte[] b = new byte[4096];
while ((nbytes = ais.read(b)) >= 0) {
if (recognizer.acceptWaveForm(b, nbytes)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
}
}
+71
View File
@@ -0,0 +1,71 @@
buildscript {
repositories {
mavenCentral()
}
}
plugins {
id 'java-library'
id 'maven-publish'
id 'com.vanniktech.maven.publish' version '0.18.0'
}
repositories {
mavenCentral()
}
archivesBaseName = 'vosk'
group = 'com.alphacephei'
version = '0.3.75'
mavenPublish {
group = 'com.alphacephei'
version = version
sonatypeHost = 's01'
}
dependencies {
api group: 'net.java.dev.jna', name: 'jna', version: '5.18.1'
testImplementation 'junit:junit:4.13'
}
publishing {
publications {
mavenJava(MavenPublication) {
artifactId = 'vosk'
from components.java
pom {
name = 'Vosk'
description = 'Speech recognition library'
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 = '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/'
}
}
}
}
}
test {
dependsOn cleanTest
testLogging.showStandardStreams = true
}
java {
withSourcesJar()
withJavadocJar()
}
@@ -0,0 +1,108 @@
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.InputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
public class LibVosk {
private static void unpackDll(File targetDir, String lib) throws IOException {
try (InputStream source = LibVosk.class.getResourceAsStream("/win32-x86-64/" + lib + ".dll")) {
Files.copy(source, new File(targetDir, lib + ".dll").toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}
static {
if (Platform.isWindows()) {
// 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", LibVosk.class.getClassLoader());
File tmpDir = tmpFile.getParentFile();
new File(tmpDir, tmpFile.getName() + ".x").createNewFile();
// Now unpack dependencies
unpackDll(tmpDir, "libwinpthread-1");
unpackDll(tmpDir, "libgcc_s_seh-1");
unpackDll(tmpDir, "libstdc++-6");
} catch (IOException e) {
// Nothing for now, it will fail on next step
} finally {
Native.register(LibVosk.class, "libvosk");
}
} else {
Native.register(LibVosk.class, "vosk");
}
}
public static native void vosk_set_log_level(int level);
public static native Pointer vosk_model_new(String path);
public static native void vosk_model_free(Pointer model);
public static native Pointer vosk_spk_model_new(String path);
public static native void vosk_spk_model_free(Pointer model);
public static native Pointer vosk_recognizer_new(Model model, float sample_rate);
public static native Pointer vosk_recognizer_new_spk(Pointer model, float sample_rate, Pointer spk_model);
public static native Pointer vosk_recognizer_new_grm(Pointer model, float sample_rate, String grammar);
public static native void vosk_recognizer_set_max_alternatives(Pointer recognizer, int max_alternatives);
public static native void vosk_recognizer_set_words(Pointer recognizer, boolean words);
public static native void vosk_recognizer_set_partial_words(Pointer recognizer, boolean partial_words);
public static native void vosk_recognizer_set_spk_model(Pointer recognizer, Pointer spk_model);
public static native boolean vosk_recognizer_accept_waveform(Pointer recognizer, byte[] data, int len);
public static native boolean vosk_recognizer_accept_waveform_s(Pointer recognizer, short[] data, int len);
public static native boolean vosk_recognizer_accept_waveform_f(Pointer recognizer, float[] data, int len);
public static native String vosk_recognizer_result(Pointer recognizer);
public static native String vosk_recognizer_final_result(Pointer recognizer);
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_set_endpointer_mode(Pointer recognizer, int mode);
public static native void vosk_recognizer_set_endpointer_delays(Pointer recognizer, float t_start_max, float t_end, float t_max);
public static native void vosk_recognizer_free(Pointer recognizer);
public static native Pointer vosk_text_processor_new(String verbalizer, String tagger);
public static native void vosk_text_processor_free(Pointer processor);
public static native String vosk_text_processor_itn(Pointer processor, String input);
/**
* 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());
}
}
@@ -0,0 +1,17 @@
package org.vosk;
public enum LogLevel {
WARNINGS(-1), // Print warning and errors
INFO(0), // Print info, along with warning and error messages, but no debug
DEBUG(1); // Print debug info
private final int value;
LogLevel(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
@@ -0,0 +1,22 @@
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) throws IOException {
super(LibVosk.vosk_model_new(path));
if (getPointer() == null) {
throw new IOException("Failed to create a model");
}
}
@Override
public void close() {
LibVosk.vosk_model_free(this.getPointer());
}
}
@@ -0,0 +1,275 @@
package org.vosk;
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));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* 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");
}
}
/**
* 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);
}
public boolean acceptWaveForm(short[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform_s(this.getPointer(), data, len);
}
public boolean acceptWaveForm(float[] data, int len) {
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());
}
/**
* Endpointer delay mode
*/
public class EndpointerMode {
public static final int DEFAULT = 0;
public static final int SHORT = 1;
public static final int LONG = 2;
public static final int VERY_LONG = 3;
}
/**
* Configures endpointer mode for recognizer
*/
public void setEndpointerMode(int mode) {
LibVosk.vosk_recognizer_set_endpointer_mode(this.getPointer(), mode);
}
/**
* Set endpointer delays
*
* @param t_start_max timeout for stopping recognition in case of initial silence (usually around 5.0)
* @param t_end timeout for stopping recognition in milliseconds after we recognized something (usually around 0.5 - 1.0)
* @param t_max timeout for forcing utterance end in milliseconds (usually around 20-30)
**/
public void setEndpointerDelays(float t_start_max, float t_end, float t_max) {
LibVosk.vosk_recognizer_set_endpointer_delays(this.getPointer(), t_start_max, t_end, t_max);
}
/**
* Releases recognizer object.
* Underlying model is also unreferenced and if needed, released.
*/
@Override
public void close() {
LibVosk.vosk_recognizer_free(this.getPointer());
}
}
@@ -0,0 +1,40 @@
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));
if (getPointer() == null) {
throw new IOException("Failed to create a speaker model");
}
}
@Override
public void close() {
LibVosk.vosk_spk_model_free(this.getPointer());
}
}
+1
View File
@@ -0,0 +1 @@
Mainly for work around JNA API
@@ -0,0 +1,120 @@
package org.vosk.test;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.junit.Test;
import org.junit.Assert;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.vosk.LogLevel;
import org.vosk.Recognizer;
import org.vosk.Recognizer.EndpointerMode;
import org.vosk.LibVosk;
import org.vosk.Model;
import org.vosk.TextProcessor;
public class DecoderTest {
@Test
public void decoderTest() throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream("../../python/example/test.wav")));
Recognizer recognizer = new Recognizer(model, 16000)) {
recognizer.setMaxAlternatives(10);
recognizer.setWords(true);
recognizer.setPartialWords(true);
int nbytes;
byte[] b = new byte[4096];
while ((nbytes = ais.read(b)) >= 0) {
if (recognizer.acceptWaveForm(b, nbytes)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
Assert.assertTrue(true);
}
@Test
public void decoderTestShort() throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream("../../python/example/test.wav")));
Recognizer recognizer = new Recognizer(model, 16000)) {
int nbytes;
byte[] b = new byte[4096];
short[] s = new short[2048];
while ((nbytes = ais.read(b)) >= 0) {
ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(s);
if (recognizer.acceptWaveForm(s, nbytes / 2)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
Assert.assertTrue(true);
}
@Test
public void decoderTestGrammar() throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream("../../python/example/test.wav")));
Recognizer recognizer = new Recognizer(model, 16000, "[\"one two three four five six seven eight nine zero oh\"]")) {
int nbytes;
byte[] b = new byte[4096];
while ((nbytes = ais.read(b)) >= 0) {
if (recognizer.acceptWaveForm(b, nbytes)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
Assert.assertTrue(true);
}
@Test
public void decoderEndpointerDelays() throws IOException, UnsupportedAudioFileException {
try (Model model = new Model("model");
Recognizer recognizer = new Recognizer(model, 16000)) {
recognizer.setEndpointerMode(EndpointerMode.VERY_LONG);
recognizer.setEndpointerDelays(5.0f, 3.0f, 50.0f);
}
Assert.assertTrue(true);
}
@Test(expected = IOException.class)
public void decoderTestException() throws IOException {
Model model = new Model("model_missing");
}
@Test
public void testItn() throws IOException {
TextProcessor p = new TextProcessor("model/itn/en_itn_tagger.fst", "model/itn/en_itn_verbalizer.fst");
System.out.println(p.itn("as easy as one two three"));
}
}