Compare commits

...

281 Commits

Author SHA1 Message Date
Nickolay Shmyrev aba84973b1 Update to latest gradio 2023-12-15 00:23:37 +01:00
Nickolay Shmyrev 339b1c5d00 Fix t_max endpointer config and introduce t_start_max for silent inputs. 2023-12-13 04:45:30 +01:00
Nickolay Shmyrev a35728fa67 Simplify server argument 2023-11-27 15:40:58 +01:00
Nickolay Shmyrev 322a57b512 Fix json output format 2023-11-27 15:39:49 +01:00
Gonzalo a21d1ad051 feat: enable usage of remote server and not only localhost (#1375) 2023-11-27 17:22:59 +03:00
Nickolay Shmyrev a47fa9147b Add endpointer delays parameter 2023-11-27 15:29:31 +01:00
Wire dfb76f0126 go: do not include libdl if building on Windows (#1464) 2023-11-12 01:26:17 +03:00
Nickolay Shmyrev c3e3fc002f Add online endpointer reconfiguration 2023-10-16 13:40:32 +02:00
Nickolay Shmyrev 62fc308bdf Sometimes python interpreter destroys the handle on exit before
the object. See

https://foss.heptapod.net/pypy/cffi/-/issues/340
2023-09-04 00:33:42 +02:00
Dmitri Soloviev 60c0e33901 simplify go example (#1430) 2023-08-12 23:04:46 +03:00
jsbxyyx 5d09ee8b2b close source input stream (#1) (#1428) 2023-08-11 00:55:33 +03:00
JohnGebbie 12f29a3415 go: Add SetGrm (#1346) 2023-04-29 05:35:01 +03:00
Nickolay Shmyrev d56221bcf2 Add mkl docker build 2023-04-06 02:38:06 +02:00
Nickolay Shmyrev a2eb39d2d7 Set number of MKL threads 2023-04-06 02:10:53 +02:00
Anton Romanov 128c216c61 Fix vosk-transcriber cli json format (#1304)
Fix error UnboundLocalError: local variable 'monologue' referenced before assignment in transcriber.py line 102
2023-03-29 03:12:16 +03:00
mason-acronode da87d0dad3 c# supports GPU inference (#1307)
* Added Batch P/Invoke to be able to use GPU based inference

* Modified Result method

* Modified Result method

* Fixed code to call BatchModel

---------

Co-authored-by: minsik.sim <minsik.sim@cyara.com>
2023-03-25 12:28:14 +03:00
Nickolay Shmyrev 9cee2899bb Update publishing plugin and simplify gradle build 2023-03-15 22:50:42 +01:00
Doomsdayrs a40742bbaf Kotlin: Numerous Improvements (#1274)
* kotlin: bump version for future release

* kotlin: Unify dependency versions

* kotlin: Add AUTHORS

* kotlin: Add MAINTENANCE.md

* kotlin: Add README.md

* kotlin: Update common/Vosk.kt documentation

* kotlin: Fix indentation in build.gradle.kts

* kotlin: Add .idea files to unify how IDEs work

* kotlin: Reformat all code

* kotlin: Update all code headers

* kotlin: Add @JvmStatic to objects

* kotlin: Use Consumer instead of Kotlin lambda in StorageService.kt

* kotlin: Annotate SpeechService.kt as throwing IOException

* kotlin: Add gradle migration settings

* kotlin: Add Deprecated annotation to jvm/LibVosk.setLogLevel

* kotlin: Overhaul exceptions

* Update documentation

* Add function for creating a Recognizer with a proper list

* Update documentation
2023-03-03 19:12:54 +03:00
Doomsdayrs d714dff8d3 Add Kotlin Multiplatform (#1241)
* Init

* Implement common

* Implement JVM target

* Ignore build/ directory

* Implement android

* Disable kotlin/native targets

* Remove jCenter()

* Upgrade android tools to 7.3.0

* Enforce not null for essential windows operations

* Add license headers

* Add maven-publish

* Add dokka for javadoc

* Add disabled kotlin/native for linux

This is disabled currently due to vosk
 not having a proper installation method on linux yet.

* Add empty constructors for JVM classes

* Fix library initialization for JVM

* Add DecoderDemo

* Add serialization support

* Convert no arg functions with returns to val properties

* Properly implement DecoderTest

* Import other android classes

* Properly name json parser as voskJson

* Add license headers to native target

* Unify free functions with Freeable interface

This makes it easy for Kotlin/Native to use a "use" function to
 auto free after use of a Freeable.

* Document JVM default constructor

* Add JVM specific constructors with NIO/IO

* Inline default constructors in Common

* Properly handle invalid paths

* Add android publishing block

* Merge serialization into common

* Update to Kotlin 1.8.10

* Update to JNA 5.13.0

* Put native target behind environment variable or override.

Due to a lack of official packaging,
 this is not possible currently.

* Properly handle Recognizer.acceptWaveform exceptions

* Add flow extension for converting (InputStream->Recognizer) to a flow.

* Use ByteFlow for waveform flow instead.

This allows custom readers, and more advanced backends,
 such as the Dicio example in DecoderTest.kt .
2023-02-17 03:47:20 +03:00
Nickolay Shmyrev 790c564d14 Ignore non-audio files in folder transcription 2023-02-10 00:57:14 +01:00
Nickolay Shmyrev 988ba3f257 Bump JNA dependency everywhere 2023-02-08 22:55:22 +01:00
Nickolay Shmyrev 2796da0a50 Sync android lib to java lib, throw exceptions on errors 2023-02-08 22:07:02 +01:00
Nickolay Shmyrev d9c6fc4958 Check if ivector folder is required 2023-02-08 21:00:15 +01:00
Nickolay Shmyrev fff40ce1a1 Gradle doesn't understand + in version 2022-12-18 22:25:26 +01:00
Nicholas Albion 2deb7de1dd Fixed #883 - use right class loader (#1228) 2022-12-17 14:45:15 +03:00
Nicholas Albion 7d87267c31 copied documentation to javadoc (#1230)
Co-authored-by: Nickolay V. Shmyrev <nshmyrev@gmail.com>
2022-12-17 14:41:33 +03:00
Nicholas Albion 64d84b01b1 added Recognizer.setGrammar(String) for java (#1229) 2022-12-17 11:43:27 +03:00
Nickolay Shmyrev cf2560c9f8 Bump debian requirement 2022-12-14 17:58:40 +01:00
Nickolay Shmyrev 800d3d7089 Bump version 2022-12-14 17:38:53 +01:00
Nickolay Shmyrev b471207f7a Protect against segmentation faults with corrupted model folder 2022-12-14 17:32:55 +01:00
Edwin Hendriks 25c59b52e3 add -m (language model) argument to test_microphone.py (#1219)
* added language model as parameter

* fix fore more help explanation
2022-12-07 22:53:21 +03:00
Nickolay Shmyrev 4c72097478 Allow to configure GPU model path. See https://github.com/alphacep/vosk-server/issues/207 2022-11-19 01:13:42 +01:00
Tomas Mehdi 1053cfa0f8 JSON output_type with texts (#1180) 2022-10-26 22:41:04 +03:00
gmat 21a42cb6cd new output type json for gecko project (#1166)
add a output type `json` to get output file compatible with transcription file format for the gecko project annotation https://github.com/gong-io/gecko
2022-10-06 16:27:29 +03:00
Nickolay Shmyrev 16c4a0d985 Bump version 2022-09-25 21:00:24 +02:00
Nickolay Shmyrev 298253401a Update approach to machine detection on cross-compilation
See for details issue #1155
2022-09-25 21:00:24 +02:00
Nickolay Shmyrev 32aa980069 Allow to change grammar of existing recognizer. Probably can be faster though
if we do not reinit feature pipeline
2022-09-13 23:12:13 +02:00
vadimdddd 7b4d396eb1 fix quotes and import's order (#1143) 2022-09-13 21:51:45 +03:00
vadimdddd 36968fbb30 Fix python style issues (#1140)
* pylint_fix v.2

* init: fix quotes
2022-09-12 23:08:59 +03:00
vadimdddd 7474888801 Fix python style issues (#1131) 2022-09-09 00:13:02 +03:00
vadimdddd d46b7a43eb Split results by newlines (#1124) 2022-08-26 17:22:10 +03:00
vadimdddd 2376b32a8a Add SRTResult to KaldiRecognizer (#1080) 2022-08-24 12:48:18 +03:00
vadimdddd b8a88cc30c Add gradio recognizer (#1114)
Demonstrate speech recognition in gradio
2022-08-19 17:31:47 +03:00
Nickolay V. Shmyrev be0b117711 Add training colab 2022-08-17 19:11:45 +02:00
Nickolay V. Shmyrev 449c8ea5af Introduce stop stage espnet style 2022-08-17 14:30:56 +02:00
Nickolay V. Shmyrev 900da76652 Import script locally 2022-08-17 12:50:59 +02:00
Nickolay V. Shmyrev df0ee24084 Add adaptation colab 2022-08-17 12:38:17 +02:00
Nickolay V. Shmyrev d3d8f53156 Add Kaldi build colab 2022-08-17 10:02:43 +02:00
vadimdddd 6eee303d7e Fix decoding files with spaces (#1084)
Fix decoding files with spaces
2022-08-02 20:56:04 +03:00
Nickolay Shmyrev 053d71f5aa Bug fix in notebook 2022-08-01 22:59:38 +02:00
Nickolay Shmyrev 4fbbf5882c Add colab demo 2022-08-01 22:52:57 +02:00
Nickolay Shmyrev 7012103b3b Simplify the go interface. Move from []byte to strings. Fixes #1095 2022-07-31 09:58:33 +02:00
Nickolay Shmyrev 967024d20a Fix precedence of current path for dll load. Fixes issue #1096 2022-07-30 09:15:28 +02:00
Nicolas Dato b966a8078b Fix comment (#1091) 2022-07-26 23:07:25 +03:00
vadimdddd f63b015284 Add new dependency websockets (#1079)
add websockets to dependencies
2022-07-19 19:58:24 +03:00
Nickolay Shmyrev 0a9672d910 Attempt to build manylinux wheel 2022-07-15 00:40:38 +02:00
Nickolay Shmyrev 4ccccd0cd2 Bump version 2022-07-14 21:38:36 +02:00
Nickolay Shmyrev 354fb672a3 Merge branch 'master' of github.com:alphacep/vosk-api 2022-07-13 14:09:05 +02:00
Nickolay Shmyrev 73abf0740a Add Ruby bindings 2022-07-13 14:08:50 +02:00
Nickolay Shmyrev 81c82935ac Add usage example 2022-07-07 01:09:32 +02:00
Nickolay Shmyrev ac3ec56584 Add notes about Go and Rust 2022-07-05 01:18:08 +02:00
Nickolay Shmyrev 2cbe12d4d0 Add link to rust bindings 2022-07-05 01:17:43 +02:00
Nickolay Shmyrev 1475b0e986 Async ffmpeg for trancriber and code refactoring 2022-07-05 01:13:05 +02:00
vadimdddd 8ceab0b9b1 Add vosk-server to transcriber (#1024)
Allow to use vosk-server for transcription
2022-07-04 13:50:38 +03:00
Nickolay Shmyrev 1496b597d3 Fixes issues with models without alignment 2022-07-03 13:00:05 +02:00
vadimdddd 983519e629 Add compatibility with python 3.5 issue(#1021) (#1041)
Added format for python3.5
2022-06-29 18:00:40 +03:00
Nickolay Shmyrev 58fa98ccd7 Wait for microphone to finalize. Fixes crash in issue #1034 2022-06-28 01:01:53 +03:00
Nickolay Shmyrev a7bc5a22d4 We support Polish now 2022-06-05 23:03:57 +02:00
Rémi Bernon 23bbff0b56 build: Add a CMakeLists.txt. (#992) 2022-06-04 17:34:42 +03:00
Kay Gosho a47b58e2f4 Specify device to get microphone input (#993) 2022-06-03 15:33:50 +03:00
Nickolay Shmyrev 8cf64ee93e Add RISCV support 2022-06-02 01:44:16 +02:00
vadimdddd 630edeb3d6 fixed error if parent directory doesn't exist #988 (#990)
Create missing parent directory
2022-06-01 17:52:16 +03:00
Nickolay Shmyrev b1b216d4c8 Bump versions 2022-05-26 15:22:16 +02:00
Nickolay Shmyrev 55dd29b0ff Fix transcriber bugs while processing folder 2022-05-26 14:05:54 +02:00
Nickolay Shmyrev ea0568a38d Change target binary library name and copy header 2022-05-26 13:29:14 +02:00
Nickolay Shmyrev 298c86d0d4 Bump version and add python requirements 2022-05-26 12:46:06 +02:00
Nickolay Shmyrev 859420809b Add extra comments 2022-05-26 11:45:16 +02:00
Nickolay Shmyrev 0fe3a89768 Update to 0.3.40 2022-05-26 11:41:14 +02:00
Nickolay Shmyrev 5b892fbfc5 Architecture should be universal2 2022-05-25 19:52:05 +03:00
Nickolay Shmyrev fb4ed21a7f Shave transcriber code 2022-05-24 22:53:57 +02:00
vadimdddd 4209f3a9fe Vosk model loader(#871) (#941)
* methods get_model_by_name, get_model_by_lang, get_model were added into the model class

* importing modules changed to using components; introduced constant MODELS_HOME_DIR; simplified code

* added new model folders into init; changed samples and transcriber bin for new mode loader

* changed back in cli.py lang arg to args.lang

* added 3 directories instead of 1 to check for models

* cli.py: added 3 args instead of 1 for model; __init__.py: changed script get_model_path for run get_model_by_name/lang inside current directory

* deleted default env var

* cli.py: changed arg_name; __init__.py: changed const name, changed model loading only for last directory

* deleted unused method

* changed by_name, by_lang methods, added download_model method

* deleted env variable initialization

* deleted print()

* deteled unused modules

* added progress_bar, added folder AppData/Local/vosk for model search

* changed download_model methond; added my_hook method
2022-05-24 21:06:13 +03:00
Nickolay Shmyrev ff2c80d5f1 Add x86 crossbuild 2022-05-24 20:00:03 +02:00
Nickolay Shmyrev 3a07a08121 Universal binary in node 2022-05-24 17:30:49 +02:00
Nickolay Shmyrev 592da81a8c Update nuget package for 0.3.38 2022-05-24 17:05:14 +02:00
Nickolay Shmyrev def8c93711 Remove semicolon 2022-05-24 15:23:03 +03:00
Nickolay Shmyrev f73088da58 We create universal binary on OSX 2022-05-24 15:11:05 +03:00
Nickolay Shmyrev 06a761ecbd Bump openblas 2022-05-15 23:58:30 +02:00
Nickolay Shmyrev 97d737a30a Bump version 2022-05-15 23:36:46 +02:00
Nickolay Shmyrev c7bffbf603 No need for g++ in C code, fix osx warning 2022-05-15 23:20:33 +02:00
Nickolay Shmyrev 02c40ea612 Bring back incremental decoder, now works better with kaldi fix 2022-05-15 23:20:19 +02:00
Mark Delk ce5ffb980a use comma instead of equal sign in rpath linker opts (#963)
Using `=` for linker options is a GNU extension which doesn't work with
clang.

Using `,` should work for both gcc and clang.
2022-05-12 00:34:43 +03:00
Nickolay Shmyrev d5ca98a982 Revert incremental decoder patch, leads to very slow decoding in some cases due to lattice blow-up 2022-05-06 00:34:50 +02:00
Nickolay Shmyrev b0146782d6 Reorganize transcriber binary 2022-04-29 03:01:09 +02:00
Nickolay Shmyrev 5aaea8fc90 Simplify makefile 2022-04-29 02:35:17 +02:00
Chupligin Sergey 5d7752b657 Allow build with shared librares (#939) 2022-04-29 03:23:22 +03:00
vadimdddd 9d94746479 Add transcriber tool (#851)
Add transcriber tool
2022-04-20 14:48:22 +03:00
Nickolay V. Shmyrev a87f2e1e07 Czech model 2022-04-13 22:31:45 +02:00
Nickolay Shmyrev 7b7d814484 Introduce incremental decoder with confidences in partial results 2022-04-07 01:07:47 +02:00
Nickolay Shmyrev 2daf67f31c C# style method name 2022-03-29 23:05:27 +02:00
Nickolay V. Shmyrev 62dd631379 Merge pull request #894 from gauthiersornet/patch-1
Update VoskDemo.cs
2022-03-22 22:35:16 +03:00
gauthiersornet 2511192ecb Update VoskDemo.cs
To read shorts from a binary buffer => fbuffer[i] = BitConverter.ToInt16(buffer, n);
2022-03-22 20:29:59 +01:00
Nickolay Shmyrev 22cb90de4a Add Hindi 2022-03-17 20:08:39 +01:00
Nickolay Shmyrev 3951834df2 Move decoding parts to decoding stage. Enable upsampling/downsampling 2022-03-05 14:52:11 +01:00
Nickolay Shmyrev 1ea0de106c Add trainign setup 2022-03-05 00:28:27 +01:00
Nickolay Shmyrev a9bf929ebd Add NLSML output for GPU recognizer 2022-03-03 23:01:49 +01:00
Nickolay Shmyrev 3336cd704b Add resampler 2022-03-03 21:48:25 +01:00
Nickolay Shmyrev a57a84f90e Refactor GPU API to hide the ID and keep it closer to CPU recognizer 2022-03-03 21:09:09 +01:00
Nickolay Shmyrev ad546a8f1a Also read processing options 2022-02-17 10:43:05 +01:00
Nickolay Shmyrev 1f447a8dfc Rename according to Kaldi changes 2022-02-10 20:52:55 +01:00
Nickolay Shmyrev f574d896e9 Emtpy result should be also xml 2022-02-03 23:43:00 +01:00
Nickolay Shmyrev a561c2d6d4 Don't add space before string 2022-02-03 23:26:53 +01:00
Nickolay Shmyrev 79b8395be0 Add NLSML output 2022-02-03 23:08:09 +01:00
Nickolay Shmyrev d2c11a611f Read list of files from arguments 2022-01-30 22:57:36 +01:00
Nickolay Shmyrev b0903413b1 Set soname for Android library 2022-01-21 13:22:26 +01:00
Nickolay Shmyrev 2135223490 Put stream information in a single structure 2022-01-12 14:58:43 +01:00
Nickolay Shmyrev 6f86944a06 Implement wave chunking for cuda decoder 2022-01-12 01:32:20 +01:00
Nickolay Shmyrev 9861be2787 Add libs as dependencies in Makefile 2022-01-10 20:21:24 +01:00
Nickolay Shmyrev c6fab363e6 Don't close channel which not yet started 2022-01-09 15:15:20 +01:00
Nickolay Shmyrev c32099705f Fix branch name and add implib dump 2022-01-07 17:33:47 +01:00
Nickolay Shmyrev a1eac015dc Add Esperanto 2022-01-07 16:27:57 +01:00
Nickolay Shmyrev 64dfc65d51 Merge branch 'master' of github.com:alphacep/vosk-api 2022-01-05 20:32:25 +01:00
Nickolay Shmyrev 70d5cbd0e0 Update README with Japanese 2022-01-05 20:32:08 +01:00
Nickolay Shmyrev 5428d36d16 Round times 2021-12-26 01:12:18 +01:00
Nickolay V. Shmyrev ed4c15b7aa Merge pull request #800 from alphacep/batch
Batch GPU decoding
2021-12-24 03:35:51 +03:00
Nickolay Shmyrev 525b722c44 Compile without CUDA too 2021-12-24 01:35:06 +01:00
Nickolay Shmyrev 72bf210164 Put the demo into main folder 2021-12-24 01:07:38 +01:00
Nickolay Shmyrev 93e81c3bc8 Bigger frames per chunk for our big models 2021-12-24 00:22:42 +01:00
Nickolay Shmyrev cb0f8e6411 Per-stream wait API 2021-12-23 22:34:47 +01:00
Nickolay Shmyrev 848b2dc753 Expose results in Python 2021-12-17 22:57:00 +01:00
Nickolay Shmyrev 60f0396fe0 Reset lattice on endpoint 2021-12-17 01:13:09 +01:00
Nickolay Shmyrev 344e137a61 Decoding works, results are empty yet 2021-12-13 01:21:59 +01:00
Nickolay Shmyrev 6977be7fb7 Batch recognizer draft 2021-12-12 21:37:44 +01:00
Nickolay V. Shmyrev a4721de8aa Merge pull request #759 from bertyhell/patch-1
Output correct SRT format using milliseconds (NodeJS SRT example)
2021-11-11 12:52:00 +03:00
Bert Verhelst 378ba122c8 Output correct SRT format using miliseconds 2021-11-11 10:49:50 +01:00
Nickolay Shmyrev 287160622f Update to latest state 0.3.32 2021-11-10 22:26:31 +03:00
Nickolay Shmyrev a5d788a2e9 One more fix to expose aar dependencies 2021-11-10 00:33:03 +01:00
Nickolay Shmyrev 7f651e1e45 Expose JNA dependency. Fix issue #757 2021-11-09 23:02:17 +01:00
Nickolay Shmyrev ad5bec114d Fix issue with empty lattice 2021-11-08 13:46:35 +01:00
Nickolay Shmyrev f71c62ad0f Publish Java jars on Mavencentral too 2021-11-07 21:26:33 +01:00
Nickolay Shmyrev 44f7dd2d8b Publish to sonatype 2021-11-07 20:41:49 +01:00
Nickolay Shmyrev 15a9508a78 Use ndk directory instead of sdk 2021-11-07 14:32:29 +01:00
Nickolay Shmyrev bdea9a53e8 Bump android version 2021-11-07 14:30:08 +01:00
Nickolay Shmyrev 81f58667ff Update Android build 2021-11-07 13:45:27 +01:00
Nickolay V. Shmyrev 680a2e4c31 Merge pull request #752 from sskorol/cuda-fix
Added missing cuda lib to Vosk compilation flags
2021-11-06 19:04:22 +03:00
sskorol 13993db542 Added missing cuda lib to Vosk compilation flags 2021-11-06 17:24:49 +02:00
Nickolay Shmyrev 59d595a4f0 Replace about in readme 2021-10-31 00:15:52 +02:00
Nickolay Shmyrev 4c562e15a4 Bump version to 0.3.32 2021-10-30 22:45:10 +02:00
Nickolay Shmyrev 5bcdf454ec Add fbank feature support 2021-10-30 22:45:01 +02:00
Nickolay Shmyrev 4ccdda44ac Extend documentation 2021-10-12 22:35:31 +02:00
Nickolay Shmyrev 5e46825474 Add try/catch wrapper for C++ method to raise native exceptions. Python and Java
are implemented, others on the way
2021-10-12 22:31:36 +02:00
Nickolay Shmyrev fcab5a9581 Revert CFFI bump 2021-10-10 22:09:55 +02:00
Nickolay Shmyrev e7f5e0ac23 Bump cffi version 2021-10-10 21:21:32 +02:00
Nickolay Shmyrev 9a3906831b Properly convert lattice. Fixes issue #713 2021-10-08 21:11:00 +02:00
Nickolay Shmyrev 195db43b9e Rename branches in kaldi repo 2021-10-07 01:18:47 +02:00
Nickolay Shmyrev 332553ec1e Revert rescoring to more accurate pure fst composition 2021-10-04 01:05:04 +02:00
Nickolay Shmyrev 646af3f652 Explain more about sample rate in constructor 2021-09-17 11:17:38 +02:00
Nickolay V. Shmyrev f24ac65fcb Merge pull request #688 from scroot/patch-1
Update vosk.go
2021-09-16 18:42:03 +03:00
scroot 14312c93f9 Update vosk.go
* fix partial result
+ Free
2021-09-16 09:55:26 +08:00
Nickolay Shmyrev 4346d4155d Fix go example 2021-09-02 10:48:19 +02:00
Nickolay Shmyrev 7790ac5040 Update versions in bindings 2021-08-31 22:42:42 +02:00
Nickolay Shmyrev 7b3ea0b59d Merge branch 'master' of github.com:alphacep/vosk-api 2021-08-31 21:56:49 +02:00
Nickolay Shmyrev e2af710369 Rework rescoring for faster and more accurate results 2021-08-31 21:56:21 +02:00
Nickolay V. Shmyrev 6b1b620f39 Merge pull request #678 from agorman/go-bindings
Cleaning up and completing go bindings
2021-08-31 22:34:19 +03:00
Andy Gorman 966524da16 gofmt 2021-08-31 12:24:19 -07:00
Andy Gorman 83c999f298 Cleaning up and completing go bindings 2021-08-31 12:18:34 -07:00
Nickolay Shmyrev abff8a4f56 Organize makefile structure 2021-07-29 11:58:31 +02:00
Timur 188575f3a2 Added MKL build options (#647)
Co-authored-by: Kasimov Timur <t.kasimov@cft.ru>
2021-07-29 11:03:39 +03:00
Nickolay Shmyrev 9f4d8ca187 Update doc 2021-07-12 20:29:42 +02:00
Nickolay Shmyrev 72cc8f3a5e Added test doc 2021-07-12 20:23:49 +02:00
Nickolay Shmyrev 915dcab597 Add doc 2021-07-11 15:54:42 +02:00
Nickolay Shmyrev d82052b168 Better have it here 2021-07-11 11:26:32 +02:00
Nickolay Shmyrev dbb65bc71c Unify example 2021-07-11 11:01:56 +02:00
Nickolay Shmyrev 2498bc595b Add module file 2021-07-11 10:22:24 +02:00
Nickolay Shmyrev fee63d712f Add go bindings 2021-07-10 23:44:15 +02:00
Nickolay Shmyrev 5965ea30e6 Fetch_sub returns original value 2021-07-06 12:11:12 +02:00
Nickolay Shmyrev 5c75495c03 Atomic refcounting for thread safety. See
https://github.com/alphacep/vosk-api/issues/606

for more details
2021-07-06 11:09:34 +02:00
Nickolay Shmyrev 98ae3c66cb Bump version 2021-06-28 02:09:06 +02:00
Nickolay Shmyrev 942e15484a Protect against multiple resets 2021-06-28 01:59:43 +02:00
Lars Kiesow 2349e66a97 Subtitles require word times (#607)
This is a port of the recent addition of commit 7ccf743, adding
`KaldiRecognizer.SetWords(True)` to the other examples dealing with
subtitles to the WebVTT example.

Without this, the example will not work with the most recent `vosk`
(0.3.30) Python package.
2021-06-27 18:06:11 +03:00
Nickolay Shmyrev 5750e3224f Merge branch 'master' of github.com:alphacep/vosk-api 2021-06-24 20:09:12 +02:00
Nickolay Shmyrev 558b4dd69e Don't align lattice twice 2021-06-24 20:08:54 +02:00
Lars Kiesow 02ef49f67e Allow Saving WebVTT (#605)
This patch is a small extension to the WebVTT example which allows to
directly save the WebVTT output to a file like this:

    ./test_webvtt.py test.wav out.vtt
2021-06-24 19:35:30 +03:00
Lars Kiesow 7cdf8f1d03 Add Python WebVTT Example (#601)
This patch adds an example for using webvtt-py to generate WebVTT files
from Vosk output. This is similar to the SRT example but still very
useful for generating an example video subtitle usable in web contexts.
2021-06-23 01:16:33 +03:00
Nickolay Shmyrev 7f894f784a Better check for the model files 2021-06-21 00:19:55 +02:00
Nickolay Shmyrev a770251151 Bump nodejs version to 0.3.30 2021-06-20 21:30:58 +02:00
Nickolay Shmyrev 7ccf743bb6 SRT requires word times 2021-06-10 10:37:15 +02:00
Nickolay Shmyrev 75bedfe06d Add a method to show/hide words and their times 2021-06-07 01:04:37 +02:00
Nickolay Shmyrev 4ea9885d44 Bump version 2021-05-30 21:59:46 +02:00
Nickolay Shmyrev 0930def9ec Fix critical accuracy issues, actually use rescoring 2021-05-30 21:58:06 +02:00
Nickolay Shmyrev 6aa5af7640 Add reset test 2021-05-26 21:22:07 +02:00
Nickolay Shmyrev e74fe5edf7 Reset reset flag 2021-05-26 21:01:27 +02:00
Nickolay Shmyrev cbb5d0fcdf Implement reset method in SpeechService 2021-05-26 20:51:44 +02:00
Nickolay Shmyrev d489bc40e4 Update Java part too 2021-05-26 00:59:08 +02:00
Nickolay Shmyrev 499b2f183a Introduce new API to set speaker model to already initialized recognizer.
Introduce a method to reset recognizer results to start from scratch without
computation of the result.
2021-05-26 00:46:32 +02:00
Nickolay Shmyrev f57b926f66 Unpack library, loading works on Windows 2021-05-23 01:29:29 +02:00
Nickolay Shmyrev 733dca5aea Attempt to fix loading on Windows 2021-05-22 00:41:30 +02:00
Nickolay Shmyrev 1ab7e8ca87 Use older API for backward compatibility 2021-05-20 20:48:21 +02:00
Nickolay Shmyrev 53426f794c Add note about Ukrainian 2021-05-20 01:29:15 +02:00
Nickolay Shmyrev f8189685e5 Add max alternatives output 2021-05-19 18:47:25 +02:00
Nickolay Shmyrev e6bd200c85 Proper path delimiter on windows 2021-05-13 09:36:56 +02:00
Nickolay Shmyrev 4a4c33fd9d Load dependent libraries 2021-05-10 01:39:26 +02:00
Nickolay Shmyrev dc44922b92 Add code to expand path 2021-05-10 01:26:05 +02:00
Nickolay Shmyrev 67896cfba7 Bump bindings versions 2021-05-05 20:50:25 +02:00
Nickolay Shmyrev ee8663e6d9 RNNLM rescoring support 2021-05-05 19:34:30 +02:00
Nickolay Shmyrev 652c05f052 Reformat and simplify code a bit 2021-05-02 21:44:54 +02:00
Nickolay Shmyrev 193d129d9e Model can be a symlink 2021-04-30 11:58:11 +02:00
Sadra Sabouri e995df4bc3 New Examples for Nodejs (Base on Python Examples) (#515) 2021-04-30 10:16:36 +03:00
Sergey Korol f6a30c3626 Added missing GPU methods to nuget package. (#514) 2021-04-29 20:57:56 +03:00
Nickolay Shmyrev ee95420f8f Fix spk model initialization 2021-04-27 23:24:10 +02:00
Nickolay Shmyrev 2221cd0209 Reorganize methods a bit 2021-04-26 23:25:05 +02:00
Nickolay Shmyrev 8368d831aa Add async processing demo 2021-04-26 22:34:33 +02:00
Nickolay Shmyrev 91a128b3ed Fix package name 2021-04-15 13:54:48 +02:00
Nickolay Shmyrev 83d8b63351 Merge branch 'master' of github.com:alphacep/vosk-api 2021-04-15 12:57:17 +02:00
Nickolay Shmyrev 0881aa856f Update for new API 2021-04-15 12:56:59 +02:00
Nickolay Shmyrev 77abb02ada Bump version 2021-04-12 12:23:11 +02:00
François Billioud 119c6cd0dc Update ffi-napi and improve dependency to ref-napi (#483)
With this change, we will use the same version of ref-napi than the one declared in ffi-napi, which reduce dependency tree, bundle size, risks of errors that could be fixed in one version and not in the other, etc
2021-04-01 22:12:14 +03:00
Nickolay Shmyrev cc649aa78e Fixes demo 2021-04-01 20:33:01 +02:00
François Billioud 0b0c9fce0e Types for typescript projects, and jsDoc (#461)
Implement Javascript API
2021-04-01 21:25:55 +03:00
Peter Kronenberg d845e2107f Allow libvosk.dll to get loaded on Windows (#478)
* Allow libvosk.dll to get loaded on Windows

Authored-by: Peter Kronenberg <peter.kronenberg@torch.ai>
2021-03-31 18:55:45 +03:00
Nickolay V. Shmyrev 69992a1b39 Android through JNA framework unified with Java (#476)
* Move to JNA

* Update for android

* Joint publishing

* Fix the developer id

* Added grammar constructor for Java
2021-03-30 23:36:26 +03:00
Nickolay Shmyrev f351280f49 Allow extra cflags 2021-03-30 19:24:00 +02:00
Nickolay Shmyrev c15065b044 Wrap short and float 2021-03-30 17:34:00 +02:00
Nickolay Shmyrev db41f16051 Docs are on the separate project 2021-03-29 00:38:54 +02:00
Nickolay Shmyrev e276de61be Give jar a name and fix OSX library path 2021-03-29 00:20:52 +02:00
Nickolay Shmyrev 43c786ab18 Move jars to our own maven and create a demo 2021-03-28 23:38:43 +02:00
Nickolay Shmyrev 1199f39d55 Move project to a library 2021-03-28 13:02:32 +02:00
Nickolay Shmyrev 70aab86257 Remove test code 2021-03-28 10:11:53 +02:00
Nickolay Shmyrev e4b0af7a8e Update nuget package, add osx library 2021-03-27 23:40:02 +01:00
Martin Mende a120d06f6b Fixed nodejs platform check (#464) 2021-03-24 17:08:39 +03:00
Nickolay Shmyrev e01ca37e45 Add osx module 2021-03-18 00:46:51 +01:00
Nickolay Shmyrev f5c3d898e2 Option to compile on Mac 2021-03-18 02:10:56 +03:00
Nickolay Shmyrev a5a3697b7c Copy data before queue, original data can be destroyed.
Fixes issue #444

Thanks to Alexander Zatvornitsky
2021-03-01 21:25:41 +01:00
Nickolay Shmyrev 4be9874ba2 Reformat 2021-02-28 22:40:40 +01:00
Peter Kronenberg 5647a2dc6a Java example with better type safety, Java objects and support for au… (#429)
Java example with better type safety, Java objects and support for autoclosable

Authored-by: Peter Kronenberg <peter.kronenberg@torch.ai>
2021-03-01 00:35:31 +03:00
Nickolay Shmyrev a067a5b5f3 Enable pitch if conf/pitch.conf is present
Fixes issue #442
2021-02-26 20:34:17 +01:00
Nickolay Shmyrev 475b0ecfc1 Free symbol table only if we loaded it 2021-02-25 19:17:13 +01:00
Nickolay V. Shmyrev 2a9a605144 Merge pull request #436 from sskorol/435-sync-master-with-gpu
Sync master with GPU
2021-02-22 13:41:37 +03:00
sskorol eea7ca571b - Added an optional HAVE_CUDA flag to build Vosk with GPU support.
- Added missing GpuInit/ThreadInit python wrappers.
2021-02-22 12:30:46 +02:00
Nickolay Shmyrev 11c16610ee Fix memory leaks for big models. Fixes issue #425. 2021-02-19 19:25:07 +01:00
Nickolay Shmyrev 2f4124eb66 Demonstrate speaker 2021-02-16 17:40:21 +01:00
Nickolay Shmyrev db3e31d7ce Automatically put .so file in resources 2021-02-16 17:33:09 +01:00
Nickolay Shmyrev d917af21ab Better search for Windows dlls 2021-02-12 22:24:54 +01:00
Nickolay Shmyrev 948c8c7cfd Update to 0.3.21 2021-02-12 10:13:50 +01:00
Nickolay Shmyrev dec8e1acf3 Move to JNA instead of JNR-FFI for better Android compatibility 2021-02-11 00:04:19 +01:00
Nickolay Shmyrev 3c020526ce No need for byte buffer 2021-02-10 23:32:47 +01:00
Nickolay Shmyrev b0da19b07f Java API through JNR-FFI 2021-02-10 23:16:20 +01:00
Nickolay Shmyrev 70bcd9b018 Platform is hardcoded now 2021-02-09 23:43:56 +01:00
Nickolay Shmyrev d2604b609d Copy out lib files too 2021-02-09 23:36:32 +01:00
Nickolay Shmyrev e960e0cacf Proper libraries and demo 2021-02-09 21:43:21 +01:00
Nickolay Shmyrev 77b114d434 Rework node bindings to use node-ffi-napi 2021-02-08 23:00:56 +01:00
Nickolay V. Shmyrev 2860092cef Merge pull request #401 from proger/patch-1
test_microphone: AcceptWaveform wants bytes
2021-02-08 01:50:07 +03:00
Vlad Ki c6119c4835 test_microphone: AcceptWavform wants bytes 2021-02-08 00:38:28 +02:00
Nickolay Shmyrev 415d1927e0 Add win32 wheel 2021-02-07 23:08:27 +01:00
Nickolay Shmyrev 3d1e21d242 Update dockcross build to cffi 2021-02-07 21:33:39 +01:00
Nickolay Shmyrev 7a75e1c3f4 Add arm architectures 2021-02-07 20:28:14 +01:00
Nickolay Shmyrev c3430e448a Add build for Windows wheel 2021-02-07 18:11:38 +01:00
Nickolay Shmyrev ae49ea60d2 Rework manylinux to use cffi 2021-02-07 15:26:23 +01:00
Nickolay Shmyrev 02dc0ce0c8 Take source location from environment 2021-02-07 15:17:35 +01:00
Nickolay Shmyrev 15697a18e8 Platform-specific wheel 2021-02-07 14:58:10 +01:00
Nickolay Shmyrev 481881e59d Fully move python to cffi 2021-02-07 13:23:03 +01:00
Nickolay Shmyrev 11a25b26a7 Add cffi wrapper 2021-02-07 10:57:57 +01:00
Nickolay Shmyrev bf87358f6c Add win32 build 2021-02-07 10:12:32 +01:00
Nickolay Shmyrev 04a8242230 Add vosk-api build 2021-02-07 01:55:47 +01:00
Nickolay Shmyrev ceb96c301c Separate openfst root 2021-02-07 01:48:45 +01:00
Nickolay Shmyrev 307df8fdc0 Add Win cross-compilation docker 2021-02-07 01:41:37 +01:00
Nickolay Shmyrev c44875a2dd Build libvosk in src folder, will be used for many bindings 2021-02-07 00:42:25 +01:00
Nickolay Shmyrev 31f11990ca Rename voskrecognizer 2021-02-07 00:32:47 +01:00
Nickolay Shmyrev b79b85856d Refactor C# API to properly work with nuget and precompiled libvosk.so library 2021-02-06 23:10:51 +01:00
Nickolay Shmyrev 6e861c6a19 Add nuget platforms 2021-02-05 00:39:27 +01:00
Nickolay Shmyrev cf62296a51 Update flags to hopefully fix the build 2021-02-02 14:43:12 +01:00
Nickolay Shmyrev 387b132814 Fix model version in Makefile. Thanks to Peter Kronenberg. 2021-01-26 23:19:34 +01:00
Nickolay Shmyrev de83de8624 Implement decoding on iOS with a microphone 2021-01-24 21:59:21 +01:00
Nickolay Shmyrev fe91b5a717 Preprocess header on the fly 2021-01-10 21:11:35 +01:00
Nickolay Shmyrev a052506a5d Add cffi example 2021-01-10 20:53:43 +01:00
Nickolay Shmyrev 6f2d6d0d69 Proper microphone recognizer with the queue 2021-01-09 23:16:35 +01:00
Nickolay Shmyrev a8ae6025bd Add a bit more optimization 2021-01-09 16:16:32 +01:00
Nickolay Shmyrev 1b8332a609 Raise to 0.3.17 2021-01-09 02:29:56 +01:00
Nickolay Shmyrev fe16ec7e57 Set lowest arch for linux 2021-01-09 01:47:23 +01:00
Nickolay Shmyrev c5ce5e46bd Add c++17 2021-01-09 01:46:13 +01:00
Nickolay Shmyrev 99d66670bc Update Android build 2021-01-08 13:30:28 +01:00
Nickolay Shmyrev 072b42cac6 Use our own dockcross 2021-01-08 00:56:18 +01:00
242 changed files with 26955 additions and 2723 deletions
+38 -31
View File
@@ -1,22 +1,25 @@
# Built application files
*.apk
*.ap_
# Java class files
*.class
# Object files
*.o
# Temp files
nohup.out
# Gradle files
.gradle/
build/
gradlew
gradlew.bat
gradle
# Local configuration file (sdk path, etc)
local.properties
gradle.properties
# Android
android/build
android/lib/build
android/model-en/build
android/model-en/src/main/assets/model-en-us
android/repo
*.apk
*.ap_
# Cmake
.cxx
@@ -27,12 +30,8 @@ wheelhouse
__pycache__
*.egg-info
python/dist
python/vosk/*.cc
python/vosk/*.c
python/vosk/*.h
python/vosk/*.i
python/vosk/vosk.py
python/vosk/vosk_wrap.cpp
python/build
python/vosk/*.so
python/test/db
python/test/hyp
python/test/model
@@ -41,24 +40,32 @@ python/test/result.txt
python/test/wav.scp
# Java
*.so
java/org
java/*.cc
java/model-spk/
java/model/
*.class
java/lib/model
java/demo/model
java/lib/build
java/demo/build
# CSharp
csharp/gen
csharp/*.exe
csharp/*.c
csharp/model/
csharp/test.wav
Vosk.dll
*.dll
*.so
*.dylib
*.nupkg
csharp/demo/model
csharp/demo/test.wav
csharp/demo/bin
csharp/demo/obj
# Node
nodejs/vosk_wrap.cc
nodejs/example/model
nodejs/example/test.wav
nodejs/demo/model
nodejs/demo/model-spk
nodejs/demo/test.wav
nodejs/node_modules
nodejs/package-lock.json
nodejs/build
# C
c/test_vosk
c/test_vosk_speaker
c/oprofile_data
c/model
c/test.wav
+1 -2
View File
@@ -7,11 +7,10 @@ matrix:
services:
- docker
env: DOCKER_IMAGE=alphacep/kaldi-manylinux:latest
PLAT=manylinux2010_x86_64
install:
- docker pull $DOCKER_IMAGE
script:
- docker run --rm -e PLAT=$PLAT -v `pwd`:/io $DOCKER_IMAGE $PRE_CMD /io/travis/build-wheels.sh
- docker run --rm -v `pwd`:/io $DOCKER_IMAGE $PRE_CMD /io/travis/build-wheels.sh
- ls wheelhouse/
+20
View File
@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.13)
project(vosk-api CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)
add_library(vosk
src/language_model.cc
src/model.cc
src/recognizer.cc
src/spk_model.cc
src/vosk_api.cc
)
find_package(kaldi REQUIRED)
target_link_libraries(vosk PUBLIC kaldi-base kaldi-online2 kaldi-rnnlm fstngram)
include(GNUInstallDirs)
install(TARGETS vosk DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES src/vosk_api.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+6 -4
View File
@@ -1,16 +1,18 @@
# About
# Vosk Speech Recognition Toolkit
Vosk is an offline open source speech recognition toolkit. It enables
speech recognition models for 17 languages and dialects - English, Indian
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.
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++ and others.
like Python, Java, Node.JS, C#, C++, Rust, Go and others.
Vosk supplies speech recognition for chatbots, smart home appliances,
virtual assistants. It can also create subtitles for movies,
-69
View File
@@ -1,69 +0,0 @@
# Vosk CMake File
cmake_minimum_required(VERSION 3.4.1)
if ("x${ANDROID_ABI}" STREQUAL "xarmeabi-v7a")
set(OPENBLAS_ARCH "armv7")
set(KALDI_SUFFIX "arm_32")
elseif ("x${ANDROID_ABI}" STREQUAL "xarm64-v8a")
set(OPENBLAS_ARCH "armv8")
set(KALDI_SUFFIX "arm_64")
elseif ("x${ANDROID_ABI}" STREQUAL "xx86")
set(OPENBLAS_ARCH "atom")
set(KALDI_SUFFIX "x86")
else ("x${ANDROID_ABI}" STREQUAL "xarmeabi-v7a")
set(OPENBLAS_ARCH "atom")
set(KALDI_SUFFIX "x86_64")
endif ("x${ANDROID_ABI}" STREQUAL "xarmeabi-v7a")
set(KALDI_ROOT "${PROJECT_SOURCE_DIR}/build/kaldi_${KALDI_SUFFIX}/kaldi")
set(LIB_ROOT "${PROJECT_SOURCE_DIR}/build/kaldi_${KALDI_SUFFIX}/local")
set(API_SOURCES
"${PROJECT_SOURCE_DIR}/../src/kaldi_recognizer.cc"
"${PROJECT_SOURCE_DIR}/../src/kaldi_recognizer.h"
"${PROJECT_SOURCE_DIR}/../src/language_model.cc"
"${PROJECT_SOURCE_DIR}/../src/language_model.h"
"${PROJECT_SOURCE_DIR}/../src/model.cc"
"${PROJECT_SOURCE_DIR}/../src/model.h"
"${PROJECT_SOURCE_DIR}/../src/spk_model.cc"
"${PROJECT_SOURCE_DIR}/../src/spk_model.h"
"${PROJECT_SOURCE_DIR}/../src/vosk_api.cc"
"${PROJECT_SOURCE_DIR}/../src/vosk_api.h"
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DFST_NO_DYNAMIC_LINKING")
add_library( vosk_jni SHARED
build/generated-src/cpp/vosk_wrap.cc
${API_SOURCES}
)
include_directories("${PROJECT_SOURCE_DIR}/../src" "build/kaldi_${KALDI_SUFFIX}/kaldi/src" "build/kaldi_${KALDI_SUFFIX}/local/include")
target_link_libraries( vosk_jni
${KALDI_ROOT}/src/online2/kaldi-online2.a
${KALDI_ROOT}/src/decoder/kaldi-decoder.a
${KALDI_ROOT}/src/ivector/kaldi-ivector.a
${KALDI_ROOT}/src/gmm/kaldi-gmm.a
${KALDI_ROOT}/src/nnet3/kaldi-nnet3.a
${KALDI_ROOT}/src/tree/kaldi-tree.a
${KALDI_ROOT}/src/feat/kaldi-feat.a
${KALDI_ROOT}/src/lat/kaldi-lat.a
${KALDI_ROOT}/src/lm/kaldi-lm.a
${KALDI_ROOT}/src/hmm/kaldi-hmm.a
${KALDI_ROOT}/src/transform/kaldi-transform.a
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a
${KALDI_ROOT}/src/matrix/kaldi-matrix.a
${KALDI_ROOT}/src/fstext/kaldi-fstext.a
${KALDI_ROOT}/src/util/kaldi-util.a
${KALDI_ROOT}/src/base/kaldi-base.a
${LIB_ROOT}/lib/libfst.a
${LIB_ROOT}/lib/libfstngram.a
${LIB_ROOT}/lib/libopenblas_${OPENBLAS_ARCH}-r0.3.7.a
${LIB_ROOT}/lib/libclapack.a
${LIB_ROOT}/lib/liblapack.a
${LIB_ROOT}/lib/libblas.a
${LIB_ROOT}/lib/libf2c.a
log
)
-141
View File
@@ -1,141 +0,0 @@
#!/bin/bash
# Copyright 2019 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.
if [ "x$ANDROID_SDK_HOME" == "x" ]; then
echo "ANDROID_SDK_HOME environment variable is undefined, define it with local.properties or with export"
exit 1
fi
if [ ! -d "$ANDROID_SDK_HOME" ]; then
echo "ANDROID_SDK_HOME ($ANDROID_SDK_HOME) is missing. Make sure you have sdk installed"
exit 1
fi
if [ ! -d "$ANDROID_SDK_HOME/ndk-bundle" ]; then
echo "$ANDROID_SDK_HOME/ndk-bundle is missing. Make sure you have ndk installed within sdk"
exit 1
fi
set -x
OS_NAME=`echo $(uname -s) | tr '[:upper:]' '[:lower:]'`
ANDROID_NDK_HOME=$ANDROID_SDK_HOME/ndk-bundle
ANDROID_TOOLCHAIN_PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/${OS_NAME}-x86_64
WORKDIR_X86=`pwd`/build/kaldi_x86
WORKDIR_X86_64=`pwd`/build/kaldi_x86_64
WORKDIR_ARM32=`pwd`/build/kaldi_arm_32
WORKDIR_ARM64=`pwd`/build/kaldi_arm_64
PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/${OS_NAME}-x86_64/bin
OPENFST_VERSION=1.6.7
mkdir -p $WORKDIR_ARM64/local/lib $WORKDIR_ARM32/local/lib $WORKDIR_X86_64/local/lib $WORKDIR_X86/local/lib
# Build standalone CLAPACK since gfortran is missing
cd build
git clone https://github.com/simonlynen/android_libs
cd android_libs/lapack
sed -i.bak -e 's/APP_STL := gnustl_static/APP_STL := c++_static/g' jni/Application.mk && \
sed -i.bak -e 's/android-10/android-21/g' project.properties && \
sed -i.bak -e 's/APP_ABI := armeabi armeabi-v7a/APP_ABI := armeabi-v7a arm64-v8a x86_64 x86/g' jni/Application.mk && \
sed -i.bak -e 's/LOCAL_MODULE:= testlapack/#LOCAL_MODULE:= testlapack/g' jni/Android.mk && \
sed -i.bak -e 's/LOCAL_SRC_FILES:= testclapack.cpp/#LOCAL_SRC_FILES:= testclapack.cpp/g' jni/Android.mk && \
sed -i.bak -e 's/LOCAL_STATIC_LIBRARIES := lapack/#LOCAL_STATIC_LIBRARIES := lapack/g' jni/Android.mk && \
sed -i.bak -e 's/include $(BUILD_SHARED_LIBRARY)/#include $(BUILD_SHARED_LIBRARY)/g' jni/Android.mk && \
${ANDROID_NDK_HOME}/ndk-build && \
cp obj/local/armeabi-v7a/*.a ${WORKDIR_ARM32}/local/lib && \
cp obj/local/arm64-v8a/*.a ${WORKDIR_ARM64}/local/lib
cp obj/local/x86_64/*.a ${WORKDIR_X86_64}/local/lib
cp obj/local/x86/*.a ${WORKDIR_X86}/local/lib
# Architecture-specific part
for arch in arm32 arm64 x86_64 x86; do
#for arch in x86_64; do
case $arch in
arm32)
BLAS_ARCH=ARMV7
WORKDIR=$WORKDIR_ARM32
HOST=arm-linux-androideabi
AR=arm-linux-androideabi-ar
CC=armv7a-linux-androideabi21-clang
CXX=armv7a-linux-androideabi21-clang++
ARCHFLAGS="-mfloat-abi=softfp -mfpu=neon"
;;
arm64)
BLAS_ARCH=ARMV8
WORKDIR=$WORKDIR_ARM64
HOST=aarch64-linux-android
AR=aarch64-linux-android-ar
CC=aarch64-linux-android21-clang
CXX=aarch64-linux-android21-clang++
ARCHFLAGS=""
;;
x86_64)
BLAS_ARCH=ATOM
WORKDIR=$WORKDIR_X86_64
HOST=x86_64-linux-android
AR=x86_64-linux-android-ar
CC=x86_64-linux-android21-clang
CXX=x86_64-linux-android21-clang++
ARCHFLAGS=""
;;
x86)
BLAS_ARCH=ATOM
WORKDIR=$WORKDIR_X86
HOST=i686-linux-android
AR=i686-linux-android-ar
CC=i686-linux-android21-clang
CXX=i686-linux-android21-clang++
ARCHFLAGS=""
;;
esac
# openblas first
cd $WORKDIR
git clone -b v0.3.7 --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
make -C OpenBLAS install PREFIX=$WORKDIR/local
# tools directory --> we'll only compile OpenFST
cd $WORKDIR
git clone https://github.com/alphacep/openfst
cd openfst
autoreconf -i
CXX=$CXX CXXFLAGS="$ARCHFLAGS -O3 -DFST_NO_DYNAMIC_LINKING" ./configure --prefix=${WORKDIR}/local \
--enable-shared --enable-static --with-pic --disable-bin \
--enable-lookahead-fsts --enable-ngram-fsts --host=$HOST --build=x86-linux-gnu
make -j 8
make install
# Kaldi itself
cd $WORKDIR
git clone -b android-mix --single-branch https://github.com/alphacep/kaldi
cd $WORKDIR/kaldi/src
if [ "`uname`" == "Darwin" ]; then
sed -i.bak -e 's/libfst.dylib/libfst.a/' configure
fi
CXX=$CXX CXXFLAGS="$ARCHFLAGS -O3 -DFST_NO_DYNAMIC_LINKING" ./configure --use-cuda=no \
--mathlib=OPENBLAS --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
make -j 8 online2 lm
done
+37 -94
View File
@@ -1,110 +1,53 @@
buildscript {
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
classpath 'com.android.tools.build:gradle:7.4.0'
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.24.0'
}
}
plugins {
id "com.jfrog.bintray" version "1.8.5"
}
def archiveName = "vosk-android"
def libVersion = "0.3.16"
allprojects {
repositories {
google()
jcenter()
}
version = '0.3.47'
}
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
subprojects {
android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 21
targetSdkVersion 29
versionCode 6
versionName = libVersion
archivesBaseName = archiveName
externalNativeBuild {
cmake {
arguments "-DCMAKE_VERBOSE_MAKEFILE=ON", "-DANDROID_ARM_NEON=TRUE", "-DCMAKE_CXX_FLAGS_RELEASE=-O3"
apply plugin: 'com.android.library'
apply plugin: 'com.vanniktech.maven.publish'
repositories {
google()
mavenCentral()
}
mavenPublishing {
publishToMavenCentral(com.vanniktech.maven.publish.SonatypeHost.S01, false)
signAllPublications()
}
mavenPublishing {
pom {
url = 'http://www.alphacephei.com.com/vosk/'
licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id = 'com.alphacephei'
name = 'Alpha Cephei Inc'
email = 'contact@alphacephei.com'
}
}
scm {
connection = 'scm:git:git://github.com/alphacep/vosk-api.git'
url = 'https://github.com/alphacep/vosk-api/'
}
}
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64', 'x86'
}
}
sourceSets {
main {
java.srcDirs = ['src/main/java', 'build/generated-src']
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
bintray {
user = properties.getProperty("bintray.user")
key = properties.getProperty("bintray.apikey")
pkg {
repo = 'vosk'
name = 'vosk-android'
userOrg = "alphacep"
licenses = ['Apache2.0']
websiteUrl = 'https://github.com/alphacep/vosk-api'
issueTrackerUrl = 'https://github.com/alphacep/vosk-api/issues'
vcsUrl = 'https://github.com/alphacep/vosk-api'
version {
name = libVersion
vcsTag = libVersion
}
}
publications = ['aar']
}
publishing {
publications {
aar(MavenPublication) {
groupId 'com.alphacep'
artifactId archiveName
version libVersion
artifact("$buildDir/outputs/aar/$archiveName-release.aar")
}
}
}
task swig {
doLast {
mkdir 'build/generated-src/java'
mkdir 'build/generated-src/cpp'
exec {
commandLine 'swig',
"-c++",
"-java", "-package", "org.kaldi",
"-outdir", "build/generated-src/java", "-o", "build/generated-src/cpp/vosk_wrap.cc",
"../src/vosk.i"
}
}
}
task kaldi(type: Exec) {
commandLine './build-kaldi.sh'
environment ANDROID_SDK_HOME: android.getSdkDirectory()
}
preBuild.dependsOn kaldi, swig
+135
View File
@@ -0,0 +1,135 @@
#!/bin/bash
# Copyright 2019-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.
# 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.
if [ "x$ANDROID_NDK_HOME" == "x" ]; then
echo "ANDROID_NDK_HOME environment variable is undefined, define it with local.properties or with export"
exit 1
fi
if [ ! -d "$ANDROID_NDK_HOME" ]; then
echo "ANDROID_NDK_HOME ($ANDROID_NDK_HOME) is missing. Make sure you have ndk installed"
exit 1
fi
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=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/${OS_NAME}-x86_64/bin:$PATH
OPENFST_VERSION=1.8.0
for arch in armeabi-v7a arm64-v8a x86_64 x86; do
WORKDIR=${WORKDIR_BASE}/kaldi_${arch}
case $arch in
armeabi-v7a)
BLAS_ARCH=ARMV7
HOST=arm-linux-androideabi
AR=llvm-ar
RANLIB=llvm-ranlib
CC=armv7a-linux-androideabi21-clang
CXX=armv7a-linux-androideabi21-clang++
ARCHFLAGS="-mfloat-abi=softfp -mfpu=neon"
;;
arm64-v8a)
BLAS_ARCH=ARMV8
HOST=aarch64-linux-android
AR=llvm-ar
RANLIB=llvm-ranlib
CC=aarch64-linux-android21-clang
CXX=aarch64-linux-android21-clang++
ARCHFLAGS=""
;;
x86_64)
BLAS_ARCH=ATOM
HOST=x86_64-linux-android
AR=llvm-ar
RANLIB=llvm-ranlib
CC=x86_64-linux-android21-clang
CXX=x86_64-linux-android21-clang++
ARCHFLAGS=""
;;
x86)
BLAS_ARCH=ATOM
HOST=i686-linux-android
AR=llvm-ar
RANLIB=llvm-ranlib
CC=i686-linux-android21-clang
CXX=i686-linux-android21-clang++
ARCHFLAGS=""
;;
esac
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
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 \
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
-DCMAKE_CROSSCOMPILING=True ..
make -j 8 -C F2CLIBS/libf2c
make -j 8 -C BLAS/SRC
make -j 8 -C SRC
find . -name "*.a" | xargs cp -t $WORKDIR/local/lib
# tools directory --> we'll only compile OpenFST
cd $WORKDIR
git clone https://github.com/alphacep/openfst
cd openfst
autoreconf -i
CXX=$CXX CXXFLAGS="$ARCHFLAGS -O3 -DFST_NO_DYNAMIC_LINKING" ./configure --prefix=${WORKDIR}/local \
--enable-shared --enable-static --with-pic --disable-bin \
--enable-lookahead-fsts --enable-ngram-fsts --host=$HOST --build=x86-linux-gnu
make -j 8
make install
# Kaldi itself
cd $WORKDIR
git clone -b vosk-android --single-branch https://github.com/alphacep/kaldi
cd $WORKDIR/kaldi/src
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
# Vosk-api
cd $WORKDIR
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"
cp $WORKDIR/vosk/libvosk.so $WORKDIR/../../src/main/jniLibs/$arch/libvosk.so
done
+39
View File
@@ -0,0 +1,39 @@
def archiveName = "vosk-android"
def pomName = "Vosk Android"
def pomDescription = "Vosk speech recognition library for Android"
android {
namespace 'org.vosk'
compileSdkVersion 33
defaultConfig {
minSdkVersion 21
targetSdkVersion 33
versionCode 10
versionName = version
archivesBaseName = archiveName
ndkVersion = "25.2.9519653"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
task buildVosk(type: Exec) {
commandLine './build-vosk.sh'
environment ANDROID_NDK_HOME: android.getNdkDirectory()
}
dependencies {
api 'net.java.dev.jna:jna:5.13.0@aar'
}
//preBuild.dependsOn buildVosk
mavenPublishing {
coordinates("com.alphacephei", archiveName, version)
pom {
name = pomName
description = pomDescription
}
}
+3
View File
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest>
</manifest>
@@ -0,0 +1,72 @@
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;
import java.io.InputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
public class LibVosk {
static {
Native.register(LibVosk.class, "vosk");
}
public static native void vosk_set_log_level(int level);
public static native Pointer vosk_model_new(String path);
public static native void vosk_model_free(Pointer model);
public static native Pointer vosk_spk_model_new(String path);
public static native void vosk_spk_model_free(Pointer model);
public static native Pointer vosk_recognizer_new(Model model, float sample_rate);
public static native Pointer vosk_recognizer_new_spk(Pointer model, float sample_rate, Pointer spk_model);
public static native Pointer vosk_recognizer_new_grm(Pointer model, float sample_rate, String grammar);
public static native void vosk_recognizer_set_max_alternatives(Pointer recognizer, int max_alternatives);
public static native void vosk_recognizer_set_words(Pointer recognizer, boolean words);
public static native void vosk_recognizer_set_partial_words(Pointer recognizer, boolean partial_words);
public static native void vosk_recognizer_set_spk_model(Pointer recognizer, Pointer spk_model);
public static native boolean vosk_recognizer_accept_waveform(Pointer recognizer, byte[] data, int len);
public static native boolean vosk_recognizer_accept_waveform_s(Pointer recognizer, short[] data, int len);
public static native boolean vosk_recognizer_accept_waveform_f(Pointer recognizer, float[] data, int len);
public static native String vosk_recognizer_result(Pointer recognizer);
public static native String vosk_recognizer_final_result(Pointer recognizer);
public static native String vosk_recognizer_partial_result(Pointer recognizer);
public static native void vosk_recognizer_set_grm(Pointer recognizer, String grammar);
public static native void vosk_recognizer_reset(Pointer recognizer);
public static native void vosk_recognizer_free(Pointer recognizer);
/**
* Set log level for Kaldi messages.
*
* @param loglevel the level
* 0 - default value to print info and error messages but no debug
* less than 0 - don't print info messages
* greater than 0 - more verbose mode
*/
public static void setLogLevel(LogLevel loglevel) {
vosk_set_log_level(loglevel.getValue());
}
}
@@ -0,0 +1,17 @@
package org.vosk;
public enum LogLevel {
WARNINGS(-1), // Print warning and errors
INFO(0), // Print info, along with warning and error messages, but no debug
DEBUG(1); // Print debug info
private final int value;
LogLevel(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
@@ -0,0 +1,22 @@
package org.vosk;
import java.io.IOException;
import com.sun.jna.PointerType;
public class Model extends PointerType implements AutoCloseable {
public Model() {
}
public Model(String path) throws IOException {
super(LibVosk.vosk_model_new(path));
if (getPointer() == null) {
throw new IOException("Failed to create a model");
}
}
@Override
public void close() {
LibVosk.vosk_model_free(this.getPointer());
}
}
@@ -0,0 +1,247 @@
package org.vosk;
import com.sun.jna.PointerType;
import java.io.IOException;
public class Recognizer extends PointerType implements AutoCloseable {
/**
* Creates the recognizer object.
*
* The recognizers process the speech and return text using shared model data
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @throws IOException if the recognizer could not be created
*/
public Recognizer(Model model, float sampleRate) throws IOException {
super(LibVosk.vosk_recognizer_new(model, sampleRate));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* Creates the recognizer object with speaker recognition.
*
* With the speaker recognition mode the recognizer not just recognize
* text but also return speaker vectors one can use for speaker identification
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param spkModel speaker model for speaker identification
* @throws IOException if the recognizer could not be created
*/
public Recognizer(Model model, float sampleRate, SpeakerModel spkModel) throws IOException {
super(LibVosk.vosk_recognizer_new_spk(model.getPointer(), sampleRate, spkModel.getPointer()));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* Creates the recognizer object with the phrase list.
*
* Sometimes when you want to improve recognition accuracy and when you don't need
* to recognize large vocabulary you can specify a list of phrases to recognize. This
* will improve recognizer speed and accuracy but might return [unk] if user said
* something different.
*
* Only recognizers with lookahead models support this type of quick configuration.
* Precompiled HCLG graph models are not supported.
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
* for example "["one two three four five", "[unk]"]".
* @throws IOException if the recognizer could not be created
*/
public Recognizer(Model model, float sampleRate, String grammar) throws IOException {
super(LibVosk.vosk_recognizer_new_grm(model.getPointer(), sampleRate, grammar));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* Configures recognizer to output n-best results.
*
* <pre>
* {
* "alternatives": [
* { "text": "one two three four five", "confidence": 0.97 },
* { "text": "one two three for five", "confidence": 0.03 },
* ]
* }
* </pre>
*
* @param maxAlternatives - maximum alternatives to return from recognition results
*/
public void setMaxAlternatives(int maxAlternatives) {
LibVosk.vosk_recognizer_set_max_alternatives(this.getPointer(), maxAlternatives);
}
/** Enables words with times in the output
*
* <pre>
* "result" : [{
* "conf" : 1.000000,
* "end" : 1.110000,
* "start" : 0.870000,
* "word" : "what"
* }, {
* "conf" : 1.000000,
* "end" : 1.530000,
* "start" : 1.110000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 1.950000,
* "start" : 1.530000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.340000,
* "start" : 1.950000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.610000,
* "start" : 2.340000,
* "word" : "one"
* }],
* </pre>
*
* @param words - boolean value
*/
public void setWords(boolean words) {
LibVosk.vosk_recognizer_set_words(this.getPointer(), words);
}
/**
* Like above return words and confidences in partial results.
*
* @param partial_words - boolean value
*/
public void setPartialWords(boolean partial_words) {
LibVosk.vosk_recognizer_set_partial_words(this.getPointer(), partial_words);
}
/**
* Adds speaker model to already initialized recognizer.
*
* Can add speaker recognition model to already created recognizer.
* Helps to initialize speaker recognition for grammar-based recognizer.
*
* @param spkModel Speaker recognition model
*/
public void setSpeakerModel(SpeakerModel spkModel) {
LibVosk.vosk_recognizer_set_spk_model(this.getPointer(), spkModel.getPointer());
}
/**
* Accept and process new chunk of voice data.
*
* @param data - audio data in PCM 16-bit mono format
* @param len - length of the audio data
* @return 1 if silence is occurred and you can retrieve a new utterance with result method
* 0 if decoding continues
* -1 if exception occurred
*/
public boolean acceptWaveForm(byte[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform(this.getPointer(), data, len);
}
public boolean acceptWaveForm(short[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform_s(this.getPointer(), data, len);
}
public boolean acceptWaveForm(float[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform_f(this.getPointer(), data, len);
}
/**
* Returns speech recognition result
*
* @return the result in JSON format which contains decoded line, decoded
* words, times in seconds and confidences. You can parse this result
* with any json parser
*
* <pre>
* {
* "text" : "what zero zero zero one"
* }
* </pre>
*
* If alternatives enabled it returns result with alternatives, see also #setMaxAlternatives().
*
* If word times enabled returns word time, see also #setWordTimes().
*/
public String getResult() {
return LibVosk.vosk_recognizer_result(this.getPointer());
}
/**
* Returns partial speech recognition.
*
* @return partial speech recognition text which is not yet finalized.
* result may change as recognizer process more data.
*
* <pre>
* {
* "partial" : "cyril one eight zero"
* }
* </pre>
*/
public String getPartialResult() {
return LibVosk.vosk_recognizer_partial_result(this.getPointer());
}
/**
* Returns speech recognition result. Same as result, but doesn't wait for silence.
* You usually call it in the end of the stream to get final bits of audio. It
* flushes the feature pipeline, so all remaining audio chunks got processed.
*
* @return speech result in JSON format.
*/
public String getFinalResult() {
return LibVosk.vosk_recognizer_final_result(this.getPointer());
}
/**
* Reconfigures recognizer to use grammar.
*
* @param grammar Set of phrases in JSON array of strings or "[]" to use default model graph.
* @see #Recognizer(Model, float, String)
*/
public void setGrammar(String grammar) {
LibVosk.vosk_recognizer_set_grm(this.getPointer(), grammar);
}
/**
* Resets the recognizer.
* Resets current results so the recognition can continue from scratch.
*/
public void reset() {
LibVosk.vosk_recognizer_reset(this.getPointer());
}
/**
* Releases recognizer object.
* Underlying model is also unreferenced and if needed, released.
*/
@Override
public void close() {
LibVosk.vosk_recognizer_free(this.getPointer());
}
}
@@ -0,0 +1,40 @@
package org.vosk;
import com.sun.jna.PointerType;
import java.io.IOException;
/**
* Helps to initialize speaker recognition for grammar-based recognizer.
*/
public class SpeakerModel extends PointerType implements AutoCloseable {
public SpeakerModel() {
}
/**
* Loads speaker model data from the file.
*
* The path must contain:
* - a config file: mfcc.conf
* - kaldi nnet: final.ext.raw
* - mean.vec
* - transform.mat
*
* @param path the path of the model on the filesystem
* @throws IOException if the model could not be created
*
* @see <a href="http://kaldi-asr.org/doc/structkaldi_1_1MfccOptions.html">Kaldi MfccOptions</a>
* @see <a href="http://kaldi-asr.org/doc/classkaldi_1_1nnet3_1_1Nnet.html">Kaldi Nnet</a>
*/
public SpeakerModel(String path) throws IOException {
super(LibVosk.vosk_spk_model_new(path));
if (getPointer() == null) {
throw new IOException("Failed to create a speaker model");
}
}
@Override
public void close() {
LibVosk.vosk_spk_model_free(this.getPointer());
}
}
@@ -12,28 +12,35 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package org.kaldi;
package org.vosk.android;
/** Interface to receive recognition results */
/**
* Interface to receive recognition results
*/
public interface RecognitionListener {
/**
* Called when partial recognition result is available.
*/
public void onPartialResult(String hypothesis);
void onPartialResult(String hypothesis);
/**
* Called after the recognition is ended.
* Called after silence occured.
*/
public void onResult(String hypothesis);
void onResult(String hypothesis);
/**
* Called after stream end.
*/
void onFinalResult(String hypothesis);
/**
* Called when an error occurs.
*/
public void onError(Exception exception);
void onError(Exception exception);
/**
* Called after timeout expired
*/
public void onTimeout();
void onTimeout();
}
@@ -12,54 +12,46 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package org.kaldi;
import static java.lang.String.format;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
package org.vosk.android;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder.AudioSource;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.annotation.SuppressLint;
import org.vosk.Recognizer;
import java.io.IOException;
/**
* Service that records audio in a thread, passes it to a recognizer and emits
* Service that records audio in a thread, passes it to a recognizer and emits
* recognition results. Recognition events are passed to a client using
* {@link RecognitionListener}
*
*/
public class SpeechService {
protected static final String TAG = SpeechService.class.getSimpleName();
private final KaldiRecognizer recognizer;
private final Recognizer recognizer;
private final int sampleRate;
private final static float BUFFER_SIZE_SECONDS = 0.4f;
private int bufferSize;
private final static float BUFFER_SIZE_SECONDS = 0.2f;
private final int bufferSize;
private final AudioRecord recorder;
private Thread recognizerThread;
private RecognizerThread recognizerThread;
private final Handler mainHandler = new Handler(Looper.getMainLooper());
private final Collection<RecognitionListener> listeners = new HashSet<RecognitionListener>();
/**
* Creates speech service. Service holds the AudioRecord object, so you
* need to call {@link release} in order to properly finalize it.
*
* Creates speech service. Service holds the AudioRecord object, so you
* need to call {@link #shutdown()} in order to properly finalize it.
*
* @throws IOException thrown if audio recorder can not be created for some reason.
*/
public SpeechService(KaldiRecognizer recognizer, float sampleRate) throws IOException {
@SuppressLint("MissingPermission")
public SpeechService(Recognizer recognizer, float sampleRate) throws IOException {
this.recognizer = recognizer;
this.sampleRate = (int)sampleRate;
this.sampleRate = (int) sampleRate;
bufferSize = Math.round(this.sampleRate * BUFFER_SIZE_SECONDS);
recorder = new AudioRecord(
@@ -74,34 +66,17 @@ public class SpeechService {
}
}
/**
* Adds listener.
*/
public void addListener(RecognitionListener listener) {
synchronized (listeners) {
listeners.add(listener);
}
}
/**
* Removes listener.
*/
public void removeListener(RecognitionListener listener) {
synchronized (listeners) {
listeners.remove(listener);
}
}
/**
* Starts recognition. Does nothing if recognition is active.
*
*
* @return true if recognition was actually started
*/
public boolean startListening() {
public boolean startListening(RecognitionListener listener) {
if (null != recognizerThread)
return false;
recognizerThread = new RecognizerThread();
recognizerThread = new RecognizerThread(listener);
recognizerThread.start();
return true;
}
@@ -109,16 +84,16 @@ public class SpeechService {
/**
* 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.
*
* <p>
* timeout - timeout in milliseconds to listen.
*
* @return true if recognition was actually started
*/
public boolean startListening(int timeout) {
public boolean startListening(RecognitionListener listener, int timeout) {
if (null != recognizerThread)
return false;
recognizerThread = new RecognizerThread(timeout);
recognizerThread = new RecognizerThread(listener, timeout);
recognizerThread.start();
return true;
}
@@ -140,31 +115,28 @@ public class SpeechService {
}
/**
* Stops recognition. All listeners should receive final result if there is
* 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
*/
public boolean stop() {
boolean result = stopRecognizerThread();
if (result) {
mainHandler.post(new ResultEvent(recognizer.Result(), true));
}
return result;
return stopRecognizerThread();
}
/**
* Cancels recognition. Listeners do not receive final result. Does nothing
* if recognition is not active.
*
* @return true if recognition was actually canceled
* 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
*/
public boolean cancel() {
boolean result = stopRecognizerThread();
recognizer.Result(); // Reset recognizer state
return result;
if (recognizerThread != null) {
recognizerThread.setPause(true);
}
return stopRecognizerThread();
}
/**
* Shutdown the recognizer and release the recorder
*/
@@ -172,13 +144,33 @@ public class SpeechService {
recorder.release();
}
public void setPause(boolean paused) {
if (recognizerThread != null) {
recognizerThread.setPause(paused);
}
}
/**
* Resets recognizer in a thread, starts recognition over again
*/
public void reset() {
if (recognizerThread != null) {
recognizerThread.reset();
}
}
private final class RecognizerThread extends Thread {
private int remainingSamples;
private int timeoutSamples;
private final int timeoutSamples;
private final static int NO_TIMEOUT = -1;
private volatile boolean paused = false;
private volatile boolean reset = false;
public RecognizerThread(int timeout) {
RecognitionListener listener;
public RecognizerThread(RecognitionListener listener, int timeout) {
this.listener = listener;
if (timeout != NO_TIMEOUT)
this.timeoutSamples = timeout * sampleRate / 1000;
else
@@ -186,8 +178,25 @@ public class SpeechService {
this.remainingSamples = this.timeoutSamples;
}
public RecognizerThread() {
this(NO_TIMEOUT);
public RecognizerThread(RecognitionListener listener) {
this(listener, NO_TIMEOUT);
}
/**
* When we are paused, don't process audio by the recognizer and don't emit
* any listener results
*
* @param paused the status of pause
*/
public void setPause(boolean paused) {
this.paused = paused;
}
/**
* Set reset state to signal reset of the recognizer and start over
*/
public void reset() {
this.reset = true;
}
@Override
@@ -198,8 +207,7 @@ public class SpeechService {
recorder.stop();
IOException ioe = new IOException(
"Failed to start recording. Microphone might be already in use.");
mainHandler.post(new OnErrorEvent(ioe));
return;
mainHandler.post(() -> listener.onError(ioe));
}
short[] buffer = new short[bufferSize];
@@ -208,15 +216,24 @@ public class SpeechService {
&& ((timeoutSamples == NO_TIMEOUT) || (remainingSamples > 0))) {
int nread = recorder.read(buffer, 0, buffer.length);
if (nread < 0) {
if (paused) {
continue;
}
if (reset) {
recognizer.reset();
reset = false;
}
if (nread < 0)
throw new RuntimeException("error reading audio buffer");
if (recognizer.acceptWaveForm(buffer, nread)) {
final String result = recognizer.getResult();
mainHandler.post(() -> listener.onResult(result));
} else {
boolean isFinal = recognizer.AcceptWaveform(buffer, nread);
if (isFinal) {
mainHandler.post(new ResultEvent(recognizer.Result(), true));
} else {
mainHandler.post(new ResultEvent(recognizer.PartialResult(), false));
}
final String partialResult = recognizer.getPartialResult();
mainHandler.post(() -> listener.onPartialResult(partialResult));
}
if (timeoutSamples != NO_TIMEOUT) {
@@ -226,61 +243,16 @@ public class SpeechService {
recorder.stop();
// Remove all pending notifications.
mainHandler.removeCallbacksAndMessages(null);
// If we met timeout signal that speech ended
if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) {
mainHandler.post(new TimeoutEvent());
if (!paused) {
// If we met timeout signal that speech ended
if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) {
mainHandler.post(() -> listener.onTimeout());
} else {
final String finalResult = recognizer.getFinalResult();
mainHandler.post(() -> listener.onFinalResult(finalResult));
}
}
}
}
private abstract class RecognitionEvent implements Runnable {
public void run() {
RecognitionListener[] emptyArray = new RecognitionListener[0];
for (RecognitionListener listener : listeners.toArray(emptyArray))
execute(listener);
}
protected abstract void execute(RecognitionListener listener);
}
private class ResultEvent extends RecognitionEvent {
protected final String hypothesis;
private final boolean finalResult;
ResultEvent(String hypothesis, boolean finalResult) {
this.hypothesis = hypothesis;
this.finalResult = finalResult;
}
@Override
protected void execute(RecognitionListener listener) {
if (finalResult)
listener.onResult(hypothesis);
else
listener.onPartialResult(hypothesis);
}
}
private class OnErrorEvent extends RecognitionEvent {
private final Exception exception;
OnErrorEvent(Exception exception) {
this.exception = exception;
}
@Override
protected void execute(RecognitionListener listener) {
listener.onError(exception);
}
}
private class TimeoutEvent extends RecognitionEvent {
@Override
protected void execute(RecognitionListener listener) {
listener.onTimeout();
}
}
}
@@ -0,0 +1,165 @@
// Copyright 2019 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;
/**
* 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
* {@link RecognitionListener}
*/
public class SpeechStreamService {
private final Recognizer recognizer;
private final InputStream inputStream;
private final int sampleRate;
private final static float BUFFER_SIZE_SECONDS = 0.2f;
private final int bufferSize;
private Thread recognizerThread;
private final Handler mainHandler = new Handler(Looper.getMainLooper());
/**
* Creates speech service.
**/
public SpeechStreamService(Recognizer recognizer, InputStream inputStream, float sampleRate) {
this.recognizer = recognizer;
this.sampleRate = (int) sampleRate;
this.inputStream = inputStream;
bufferSize = Math.round(this.sampleRate * BUFFER_SIZE_SECONDS * 2);
}
/**
* Starts recognition. Does nothing if recognition is active.
*
* @return true if recognition was actually started
*/
public boolean start(RecognitionListener listener) {
if (null != recognizerThread)
return false;
recognizerThread = new 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.
* <p>
* timeout - timeout in milliseconds to listen.
*
* @return true if recognition was actually started
*/
public boolean start(RecognitionListener listener, int timeout) {
if (null != recognizerThread)
return false;
recognizerThread = new 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
*/
public boolean stop() {
if (null == recognizerThread)
return false;
try {
recognizerThread.interrupt();
recognizerThread.join();
} catch (InterruptedException e) {
// Restore the interrupted status.
Thread.currentThread().interrupt();
}
recognizerThread = null;
return true;
}
private final class RecognizerThread extends Thread {
private int remainingSamples;
private final int timeoutSamples;
private final static int NO_TIMEOUT = -1;
RecognitionListener listener;
public RecognizerThread(RecognitionListener listener, int timeout) {
this.listener = listener;
if (timeout != NO_TIMEOUT)
this.timeoutSamples = timeout * sampleRate / 1000;
else
this.timeoutSamples = NO_TIMEOUT;
this.remainingSamples = this.timeoutSamples;
}
public RecognizerThread(RecognitionListener listener) {
this(listener, NO_TIMEOUT);
}
@Override
public void run() {
byte[] buffer = new byte[bufferSize];
while (!interrupted()
&& ((timeoutSamples == NO_TIMEOUT) || (remainingSamples > 0))) {
try {
int nread = inputStream.read(buffer, 0, buffer.length);
if (nread < 0) {
break;
} else {
boolean isSilence = recognizer.acceptWaveForm(buffer, nread);
if (isSilence) {
final String result = recognizer.getResult();
mainHandler.post(() -> listener.onResult(result));
} else {
final String partialResult = recognizer.getPartialResult();
mainHandler.post(() -> listener.onPartialResult(partialResult));
}
}
if (timeoutSamples != NO_TIMEOUT) {
remainingSamples = remainingSamples - nread;
}
} catch (IOException e) {
mainHandler.post(() -> listener.onError(e));
}
}
// If we met timeout signal that speech ended
if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) {
mainHandler.post(() -> listener.onTimeout());
} else {
final String finalResult = recognizer.getFinalResult();
mainHandler.post(() -> listener.onFinalResult(finalResult));
}
}
}
}
@@ -0,0 +1,150 @@
// Copyright 2019 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.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* Provides utility methods to sync model files to external storage to allow
* C++ code access them. Relies on file named "uuid" to track updates.
*/
public class StorageService {
protected static final String TAG = StorageService.class.getSimpleName();
public interface Callback<R> {
void onComplete(R result);
}
public static void unpack(Context context, String sourcePath, final String targetPath, final Callback<Model> completeCallback, final Callback<IOException> errorCallback) {
Executor executor = Executors.newSingleThreadExecutor(); // change according to your requirements
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
try {
final String outputPath = sync(context, sourcePath, targetPath);
Model model = new Model(outputPath);
handler.post(() -> completeCallback.onComplete(model));
} catch (final IOException e) {
handler.post(() -> errorCallback.onComplete(e));
}
});
}
public static String sync(Context context, String sourcePath, String targetPath) throws IOException {
AssetManager assetManager = context.getAssets();
File externalFilesDir = context.getExternalFilesDir(null);
if (externalFilesDir == null) {
throw new IOException("cannot get external files dir, "
+ "external storage state is " + Environment.getExternalStorageState());
}
File targetDir = new File(externalFilesDir, targetPath);
String resultPath = new File(targetDir, sourcePath).getAbsolutePath();
String sourceUUID = readLine(assetManager.open(sourcePath + "/uuid"));
try {
String targetUUID = readLine(new FileInputStream(new File(targetDir, sourcePath + "/uuid")));
if (targetUUID.equals(sourceUUID)) return resultPath;
} catch (FileNotFoundException e) {
// ignore
}
deleteContents(targetDir);
copyAssets(assetManager, sourcePath, targetDir);
// Copy uuid
copyFile(assetManager, sourcePath + "/uuid", targetDir);
return resultPath;
}
private static String readLine(InputStream is) throws IOException {
return new BufferedReader(new InputStreamReader(is)).readLine();
}
private static boolean deleteContents(File dir) {
File[] files = dir.listFiles();
boolean success = true;
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
success &= deleteContents(file);
}
if (!file.delete()) {
success = false;
}
}
}
return success;
}
private static void copyAssets(AssetManager assetManager, String path, File outPath) throws IOException {
String[] assets = assetManager.list(path);
if (assets == null) {
return;
}
if (assets.length == 0) {
if (!path.endsWith("uuid"))
copyFile(assetManager, path, outPath);
} else {
File dir = new File(outPath, path);
if (!dir.exists()) {
Log.v(TAG, "Making directory " + dir.getAbsolutePath());
if (!dir.mkdirs()) {
Log.v(TAG, "Failed to create directory " + dir.getAbsolutePath());
}
}
for (String asset : assets) {
copyAssets(assetManager, path + "/" + asset, outPath);
}
}
}
private static void copyFile(AssetManager assetManager, String fileName, File outPath) throws IOException {
InputStream in;
Log.v(TAG, "Copy " + fileName + " to " + outPath);
in = assetManager.open(fileName);
OutputStream out = new FileOutputStream(outPath + "/" + fileName);
byte[] buffer = new byte[4000];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
out.close();
}
}
+32 -60
View File
@@ -1,71 +1,43 @@
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
}
}
plugins {
id "com.jfrog.bintray"
}
def archiveName = "vosk-model-en"
def libVersion = "0.3.16"
allprojects {
repositories {
google()
jcenter()
}
}
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
def pomName = "Vosk English Model"
def pomDescription = "Small English model for Android"
android {
compileSdkVersion 29
namespace "org.vosk"
compileSdkVersion 33
defaultConfig {
minSdkVersion 21
targetSdkVersion 29
versionCode 6
versionName = libVersion
targetSdkVersion 33
versionCode 10
versionName = version
archivesBaseName = archiveName
}
}
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
bintray {
user = properties.getProperty("bintray.user")
key = properties.getProperty("bintray.apikey")
pkg {
repo = 'vosk'
name = 'vosk-model-en'
userOrg = "alphacep"
licenses = ['Apache2.0']
websiteUrl = 'https://github.com/alphacep/vosk-api'
issueTrackerUrl = 'https://github.com/alphacep/vosk-api/issues'
vcsUrl = 'https://github.com/alphacep/vosk-api'
version {
name = libVersion
vcsTag = libVersion
}
buildFeatures {
buildConfig = false
}
publications = ['aar']
}
publishing {
publications {
aar(MavenPublication) {
groupId 'com.alphacep'
artifactId archiveName
version libVersion
artifact("$buildDir/outputs/aar/$archiveName-release.aar")
sourceSets {
main {
assets.srcDirs += "$buildDir/generated/assets"
}
}
}
tasks.register('genUUID') {
def uuid = UUID.randomUUID().toString()
def odir = file("$buildDir/generated/assets/model-en-us")
def ofile = file("$odir/uuid")
doLast {
mkdir odir
ofile.text = uuid
}
}
preBuild.dependsOn(genUUID)
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.kaldi.model.en">
<manifest>
</manifest>
@@ -0,0 +1,7 @@
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)
@@ -1,2 +0,0 @@
US English model for android
@@ -1 +0,0 @@
0.3.16
+1 -1
View File
@@ -1 +1 @@
include 'model-en'
include ':lib', ':model-en'
-3
View File
@@ -1,3 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.kaldi">
</manifest>
-262
View File
@@ -1,262 +0,0 @@
// Copyright 2019 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.kaldi;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import android.content.Context;
import android.content.res.AssetManager;
import android.os.Environment;
import android.util.Log;
/**
* Provides utility methods to keep asset files to external storage to allow
* further JNI code access assets from a filesystem.
*
* There must be special file {@value #ASSET_LIST_NAME} among the application
* assets containing relative paths of assets to synchronize. If the
* corresponding path does not exist on the external storage it is copied. If
* the path exists checksums are compared and the asset is copied only if there
* is a mismatch. Checksum is stored in a separate asset with the name that
* consists of the original name and a suffix that depends on the checksum
* algorithm (e.g. MD5). Checksum files are copied along with the corresponding
* asset files.
*
* @author Alexander Solovets
*/
public class Assets {
protected static final String TAG = Assets.class.getSimpleName();
public static final String ASSET_LIST_NAME = "assets.lst";
public static final String SYNC_DIR = "sync";
public static final String HASH_EXT = ".md5";
private final AssetManager assetManager;
private final File externalDir;
/**
* Creates new instance for asset synchronization
*
* @param context
* application context
*
* @throws IOException
* if the directory does not exist
*
* @see android.content.Context#getExternalFilesDir
* @see android.os.Environment#getExternalStorageState
*/
public Assets(Context context) throws IOException {
File appDir = context.getExternalFilesDir(null);
if (null == appDir)
throw new IOException("cannot get external files dir, "
+ "external storage state is " + Environment.getExternalStorageState());
externalDir = new File(appDir, SYNC_DIR);
assetManager = context.getAssets();
}
/**
* Creates new instance with specified destination for assets
*
* @param context
* application context to retrieve the assets
* @param path
* path to sync the files
*/
public Assets(Context context, String dest) {
externalDir = new File(dest);
assetManager = context.getAssets();
}
/**
* Returns destination path on external storage where assets are copied.
*
* @return path to application directory or null if it does not exists
*/
public File getExternalDir() {
return externalDir;
}
/**
* Returns the map of asset paths to the files checksums.
*
* @return path to the root of resources directory on external storage
* @throws IOException
* if an I/O error occurs or "assets.lst" is missing
*/
public Map<String, String> getItems() throws IOException {
Map<String, String> items = new HashMap<String, String>();
for (String path : readLines(openAsset(ASSET_LIST_NAME))) {
Reader reader = new InputStreamReader(openAsset(path + HASH_EXT));
items.put(path, new BufferedReader(reader).readLine());
}
return items;
}
/**
* Returns path to hash mappings for the previously copied files. This
* method can be used to find out assets which must be updated.
*/
public Map<String, String> getExternalItems() {
try {
Map<String, String> items = new HashMap<String, String>();
File assetFile = new File(externalDir, ASSET_LIST_NAME);
for (String line : readLines(new FileInputStream(assetFile))) {
String[] fields = line.split(" ");
items.put(fields[0], fields[1]);
}
return items;
} catch (IOException e) {
return Collections.emptyMap();
}
}
/**
* In case you want to create more smart sync implementation, this method
* returns the list of items which must be synchronized.
*/
public Collection<String> getItemsToCopy(String path) throws IOException {
Collection<String> items = new ArrayList<String>();
Queue<String> queue = new ArrayDeque<String>();
queue.offer(path);
while (!queue.isEmpty()) {
path = queue.poll();
String[] list = assetManager.list(path);
for (String nested : list)
queue.offer(nested);
if (list.length == 0)
items.add(path);
}
return items;
}
private List<String> readLines(InputStream source) throws IOException {
List<String> lines = new ArrayList<String>();
BufferedReader br = new BufferedReader(new InputStreamReader(source));
String line;
while (null != (line = br.readLine()))
lines.add(line);
return lines;
}
private InputStream openAsset(String asset) throws IOException {
return assetManager.open(new File(SYNC_DIR, asset).getPath());
}
/**
* Saves the list of synchronized items. The list is stored as a two-column
* space-separated list of items in a text file. The file is located at the
* root of synchronization directory in the external storage.
*
* @param items
* the items
* @throws IOException
* if an I/O error occurs
*/
public void updateItemList(Map<String, String> items) throws IOException {
File assetListFile = new File(externalDir, ASSET_LIST_NAME);
PrintWriter pw = new PrintWriter(new FileOutputStream(assetListFile));
for (Map.Entry<String, String> entry : items.entrySet())
pw.format("%s %s\n", entry.getKey(), entry.getValue());
pw.close();
}
/**
* Copies raw asset resource to external storage of the device.
*
* @param path
* path of the asset to copy
* @throws IOException
* if an I/O error occurs
*/
public File copy(String asset) throws IOException {
InputStream source = openAsset(asset);
File destinationFile = new File(externalDir, asset);
destinationFile.getParentFile().mkdirs();
OutputStream destination = new FileOutputStream(destinationFile);
byte[] buffer = new byte[1024];
int nread;
while ((nread = source.read(buffer)) != -1) {
if (nread == 0) {
nread = source.read();
if (nread < 0)
break;
destination.write(nread);
continue;
}
destination.write(buffer, 0, nread);
}
destination.close();
return destinationFile;
}
/**
* Performs the sync of assets in the application and on the external
* storage
*
* @return The folder on external storage with data
* @throws IOException
*/
public File syncAssets() throws IOException {
Collection<String> newItems = new ArrayList<String>();
Collection<String> unusedItems = new ArrayList<String>();
Map<String, String> items = getItems();
Map<String, String> externalItems = getExternalItems();
for (String path : items.keySet()) {
if (!items.get(path).equals(externalItems.get(path))
|| !(new File(externalDir, path).exists()))
newItems.add(path);
}
unusedItems.addAll(externalItems.keySet());
unusedItems.removeAll(items.keySet());
for (String path : newItems) {
File file = copy(path);
}
for (String path : unusedItems) {
File file = new File(externalDir, path);
file.delete();
}
updateItemList(items);
return externalDir;
}
}
+7 -44
View File
@@ -1,53 +1,16 @@
KALDI_ROOT=$(HOME)/travis/kaldi
VOSK_SOURCES= \
../src/kaldi_recognizer.cc \
../src/language_model.cc \
../src/model.cc \
../src/spk_model.cc \
../src/vosk_api.cc
CFLAGS=-g -O2 -DFST_NO_DYNAMIC_LINKING -I../src -I$(KALDI_ROOT)/src -I$(KALDI_ROOT)/tools/openfst/include
LIBS= \
$(KALDI_ROOT)/src/online2/kaldi-online2.a \
$(KALDI_ROOT)/src/decoder/kaldi-decoder.a \
$(KALDI_ROOT)/src/ivector/kaldi-ivector.a \
$(KALDI_ROOT)/src/gmm/kaldi-gmm.a \
$(KALDI_ROOT)/src/nnet3/kaldi-nnet3.a \
$(KALDI_ROOT)/src/tree/kaldi-tree.a \
$(KALDI_ROOT)/src/feat/kaldi-feat.a \
$(KALDI_ROOT)/src/lat/kaldi-lat.a \
$(KALDI_ROOT)/src/lm/kaldi-lm.a \
$(KALDI_ROOT)/src/hmm/kaldi-hmm.a \
$(KALDI_ROOT)/src/transform/kaldi-transform.a \
$(KALDI_ROOT)/src/cudamatrix/kaldi-cudamatrix.a \
$(KALDI_ROOT)/src/matrix/kaldi-matrix.a \
$(KALDI_ROOT)/src/fstext/kaldi-fstext.a \
$(KALDI_ROOT)/src/util/kaldi-util.a \
$(KALDI_ROOT)/src/base/kaldi-base.a \
$(KALDI_ROOT)/tools/OpenBLAS/install/lib/libopenblas.a \
$(KALDI_ROOT)/tools/OpenBLAS/install/lib/liblapack.a \
$(KALDI_ROOT)/tools/OpenBLAS/install/lib/libblas.a \
$(KALDI_ROOT)/tools/OpenBLAS/install/lib/libf2c.a \
$(KALDI_ROOT)/tools/openfst/lib/libfst.a \
$(KALDI_ROOT)/tools/openfst/lib/libfstngram.a
CFLAGS=-I../src
LDFLAGS=-L../src -lvosk -ldl -lpthread -Wl,-rpath,../src
all: test_vosk test_vosk_speaker
test_vosk: test_vosk.o libvosk.a
g++ $^ -o $@ $(LIBS) -lpthread
test_vosk: test_vosk.o
gcc $^ -o $@ $(LDFLAGS)
test_vosk_speaker: test_vosk_speaker.o libvosk.a
g++ $^ -o $@ $(LIBS) -lpthread
libvosk.a: $(VOSK_SOURCES:.cc=.o)
ar rcs $@ $^
test_vosk_speaker: test_vosk_speaker.o
gcc $^ -o $@ $(LDFLAGS)
%.o: %.c
g++ $(CFLAGS) -c -o $@ $<
%.o: %.cc
g++ -std=c++17 $(CFLAGS) -c -o $@ $<
gcc $(CFLAGS) -c -o $@ $<
clean:
rm -f *.o *.a test_vosk test_vosk_speaker
+1 -1
View File
@@ -8,7 +8,7 @@ int main() {
VoskModel *model = vosk_model_new("model");
VoskSpkModel *spk_model = vosk_spk_model_new("spk-model");
VoskRecognizer *recognizer = vosk_recognizer_new_spk(model, spk_model, 16000.0);
VoskRecognizer *recognizer = vosk_recognizer_new_spk(model, 16000.0, spk_model);
wavin = fopen("test.wav", "rb");
fseek(wavin, 44, SEEK_SET);
-68
View File
@@ -1,68 +0,0 @@
KALDI_ROOT ?= $(HOME)/kaldi
CFLAGS := -std=c++17 -g -O2 -DPIC -fPIC -Wno-unused-function
CPPFLAGS := -I$(KALDI_ROOT)/src -I$(KALDI_ROOT)/tools/openfst/include -I../src -DFST_NO_DYNAMIC_LINKING
KALDI_LIBS = \
${KALDI_ROOT}/src/online2/kaldi-online2.a \
${KALDI_ROOT}/src/decoder/kaldi-decoder.a \
${KALDI_ROOT}/src/ivector/kaldi-ivector.a \
${KALDI_ROOT}/src/gmm/kaldi-gmm.a \
${KALDI_ROOT}/src/nnet3/kaldi-nnet3.a \
${KALDI_ROOT}/src/tree/kaldi-tree.a \
${KALDI_ROOT}/src/feat/kaldi-feat.a \
${KALDI_ROOT}/src/lat/kaldi-lat.a \
${KALDI_ROOT}/src/lm/kaldi-lm.a \
${KALDI_ROOT}/src/hmm/kaldi-hmm.a \
${KALDI_ROOT}/src/transform/kaldi-transform.a \
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a \
${KALDI_ROOT}/src/matrix/kaldi-matrix.a \
${KALDI_ROOT}/src/fstext/kaldi-fstext.a \
${KALDI_ROOT}/src/util/kaldi-util.a \
${KALDI_ROOT}/src/base/kaldi-base.a \
${KALDI_ROOT}/tools/openfst/lib/libfst.a \
${KALDI_ROOT}/tools/openfst/lib/libfstngram.a
# On Linux
MATH_LIBS = \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/libopenblas.a \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/liblapack.a \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/libblas.a \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/libf2c.a
# On OSX
# MATH_LIBS = -framework Accelerate
all: test.exe
test.exe: libkaldiwrap.so test.cs
mcs -out:Vosk.dll -target:library gen/*.cs
mcs test.cs -r:Vosk.dll -out:test.exe
VOSK_SOURCES = \
vosk_wrap.c \
../src/kaldi_recognizer.cc \
../src/language_model.cc \
../src/model.cc \
../src/spk_model.cc \
../src/vosk_api.cc
VOSK_HEADERS = \
../src/kaldi_recognizer.h \
../src/language_model.h \
../src/model.h \
../src/vosk_api.h \
../src/spk_model.h
libkaldiwrap.so: $(VOSK_SOURCES) $(VOSK_HEADERS)
$(CXX) -fpermissive $(CFLAGS) $(CPPFLAGS) -shared -o $@ $(VOSK_SOURCES) $(KALDI_LIBS) $(MATH_LIBS)
vosk_wrap.c: ../src/vosk.i
mkdir -p gen
swig -csharp -DSWIG_CSHARP_NO_EXCEPTION_HELPER -dllimport "libkaldiwrap" \
-namespace "Kaldi" -outdir gen -o vosk_wrap.c ../src/vosk.i
run: test.exe
mono test.exe
clean:
$(RM) *.so vosk_wrap.c *.o gen/*.cs test.exe *.dll
+12
View File
@@ -0,0 +1,12 @@
This is a nuget-based wrapper for libvosk library
See demo folder for example how to use the library. You can simply run
"dotnet run" to run the demo. Make sure you unpacked the model and the
test file.
See the nuget folder for the sources of the wrapper. Run build.sh to
build nuget package.
Note we only support win64 and linux64 for now. No support for win32
since it is a little bit painful to load the libraries depending on
architecture. In theory we can add OSX some time or even Android.
+80
View File
@@ -0,0 +1,80 @@
using System;
using System.IO;
using Vosk;
public class VoskDemo
{
public static void DemoBytes(Model model)
{
// Demo byte buffer
VoskRecognizer rec = new VoskRecognizer(model, 16000.0f);
rec.SetMaxAlternatives(0);
rec.SetWords(true);
using(Stream source = File.OpenRead("test.wav")) {
byte[] buffer = new byte[4096];
int bytesRead;
while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
if (rec.AcceptWaveform(buffer, bytesRead)) {
Console.WriteLine(rec.Result());
} else {
Console.WriteLine(rec.PartialResult());
}
}
}
Console.WriteLine(rec.FinalResult());
}
public static void DemoFloats(Model model)
{
// Demo float array
VoskRecognizer rec = new VoskRecognizer(model, 16000.0f);
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] = BitConverter.ToInt16(buffer, n);
}
if (rec.AcceptWaveform(fbuffer, fbuffer.Length)) {
Console.WriteLine(rec.Result());
} else {
Console.WriteLine(rec.PartialResult());
}
}
}
Console.WriteLine(rec.FinalResult());
}
public static void DemoSpeaker(Model model)
{
// Output speakers
SpkModel spkModel = new SpkModel("model-spk");
VoskRecognizer rec = new VoskRecognizer(model, 16000.0f);
rec.SetSpkModel(spkModel);
using(Stream source = File.OpenRead("test.wav")) {
byte[] buffer = new byte[4096];
int bytesRead;
while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
if (rec.AcceptWaveform(buffer, bytesRead)) {
Console.WriteLine(rec.Result());
} else {
Console.WriteLine(rec.PartialResult());
}
}
}
Console.WriteLine(rec.FinalResult());
}
public static void Main()
{
// You can set to -1 to disable logging messages
Vosk.Vosk.SetLogLevel(0);
Model model = new Model("model");
DemoBytes(model);
DemoFloats(model);
DemoSpeaker(model);
}
}
+17
View File
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>VoskDemo</RootNamespace>
</PropertyGroup>
<PropertyGroup>
<RestoreSources>$(RestoreSources);../nuget</RestoreSources>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Vosk" Version="0.3.45" />
</ItemGroup>
</Project>
+8 -3
View File
@@ -2,13 +2,14 @@
<package>
<metadata>
<id>Vosk</id>
<version>0.3.16</version>
<version>0.3.45</version>
<authors>Alpha Cephei Inc</authors>
<owners>Alpha Cephei Inc</owners>
<license type="expression">Apache-2.0</license>
<projectUrl>https://alphacephei.com/vosk/</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Vosk is an offline open source speech recognition toolkit. It enables speech recognition models for 16 languages and dialects - English, Indian English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish, Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi.
<title>Vosk Speech Recognition Toolkit</title>
<description>Vosk is an offline open source speech recognition toolkit. It enables speech recognition models for 20+ languages and dialects - English, Indian English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish, Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino, Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech. More to come.
Vosk models are small (50 Mb) but provide continuous large vocabulary transcription, zero-latency response with streaming API, reconfigurable vocabulary and speaker identification.
@@ -18,10 +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"/>
</dependencies>
</metadata>
<files>
<file src="**" exclude="src/*.cs;build.sh;**/.keep-me;*.nupkg" />
</files>
</package>
+2
View File
@@ -0,0 +1,2 @@
mcs -out:lib/netstandard2.0/Vosk.dll -target:library src/*.cs
nuget pack
+11
View File
@@ -0,0 +1,11 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<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-universal\*.dylib" Condition="'$([MSBuild]::IsOsPlatform(OSX))'" />
<None Include="@(NativeLibs)">
<Link>%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -1,9 +0,0 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)lib/**/**">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>false</Visible>
</Content>
</ItemGroup>
</Project>
+55
View File
@@ -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);
}
}
}
}
+41
View File
@@ -0,0 +1,41 @@
namespace Vosk {
public class Model : global::System.IDisposable {
private global::System.Runtime.InteropServices.HandleRef handle;
internal Model(global::System.IntPtr cPtr) {
handle = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
}
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(Model obj) {
return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.handle;
}
~Model() {
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_Model(handle);
handle = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
}
}
}
public Model(string model_path) : this(VoskPINVOKE.new_Model(model_path)) {
}
public int FindWord(string word) {
return VoskPINVOKE.Model_vosk_model_find_word(handle, word);
}
}
}
+37
View File
@@ -0,0 +1,37 @@
namespace Vosk {
public class SpkModel : global::System.IDisposable {
private global::System.Runtime.InteropServices.HandleRef handle;
internal SpkModel(global::System.IntPtr cPtr) {
handle = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
}
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(SpkModel obj) {
return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.handle;
}
~SpkModel() {
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_SpkModel(handle);
handle = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
}
}
}
public SpkModel(string model_path) : this(VoskPINVOKE.new_SpkModel(model_path)) {
}
}
}
+17
View File
@@ -0,0 +1,17 @@
namespace Vosk {
public class Vosk {
public static void SetLogLevel(int level) {
VoskPINVOKE.SetLogLevel(level);
}
public static void GpuInit() {
VoskPINVOKE.GpuInit();
}
public static void GpuThreadInit() {
VoskPINVOKE.GpuThreadInit();
}
}
}
+88
View File
@@ -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));
}
}
}
+113
View File
@@ -0,0 +1,113 @@
namespace Vosk {
class VoskPINVOKE {
static VoskPINVOKE() {
}
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_model_new")]
public static extern global::System.IntPtr new_Model(string jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_model_free")]
public static extern void delete_Model(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_model_find_word")]
public static extern int Model_vosk_model_find_word(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_spk_model_new")]
public static extern global::System.IntPtr new_SpkModel(string jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_spk_model_free")]
public static extern void delete_SpkModel(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_new")]
public static extern global::System.IntPtr new_VoskRecognizer(global::System.Runtime.InteropServices.HandleRef jarg1, float jarg2);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_new_spk")]
public static extern global::System.IntPtr new_VoskRecognizerSpk(global::System.Runtime.InteropServices.HandleRef jarg1, float jarg2, global::System.Runtime.InteropServices.HandleRef jarg3);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_new_grm")]
public static extern global::System.IntPtr new_VoskRecognizerGrm(global::System.Runtime.InteropServices.HandleRef jarg1, float jarg2, string jarg3);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_free")]
public static extern void delete_VoskRecognizer(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_set_max_alternatives")]
public static extern void VoskRecognizer_SetMaxAlternatives(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
[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);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_accept_waveform")]
public static extern bool VoskRecognizer_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_recognizer_accept_waveform_s")]
public static extern bool VoskRecognizer_AcceptWaveformShort(global::System.Runtime.InteropServices.HandleRef jarg1, [global::System.Runtime.InteropServices.In, global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPArray)]short[] jarg2, int jarg3);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_accept_waveform_f")]
public static extern bool VoskRecognizer_AcceptWaveformFloat(global::System.Runtime.InteropServices.HandleRef jarg1, [global::System.Runtime.InteropServices.In, global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPArray)]float[] jarg2, int jarg3);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_result")]
public static extern global::System.IntPtr VoskRecognizer_Result(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_partial_result")]
public static extern global::System.IntPtr VoskRecognizer_PartialResult(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_final_result")]
public static extern global::System.IntPtr VoskRecognizer_FinalResult(global::System.Runtime.InteropServices.HandleRef jarg1);
[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_set_log_level")]
public static extern void SetLogLevel(int jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_gpu_init")]
public static extern void GpuInit();
[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);
}
}
+96
View File
@@ -0,0 +1,96 @@
namespace Vosk {
public class VoskRecognizer : System.IDisposable {
private System.Runtime.InteropServices.HandleRef handle;
internal VoskRecognizer(System.IntPtr cPtr) {
handle = new System.Runtime.InteropServices.HandleRef(this, cPtr);
}
internal static System.Runtime.InteropServices.HandleRef getCPtr(VoskRecognizer obj) {
return (obj == null) ? new System.Runtime.InteropServices.HandleRef(null, System.IntPtr.Zero) : obj.handle;
}
~VoskRecognizer() {
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_VoskRecognizer(handle);
handle = new System.Runtime.InteropServices.HandleRef(null, System.IntPtr.Zero);
}
}
}
public VoskRecognizer(Model model, float sample_rate) : this(VoskPINVOKE.new_VoskRecognizer(Model.getCPtr(model), sample_rate)) {
}
public VoskRecognizer(Model model, float sample_rate, SpkModel spk_model) : this(VoskPINVOKE.new_VoskRecognizerSpk(Model.getCPtr(model), sample_rate, SpkModel.getCPtr(spk_model))) {
}
public VoskRecognizer(Model model, float sample_rate, string grammar) : this(VoskPINVOKE.new_VoskRecognizerGrm(Model.getCPtr(model), sample_rate, grammar)) {
}
public void SetMaxAlternatives(int max_alternatives) {
VoskPINVOKE.VoskRecognizer_SetMaxAlternatives(handle, max_alternatives);
}
public void SetWords(bool words) {
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));
}
public bool AcceptWaveform(byte[] data, int len) {
return VoskPINVOKE.VoskRecognizer_AcceptWaveform(handle, data, len);
}
public bool AcceptWaveform(short[] sdata, int len) {
return VoskPINVOKE.VoskRecognizer_AcceptWaveformShort(handle, sdata, len);
}
public bool AcceptWaveform(float[] fdata, int len) {
return VoskPINVOKE.VoskRecognizer_AcceptWaveformFloat(handle, fdata, 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 Result() {
return PtrToStringUTF8(VoskPINVOKE.VoskRecognizer_Result(handle));
}
public string PartialResult() {
return PtrToStringUTF8(VoskPINVOKE.VoskRecognizer_PartialResult(handle));
}
public string FinalResult() {
return PtrToStringUTF8(VoskPINVOKE.VoskRecognizer_FinalResult(handle));
}
public void Reset() {
VoskPINVOKE.VoskRecognizer_Reset(handle);
}
}
}
-47
View File
@@ -1,47 +0,0 @@
using System;
using System.IO;
using Kaldi;
public class Test
{
public static void Main()
{
Vosk.SetLogLevel(0);
Model model = new Model("model");
KaldiRecognizer rec = new KaldiRecognizer(model, 16000.0f);
using(Stream source = File.OpenRead("test.wav")) {
byte[] buffer = new byte[4096];
int bytesRead;
while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
if (rec.AcceptWaveform(buffer, bytesRead)) {
Console.WriteLine(rec.Result());
} else {
Console.WriteLine(rec.PartialResult());
}
}
}
Console.WriteLine(rec.FinalResult());
rec = new KaldiRecognizer(model, 16000.0f);
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);
}
if (rec.AcceptWaveform(fbuffer, fbuffer.Length)) {
Console.WriteLine(rec.Result());
GC.Collect();
} else {
Console.WriteLine(rec.PartialResult());
}
}
}
Console.WriteLine(rec.FinalResult());
}
}
-1
View File
@@ -1 +0,0 @@
See https://alphacephei.com/vosk/accuracy
-1
View File
@@ -1 +0,0 @@
See https://alphacephei.com/vosk/adaptation
-1
View File
@@ -1 +0,0 @@
See https://alphacephei.com/vosk/models
+176
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
See example subfolder for instructions how to use the module
+7
View File
@@ -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
+31
View File
@@ -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
```
+2
View File
@@ -0,0 +1,2 @@
// Example package for Vosk Go bindings.
package main
+61
View File
@@ -0,0 +1,61 @@
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()
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"])
}
+7
View File
@@ -0,0 +1,7 @@
module github.com/alphacep/vosk-api/go
go 1.16
replace (
github.com/alphacep/vosk-api/go => ./
)
+170
View File
@@ -0,0 +1,170 @@
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"
// VoskModel contains a reference to the C VoskModel
type VoskModel struct {
model *C.struct_VoskModel
}
// NewModel creates a new VoskModel instance
func NewModel(modelPath string) (*VoskModel, error) {
cmodelPath := C.CString(modelPath)
defer C.free(unsafe.Pointer(cmodelPath))
internal := C.vosk_model_new(cmodelPath)
model := &VoskModel{model: internal}
return model, nil
}
func (m *VoskModel) Free() {
C.vosk_model_free(m.model)
}
func freeModel(model *VoskModel) {
C.vosk_model_free(model.model)
}
// 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) {
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))
}
// 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()
}
+33 -20
View File
@@ -13,11 +13,12 @@
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 */; };
92D86BD5253F823F0040D53F /* vosk-model-small-en-us-0.4 in Resources */ = {isa = PBXBuildFile; fileRef = 92D86BD3253F823E0040D53F /* vosk-model-small-en-us-0.4 */; };
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 */; };
/* End PBXBuildFile section */
@@ -30,13 +31,14 @@
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>"; };
92D86BD3253F823E0040D53F /* vosk-model-small-en-us-0.4 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "vosk-model-small-en-us-0.4"; sourceTree = "<group>"; };
92D6B8D225BDFEAC007FF08D /* VoskModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoskModel.swift; sourceTree = "<group>"; };
92D86BD4253F823F0040D53F /* vosk-model-spk-0.4 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "vosk-model-spk-0.4"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -45,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;
};
@@ -83,6 +85,7 @@
9237522A240C550B00DD6076 /* LaunchScreen.storyboard */,
9237522D240C550B00DD6076 /* Info.plist */,
92375233240C558900DD6076 /* Vosk.swift */,
92D6B8D225BDFEAC007FF08D /* VoskModel.swift */,
);
path = VoskApiTest;
sourceTree = "<group>";
@@ -90,11 +93,11 @@
92375239240C642000DD6076 /* Vosk */ = {
isa = PBXGroup;
children = (
92D86BD3253F823E0040D53F /* vosk-model-small-en-us-0.4 */,
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;
@@ -103,7 +106,7 @@
92375242240C6DAF00DD6076 /* Frameworks */ = {
isa = PBXGroup;
children = (
92375245240C6DC900DD6076 /* libstdc++.tbd */,
92833002273C466E00058B52 /* libc++.tbd */,
92375243240C6DAF00DD6076 /* Accelerate.framework */,
);
name = Frameworks;
@@ -142,7 +145,7 @@
9237521D240C550B00DD6076 = {
CreatedOnToolsVersion = 8.3.2;
LastSwiftMigration = 0920;
ProvisioningStyle = Automatic;
ProvisioningStyle = Manual;
};
};
};
@@ -169,12 +172,12 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
92BACED125BE125A00B5CC93 /* vosk-model-small-en-us-0.15 in Resources */,
92375274240C6F1E00DD6076 /* 10001-90210-01803.wav in Resources */,
9237522C240C550B00DD6076 /* LaunchScreen.storyboard in Resources */,
92375229240C550B00DD6076 /* Assets.xcassets in Resources */,
92D86BD6253F823F0040D53F /* vosk-model-spk-0.4 in Resources */,
92375227240C550B00DD6076 /* Main.storyboard in Resources */,
92D86BD5253F823F0040D53F /* vosk-model-small-en-us-0.4 in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -187,6 +190,7 @@
files = (
92375224240C550B00DD6076 /* ViewController.swift in Sources */,
92375222240C550B00DD6076 /* AppDelegate.swift in Sources */,
92D6B8D325BDFEAC007FF08D /* VoskModel.swift in Sources */,
92375234240C558900DD6076 /* Vosk.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -219,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;
@@ -241,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;
@@ -278,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;
@@ -300,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;
@@ -315,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";
@@ -329,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 = (
@@ -338,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;
};
@@ -351,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 = (
@@ -360,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,12 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:../VoskApiTest/Vosk/vosk-model-small-en-us-0.4">
</FileRef>
<FileRef
location = "group:../VoskApiTest/Vosk/vosk-model-spk-0.4">
</FileRef>
<FileRef
location = "self:">
</FileRef>
+42 -13
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="bdW-KL-Y8Z">
<device id="retina5_5" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
@@ -10,23 +10,52 @@
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<scene sceneID="nEc-89-Iqu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="VoskApiTest" customModuleProvider="target" sceneMemberID="viewController">
<textView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" id="CtX-mx-X98">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<viewController id="bdW-KL-Y8Z" customClass="ViewController" customModule="VoskApiTest" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Hyr-Dz-4mU"/>
<viewControllerLayoutGuide type="bottom" id="w4A-5X-uBu"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="m5v-US-bvR">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="IaT-no-U3i" userLabel="Microphone">
<rect key="frame" x="124" y="34" width="157" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Recognize Microphone"/>
<connections>
<action selector="runRecognizeMicrohpone:" destination="bdW-KL-Y8Z" eventType="touchUpInside" id="hGB-lz-N2B"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GC5-nT-FQR" userLabel="File">
<rect key="frame" x="90" y="84" width="221" height="41"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Recognize File"/>
<connections>
<action selector="runRecognizeFile:" destination="bdW-KL-Y8Z" eventType="touchUpInside" id="xp5-Yi-rnN"/>
</connections>
</button>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" fixedFrame="YES" text="Results here" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="w4X-cu-USq">
<rect key="frame" x="11" y="112" width="383" height="569"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</view>
<connections>
<outlet property="mainText" destination="CtX-mx-X98" id="oJy-5J-NKp"/>
<outlet property="mainText" destination="w4X-cu-USq" id="rZS-nz-Wql"/>
<outlet property="recognizeFile" destination="GC5-nT-FQR" id="dRe-tc-IA0"/>
<outlet property="recognizeMicrophone" destination="IaT-no-U3i" id="IuM-aa-pAP"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="nWA-4D-pA6" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="32.799999999999997" y="32.833583208395808"/>
<point key="canvasLocation" x="-17.39130434782609" y="-285.32608695652175"/>
</scene>
</scenes>
</document>
+95 -12
View File
@@ -3,30 +3,113 @@
// VoskApiTest
//
// Created by Niсkolay Shmyrev on 01.03.20.
// Copyright © 2020 Alpha Cephei. All rights reserved.
// Copyright © 2020-2021 Alpha Cephei. All rights reserved.
//
import UIKit
import AVFoundation
enum WorkMode {
case stopped
case microphone
case file
}
class ViewController: UIViewController {
@IBOutlet var mainText: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.global(qos: .userInitiated).async {
DispatchQueue.main.async {
self.mainText.text = "Processing file..."
var mode: WorkMode!
@IBOutlet weak var recognizeFile: UIButton!
@IBOutlet weak var mainText: UITextView!
@IBOutlet weak var recognizeMicrophone: UIButton!
var audioEngine : AVAudioEngine!
var processingQueue: DispatchQueue!
var model : VoskModel!
func setMode(mode: WorkMode) {
switch mode {
case .stopped:
self.recognizeFile.isEnabled = true
self.recognizeMicrophone.isEnabled = true
self.recognizeMicrophone.setTitle("Recognize Microphone",for: .normal)
case .microphone:
self.recognizeFile.isEnabled = false
self.recognizeMicrophone.isEnabled = true
self.recognizeMicrophone.setTitle("Stop Microphone",for: .normal)
self.mainText.text = ""
case .file:
self.recognizeFile.isEnabled = false
self.recognizeMicrophone.isEnabled = false
self.mainText.text = "Processing file..."
}
self.mode = mode
}
func startAudioEngine() {
do {
// Create a new audio engine.
audioEngine = AVAudioEngine()
let inputNode = audioEngine.inputNode
let formatInput = inputNode.inputFormat(forBus: 0)
let formatPcm = AVAudioFormat.init(commonFormat: AVAudioCommonFormat.pcmFormatInt16, sampleRate: formatInput.sampleRate, channels: 1, interleaved: true)
let recognizer = Vosk(model: model, sampleRate: Float(formatInput.sampleRate))
inputNode.installTap(onBus: 0,
bufferSize: UInt32(formatInput.sampleRate / 10),
format: formatPcm) { buffer, time in
self.processingQueue.async {
let res = recognizer.recognizeData(buffer: buffer)
DispatchQueue.main.async {
self.mainText.text = res + "\n" + self.mainText.text
}
}
}
let vosk = Vosk()
let res = vosk.recognizeFile()
// Start the stream of audio data.
audioEngine.prepare()
try audioEngine.start()
} catch {
print("Unable to start AVAudioEngine: \(error.localizedDescription)")
}
}
func stopAudioEngine() {
audioEngine.stop()
}
@IBAction func runRecognizeMicrohpone(_ sender: Any) {
if (mode == .stopped) {
setMode(mode: .microphone)
startAudioEngine()
} else {
stopAudioEngine()
setMode(mode: .stopped)
}
}
@IBAction func runRecognizeFile(_ sender: Any) {
setMode(mode: .file)
processingQueue.async {
let recognizer = Vosk(model: self.model, sampleRate: 16000.0)
let res = recognizer.recognizeFile()
DispatchQueue.main.async {
self.mainText.text = res
self.setMode(mode: .stopped)
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
setMode(mode: .stopped)
processingQueue = DispatchQueue(label: "recognizerQueue")
model = VoskModel()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
+33 -21
View File
@@ -3,40 +3,52 @@
// VoskApiTest
//
// Created by Niсkolay Shmyrev on 01.03.20.
// Copyright © 2020 Alpha Cephei. All rights reserved.
// Copyright © 2020-2021 Alpha Cephei. All rights reserved.
//
import Foundation
import AVFoundation
public final class Vosk {
var recognizer : OpaquePointer!
init(model: VoskModel, sampleRate: Float) {
recognizer = vosk_recognizer_new_spk(model.model, sampleRate, model.spkModel)
}
deinit {
vosk_recognizer_free(recognizer);
}
func recognizeFile() -> String {
var sres = ""
if let resourcePath = Bundle.main.resourcePath {
// Set to -1 to disable logs
vosk_set_log_level(0);
let modelPath = resourcePath + "/vosk-model-small-en-us-0.4"
let spkModelPath = resourcePath + "/vosk-model-spk-0.4"
let model = vosk_model_new(modelPath)
let spkModel = vosk_spk_model_new(spkModelPath)
let recognizer = vosk_recognizer_new_spk(model, spkModel, 16000.0)
let audioFile = URL(fileURLWithPath: resourcePath + "/10001-90210-01803.wav")
if let data = try? Data(contentsOf: audioFile) {
let _ = data.withUnsafeBytes {
vosk_recognizer_accept_waveform(recognizer, $0, Int32(data.count))
}
let res = vosk_recognizer_final_result(recognizer);
sres = String(validatingUTF8: res!)!;
print(sres);
let _ = data.withUnsafeBytes {
vosk_recognizer_accept_waveform(recognizer, $0, Int32(data.count))
}
let res = vosk_recognizer_final_result(recognizer);
sres = String(validatingUTF8: res!)!;
print(sres);
}
vosk_recognizer_free(recognizer)
vosk_model_free(model)
}
return sres
}
func recognizeData(buffer : AVAudioPCMBuffer) -> String {
let dataLen = Int(buffer.frameLength * 2)
let channels = UnsafeBufferPointer(start: buffer.int16ChannelData, count: 1)
let endOfSpeech = channels[0].withMemoryRebound(to: Int8.self, capacity: dataLen) {
vosk_recognizer_accept_waveform(recognizer, $0, Int32(dataLen))
}
let res = endOfSpeech == 1 ?vosk_recognizer_result(recognizer) :vosk_recognizer_partial_result(recognizer)
return String(validatingUTF8: res!)!;
}
}
+117 -36
View File
@@ -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
+36
View File
@@ -0,0 +1,36 @@
//
// Vosk.swift
// VoskApiTest
//
// Created by Niсkolay Shmyrev on 01.03.20.
// Copyright © 2020-2021 Alpha Cephei. All rights reserved.
//
import Foundation
public final class VoskModel {
var model : OpaquePointer!
var spkModel : OpaquePointer!
init() {
// Set to -1 to disable logs
vosk_set_log_level(0);
if let resourcePath = Bundle.main.resourcePath {
let modelPath = resourcePath + "/vosk-model-small-en-us-0.15"
let spkModelPath = resourcePath + "/vosk-model-spk-0.4"
model = vosk_model_new(modelPath)
spkModel = vosk_spk_model_new(spkModelPath)
}
}
deinit {
vosk_model_free(model)
vosk_spk_model_free(spkModel)
}
}
-72
View File
@@ -1,72 +0,0 @@
KALDI_ROOT ?= $(HOME)/kaldi
CFLAGS := -g -O2 -DPIC -fPIC -Wno-unused-function -std=c++17
CPPFLAGS := -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I$(KALDI_ROOT)/src -I$(KALDI_ROOT)/tools/openfst/include -I../src
KALDI_LIBS = \
${KALDI_ROOT}/src/online2/kaldi-online2.a \
${KALDI_ROOT}/src/decoder/kaldi-decoder.a \
${KALDI_ROOT}/src/ivector/kaldi-ivector.a \
${KALDI_ROOT}/src/gmm/kaldi-gmm.a \
${KALDI_ROOT}/src/nnet3/kaldi-nnet3.a \
${KALDI_ROOT}/src/tree/kaldi-tree.a \
${KALDI_ROOT}/src/feat/kaldi-feat.a \
${KALDI_ROOT}/src/lat/kaldi-lat.a \
${KALDI_ROOT}/src/lm/kaldi-lm.a \
${KALDI_ROOT}/src/hmm/kaldi-hmm.a \
${KALDI_ROOT}/src/transform/kaldi-transform.a \
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a \
${KALDI_ROOT}/src/matrix/kaldi-matrix.a \
${KALDI_ROOT}/src/fstext/kaldi-fstext.a \
${KALDI_ROOT}/src/util/kaldi-util.a \
${KALDI_ROOT}/src/base/kaldi-base.a \
${KALDI_ROOT}/tools/openfst/lib/libfst.a \
${KALDI_ROOT}/tools/openfst/lib/libfstngram.a \
# On Linux
MATH_LIBS = \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/libopenblas.a \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/liblapack.a \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/libblas.a \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/libf2c.a
all: libvosk_jni.so
VOSK_SOURCES = \
vosk_wrap.cc \
../src/kaldi_recognizer.cc \
../src/kaldi_recognizer.h \
../src/language_model.cc \
../src/language_model.h \
../src/model.cc \
../src/model.h \
../src/spk_model.cc \
../src/spk_model.h \
../src/vosk_api.cc \
../src/vosk_api.h
libvosk_jni.so: $(VOSK_SOURCES)
$(CXX) -shared -o $@ $(CPPFLAGS) $(CFLAGS) $(VOSK_SOURCES) $(KALDI_LIBS) $(MATH_LIBS)
vosk_wrap.cc: ../src/vosk.i
mkdir -p org/kaldi
swig -c++ -I../src \
-java -package org.kaldi \
-outdir org/kaldi -o $@ $<
clean:
$(RM) *.so *_wrap.cc *_wrap.o test/*.class
$(RM) -r org model-en
model:
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
unzip vosk-model-small-en-us-0.3.zip && rm vosk-model-small-en-us-0.3.zip
mv vosk-model-small-en-us-0.3 model
model-spk:
wget https://alphacephei.com/kaldi/models/vosk-model-spk-0.3.zip
unzip vosk-model-spk-0.3.zip && rm vosk-model-spk-0.3.zip
mv vosk-model-spk-0.3 model-spk
run: model model-spk
javac test/*.java org/kaldi/*.java
java -Djava.library.path=. -cp . test.DecoderTest
+4 -16
View File
@@ -1,19 +1,7 @@
Java API sample
Java bindings for Vosk API using jnr-ffi
Doesn't work on Windows or Mac yet, help to prepare the packaged jars is welcome.
See demo project for details, build it with Gradle.
For now to try it:
Download model and unpack as "model" folder in the demo project.
On Linux you can do
1. Build recent kaldi
1. `git clone https://github.com/alphacep/vosk-api`
1. `cd vosk-api/java`
1. `export KALDI_ROOT=<KALDI_ROOT>`
1. `export JAVA_HOME=<JAVA_HOME>`
1. `make`
1. `make run`
For details of the code you can check:
https://github.com/alphacep/vosk-api/blob/master/java/test/DecoderTest.java
Make sure you are using recent JDK and Gradle.
+15
View File
@@ -0,0 +1,15 @@
plugins {
id 'application'
}
application {
mainClass = 'org.vosk.demo.DecoderDemo'
}
repositories {
mavenCentral()
}
dependencies {
implementation group: 'com.alphacephei', name: 'vosk', version: '0.3.45'
}
@@ -0,0 +1,38 @@
package org.vosk.demo;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.vosk.LogLevel;
import org.vosk.Recognizer;
import org.vosk.LibVosk;
import org.vosk.Model;
public class DecoderDemo {
public static void main(String[] argv) throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream("../../python/example/test.wav")));
Recognizer recognizer = new Recognizer(model, 16000)) {
int nbytes;
byte[] b = new byte[4096];
while ((nbytes = ais.read(b)) >= 0) {
if (recognizer.acceptWaveForm(b, nbytes)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
}
}
+71
View File
@@ -0,0 +1,71 @@
buildscript {
repositories {
mavenCentral()
}
}
plugins {
id 'java-library'
id 'maven-publish'
id 'com.vanniktech.maven.publish' version '0.18.0'
}
repositories {
mavenCentral()
}
archivesBaseName = 'vosk'
group = 'com.alphacephei'
version = '0.3.45'
mavenPublish {
group = 'com.alphacephei'
version = version
sonatypeHost = 's01'
}
dependencies {
api group: 'net.java.dev.jna', name: 'jna', version: '5.13.0'
testImplementation 'junit:junit:4.13'
}
publishing {
publications {
mavenJava(MavenPublication) {
artifactId = 'vosk'
from components.java
pom {
name = 'Vosk'
description = 'Speech recognition library'
url = 'http://www.alphacephei.com.com/vosk/'
licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id = 'alphacephei'
name = 'Alpha Cephei Inc'
email = 'contact@alphacephei.com'
}
}
scm {
connection = 'scm:git:git://github.com/alphacep/vosk-api.git'
url = 'https://github.com/alphacep/vosk-api/'
}
}
}
}
}
test {
dependsOn cleanTest
testLogging.showStandardStreams = true
}
java {
withSourcesJar()
withJavadocJar()
}
@@ -0,0 +1,98 @@
package org.vosk;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
public class LibVosk {
private static void unpackDll(File targetDir, String lib) throws IOException {
try (InputStream source = LibVosk.class.getResourceAsStream("/win32-x86-64/" + lib + ".dll")) {
Files.copy(source, new File(targetDir, lib + ".dll").toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}
static {
if (Platform.isWindows()) {
// We have to unpack dependencies
try {
// To get a tmp folder we unpack small library and mark it for deletion
File tmpFile = Native.extractFromResourcePath("/win32-x86-64/empty", LibVosk.class.getClassLoader());
File tmpDir = tmpFile.getParentFile();
new File(tmpDir, tmpFile.getName() + ".x").createNewFile();
// Now unpack dependencies
unpackDll(tmpDir, "libwinpthread-1");
unpackDll(tmpDir, "libgcc_s_seh-1");
unpackDll(tmpDir, "libstdc++-6");
} catch (IOException e) {
// Nothing for now, it will fail on next step
} finally {
Native.register(LibVosk.class, "libvosk");
}
} else {
Native.register(LibVosk.class, "vosk");
}
}
public static native void vosk_set_log_level(int level);
public static native Pointer vosk_model_new(String path);
public static native void vosk_model_free(Pointer model);
public static native Pointer vosk_spk_model_new(String path);
public static native void vosk_spk_model_free(Pointer model);
public static native Pointer vosk_recognizer_new(Model model, float sample_rate);
public static native Pointer vosk_recognizer_new_spk(Pointer model, float sample_rate, Pointer spk_model);
public static native Pointer vosk_recognizer_new_grm(Pointer model, float sample_rate, String grammar);
public static native void vosk_recognizer_set_max_alternatives(Pointer recognizer, int max_alternatives);
public static native void vosk_recognizer_set_words(Pointer recognizer, boolean words);
public static native void vosk_recognizer_set_partial_words(Pointer recognizer, boolean partial_words);
public static native void vosk_recognizer_set_spk_model(Pointer recognizer, Pointer spk_model);
public static native boolean vosk_recognizer_accept_waveform(Pointer recognizer, byte[] data, int len);
public static native boolean vosk_recognizer_accept_waveform_s(Pointer recognizer, short[] data, int len);
public static native boolean vosk_recognizer_accept_waveform_f(Pointer recognizer, float[] data, int len);
public static native String vosk_recognizer_result(Pointer recognizer);
public static native String vosk_recognizer_final_result(Pointer recognizer);
public static native String vosk_recognizer_partial_result(Pointer recognizer);
public static native void vosk_recognizer_set_grm(Pointer recognizer, String grammar);
public static native void vosk_recognizer_reset(Pointer recognizer);
public static native void vosk_recognizer_free(Pointer recognizer);
/**
* Set log level for Kaldi messages.
*
* @param loglevel the level
* 0 - default value to print info and error messages but no debug
* less than 0 - don't print info messages
* greater than 0 - more verbose mode
*/
public static void setLogLevel(LogLevel loglevel) {
vosk_set_log_level(loglevel.getValue());
}
}
@@ -0,0 +1,17 @@
package org.vosk;
public enum LogLevel {
WARNINGS(-1), // Print warning and errors
INFO(0), // Print info, along with warning and error messages, but no debug
DEBUG(1); // Print debug info
private final int value;
LogLevel(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
@@ -0,0 +1,22 @@
package org.vosk;
import java.io.IOException;
import com.sun.jna.PointerType;
public class Model extends PointerType implements AutoCloseable {
public Model() {
}
public Model(String path) throws IOException {
super(LibVosk.vosk_model_new(path));
if (getPointer() == null) {
throw new IOException("Failed to create a model");
}
}
@Override
public void close() {
LibVosk.vosk_model_free(this.getPointer());
}
}
@@ -0,0 +1,247 @@
package org.vosk;
import com.sun.jna.PointerType;
import java.io.IOException;
public class Recognizer extends PointerType implements AutoCloseable {
/**
* Creates the recognizer object.
*
* The recognizers process the speech and return text using shared model data
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @throws IOException if the recognizer could not be created
*/
public Recognizer(Model model, float sampleRate) throws IOException {
super(LibVosk.vosk_recognizer_new(model, sampleRate));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* Creates the recognizer object with speaker recognition.
*
* With the speaker recognition mode the recognizer not just recognize
* text but also return speaker vectors one can use for speaker identification
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param spkModel speaker model for speaker identification
* @throws IOException if the recognizer could not be created
*/
public Recognizer(Model model, float sampleRate, SpeakerModel spkModel) throws IOException {
super(LibVosk.vosk_recognizer_new_spk(model.getPointer(), sampleRate, spkModel.getPointer()));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* Creates the recognizer object with the phrase list.
*
* Sometimes when you want to improve recognition accuracy and when you don't need
* to recognize large vocabulary you can specify a list of phrases to recognize. This
* will improve recognizer speed and accuracy but might return [unk] if user said
* something different.
*
* Only recognizers with lookahead models support this type of quick configuration.
* Precompiled HCLG graph models are not supported.
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
* for example "["one two three four five", "[unk]"]".
* @throws IOException if the recognizer could not be created
*/
public Recognizer(Model model, float sampleRate, String grammar) throws IOException {
super(LibVosk.vosk_recognizer_new_grm(model.getPointer(), sampleRate, grammar));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* Configures recognizer to output n-best results.
*
* <pre>
* {
* "alternatives": [
* { "text": "one two three four five", "confidence": 0.97 },
* { "text": "one two three for five", "confidence": 0.03 },
* ]
* }
* </pre>
*
* @param maxAlternatives - maximum alternatives to return from recognition results
*/
public void setMaxAlternatives(int maxAlternatives) {
LibVosk.vosk_recognizer_set_max_alternatives(this.getPointer(), maxAlternatives);
}
/** Enables words with times in the output
*
* <pre>
* "result" : [{
* "conf" : 1.000000,
* "end" : 1.110000,
* "start" : 0.870000,
* "word" : "what"
* }, {
* "conf" : 1.000000,
* "end" : 1.530000,
* "start" : 1.110000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 1.950000,
* "start" : 1.530000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.340000,
* "start" : 1.950000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.610000,
* "start" : 2.340000,
* "word" : "one"
* }],
* </pre>
*
* @param words - boolean value
*/
public void setWords(boolean words) {
LibVosk.vosk_recognizer_set_words(this.getPointer(), words);
}
/**
* Like above return words and confidences in partial results.
*
* @param partial_words - boolean value
*/
public void setPartialWords(boolean partial_words) {
LibVosk.vosk_recognizer_set_partial_words(this.getPointer(), partial_words);
}
/**
* Adds speaker model to already initialized recognizer.
*
* Can add speaker recognition model to already created recognizer.
* Helps to initialize speaker recognition for grammar-based recognizer.
*
* @param spkModel Speaker recognition model
*/
public void setSpeakerModel(SpeakerModel spkModel) {
LibVosk.vosk_recognizer_set_spk_model(this.getPointer(), spkModel.getPointer());
}
/**
* Accept and process new chunk of voice data.
*
* @param data - audio data in PCM 16-bit mono format
* @param len - length of the audio data
* @return 1 if silence is occurred and you can retrieve a new utterance with result method
* 0 if decoding continues
* -1 if exception occurred
*/
public boolean acceptWaveForm(byte[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform(this.getPointer(), data, len);
}
public boolean acceptWaveForm(short[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform_s(this.getPointer(), data, len);
}
public boolean acceptWaveForm(float[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform_f(this.getPointer(), data, len);
}
/**
* Returns speech recognition result
*
* @return the result in JSON format which contains decoded line, decoded
* words, times in seconds and confidences. You can parse this result
* with any json parser
*
* <pre>
* {
* "text" : "what zero zero zero one"
* }
* </pre>
*
* If alternatives enabled it returns result with alternatives, see also #setMaxAlternatives().
*
* If word times enabled returns word time, see also #setWordTimes().
*/
public String getResult() {
return LibVosk.vosk_recognizer_result(this.getPointer());
}
/**
* Returns partial speech recognition.
*
* @return partial speech recognition text which is not yet finalized.
* result may change as recognizer process more data.
*
* <pre>
* {
* "partial" : "cyril one eight zero"
* }
* </pre>
*/
public String getPartialResult() {
return LibVosk.vosk_recognizer_partial_result(this.getPointer());
}
/**
* Returns speech recognition result. Same as result, but doesn't wait for silence.
* You usually call it in the end of the stream to get final bits of audio. It
* flushes the feature pipeline, so all remaining audio chunks got processed.
*
* @return speech result in JSON format.
*/
public String getFinalResult() {
return LibVosk.vosk_recognizer_final_result(this.getPointer());
}
/**
* Reconfigures recognizer to use grammar.
*
* @param grammar Set of phrases in JSON array of strings or "[]" to use default model graph.
* @see #Recognizer(Model, float, String)
*/
public void setGrammar(String grammar) {
LibVosk.vosk_recognizer_set_grm(this.getPointer(), grammar);
}
/**
* Resets the recognizer.
* Resets current results so the recognition can continue from scratch.
*/
public void reset() {
LibVosk.vosk_recognizer_reset(this.getPointer());
}
/**
* Releases recognizer object.
* Underlying model is also unreferenced and if needed, released.
*/
@Override
public void close() {
LibVosk.vosk_recognizer_free(this.getPointer());
}
}
@@ -0,0 +1,40 @@
package org.vosk;
import com.sun.jna.PointerType;
import java.io.IOException;
/**
* Helps to initialize speaker recognition for grammar-based recognizer.
*/
public class SpeakerModel extends PointerType implements AutoCloseable {
public SpeakerModel() {
}
/**
* Loads speaker model data from the file.
*
* The path must contain:
* - a config file: mfcc.conf
* - kaldi nnet: final.ext.raw
* - mean.vec
* - transform.mat
*
* @param path the path of the model on the filesystem
* @throws IOException if the model could not be created
*
* @see <a href="http://kaldi-asr.org/doc/structkaldi_1_1MfccOptions.html">Kaldi MfccOptions</a>
* @see <a href="http://kaldi-asr.org/doc/classkaldi_1_1nnet3_1_1Nnet.html">Kaldi Nnet</a>
*/
public SpeakerModel(String path) throws IOException {
super(LibVosk.vosk_spk_model_new(path));
if (getPointer() == null) {
throw new IOException("Failed to create a speaker model");
}
}
@Override
public void close() {
LibVosk.vosk_spk_model_free(this.getPointer());
}
}
+1
View File
@@ -0,0 +1 @@
Mainly for work around JNA API
@@ -0,0 +1,103 @@
package org.vosk.test;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.junit.Test;
import org.junit.Assert;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.vosk.LogLevel;
import org.vosk.Recognizer;
import org.vosk.LibVosk;
import org.vosk.Model;
public class DecoderTest {
@Test
public void decoderTest() throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream("../../python/example/test.wav")));
Recognizer recognizer = new Recognizer(model, 16000)) {
recognizer.setMaxAlternatives(10);
recognizer.setWords(true);
recognizer.setPartialWords(true);
int nbytes;
byte[] b = new byte[4096];
while ((nbytes = ais.read(b)) >= 0) {
if (recognizer.acceptWaveForm(b, nbytes)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
Assert.assertTrue(true);
}
@Test
public void decoderTestShort() throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream("../../python/example/test.wav")));
Recognizer recognizer = new Recognizer(model, 16000)) {
int nbytes;
byte[] b = new byte[4096];
short[] s = new short[2048];
while ((nbytes = ais.read(b)) >= 0) {
ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(s);
if (recognizer.acceptWaveForm(s, nbytes / 2)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
Assert.assertTrue(true);
}
@Test
public void decoderTestGrammar() throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream("../../python/example/test.wav")));
Recognizer recognizer = new Recognizer(model, 16000, "[\"one two three four five six seven eight nine zero oh\"]")) {
int nbytes;
byte[] b = new byte[4096];
while ((nbytes = ais.read(b)) >= 0) {
if (recognizer.acceptWaveForm(b, nbytes)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
Assert.assertTrue(true);
}
@Test(expected = IOException.class)
public void decoderTestException() throws IOException {
Model model = new Model("model_missing");
}
}
-37
View File
@@ -1,37 +0,0 @@
package test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.*;
import org.kaldi.KaldiRecognizer;
import org.kaldi.Model;
import org.kaldi.SpkModel;
import org.kaldi.Vosk;
public class DecoderTest {
public static void main(String args[]) throws IOException {
Vosk.SetLogLevel(-10);
FileInputStream ais = new FileInputStream(new File("../python/example/test.wav"));
Model model = new Model("model");
SpkModel spkModel = new SpkModel("model-spk");
KaldiRecognizer rec = new KaldiRecognizer(model, spkModel, 16000.0f);
int nbytes;
byte[] b = new byte[4096];
while ((nbytes = ais.read(b)) >= 0) {
if (rec.AcceptWaveform(b)) {
System.out.println(rec.Result());
} else {
System.out.println(rec.PartialResult());
}
}
System.out.println(rec.FinalResult());
}
}
+3
View File
@@ -0,0 +1,3 @@
.gradle/
.idea/
build/
+3
View File
@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml
+1
View File
@@ -0,0 +1 @@
vosk-api-kotlin
+127
View File
@@ -0,0 +1,127 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
<option name="SMART_TABS" value="true" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>
+5
View File
@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright &amp;#36;today.year Alpha Cephei Inc.&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10; http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
<option name="myName" value="Apache-2.0" />
</copyright>
</component>
+7
View File
@@ -0,0 +1,7 @@
<component name="CopyrightManager">
<settings default="Apache-2.0">
<module2copyright>
<element module="All" copyright="Apache-2.0" />
</module2copyright>
</settings>
</component>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
+25
View File
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="Google" />
<option name="name" value="Google" />
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
</remote-repository>
</component>
</project>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Embedded JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
+1
View File
@@ -0,0 +1 @@
Doomsdayrs doomsdayrs@gmail.com
+8
View File
@@ -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.

Some files were not shown because too many files have changed in this diff Show More