Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fc584f266d | |||
| ad6bbd3331 | |||
| 2dd9ea9aee |
@@ -10,6 +10,7 @@ gradlew
|
||||
gradlew.bat
|
||||
gradle
|
||||
local.properties
|
||||
gradle.properties
|
||||
|
||||
# Android
|
||||
android/build
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
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
|
||||
src/postprocessor.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})
|
||||
@@ -0,0 +1,27 @@
|
||||
# Vosk Speech Recognition Toolkit
|
||||
|
||||
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, 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++, Rust, Go and others.
|
||||
|
||||
Vosk supplies speech recognition for chatbots, smart home appliances,
|
||||
virtual assistants. It can also create subtitles for movies,
|
||||
transcription for lectures and interviews.
|
||||
|
||||
Vosk scales from small devices like Raspberry Pi or Android smartphone to
|
||||
big clusters.
|
||||
|
||||
# Documentation
|
||||
|
||||
For installation instructions, examples and documentation visit [Vosk
|
||||
Website](https://alphacephei.com/vosk).
|
||||
@@ -1,26 +1,21 @@
|
||||
# About
|
||||
<!-- WEHUB_ZH_README -->
|
||||
> [!NOTE]
|
||||
> 本文档由 WeHub 基于上游 README 翻译整理,属于社区翻译,非官方中文文档。
|
||||
> [English](./README.en.md) · [原始项目](https://github.com/alphacep/vosk-api) · [上游 README](https://github.com/alphacep/vosk-api/blob/HEAD/README.md)
|
||||
> 原作者、版权与许可证归属以原始项目及本仓库 LICENSE 文件为准。
|
||||
|
||||
Vosk is an offline open source speech recognition toolkit. It enables
|
||||
speech recognition models for 18 languages and dialects - English, Indian
|
||||
English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish,
|
||||
Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino,
|
||||
Ukrainian.
|
||||
# Vosk Speech Recognition Toolkit
|
||||
|
||||
Vosk models are small (50 Mb) but provide continuous large vocabulary
|
||||
transcription, zero-latency response with streaming API, reconfigurable
|
||||
vocabulary and speaker identification.
|
||||
Vosk 是一款离线开源语音识别工具包。它支持 20 多种语言及方言的语音识别——英语、印度英语、德语、法语、西班牙语、葡萄牙语、中文、俄语、土耳其语、越南语、意大利语、荷兰语、加泰罗尼亚语、阿拉伯语、希腊语、波斯语、菲律宾语、乌克兰语、哈萨克语、瑞典语、日语、世界语、印地语、捷克语、波兰语。更多语言即将推出。
|
||||
|
||||
Speech recognition bindings implemented for various programming languages
|
||||
like Python, Java, Node.JS, C#, C++ and others.
|
||||
Vosk 模型体积小(50 Mb),但可提供连续大词汇量转写、通过流式 API(streaming API)实现零延迟响应、可重新配置的词汇表以及说话人识别。
|
||||
|
||||
Vosk supplies speech recognition for chatbots, smart home appliances,
|
||||
virtual assistants. It can also create subtitles for movies,
|
||||
transcription for lectures and interviews.
|
||||
已为 Python、Java、Node.JS、C#、C++、Rust、Go 等多种编程语言实现语音识别绑定。
|
||||
|
||||
Vosk scales from small devices like Raspberry Pi or Android smartphone to
|
||||
big clusters.
|
||||
Vosk 为聊天机器人、智能家居设备、虚拟助手提供语音识别,还可为电影生成字幕,为讲座和访谈提供转写。
|
||||
|
||||
# Documentation
|
||||
Vosk 的部署规模可从小型设备(如 Raspberry Pi 或 Android 智能手机)扩展到大型集群。
|
||||
|
||||
For installation instructions, examples and documentation visit [Vosk
|
||||
Website](https://alphacephei.com/vosk).
|
||||
# 文档
|
||||
|
||||
有关安装说明、示例和文档,请访问 [Vosk 网站](https://alphacephei.com/vosk).
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# WeHub 来源说明
|
||||
|
||||
- 原始项目:`alphacep/vosk-api`
|
||||
- 原始仓库:https://github.com/alphacep/vosk-api
|
||||
- 导入方式:上游默认分支的最新快照
|
||||
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
|
||||
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
|
||||
+28
-33
@@ -1,57 +1,52 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||
classpath 'com.android.tools.build:gradle:8.13.0'
|
||||
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.34.0'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
version = '0.3.30'
|
||||
version = '0.3.75'
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'com.vanniktech.maven.publish'
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
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()
|
||||
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'
|
||||
}
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
url = "$rootDir/repo"
|
||||
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/'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+30
-19
@@ -29,7 +29,7 @@ set -x
|
||||
OS_NAME=`echo $(uname -s) | tr '[:upper:]' '[:lower:]'`
|
||||
ANDROID_TOOLCHAIN_PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/${OS_NAME}-x86_64
|
||||
WORKDIR_BASE=`pwd`/build
|
||||
PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/${OS_NAME}-x86_64/bin
|
||||
PATH=$ANDROID_TOOLCHAIN_PATH/bin:$PATH
|
||||
OPENFST_VERSION=1.8.0
|
||||
|
||||
for arch in armeabi-v7a arm64-v8a x86_64 x86; do
|
||||
@@ -40,34 +40,43 @@ case $arch in
|
||||
armeabi-v7a)
|
||||
BLAS_ARCH=ARMV7
|
||||
HOST=arm-linux-androideabi
|
||||
AR=arm-linux-androideabi-ar
|
||||
AR=llvm-ar
|
||||
RANLIB=llvm-ranlib
|
||||
CC=armv7a-linux-androideabi21-clang
|
||||
CXX=armv7a-linux-androideabi21-clang++
|
||||
ARCHFLAGS="-mfloat-abi=softfp -mfpu=neon"
|
||||
PAGESIZE_LDFLAGS=""
|
||||
;;
|
||||
arm64-v8a)
|
||||
BLAS_ARCH=ARMV8
|
||||
HOST=aarch64-linux-android
|
||||
AR=aarch64-linux-android-ar
|
||||
AR=llvm-ar
|
||||
RANLIB=llvm-ranlib
|
||||
CC=aarch64-linux-android21-clang
|
||||
CXX=aarch64-linux-android21-clang++
|
||||
ARCHFLAGS=""
|
||||
# Ensure compatibility with 16KiB page size devices
|
||||
PAGESIZE_LDFLAGS="-Wl,-z,common-page-size=4096 -Wl,-z,max-page-size=16384"
|
||||
;;
|
||||
x86_64)
|
||||
BLAS_ARCH=ATOM
|
||||
HOST=x86_64-linux-android
|
||||
AR=x86_64-linux-android-ar
|
||||
AR=llvm-ar
|
||||
RANLIB=llvm-ranlib
|
||||
CC=x86_64-linux-android21-clang
|
||||
CXX=x86_64-linux-android21-clang++
|
||||
ARCHFLAGS=""
|
||||
PAGESIZE_LDFLAGS=""
|
||||
;;
|
||||
x86)
|
||||
BLAS_ARCH=ATOM
|
||||
HOST=i686-linux-android
|
||||
AR=i686-linux-android-ar
|
||||
AR=llvm-ar
|
||||
RANLIB=llvm-ranlib
|
||||
CC=i686-linux-android21-clang
|
||||
CXX=i686-linux-android21-clang++
|
||||
ARCHFLAGS=""
|
||||
PAGESIZE_LDFLAGS=""
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -75,16 +84,16 @@ mkdir -p $WORKDIR/local/lib
|
||||
|
||||
# openblas first
|
||||
cd $WORKDIR
|
||||
git clone -b v0.3.13 --single-branch https://github.com/xianyi/OpenBLAS
|
||||
make -C OpenBLAS TARGET=$BLAS_ARCH ONLY_CBLAS=1 AR=$AR CC=$CC HOSTCC=gcc ARM_SOFTFP_ABI=1 USE_THREAD=0 NUM_THREADS=1 -j4
|
||||
git clone -b v0.3.20 --single-branch https://github.com/xianyi/OpenBLAS
|
||||
make -C OpenBLAS TARGET=$BLAS_ARCH ONLY_CBLAS=1 AR=$AR CC=$CC HOSTCC=gcc ARM_SOFTFP_ABI=1 USE_THREAD=0 NUM_THREADS=1 -j 8
|
||||
make -C OpenBLAS install PREFIX=$WORKDIR/local
|
||||
|
||||
# CLAPACK
|
||||
cd $WORKDIR
|
||||
git clone -b v3.2.1 --single-branch https://github.com/alphacep/clapack
|
||||
mkdir -p clapack/BUILD && cd clapack/BUILD
|
||||
cmake -DCMAKE_C_FLAGS=$ARCHFLAGS -DCMAKE_C_COMPILER_TARGET=$HOST \
|
||||
-DCMAKE_C_COMPILER=$CC -DCMAKE_SYSTEM_NAME=Generic -DCMAKE_AR=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/${OS_NAME}-x86_64/bin/$AR \
|
||||
cmake -DCMAKE_C_FLAGS="$ARCHFLAGS" -DCMAKE_C_COMPILER_TARGET=$HOST \
|
||||
-DCMAKE_C_COMPILER=$CC -DCMAKE_SYSTEM_NAME=Generic -DCMAKE_AR=$ANDROID_TOOLCHAIN_PATH/bin/$AR \
|
||||
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
|
||||
-DCMAKE_CROSSCOMPILING=True ..
|
||||
make -j 8 -C F2CLIBS/libf2c
|
||||
@@ -105,25 +114,27 @@ make install
|
||||
|
||||
# Kaldi itself
|
||||
cd $WORKDIR
|
||||
git clone -b android-mix --single-branch https://github.com/alphacep/kaldi
|
||||
git clone -b vosk-android --single-branch https://github.com/alphacep/kaldi
|
||||
cd $WORKDIR/kaldi/src
|
||||
CXX=$CXX CXXFLAGS="$ARCHFLAGS -O3 -DFST_NO_DYNAMIC_LINKING" ./configure --use-cuda=no \
|
||||
CXX=$CXX AR=$AR RANLIB=$RANLIB CXXFLAGS="$ARCHFLAGS -O3 -DFST_NO_DYNAMIC_LINKING" ./configure --use-cuda=no \
|
||||
--mathlib=OPENBLAS_CLAPACK --shared \
|
||||
--android-incdir=${ANDROID_TOOLCHAIN_PATH}/sysroot/usr/include \
|
||||
--host=$HOST --openblas-root=${WORKDIR}/local \
|
||||
--fst-root=${WORKDIR}/local --fst-version=${OPENFST_VERSION}
|
||||
make -j 8 depend
|
||||
cd $WORKDIR/kaldi/src
|
||||
make -j 8 online2 lm rnnlm
|
||||
make -j 8 online2 rnnlm
|
||||
|
||||
# Vosk-api
|
||||
cd $WORKDIR
|
||||
#rm -rf vosk-api
|
||||
git clone -b master --single-branch https://github.com/alphacep/vosk-api
|
||||
cd vosk-api/src
|
||||
make -j 8 KALDI_ROOT=${WORKDIR}/kaldi OPENFST_ROOT=${WORKDIR}/local OPENBLAS_ROOT=${WORKDIR}/local CXX=$CXX EXTRA_LDFLAGS="-llog -static-libstdc++"
|
||||
|
||||
# Copy JNI library to sources
|
||||
cp $WORKDIR/vosk-api/src/libvosk.so $WORKDIR/../../src/main/jniLibs/$arch/libvosk.so
|
||||
mkdir -p $WORKDIR/vosk
|
||||
make -j 8 -C ${WORKDIR_BASE}/../../../src \
|
||||
OUTDIR=$WORKDIR/vosk \
|
||||
KALDI_ROOT=${WORKDIR}/kaldi \
|
||||
OPENFST_ROOT=${WORKDIR}/local \
|
||||
OPENBLAS_ROOT=${WORKDIR}/local \
|
||||
CXX=$CXX \
|
||||
EXTRA_LDFLAGS="-llog -static-libstdc++ -Wl,-soname,libvosk.so ${PAGESIZE_LDFLAGS}"
|
||||
cp $WORKDIR/vosk/libvosk.so $WORKDIR/../../src/main/jniLibs/$arch/libvosk.so
|
||||
|
||||
done
|
||||
|
||||
+12
-15
@@ -3,13 +3,15 @@ def pomName = "Vosk Android"
|
||||
def pomDescription = "Vosk speech recognition library for Android"
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
namespace 'org.vosk'
|
||||
compileSdkVersion 36
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
versionCode 6
|
||||
targetSdkVersion 36
|
||||
versionCode 10
|
||||
versionName = version
|
||||
archivesBaseName = archiveName
|
||||
ndkVersion = "28.2.13676358"
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
@@ -19,24 +21,19 @@ android {
|
||||
|
||||
task buildVosk(type: Exec) {
|
||||
commandLine './build-vosk.sh'
|
||||
environment ANDROID_NDK_HOME: android.getSdkDirectory()
|
||||
environment ANDROID_NDK_HOME: android.getNdkDirectory()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'net.java.dev.jna:jna:4.4.0@aar'
|
||||
api 'net.java.dev.jna:jna:5.18.1@aar'
|
||||
}
|
||||
|
||||
//preBuild.dependsOn buildVosk
|
||||
|
||||
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 +0,0 @@
|
||||
include 'model-en'
|
||||
@@ -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>
|
||||
@@ -36,6 +36,8 @@ public class LibVosk {
|
||||
|
||||
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);
|
||||
@@ -50,10 +52,30 @@ 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_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());
|
||||
}
|
||||
|
||||
@@ -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,32 +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);
|
||||
}
|
||||
@@ -39,22 +170,104 @@ 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());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.vosk;
|
||||
|
||||
import com.sun.jna.PointerType;
|
||||
|
||||
public class TextProcessor extends PointerType implements AutoCloseable {
|
||||
public TextProcessor() {
|
||||
}
|
||||
|
||||
public TextProcessor(String verbalizer, String tagger) {
|
||||
super(LibVosk.vosk_text_processor_new(verbalizer, tagger));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
LibVosk.vosk_text_processor_free(this.getPointer());
|
||||
}
|
||||
|
||||
public String itn(String input) {
|
||||
return LibVosk.vosk_text_processor_itn(this.getPointer(), input);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -65,6 +66,51 @@ public class SpeechService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates speech service with a caller-supplied {@link AudioRecord}.
|
||||
* <p>
|
||||
* Use this when you need to control the audio input device - for example,
|
||||
* to pin recording to the built-in microphone when an external USB device
|
||||
* without a microphone is present:
|
||||
* <pre>
|
||||
* AudioRecord recorder = new AudioRecord.Builder()
|
||||
* .setAudioSource(MediaRecorder.AudioSource.VOICE_RECOGNITION)
|
||||
* .setAudioFormat(format)
|
||||
* .build();
|
||||
* if (Build.VERSION.SDK_INT >= 28) {
|
||||
* AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
* for (AudioDeviceInfo d : am.getDevices(AudioManager.GET_DEVICES_INPUTS)) {
|
||||
* if (d.getType() == AudioDeviceInfo.TYPE_BUILTIN_MIC) {
|
||||
* recorder.setPreferredDevice(d);
|
||||
* break;
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* SpeechService service = new SpeechService(recognizer, 16000f, recorder);
|
||||
* </pre>
|
||||
* <p>
|
||||
* The caller retains ownership of {@code recorder}: if this constructor
|
||||
* throws, the recorder is <em>not</em> released. Call
|
||||
* {@link AudioRecord#release()} yourself in that case.
|
||||
*
|
||||
* @param recognizer the Vosk recognizer
|
||||
* @param sampleRate sample rate in Hz; must match {@code recorder}'s configuration
|
||||
* @param recorder a fully-initialised {@link AudioRecord}
|
||||
* @throws IOException if {@code recorder} is in STATE_UNINITIALIZED
|
||||
*/
|
||||
public SpeechService(Recognizer recognizer, float sampleRate, AudioRecord recorder)
|
||||
throws IOException {
|
||||
this.recognizer = recognizer;
|
||||
this.sampleRate = (int) sampleRate;
|
||||
this.recorder = recorder;
|
||||
|
||||
bufferSize = Math.round(this.sampleRate * BUFFER_SIZE_SECONDS);
|
||||
|
||||
if (recorder.getState() == AudioRecord.STATE_UNINITIALIZED) {
|
||||
throw new IOException(
|
||||
"Failed to initialize recorder. Microphone might be already in use.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts recognition. Does nothing if recognition is active.
|
||||
@@ -136,6 +182,19 @@ public class SpeechService {
|
||||
return stopRecognizerThread();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the audio session ID of the underlying {@link AudioRecord}.
|
||||
* <p>
|
||||
* The session ID can be used to attach audio effects such as
|
||||
* {@link android.media.audiofx.NoiseSuppressor} to the recording session.
|
||||
*
|
||||
* @return audio session ID, or {@link AudioRecord#ERROR} if unavailable
|
||||
*/
|
||||
public int getAudioSessionId() {
|
||||
return recorder.getAudioSessionId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the recognizer and release the recorder
|
||||
*/
|
||||
|
||||
@@ -3,11 +3,12 @@ def pomName = "Vosk English Model"
|
||||
def pomDescription = "Small English model for Android"
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
namespace "org.vosk"
|
||||
compileSdkVersion 36
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
versionCode 6
|
||||
targetSdkVersion 36
|
||||
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>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
US English model for mobile Vosk applications
|
||||
|
||||
Copyright 2020 Alpha Cephei Inc
|
||||
|
||||
Accuracy: 10.38 (tedlium test) 9.85 (librispeech test-clean)
|
||||
Speed: 0.11xRT (desktop)
|
||||
Latency: 0.15s (right context)
|
||||
+4
-4
@@ -1,16 +1,16 @@
|
||||
CFLAGS=-I../src
|
||||
LDFLAGS=-L../src -lvosk -ldl -lpthread -Wl,-rpath=../src
|
||||
LDFLAGS=-L../src -lvosk -ldl -lpthread -Wl,-rpath,../src
|
||||
|
||||
all: test_vosk test_vosk_speaker
|
||||
|
||||
test_vosk: test_vosk.o
|
||||
g++ $^ -o $@ $(LDFLAGS)
|
||||
gcc $^ -o $@ $(LDFLAGS)
|
||||
|
||||
test_vosk_speaker: test_vosk_speaker.o
|
||||
g++ $^ -o $@ $(LDFLAGS)
|
||||
gcc $^ -o $@ $(LDFLAGS)
|
||||
|
||||
%.o: %.c
|
||||
g++ $(CFLAGS) -c -o $@ $<
|
||||
gcc $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a test_vosk test_vosk_speaker
|
||||
|
||||
@@ -28,13 +28,16 @@ public class VoskDemo
|
||||
{
|
||||
// Demo float array
|
||||
VoskRecognizer rec = new VoskRecognizer(model, 16000.0f);
|
||||
|
||||
rec.SetEndpointerMode(EndpointerMode.LONG);
|
||||
|
||||
using(Stream source = File.OpenRead("test.wav")) {
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
|
||||
float[] fbuffer = new float[bytesRead / 2];
|
||||
for (int i = 0, n = 0; i < fbuffer.Length; i++, n+=2) {
|
||||
fbuffer[i] = (short)(buffer[n] | buffer[n+1] << 8);
|
||||
fbuffer[i] = BitConverter.ToInt16(buffer, n);
|
||||
}
|
||||
if (rec.AcceptWaveform(fbuffer, fbuffer.Length)) {
|
||||
Console.WriteLine(rec.Result());
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>VoskDemo</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Vosk" Version="0.3.30" />
|
||||
<PackageReference Include="Vosk" Version="0.3.75" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PackageId>Vosk</PackageId>
|
||||
<Version>0.3.75</Version>
|
||||
<authors>Alpha Cephei Inc</authors>
|
||||
<owners>Alpha Cephei Inc</owners>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="CopyFiles" AfterTargets="Build">
|
||||
<Copy SourceFiles="bin/Release/net8.0/Vosk.dll" DestinationFolder="lib/net8.0" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
@@ -2,13 +2,14 @@
|
||||
<package>
|
||||
<metadata>
|
||||
<id>Vosk</id>
|
||||
<version>0.3.30</version>
|
||||
<version>0.3.75</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,13 +19,14 @@ 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"/>
|
||||
<group targetFramework="net8.0"/>
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="**" exclude="src/*.cs;build.sh;**/.keep-me;*.nupkg" />
|
||||
<file src="**" exclude="bin/**;obj/**;build.sh;src/*.cs;*.nupkg;**/.keep-me" />
|
||||
</files>
|
||||
</package>
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
mcs -out:lib/netstandard2.0/Vosk.dll -target:library src/*.cs
|
||||
nuget pack
|
||||
rm -rf bin lib obj
|
||||
/home/shmyrev/local/dotnet/dotnet pack Vosk.csproj -p:NuspecFile=Vosk.nuspec -o .
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,7 +32,7 @@ public class Model : global::System.IDisposable {
|
||||
public Model(string model_path) : this(VoskPINVOKE.new_Model(model_path)) {
|
||||
}
|
||||
|
||||
public int vosk_model_find_word(string word) {
|
||||
public int FindWord(string word) {
|
||||
return VoskPINVOKE.Model_vosk_model_find_word(handle, word);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,9 @@ class VoskPINVOKE {
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_set_words")]
|
||||
public static extern void VoskRecognizer_SetWords(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_set_partial_words")]
|
||||
public static extern void VoskRecognizer_SetPartialWords(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_set_spk_model")]
|
||||
public static extern void VoskRecognizer_SetSpkModel(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2);
|
||||
|
||||
@@ -62,6 +65,12 @@ class VoskPINVOKE {
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_reset")]
|
||||
public static extern void VoskRecognizer_Reset(global::System.Runtime.InteropServices.HandleRef jarg1);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_set_endpointer_mode")]
|
||||
public static extern void VoskRecognizer_SetEndpointerMode(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_set_endpointer_delays")]
|
||||
public static extern void VoskRecognizer_SetEndpointerDelays(global::System.Runtime.InteropServices.HandleRef jarg1, float jarg2, float jarg3, float jarg4);
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_set_log_level")]
|
||||
public static extern void SetLogLevel(int jarg1);
|
||||
|
||||
@@ -70,6 +79,40 @@ 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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
namespace Vosk {
|
||||
|
||||
public enum EndpointerMode {
|
||||
DEFAULT = 0,
|
||||
SHORT = 1,
|
||||
LONG = 2,
|
||||
VERY_LONG = 3
|
||||
}
|
||||
|
||||
public class VoskRecognizer : System.IDisposable {
|
||||
private System.Runtime.InteropServices.HandleRef handle;
|
||||
|
||||
@@ -46,6 +53,10 @@ public class VoskRecognizer : System.IDisposable {
|
||||
VoskPINVOKE.VoskRecognizer_SetWords(handle, words ? 1 : 0);
|
||||
}
|
||||
|
||||
public void SetPartialWords(bool partial_words) {
|
||||
VoskPINVOKE.VoskRecognizer_SetPartialWords(handle, partial_words ? 1 : 0);
|
||||
}
|
||||
|
||||
public void SetSpkModel(SpkModel spk_model) {
|
||||
VoskPINVOKE.VoskRecognizer_SetSpkModel(handle, SpkModel.getCPtr(spk_model));
|
||||
}
|
||||
@@ -87,6 +98,14 @@ public class VoskRecognizer : System.IDisposable {
|
||||
VoskPINVOKE.VoskRecognizer_Reset(handle);
|
||||
}
|
||||
|
||||
public void SetEndpointerMode(EndpointerMode mode) {
|
||||
VoskPINVOKE.VoskRecognizer_SetEndpointerMode(handle, (int) mode);
|
||||
}
|
||||
|
||||
public void SetEndpointerDelays(float t_start_max, float t_end, float t_max) {
|
||||
VoskPINVOKE.VoskRecognizer_SetEndpointerDelays(handle, t_start_max, t_end, t_max);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. this License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
@@ -0,0 +1 @@
|
||||
See example subfolder for instructions how to use the module
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
package vosk
|
||||
|
||||
// #cgo CPPFLAGS: -I ${SRCDIR}/../src
|
||||
// #cgo !windows LDFLAGS: -L ${SRCDIR}/../src -lvosk -ldl -lpthread
|
||||
// #cgo windows LDFLAGS: -L ${SRCDIR}/../src -lvosk -lpthread
|
||||
// #include <stdlib.h>
|
||||
// #include <vosk_api.h>
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
// VoskBatchModel contains a reference to the C VoskBatchModel
|
||||
type VoskBatchModel struct {
|
||||
model *C.struct_VoskBatchModel
|
||||
}
|
||||
|
||||
// NewBatchModel creates a new VoskBatchModel instance
|
||||
func NewBatchModel(modelPath string) (*VoskBatchModel, error) {
|
||||
cmodelPath := C.CString(modelPath)
|
||||
defer C.free(unsafe.Pointer(cmodelPath))
|
||||
internal := C.vosk_batch_model_new(cmodelPath)
|
||||
model := &VoskBatchModel{model: internal}
|
||||
return model, nil
|
||||
}
|
||||
|
||||
func (m *VoskBatchModel) Free() {
|
||||
C.vosk_batch_model_free(m.model)
|
||||
}
|
||||
|
||||
func (m *VoskBatchModel) Wait() {
|
||||
C.vosk_batch_model_wait(m.model);
|
||||
}
|
||||
|
||||
func freeBatchModel(model *VoskBatchModel) {
|
||||
C.vosk_batch_model_free(model.model)
|
||||
}
|
||||
|
||||
// VoskBatchRecognizer contains a reference to the C VoskBatchRecognizer
|
||||
type VoskBatchRecognizer struct {
|
||||
rec *C.struct_VoskBatchRecognizer
|
||||
}
|
||||
|
||||
func freeBatchRecognizer(recognizer *VoskBatchRecognizer) {
|
||||
C.vosk_batch_recognizer_free(recognizer.rec)
|
||||
}
|
||||
|
||||
func (r *VoskBatchRecognizer) Free() {
|
||||
C.vosk_batch_recognizer_free(r.rec)
|
||||
}
|
||||
|
||||
// NewBatchRecognizer creates a new VoskBatchRecognizer instance
|
||||
func NewBatchRecognizer(model *VoskBatchModel, sampleRate float64) (*VoskBatchRecognizer, error) {
|
||||
internal := C.vosk_batch_recognizer_new(model.model, C.float(sampleRate))
|
||||
rec := &VoskBatchRecognizer{rec: internal}
|
||||
return rec, nil
|
||||
}
|
||||
|
||||
// AcceptWaveform accepts and processes a new chunk of the voice data.
|
||||
func (r *VoskBatchRecognizer) AcceptWaveform(buffer []byte) {
|
||||
cbuf := C.CBytes(buffer)
|
||||
defer C.free(cbuf)
|
||||
C.vosk_batch_recognizer_accept_waveform(r.rec, (*C.char)(cbuf), C.int(len(buffer)))
|
||||
}
|
||||
|
||||
/** Set NLSML output
|
||||
* @param nlsml - boolean value
|
||||
*/
|
||||
//void vosk_batch_recognizer_set_nlsml(VoskBatchRecognizer *recognizer, int nlsml);
|
||||
|
||||
func (r *VoskBatchRecognizer) SetNlsml(nlsml int) {
|
||||
C.vosk_batch_recognizer_set_nlsml(r.rec, C.int(nlsml))
|
||||
}
|
||||
|
||||
/** Closes the stream */
|
||||
//void vosk_batch_recognizer_finish_stream(VoskBatchRecognizer *recognizer);
|
||||
|
||||
func (r *VoskBatchRecognizer) FinishStream() {
|
||||
C.vosk_batch_recognizer_finish_stream(r.rec)
|
||||
}
|
||||
|
||||
/** Return results */
|
||||
//const char *vosk_batch_recognizer_front_result(VoskBatchRecognizer *recognizer);
|
||||
|
||||
func (r *VoskBatchRecognizer) FrontResult() string {
|
||||
return C.GoString(C.vosk_batch_recognizer_front_result(r.rec))
|
||||
}
|
||||
|
||||
/** Release and free first retrieved result */
|
||||
//void vosk_batch_recognizer_pop(VoskBatchRecognizer *recognizer);
|
||||
|
||||
func (r *VoskBatchRecognizer) Pop() {
|
||||
C.vosk_batch_recognizer_pop(r.rec)
|
||||
}
|
||||
|
||||
/** Get amount of pending chunks for more intelligent waiting */
|
||||
//int vosk_batch_recognizer_get_pending_chunks(VoskBatchRecognizer *recognizer);
|
||||
func (r *VoskBatchRecognizer) GetPendingChunks() int {
|
||||
i := C.vosk_batch_recognizer_get_pending_chunks(r.rec)
|
||||
return int(i)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
This example expects a `s16le` converted audio file and converts it to text in a
|
||||
manner that imitates the Python example of [test_gpu_batch.py](../python/example/test_gpu_batch.py).
|
||||
|
||||
Note that the `libvosk.so` must be in the library path. This was successfully tested on
|
||||
Ubuntu 24.04 with Go 1.18, gcc-11, NVIDIA driver 570.172.08.
|
||||
@@ -0,0 +1,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
vosk "github.com/alphacep/vosk-api/go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var filename string
|
||||
flag.StringVar(&filename, "f", "", "file to transcribe")
|
||||
flag.Parse()
|
||||
|
||||
vosk.GPUInit()
|
||||
|
||||
model, err := vosk.NewBatchModel("model")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
rec, err := vosk.NewBatchRecognizer(model, 16000.0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
buf := make([]byte, 8000)
|
||||
|
||||
for {
|
||||
if _, err := file.Read(buf); err != nil {
|
||||
if err != io.EOF {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
rec.AcceptWaveform(buf)
|
||||
model.Wait()
|
||||
if rec.FrontResult() != "" {
|
||||
fmt.Println(rec.FrontResult())
|
||||
rec.Pop()
|
||||
}
|
||||
}
|
||||
// Is this needed? rec.FinishStream()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Go bindings for Vosk speech recognition toolkit. Vosk is an offline
|
||||
// open source speech to text API for Android, iOS, Raspberry Pi and
|
||||
// servers. It enables speech recognition models for 18 languages and
|
||||
// dialects - English, Indian English, German, French, Spanish, Portuguese,
|
||||
// Chinese, Russian, Turkish, Vietnamese, Italian, Dutch, Catalan, Arabic,
|
||||
// Greek, Farsi, Filipino, Ukrainian.
|
||||
package vosk
|
||||
@@ -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
|
||||
```
|
||||
@@ -0,0 +1,2 @@
|
||||
// Example package for Vosk Go bindings.
|
||||
package main
|
||||
@@ -1,36 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
".."
|
||||
)
|
||||
|
||||
func main() {
|
||||
var filename string
|
||||
flag.StringVar(&filename, "f", "", "file to transcribe")
|
||||
flag.Parse()
|
||||
model, err := vosk.NewModel("model")
|
||||
rec, err := vosk.NewRecognizer(model)
|
||||
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
fileinfo, err := file.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
filesize := fileinfo.Size()
|
||||
buffer := make([]byte, filesize)
|
||||
|
||||
_, err = file.Read(buffer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
println(vosk.VoskFinalResult(rec, buffer))
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
vosk "github.com/alphacep/vosk-api/go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var filename string
|
||||
flag.StringVar(&filename, "f", "", "file to transcribe")
|
||||
flag.Parse()
|
||||
|
||||
vosk.GPUInit()
|
||||
|
||||
model, err := vosk.NewModel("model")
|
||||
if err != nil {
|
||||
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 {
|
||||
log.Fatal(err)
|
||||
}
|
||||
rec.SetWords(1)
|
||||
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
buf := make([]byte, 4096)
|
||||
|
||||
for {
|
||||
_, err := file.Read(buf)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if rec.AcceptWaveform(buf) != 0 {
|
||||
fmt.Println(rec.Result())
|
||||
}
|
||||
}
|
||||
|
||||
// Unmarshal example for final result
|
||||
var jres map[string]interface{}
|
||||
json.Unmarshal([]byte(rec.FinalResult()), &jres)
|
||||
fmt.Println(jres["text"])
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
module alphacephei.com/vosk
|
||||
module github.com/alphacep/vosk-api/go
|
||||
|
||||
go 1.16
|
||||
|
||||
replace (
|
||||
github.com/alphacep/vosk-api/go => ./
|
||||
)
|
||||
|
||||
+155
-37
@@ -1,62 +1,180 @@
|
||||
package vosk
|
||||
|
||||
// #cgo CPPFLAGS: -I ${SRCDIR}/../src
|
||||
// #cgo LDFLAGS: -L ${SRCDIR}/../src -lvosk -ldl -lpthread
|
||||
// #cgo !windows LDFLAGS: -L ${SRCDIR}/../src -lvosk -ldl -lpthread
|
||||
// #cgo windows LDFLAGS: -L ${SRCDIR}/../src -lvosk -lpthread
|
||||
// #include <stdlib.h>
|
||||
// #include <vosk_api.h>
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
// VoskModel contains a reference to the C VoskModel
|
||||
type VoskModel struct {
|
||||
model *C.struct_VoskModel
|
||||
}
|
||||
|
||||
// VoskSpkModel contains a reference to the C VoskSpkModel
|
||||
type VoskSpkModel struct {
|
||||
spkModel *C.struct_VoskSpkModel
|
||||
}
|
||||
|
||||
// VoskRecognizer contains a reference to the C VoskRecognizer
|
||||
type VoskRecognizer struct {
|
||||
rec *C.struct_VoskRecognizer
|
||||
}
|
||||
|
||||
func VoskFinalResult(recognizer *VoskRecognizer, buffer []byte) string {
|
||||
cbuf := C.CBytes(buffer)
|
||||
defer C.free(cbuf)
|
||||
_ = C.vosk_recognizer_accept_waveform(recognizer.rec, (*C.char)(cbuf), C.int(len(buffer)))
|
||||
result := C.GoString(C.vosk_recognizer_final_result(recognizer.rec))
|
||||
return result
|
||||
model *C.struct_VoskModel
|
||||
}
|
||||
|
||||
// NewModel creates a new VoskModel instance
|
||||
func NewModel(modelPath string) (*VoskModel, error) {
|
||||
var internal *C.struct_VoskModel
|
||||
internal = C.vosk_model_new(C.CString(modelPath))
|
||||
model := &VoskModel{model: internal}
|
||||
return model, nil
|
||||
cmodelPath := C.CString(modelPath)
|
||||
defer C.free(unsafe.Pointer(cmodelPath))
|
||||
internal := C.vosk_model_new(cmodelPath)
|
||||
model := &VoskModel{model: internal}
|
||||
return model, nil
|
||||
}
|
||||
|
||||
// NewRecognizer creates a new VoskRecognizer instance
|
||||
func NewRecognizer(model *VoskModel) (*VoskRecognizer, error) {
|
||||
var internal *C.struct_VoskRecognizer
|
||||
internal = C.vosk_recognizer_new(model.model, 16000.0)
|
||||
rec := &VoskRecognizer{rec: internal}
|
||||
return rec, nil
|
||||
func (m *VoskModel) Free() {
|
||||
C.vosk_model_free(m.model)
|
||||
}
|
||||
|
||||
func freeModel(model *VoskModel) {
|
||||
C.vosk_model_free(model.model)
|
||||
C.vosk_model_free(model.model)
|
||||
}
|
||||
|
||||
func freeRecognizer(recognizer *VoskRecognizer) {
|
||||
C.vosk_recognizer_free(recognizer.rec)
|
||||
// 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 string) int {
|
||||
cstr := C.CString(word)
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
i := C.vosk_model_find_word(m.model, cstr)
|
||||
return int(i)
|
||||
}
|
||||
|
||||
// VoskSpkModel contains a reference to the C VoskSpkModel
|
||||
type VoskSpkModel struct {
|
||||
spkModel *C.struct_VoskSpkModel
|
||||
}
|
||||
|
||||
// NewSpkModel creates a new VoskSpkModel instance
|
||||
func NewSpkModel(spkModelPath string) (*VoskSpkModel, error) {
|
||||
var internal *C.struct_VoskSpkModel
|
||||
internal = C.vosk_spk_model_new(C.CString(spkModelPath))
|
||||
spkModel := &VoskSpkModel{spkModel: internal}
|
||||
return spkModel, nil
|
||||
cspkModelPath := C.CString(spkModelPath)
|
||||
defer C.free(unsafe.Pointer(cspkModelPath))
|
||||
internal := C.vosk_spk_model_new(cspkModelPath)
|
||||
spkModel := &VoskSpkModel{spkModel: internal}
|
||||
return spkModel, nil
|
||||
}
|
||||
|
||||
func freeSpkModel(model *VoskSpkModel) {
|
||||
C.vosk_spk_model_free(model.spkModel)
|
||||
}
|
||||
|
||||
func(s *VoskSpkModel) Free() {
|
||||
C.vosk_spk_model_free(s.spkModel)
|
||||
}
|
||||
|
||||
// VoskRecognizer contains a reference to the C VoskRecognizer
|
||||
type VoskRecognizer struct {
|
||||
rec *C.struct_VoskRecognizer
|
||||
}
|
||||
|
||||
func freeRecognizer(recognizer *VoskRecognizer) {
|
||||
C.vosk_recognizer_free(recognizer.rec)
|
||||
}
|
||||
|
||||
func (r *VoskRecognizer) Free() {
|
||||
C.vosk_recognizer_free(r.rec)
|
||||
}
|
||||
|
||||
// NewRecognizer creates a new VoskRecognizer instance
|
||||
func NewRecognizer(model *VoskModel, sampleRate float64) (*VoskRecognizer, error) {
|
||||
internal := C.vosk_recognizer_new(model.model, C.float(sampleRate))
|
||||
rec := &VoskRecognizer{rec: internal}
|
||||
return rec, nil
|
||||
}
|
||||
|
||||
// NewRecognizerSpk creates a new VoskRecognizer instance with a speaker model.
|
||||
func NewRecognizerSpk(model *VoskModel, sampleRate float64, spkModel *VoskSpkModel) (*VoskRecognizer, error) {
|
||||
internal := C.vosk_recognizer_new_spk(model.model, C.float(sampleRate), spkModel.spkModel)
|
||||
rec := &VoskRecognizer{rec: internal}
|
||||
return rec, nil
|
||||
}
|
||||
|
||||
// NewRecognizerGrm creates a new VoskRecognizer instance with the phrase list.
|
||||
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
|
||||
}
|
||||
|
||||
// SetSpkModel adds a speaker model to an already initialized recognizer.
|
||||
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))
|
||||
}
|
||||
|
||||
// SetWords enables words with times in the ouput.
|
||||
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))
|
||||
}
|
||||
|
||||
// SetEndpointerDelays sets the recognition timeouts, where startMax
|
||||
// is the timeout for stopping recognition in case of initial silence
|
||||
// (usually around 5), end is the timeout for stopping recognition
|
||||
// in milliseconds after we recognized something (usually around 0.5-1.0),
|
||||
// and max is the timeout for forcing utterance end in milliseconds
|
||||
// (usually around 20-30).
|
||||
func (r *VoskRecognizer) SetEndpointerDelays(startMax, end, max float64) {
|
||||
C.vosk_recognizer_set_endpointer_delays(r.rec, C.float(startMax), C.float(end), C.float(max))
|
||||
}
|
||||
|
||||
// AcceptWaveform accepts and processes a new chunk of the voice data.
|
||||
func (r *VoskRecognizer) AcceptWaveform(buffer []byte) int {
|
||||
cbuf := C.CBytes(buffer)
|
||||
defer C.free(cbuf)
|
||||
i := C.vosk_recognizer_accept_waveform(r.rec, (*C.char)(cbuf), C.int(len(buffer)))
|
||||
return int(i)
|
||||
}
|
||||
|
||||
// Result returns a speech recognition result.
|
||||
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() 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() string {
|
||||
return C.GoString(C.vosk_recognizer_final_result(r.rec))
|
||||
}
|
||||
|
||||
// Reset resets the recognizer.
|
||||
func (r *VoskRecognizer) Reset() {
|
||||
C.vosk_recognizer_reset(r.rec)
|
||||
}
|
||||
|
||||
// SetLogLevel sets the log level for Kaldi messages.
|
||||
func SetLogLevel(logLevel int) {
|
||||
C.vosk_set_log_level(C.int(logLevel))
|
||||
}
|
||||
|
||||
// GPUInit automatically selects a CUDA device and allows multithreading.
|
||||
func GPUInit() {
|
||||
C.vosk_gpu_init()
|
||||
}
|
||||
|
||||
// GPUThreadInit inits CUDA device in a multi-threaded environment.
|
||||
func GPUThreadInit() {
|
||||
C.vosk_gpu_thread_init()
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
92375229240C550B00DD6076 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92375228240C550B00DD6076 /* Assets.xcassets */; };
|
||||
9237522C240C550B00DD6076 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9237522A240C550B00DD6076 /* LaunchScreen.storyboard */; };
|
||||
92375234240C558900DD6076 /* Vosk.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92375233240C558900DD6076 /* Vosk.swift */; };
|
||||
9237523C240C642000DD6076 /* libkaldiwrap.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9237523A240C642000DD6076 /* libkaldiwrap.a */; };
|
||||
92375244240C6DAF00DD6076 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92375243240C6DAF00DD6076 /* Accelerate.framework */; };
|
||||
92375246240C6DC900DD6076 /* libstdc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 92375245240C6DC900DD6076 /* libstdc++.tbd */; };
|
||||
92375274240C6F1E00DD6076 /* 10001-90210-01803.wav in Resources */ = {isa = PBXBuildFile; fileRef = 92375256240C6E3D00DD6076 /* 10001-90210-01803.wav */; };
|
||||
925527A9273C492C00FFD9CC /* libvosk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 925527A8273C492C00FFD9CC /* libvosk.a */; };
|
||||
92833003273C466E00058B52 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 92833002273C466E00058B52 /* libc++.tbd */; };
|
||||
92BACED125BE125A00B5CC93 /* vosk-model-small-en-us-0.15 in Resources */ = {isa = PBXBuildFile; fileRef = 928CC50C25BE124400490481 /* vosk-model-small-en-us-0.15 */; };
|
||||
92D6B8D325BDFEAC007FF08D /* VoskModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92D6B8D225BDFEAC007FF08D /* VoskModel.swift */; };
|
||||
92D86BD6253F823F0040D53F /* vosk-model-spk-0.4 in Resources */ = {isa = PBXBuildFile; fileRef = 92D86BD4253F823F0040D53F /* vosk-model-spk-0.4 */; };
|
||||
@@ -31,10 +31,10 @@
|
||||
9237522B240C550B00DD6076 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
9237522D240C550B00DD6076 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
92375233240C558900DD6076 /* Vosk.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vosk.swift; sourceTree = "<group>"; };
|
||||
9237523A240C642000DD6076 /* libkaldiwrap.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libkaldiwrap.a; sourceTree = "<group>"; };
|
||||
92375243240C6DAF00DD6076 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
|
||||
92375245240C6DC900DD6076 /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.tbd"; path = "usr/lib/libstdc++.tbd"; sourceTree = SDKROOT; };
|
||||
92375256240C6E3D00DD6076 /* 10001-90210-01803.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = "10001-90210-01803.wav"; sourceTree = "<group>"; };
|
||||
925527A8273C492C00FFD9CC /* libvosk.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libvosk.a; sourceTree = "<group>"; };
|
||||
92833002273C466E00058B52 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||
928CC50C25BE124400490481 /* vosk-model-small-en-us-0.15 */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "vosk-model-small-en-us-0.15"; path = "/Users/shmyrev/Documents/IOS/VoskApiTest/VoskApiTest/Vosk/vosk-model-small-en-us-0.15"; sourceTree = "<absolute>"; };
|
||||
92AA22AD244CDD1200DA464B /* vosk_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vosk_api.h; sourceTree = "<group>"; };
|
||||
92AA22AE244CDD5200DA464B /* bridging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bridging.h; sourceTree = "<group>"; };
|
||||
@@ -47,9 +47,9 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
92375246240C6DC900DD6076 /* libstdc++.tbd in Frameworks */,
|
||||
92833003273C466E00058B52 /* libc++.tbd in Frameworks */,
|
||||
92375244240C6DAF00DD6076 /* Accelerate.framework in Frameworks */,
|
||||
9237523C240C642000DD6076 /* libkaldiwrap.a in Frameworks */,
|
||||
925527A9273C492C00FFD9CC /* libvosk.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -93,11 +93,11 @@
|
||||
92375239240C642000DD6076 /* Vosk */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
928CC50C25BE124400490481 /* vosk-model-small-en-us-0.15 */,
|
||||
92D86BD4253F823F0040D53F /* vosk-model-spk-0.4 */,
|
||||
92375256240C6E3D00DD6076 /* 10001-90210-01803.wav */,
|
||||
928CC50C25BE124400490481 /* vosk-model-small-en-us-0.15 */,
|
||||
925527A8273C492C00FFD9CC /* libvosk.a */,
|
||||
92AA22AD244CDD1200DA464B /* vosk_api.h */,
|
||||
9237523A240C642000DD6076 /* libkaldiwrap.a */,
|
||||
92375256240C6E3D00DD6076 /* 10001-90210-01803.wav */,
|
||||
);
|
||||
name = Vosk;
|
||||
path = VoskApiTest/Vosk;
|
||||
@@ -106,7 +106,7 @@
|
||||
92375242240C6DAF00DD6076 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
92375245240C6DC900DD6076 /* libstdc++.tbd */,
|
||||
92833002273C466E00058B52 /* libc++.tbd */,
|
||||
92375243240C6DAF00DD6076 /* Accelerate.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
@@ -145,7 +145,7 @@
|
||||
9237521D240C550B00DD6076 = {
|
||||
CreatedOnToolsVersion = 8.3.2;
|
||||
LastSwiftMigration = 0920;
|
||||
ProvisioningStyle = Automatic;
|
||||
ProvisioningStyle = Manual;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -223,7 +223,6 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -245,7 +244,7 @@
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -282,7 +281,6 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -304,7 +302,7 @@
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
@@ -319,6 +317,7 @@
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = bridging.h;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
@@ -333,7 +332,10 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
ENABLE_BITCODE = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = VoskApiTest/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
@@ -342,11 +344,13 @@
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alphacephei.VoskApiTest;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_INSTALL_OBJC_HEADER = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = VoskApiTest/bridging.h;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -355,7 +359,10 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
ENABLE_BITCODE = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = VoskApiTest/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
@@ -364,10 +371,12 @@
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alphacephei.VoskApiTest;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_INSTALL_OBJC_HEADER = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = VoskApiTest/bridging.h;
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:/Users/shmyrev/Documents/IOS/VoskApiTest/VoskApiTest/Vosk/vosk-model-small-en-us-0.15">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
|
||||
@@ -14,7 +14,7 @@ public final class Vosk {
|
||||
var recognizer : OpaquePointer!
|
||||
|
||||
init(model: VoskModel, sampleRate: Float) {
|
||||
recognizer = vosk_recognizer_new_spk(model.model, model.spkModel, sampleRate)
|
||||
recognizer = vosk_recognizer_new_spk(model.model, sampleRate, model.spkModel)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
+117
-36
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 Alpha Cephei Inc.
|
||||
// Copyright 2020-2021 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.
|
||||
@@ -43,7 +43,7 @@ typedef struct VoskRecognizer VoskRecognizer;
|
||||
/** Loads model data from the file and returns the model object
|
||||
*
|
||||
* @param model_path: the path of the model on the filesystem
|
||||
@ @returns model object */
|
||||
* @returns model object or NULL if problem occured */
|
||||
VoskModel *vosk_model_new(const char *model_path);
|
||||
|
||||
|
||||
@@ -55,10 +55,18 @@ VoskModel *vosk_model_new(const char *model_path);
|
||||
void vosk_model_free(VoskModel *model);
|
||||
|
||||
|
||||
/** 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> */
|
||||
int vosk_model_find_word(VoskModel *model, const char *word);
|
||||
|
||||
|
||||
/** Loads speaker model data from the file and returns the model object
|
||||
*
|
||||
* @param model_path: the path of the model on the filesystem
|
||||
* @returns model object */
|
||||
* @returns model object or NULL if problem occured */
|
||||
VoskSpkModel *vosk_spk_model_new(const char *model_path);
|
||||
|
||||
|
||||
@@ -71,9 +79,13 @@ void vosk_spk_model_free(VoskSpkModel *model);
|
||||
|
||||
/** Creates the recognizer object
|
||||
*
|
||||
* The recognizers process the speech and return text using shared model data
|
||||
* @param sample_rate The sample rate of the audio you going to feed into the recognizer
|
||||
* @returns recognizer object */
|
||||
* 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 sample_rate 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 */
|
||||
VoskRecognizer *vosk_recognizer_new(VoskModel *model, float sample_rate);
|
||||
|
||||
|
||||
@@ -82,10 +94,14 @@ VoskRecognizer *vosk_recognizer_new(VoskModel *model, float sample_rate);
|
||||
* 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 sample_rate 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 spk_model speaker model for speaker identification
|
||||
* @param sample_rate The sample rate of the audio you going to feed into the recognizer
|
||||
* @returns recognizer object */
|
||||
VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, VoskSpkModel *spk_model, float sample_rate);
|
||||
* @returns recognizer object or NULL if problem occured */
|
||||
VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, float sample_rate, VoskSpkModel *spk_model);
|
||||
|
||||
|
||||
/** Creates the recognizer object with the phrase list
|
||||
@@ -98,42 +114,46 @@ VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, VoskSpkModel *spk_mode
|
||||
* Only recognizers with lookahead models support this type of quick configuration.
|
||||
* Precompiled HCLG graph models are not supported.
|
||||
*
|
||||
* @param sample_rate The sample rate of the audio you going to feed into the recognizer
|
||||
* @param model VoskModel containing static data for recognizer. Model can be
|
||||
* shared across recognizers, even running in different threads.
|
||||
* @param sample_rate 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 */
|
||||
* @returns recognizer object or NULL if problem occured */
|
||||
VoskRecognizer *vosk_recognizer_new_grm(VoskModel *model, float sample_rate, const char *grammar);
|
||||
|
||||
|
||||
/** Accept voice data
|
||||
/** Adds speaker model to already initialized recognizer
|
||||
*
|
||||
* accept and process new chunk of voice data
|
||||
* Can add speaker recognition model to already created recognizer. Helps to initialize
|
||||
* speaker recognition for grammar-based recognizer.
|
||||
*
|
||||
* @param data - audio data in PCM 16-bit mono format
|
||||
* @param length - length of the audio data
|
||||
* @returns true if silence is occured and you can retrieve a new utterance with result method */
|
||||
int vosk_recognizer_accept_waveform(VoskRecognizer *recognizer, const char *data, int length);
|
||||
* @param spk_model Speaker recognition model */
|
||||
void vosk_recognizer_set_spk_model(VoskRecognizer *recognizer, VoskSpkModel *spk_model);
|
||||
|
||||
|
||||
/** Same as above but the version with the short data for language bindings where you have
|
||||
* audio as array of shorts */
|
||||
int vosk_recognizer_accept_waveform_s(VoskRecognizer *recognizer, const short *data, int length);
|
||||
|
||||
|
||||
/** Same as above but the version with the float data for language bindings where you have
|
||||
* audio as array of floats */
|
||||
int vosk_recognizer_accept_waveform_f(VoskRecognizer *recognizer, const float *data, int length);
|
||||
|
||||
|
||||
/** Returns speech recognition result
|
||||
*
|
||||
* @returns the result in JSON format which contains decoded line, decoded
|
||||
* words, times in seconds and confidences. You can parse this result
|
||||
* with any json parser
|
||||
/** 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 max_alternatives - maximum alternatives to return from recognition results
|
||||
*/
|
||||
void vosk_recognizer_set_max_alternatives(VoskRecognizer *recognizer, int max_alternatives);
|
||||
|
||||
|
||||
/** Enables words with times in the output
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "result" : [{
|
||||
* "conf" : 1.000000,
|
||||
* "end" : 1.110000,
|
||||
@@ -156,13 +176,54 @@ int vosk_recognizer_accept_waveform_f(VoskRecognizer *recognizer, const float *d
|
||||
* "word" : "zero"
|
||||
* }, {
|
||||
* "conf" : 1.000000,
|
||||
* "end" : 2.610000,
|
||||
* "end" : 2.610000,
|
||||
* "start" : 2.340000,
|
||||
* "word" : "one"
|
||||
* }],
|
||||
* "text" : "what zero zero zero one"
|
||||
* </pre>
|
||||
*
|
||||
* @param words - boolean value
|
||||
*/
|
||||
void vosk_recognizer_set_words(VoskRecognizer *recognizer, int words);
|
||||
|
||||
|
||||
/** 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 */
|
||||
int vosk_recognizer_accept_waveform(VoskRecognizer *recognizer, const char *data, int length);
|
||||
|
||||
|
||||
/** Same as above but the version with the short data for language bindings where you have
|
||||
* audio as array of shorts */
|
||||
int vosk_recognizer_accept_waveform_s(VoskRecognizer *recognizer, const short *data, int length);
|
||||
|
||||
|
||||
/** Same as above but the version with the float data for language bindings where you have
|
||||
* audio as array of floats */
|
||||
int vosk_recognizer_accept_waveform_f(VoskRecognizer *recognizer, const float *data, int length);
|
||||
|
||||
|
||||
/** Returns speech recognition result
|
||||
*
|
||||
* @returns the result in JSON format which contains decoded line, decoded
|
||||
* words, times in seconds and confidences. You can parse this result
|
||||
* with any json parser
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "text" : "what zero zero zero one"
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* If alternatives enabled it returns result with alternatives, see also vosk_recognizer_set_alternatives().
|
||||
*
|
||||
* If word times enabled returns word time, see also vosk_recognizer_set_word_times().
|
||||
*/
|
||||
const char *vosk_recognizer_result(VoskRecognizer *recognizer);
|
||||
|
||||
@@ -174,7 +235,7 @@ const char *vosk_recognizer_result(VoskRecognizer *recognizer);
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "partial" : "cyril one eight zero"
|
||||
* "partial" : "cyril one eight zero"
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@@ -190,6 +251,12 @@ const char *vosk_recognizer_partial_result(VoskRecognizer *recognizer);
|
||||
const char *vosk_recognizer_final_result(VoskRecognizer *recognizer);
|
||||
|
||||
|
||||
/** Resets the recognizer
|
||||
*
|
||||
* Resets current results so the recognition can continue from scratch */
|
||||
void vosk_recognizer_reset(VoskRecognizer *recognizer);
|
||||
|
||||
|
||||
/** Releases recognizer object
|
||||
*
|
||||
* Underlying model is also unreferenced and if needed released */
|
||||
@@ -204,6 +271,20 @@ void vosk_recognizer_free(VoskRecognizer *recognizer);
|
||||
*/
|
||||
void vosk_set_log_level(int log_level);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void 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.
|
||||
*/
|
||||
void vosk_gpu_thread_init();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -8,12 +8,8 @@ application {
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url 'https://alphacephei.com/maven/'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation group: 'net.java.dev.jna', name: 'jna', version: '5.7.0'
|
||||
implementation group: 'com.alphacephei', name: 'vosk', version: '0.3.30+'
|
||||
implementation group: 'com.alphacephei', name: 'vosk', version: '0.3.75'
|
||||
}
|
||||
|
||||
+23
-10
@@ -1,18 +1,31 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'maven-publish'
|
||||
id 'com.vanniktech.maven.publish' version '0.18.0'
|
||||
}
|
||||
|
||||
archivesBaseName = 'vosk'
|
||||
group = 'com.alphacephei'
|
||||
version = '0.3.30'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
archivesBaseName = 'vosk'
|
||||
group = 'com.alphacephei'
|
||||
version = '0.3.75'
|
||||
|
||||
mavenPublish {
|
||||
group = 'com.alphacephei'
|
||||
version = version
|
||||
sonatypeHost = 's01'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation group: 'net.java.dev.jna', name: 'jna', version: '5.7.0'
|
||||
api group: 'net.java.dev.jna', name: 'jna', version: '5.18.1'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
}
|
||||
|
||||
@@ -45,14 +58,14 @@ publishing {
|
||||
}
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
url = "repo"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
dependsOn cleanTest
|
||||
testLogging.showStandardStreams = true
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -62,6 +62,8 @@ public class LibVosk {
|
||||
|
||||
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);
|
||||
@@ -76,10 +78,30 @@ 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_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());
|
||||
}
|
||||
|
||||
@@ -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,32 +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);
|
||||
}
|
||||
@@ -39,22 +170,104 @@ 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());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,8 +15,10 @@ 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 {
|
||||
|
||||
@@ -30,6 +32,7 @@ public class DecoderTest {
|
||||
|
||||
recognizer.setMaxAlternatives(10);
|
||||
recognizer.setWords(true);
|
||||
recognizer.setPartialWords(true);
|
||||
|
||||
int nbytes;
|
||||
byte[] b = new byte[4096];
|
||||
@@ -93,4 +96,25 @@ public class DecoderTest {
|
||||
}
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.gradle/
|
||||
.idea/
|
||||
build/
|
||||
@@ -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,204 @@
|
||||
import org.jetbrains.dokka.gradle.DokkaTask
|
||||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.dsl.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 "2.0.0"
|
||||
id("com.android.library")
|
||||
`maven-publish`
|
||||
id("org.jetbrains.dokka") version "1.9.20"
|
||||
kotlin("plugin.serialization") version "2.0.0"
|
||||
}
|
||||
|
||||
group = "com.alphacephei"
|
||||
version = "0.3.75"
|
||||
|
||||
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 {
|
||||
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
androidTarget {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
||||
applyDefaultHierarchyTemplate {
|
||||
withJvm()
|
||||
withAndroidTarget()
|
||||
|
||||
if (enableNative)
|
||||
withNative()
|
||||
}
|
||||
|
||||
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.14.0"
|
||||
val coroutines_version = "1.7.3"
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0")
|
||||
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 androidUnitTest by getting {
|
||||
dependencies {
|
||||
implementation("junit:junit:4.13.2")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.alphacephei.library"
|
||||
compileSdk = 34
|
||||
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
targetSdk = 34
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
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:8.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,27 @@
|
||||
/*
|
||||
* Copyright 2024 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
|
||||
|
||||
/**
|
||||
* VoskEpMode
|
||||
*/
|
||||
enum class EndPointerMode {
|
||||
ANSWER_DEFAULT,
|
||||
ANSWER_SHORT,
|
||||
ANSWER_LONG,
|
||||
ANSWER_VERY_LONG
|
||||
}
|
||||
@@ -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,273 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
* C equivalent = vosk_recognizer_set_words
|
||||
* @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)
|
||||
|
||||
|
||||
/**
|
||||
* Set endpointer scaling factor
|
||||
*
|
||||
* @param mode Endpointer mode
|
||||
**/
|
||||
fun setEndPointerMode(mode: EndPointerMode)
|
||||
|
||||
/**
|
||||
* Set endpointer delays
|
||||
*
|
||||
* @param tStartMax timeout for stopping recognition in case of initial silence (usually around 5.0)
|
||||
* @param tEnd timeout for stopping recognition in milliseconds after we recognized something (usually around 0.5 - 1.0)
|
||||
* @param tMax timeout for forcing utterance end in milliseconds (usually around 20-30)
|
||||
**/
|
||||
fun setEndPointerDelays(tStartMax: Float, tEnd: Float, tMax: Float)
|
||||
|
||||
/**
|
||||
* 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,32 @@
|
||||
/*
|
||||
* Copyright 2024 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
|
||||
|
||||
/**
|
||||
* Inverse text normalization
|
||||
*
|
||||
* @since 2024/06/19
|
||||
* @constructor Create text processor
|
||||
*/
|
||||
expect class TextProcessor constructor(tagger: Char, verbalizer: Char) : Freeable {
|
||||
|
||||
/** Release text processor */
|
||||
override fun free()
|
||||
|
||||
/** Convert string */
|
||||
fun itn(input: Char): Char
|
||||
}
|
||||
@@ -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?) : 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,213 @@
|
||||
/*
|
||||
* 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) {
|
||||
Vosk::class.java.getResourceAsStream("/win32-x86-64/$lib.dll")!!.use {
|
||||
Files.copy(
|
||||
it,
|
||||
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
|
||||
|
||||
external fun vosk_text_processor_new(tagger: Char, verbalizer: Char): Pointer
|
||||
|
||||
external fun vosk_text_processor_free(processor: TextProcessor)
|
||||
|
||||
external fun vosk_text_processor_itn(processor: TextProcessor, input: Char): Char
|
||||
|
||||
external fun vosk_recognizer_set_endpointer_mode(recognizer: Recognizer, ordinal: Int)
|
||||
|
||||
external fun vosk_recognizer_set_endpointer_delays(
|
||||
recognizer: Recognizer,
|
||||
tStartMax: Float,
|
||||
tEnd: Float,
|
||||
tMax: Float
|
||||
)
|
||||
}
|
||||
@@ -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,353 @@
|
||||
/*
|
||||
* 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()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set endpointer scaling factor
|
||||
*
|
||||
* @param mode Endpointer mode
|
||||
**/
|
||||
actual fun setEndPointerMode(mode: EndPointerMode) {
|
||||
LibVosk.vosk_recognizer_set_endpointer_mode(this, mode.ordinal)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set endpointer delays
|
||||
*
|
||||
* @param tStartMax timeout for stopping recognition in case of initial silence (usually around 5.0)
|
||||
* @param tEnd timeout for stopping recognition in milliseconds after we recognized something (usually around 0.5 - 1.0)
|
||||
* @param tMax timeout for forcing utterance end in milliseconds (usually around 20-30)
|
||||
**/
|
||||
actual fun setEndPointerDelays(
|
||||
tStartMax: Float,
|
||||
tEnd: Float,
|
||||
tMax: Float
|
||||
) {
|
||||
LibVosk.vosk_recognizer_set_endpointer_delays(this, tStartMax, tEnd, tMax)
|
||||
}
|
||||
}
|
||||
@@ -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,51 @@
|
||||
/*
|
||||
* Copyright 2024 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
|
||||
|
||||
/**
|
||||
* Inverse text normalization
|
||||
*
|
||||
* @since 2024/06/19
|
||||
*/
|
||||
actual class TextProcessor :
|
||||
Freeable, PointerType, AutoCloseable {
|
||||
|
||||
/**
|
||||
* Create text processor
|
||||
*/
|
||||
actual constructor(tagger: Char, verbalizer: Char) :
|
||||
super(LibVosk.vosk_text_processor_new(tagger, verbalizer))
|
||||
|
||||
|
||||
/** Release text processor */
|
||||
actual override fun free() {
|
||||
LibVosk.vosk_text_processor_free(this)
|
||||
}
|
||||
|
||||
/** Convert string */
|
||||
actual fun itn(input: Char): Char =
|
||||
LibVosk.vosk_text_processor_itn(this, input)
|
||||
|
||||
/**
|
||||
* @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)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user