Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a9672d910 | |||
| 4ccccd0cd2 | |||
| 354fb672a3 | |||
| 73abf0740a | |||
| 81c82935ac | |||
| ac3ec56584 | |||
| 2cbe12d4d0 | |||
| 1475b0e986 | |||
| 8ceab0b9b1 | |||
| 1496b597d3 | |||
| 983519e629 | |||
| 58fa98ccd7 | |||
| a7bc5a22d4 | |||
| 23bbff0b56 | |||
| a47b58e2f4 | |||
| 8cf64ee93e | |||
| 630edeb3d6 | |||
| b1b216d4c8 | |||
| 55dd29b0ff |
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(vosk-api CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
add_library(vosk
|
||||
src/language_model.cc
|
||||
src/model.cc
|
||||
src/recognizer.cc
|
||||
src/spk_model.cc
|
||||
src/vosk_api.cc
|
||||
)
|
||||
|
||||
find_package(kaldi REQUIRED)
|
||||
target_link_libraries(vosk PUBLIC kaldi-base kaldi-online2 kaldi-rnnlm fstngram)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS vosk DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(FILES src/vosk_api.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
@@ -4,14 +4,15 @@ Vosk is an offline open source speech recognition toolkit. It enables
|
||||
speech recognition for 20+ languages and dialects - English, Indian
|
||||
English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish,
|
||||
Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino,
|
||||
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech. More to come.
|
||||
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech, Polish.
|
||||
More to come.
|
||||
|
||||
Vosk models are small (50 Mb) but provide continuous large vocabulary
|
||||
transcription, zero-latency response with streaming API, reconfigurable
|
||||
vocabulary and speaker identification.
|
||||
|
||||
Speech recognition bindings implemented for various programming languages
|
||||
like Python, Java, Node.JS, C#, C++ and others.
|
||||
like Python, Java, Node.JS, C#, C++, Rust, Go and others.
|
||||
|
||||
Vosk supplies speech recognition for chatbots, smart home appliances,
|
||||
virtual assistants. It can also create subtitles for movies,
|
||||
|
||||
@@ -10,7 +10,7 @@ buildscript {
|
||||
}
|
||||
|
||||
allprojects {
|
||||
version = '0.3.41'
|
||||
version = '0.3.43'
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Vosk" Version="0.3.41" />
|
||||
<PackageReference Include="Vosk" Version="0.3.43" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<package>
|
||||
<metadata>
|
||||
<id>Vosk</id>
|
||||
<version>0.3.41</version>
|
||||
<version>0.3.43</version>
|
||||
<authors>Alpha Cephei Inc</authors>
|
||||
<owners>Alpha Cephei Inc</owners>
|
||||
<license type="expression">Apache-2.0</license>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
See example subfolder for instructions how to use the module
|
||||
@@ -0,0 +1,31 @@
|
||||
To try this package do the following steps:
|
||||
|
||||
On Linux (we download library and set LD_LIBRARY_PATH)
|
||||
|
||||
```
|
||||
git clone https://github.com/alphacep/vosk-api
|
||||
cd vosk-api/go/example
|
||||
wget https://github.com/alphacep/vosk-api/releases/download/v0.3.42/vosk-linux-x86_64-0.3.42.zip
|
||||
unzip vosk-linux-x86_64-0.3.42.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.42 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.42/vosk-linux-x86_64-0.3.42.zip
|
||||
unzip vosk-linux-x86_64-0.3.42.zip
|
||||
cp vosk-linux-x86_64-0.3.42/*.dll .
|
||||
cp vosk-linux-x86_64-0.3.42/*.h .
|
||||
wget https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip
|
||||
unzip vosk-model-small-en-us-0.15.zip
|
||||
mv vosk-model-small-en-us-0.15 model
|
||||
cp ../../python/example/test.wav .
|
||||
VOSK_PATH=`pwd` LD_LIBRARY_PATH=$VOSK_PATH CGO_CPPFLAGS="-I $VOSK_PATH" CGO_LDFLAGS="-L $VOSK_PATH -lvosk -lpthread -dl" go run . -f test.wav
|
||||
```
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
// Example package for Vosk Go bindings.
|
||||
package test_simple
|
||||
package main
|
||||
|
||||
@@ -12,5 +12,5 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
implementation group: 'net.java.dev.jna', name: 'jna', version: '5.7.0'
|
||||
implementation group: 'com.alphacephei', name: 'vosk', version: '0.3.41+'
|
||||
implementation group: 'com.alphacephei', name: 'vosk', version: '0.3.43+'
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ repositories {
|
||||
|
||||
archivesBaseName = 'vosk'
|
||||
group = 'com.alphacephei'
|
||||
version = '0.3.41'
|
||||
version = '0.3.43'
|
||||
|
||||
mavenPublish {
|
||||
group = 'com.alphacephei'
|
||||
|
||||
+2
-1
@@ -13,7 +13,8 @@ Vosk is an offline open source speech recognition toolkit. It enables
|
||||
speech recognition for 20+ languages and dialects - English, Indian
|
||||
English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish,
|
||||
Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino,
|
||||
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech. More to come.
|
||||
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech, Polish.
|
||||
More to come.
|
||||
|
||||
Vosk models are small (50 Mb) but provide continuous large vocabulary
|
||||
transcription, zero-latency response with streaming API, reconfigurable
|
||||
|
||||
@@ -18,11 +18,11 @@ const rec = new vosk.Recognizer({model: model, sampleRate: SAMPLE_RATE});
|
||||
var micInstance = mic({
|
||||
rate: String(SAMPLE_RATE),
|
||||
channels: '1',
|
||||
debug: false
|
||||
debug: false,
|
||||
device: 'default',
|
||||
});
|
||||
|
||||
var micInputStream = micInstance.getAudioStream();
|
||||
micInstance.start();
|
||||
|
||||
micInputStream.on('data', data => {
|
||||
if (rec.acceptWaveform(data))
|
||||
@@ -31,9 +31,16 @@ micInputStream.on('data', data => {
|
||||
console.log(rec.partialResult());
|
||||
});
|
||||
|
||||
process.on('SIGINT', function() {
|
||||
micInputStream.on('audioProcessExitComplete', function() {
|
||||
console.log("Cleaning up");
|
||||
console.log(rec.finalResult());
|
||||
console.log("\nDone");
|
||||
rec.free();
|
||||
model.free();
|
||||
});
|
||||
|
||||
process.on('SIGINT', function() {
|
||||
console.log("\nStopping");
|
||||
micInstance.stop();
|
||||
});
|
||||
|
||||
micInstance.start();
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vosk",
|
||||
"version": "0.3.41",
|
||||
"version": "0.3.43",
|
||||
"description": "Node binding for continuous offline voice recoginition with Vosk library.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
+2
-1
@@ -4,7 +4,8 @@ Vosk is an offline open source speech recognition toolkit. It enables
|
||||
speech recognition for 20+ languages and dialects - English, Indian
|
||||
English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish,
|
||||
Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino,
|
||||
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech. More to come.
|
||||
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech, Polish.
|
||||
More to come.
|
||||
|
||||
Vosk models are small (50 Mb) but provide continuous large vocabulary
|
||||
transcription, zero-latency response with streaming API, reconfigurable
|
||||
|
||||
@@ -62,6 +62,6 @@ def transcribe():
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not (1 < len(sys.argv) < 4):
|
||||
print(f'Usage: {sys.argv[0]} audiofile [output file]')
|
||||
print('Usage: {} audiofile [output file]'.format(sys.argv[0]))
|
||||
exit(1)
|
||||
transcribe()
|
||||
|
||||
+5
-3
@@ -32,6 +32,8 @@ else:
|
||||
oses = 'win_amd64'
|
||||
elif system == 'Linux' and architecture == '64bit':
|
||||
oses = 'linux_x86_64'
|
||||
elif system == 'Linux' and architecture == 'aarch64':
|
||||
oses = 'manylinux2014_aarch64'
|
||||
elif system == 'Linux':
|
||||
oses = 'linux_' + architecture
|
||||
else:
|
||||
@@ -44,7 +46,7 @@ with open("README.md", "r") as fh:
|
||||
|
||||
setuptools.setup(
|
||||
name="vosk",
|
||||
version="0.3.41",
|
||||
version="0.3.43",
|
||||
author="Alpha Cephei Inc",
|
||||
author_email="contact@alphacephei.com",
|
||||
description="Offline open source speech recognition API based on Kaldi and Vosk",
|
||||
@@ -68,7 +70,7 @@ setuptools.setup(
|
||||
cmdclass=cmdclass,
|
||||
python_requires='>=3',
|
||||
zip_safe=False, # Since we load so file from the filesystem, we can not run from zip file
|
||||
setup_requires=['cffi>=1.0', 'requests', 'tqdm'],
|
||||
install_requires=['cffi>=1.0', 'requests', 'tqdm'],
|
||||
setup_requires=['cffi>=1.0', 'requests', 'tqdm', 'srt'],
|
||||
install_requires=['cffi>=1.0', 'requests', 'tqdm', 'srt'],
|
||||
cffi_modules=['vosk_builder.py:ffibuilder'],
|
||||
)
|
||||
|
||||
@@ -86,7 +86,7 @@ class Model(object):
|
||||
if directory is None or not Path(directory).exists():
|
||||
continue
|
||||
model_file_list = os.listdir(directory)
|
||||
model_file = [model for model in model_file_list if match(f"vosk-model(-small)?-{lang}", model)]
|
||||
model_file = [model for model in model_file_list if match(r'vosk-model(-small)?-{}'.format(lang), model)]
|
||||
if model_file != []:
|
||||
return Path(directory, model_file[0])
|
||||
response = requests.get(MODEL_LIST_URL)
|
||||
@@ -98,8 +98,8 @@ class Model(object):
|
||||
return Path(directory, result_model[0])
|
||||
|
||||
def download_model(self, model_name):
|
||||
if not MODEL_DIRS[3].exists():
|
||||
MODEL_DIRS[3].mkdir()
|
||||
if not (model_name.parent).exists():
|
||||
(model_name.parent).mkdir(parents=True)
|
||||
with tqdm(unit='B', unit_scale=True, unit_divisor=1024, miniters=1,
|
||||
desc=(MODEL_PRE_URL + str(model_name.name) + '.zip').split('/')[-1]) as t:
|
||||
reporthook = self.download_progress_hook(t)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import logging
|
||||
import argparse
|
||||
import os
|
||||
|
||||
from pathlib import Path
|
||||
from vosk import list_models, list_languages
|
||||
@@ -12,6 +13,9 @@ parser = argparse.ArgumentParser(
|
||||
parser.add_argument(
|
||||
'--model', '-m', type=str,
|
||||
help='model path')
|
||||
parser.add_argument(
|
||||
'--server', '-s', const='ws://localhost:2700', action='store_const',
|
||||
help='use server for recognition')
|
||||
parser.add_argument(
|
||||
'--list-models', default=False, action='store_true',
|
||||
help='list available models')
|
||||
@@ -33,6 +37,9 @@ parser.add_argument(
|
||||
parser.add_argument(
|
||||
'--output-type', '-t', default='txt', type=str,
|
||||
help='optional arg output data type')
|
||||
parser.add_argument(
|
||||
'--tasks', '-ts', default=10, type=int,
|
||||
help='number of parallel recognition tasks')
|
||||
parser.add_argument(
|
||||
'--log-level', default='INFO',
|
||||
help='logging level')
|
||||
@@ -52,27 +59,27 @@ def main():
|
||||
return
|
||||
|
||||
if not args.input:
|
||||
logging.info('Please specify input file or directory')
|
||||
logging.info("Please specify input file or directory")
|
||||
exit(1)
|
||||
|
||||
if not Path(args.input).exists():
|
||||
logging.info('File %s does not exist, please specify an existing file/directory' % (args.input))
|
||||
exit(1)
|
||||
|
||||
if args.output !='' and not Path(args.output).exists():
|
||||
logging.info('Output %s does not exist, please specify an existing file' % (args.output))
|
||||
logging.info("File/folder '%s' does not exist, please specify an existing file/directory" % (args.input))
|
||||
exit(1)
|
||||
|
||||
transcriber = Transcriber(args)
|
||||
|
||||
if Path(args.input).is_dir() and Path(args.output).is_dir():
|
||||
transcriber.process_dir(args)
|
||||
return
|
||||
elif Path(args.input).is_file() and (args.output=='' or Path(args.output).is_file()):
|
||||
transcriber.process_file(args)
|
||||
if Path(args.input).is_dir():
|
||||
task_list = [(Path(args.input, fn), Path(args.output, Path(fn).stem).with_suffix('.' + args.output_type)) for fn in os.listdir(args.input)]
|
||||
elif Path(args.input).is_file():
|
||||
if args.output == '':
|
||||
task_list = [(Path(args.input), args.output)]
|
||||
else:
|
||||
task_list = [(Path(args.input), Path(args.output))]
|
||||
else:
|
||||
logging.info('Wrong arguments, input and output must be same type')
|
||||
logging.info("Wrong arguments")
|
||||
exit(1)
|
||||
|
||||
transcriber.process_task_list(args, task_list)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -4,10 +4,17 @@ import srt
|
||||
import datetime
|
||||
import os
|
||||
import logging
|
||||
import asyncio
|
||||
import websockets
|
||||
|
||||
from queue import Queue
|
||||
from pathlib import Path
|
||||
from timeit import default_timer as timer
|
||||
from vosk import KaldiRecognizer, Model
|
||||
from multiprocessing.dummy import Pool
|
||||
|
||||
CHUNK_SIZE = 4000
|
||||
SAMPLE_RATE = 16000.0
|
||||
|
||||
class Transcriber:
|
||||
|
||||
@@ -18,24 +25,62 @@ class Transcriber:
|
||||
def recognize_stream(self, rec, stream):
|
||||
tot_samples = 0
|
||||
result = []
|
||||
|
||||
while True:
|
||||
data = stream.stdout.read(4000)
|
||||
data = stream.stdout.read(CHUNK_SIZE)
|
||||
|
||||
if len(data) == 0:
|
||||
break
|
||||
|
||||
tot_samples += len(data)
|
||||
if rec.AcceptWaveform(data):
|
||||
tot_samples += len(data)
|
||||
result.append(json.loads(rec.Result()))
|
||||
result.append(json.loads(rec.FinalResult()))
|
||||
jres = json.loads(rec.Result())
|
||||
logging.info(jres)
|
||||
result.append(jres)
|
||||
else:
|
||||
jres = json.loads(rec.PartialResult())
|
||||
logging.info(jres)
|
||||
|
||||
jres = json.loads(rec.FinalResult())
|
||||
logging.info(jres)
|
||||
result.append(jres)
|
||||
|
||||
return result, tot_samples
|
||||
|
||||
async def recognize_stream_server(self, proc):
|
||||
async with websockets.connect(self.args.server) as websocket:
|
||||
tot_samples = 0
|
||||
result = []
|
||||
|
||||
await websocket.send('{ "config" : { "sample_rate" : %f } }' % (SAMPLE_RATE))
|
||||
while True:
|
||||
data = await proc.stdout.read(CHUNK_SIZE)
|
||||
tot_samples += len(data)
|
||||
if len(data) == 0:
|
||||
break
|
||||
await websocket.send(data)
|
||||
jres = json.loads(await websocket.recv())
|
||||
logging.info(jres)
|
||||
if not 'partial' in jres:
|
||||
result.append(jres)
|
||||
await websocket.send('{"eof" : 1}')
|
||||
jres = json.loads(await websocket.recv())
|
||||
logging.info(jres)
|
||||
result.append(jres)
|
||||
|
||||
return result, tot_samples
|
||||
|
||||
|
||||
def format_result(self, result, words_per_line=7):
|
||||
final_result = ''
|
||||
if self.args.output_type == 'srt':
|
||||
subs = []
|
||||
|
||||
for i, res in enumerate(result):
|
||||
if not 'result' in res:
|
||||
continue
|
||||
words = res['result']
|
||||
|
||||
for j in range(0, len(words), words_per_line):
|
||||
line = words[j : j + words_per_line]
|
||||
s = srt.Subtitle(index=len(subs),
|
||||
@@ -44,46 +89,84 @@ class Transcriber:
|
||||
end=datetime.timedelta(seconds=line[-1]['end']))
|
||||
subs.append(s)
|
||||
final_result = srt.compose(subs)
|
||||
|
||||
elif self.args.output_type == 'txt':
|
||||
for part in result:
|
||||
final_result += part['text'] + ' '
|
||||
return final_result
|
||||
|
||||
|
||||
def resample_ffmpeg(self, infile):
|
||||
stream = subprocess.Popen(
|
||||
['ffmpeg', '-nostdin', '-loglevel', 'quiet', '-i',
|
||||
infile,
|
||||
'-ar', '16000','-ac', '1', '-f', 's16le', '-'],
|
||||
stdout=subprocess.PIPE)
|
||||
cmd = "ffmpeg -nostdin -loglevel quiet -i {} -ar {} -ac 1 -f s16le -".format(str(infile), SAMPLE_RATE)
|
||||
stream = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
|
||||
return stream
|
||||
|
||||
async def resample_ffmpeg_async(self, infile):
|
||||
cmd = "ffmpeg -nostdin -loglevel quiet -i {} -ar {} -ac 1 -f s16le -".format(str(infile), SAMPLE_RATE)
|
||||
return await asyncio.create_subprocess_shell(cmd, stdout=subprocess.PIPE)
|
||||
|
||||
def process_entry(self, inputdata):
|
||||
logging.info(f'Recognizing {inputdata[0]}')
|
||||
async def server_worker(self):
|
||||
while True:
|
||||
try:
|
||||
input_file, output_file = self.queue.get_nowait()
|
||||
except:
|
||||
break
|
||||
|
||||
rec = KaldiRecognizer(self.model, 16000)
|
||||
logging.info('Recognizing {}'.format(input_file))
|
||||
start_time = timer()
|
||||
proc = await self.resample_ffmpeg_async(input_file)
|
||||
result, tot_samples = await self.recognize_stream_server(proc)
|
||||
|
||||
final_result = self.format_result(result)
|
||||
if output_file != '':
|
||||
logging.info('File {} processing complete'.format(output_file))
|
||||
with open(output_file, 'w', encoding='utf-8') as fh:
|
||||
fh.write(final_result)
|
||||
else:
|
||||
print(final_result)
|
||||
|
||||
await proc.wait()
|
||||
|
||||
elapsed = timer() - start_time
|
||||
logging.info('Execution time: {:.3f} sec; xRT {:.3f}'.format(elapsed, float(elapsed) * (2 * SAMPLE_RATE) / tot_samples))
|
||||
self.queue.task_done()
|
||||
|
||||
def pool_worker(self, inputdata):
|
||||
logging.info('Recognizing {}'.format(inputdata[0]))
|
||||
start_time = timer()
|
||||
|
||||
try:
|
||||
stream = self.resample_ffmpeg(inputdata[0])
|
||||
except Exception:
|
||||
logging.info('Missing ffmpeg, please install and try again')
|
||||
return
|
||||
|
||||
rec = KaldiRecognizer(self.model, SAMPLE_RATE)
|
||||
rec.SetWords(True)
|
||||
|
||||
stream = self.resample_ffmpeg(inputdata[0])
|
||||
result, tot_samples = self.recognize_stream(rec, stream)
|
||||
final_result = self.format_result(result)
|
||||
|
||||
if inputdata[1] != '':
|
||||
logging.info('File {} processing complete'.format(inputdata[1]))
|
||||
with open(inputdata[1], 'w', encoding='utf-8') as fh:
|
||||
fh.write(final_result)
|
||||
else:
|
||||
print(final_result)
|
||||
return final_result, tot_samples
|
||||
|
||||
|
||||
def process_directory(self,args):
|
||||
task_list = [(Path(args.input, fn), Path(args.output, Path(fn).stem).with_suffix('.' + args.output_type)) for fn in os.listdir(args.input)]
|
||||
with Pool() as pool:
|
||||
pool.map(self.process_entry, file_list)
|
||||
|
||||
def process_file(self, args):
|
||||
start_time = timer()
|
||||
final_result, tot_samples = self.process_entry([args.input, args.output])
|
||||
elapsed = timer() - start_time
|
||||
logging.info(f'''Execution time: {elapsed:.3f} sec; xRT: {format(tot_samples / 16000.0 / float(elapsed), '.3f')}''')
|
||||
logging.info('Execution time: {:.3f} sec; xRT {:.3f}'.format(elapsed, float(elapsed) * (2 * SAMPLE_RATE) / tot_samples))
|
||||
|
||||
async def process_task_list_server(self, task_list):
|
||||
self.queue = Queue()
|
||||
[self.queue.put(x) for x in task_list]
|
||||
workers = [asyncio.create_task(self.server_worker()) for i in range(self.args.tasks)]
|
||||
await asyncio.gather(*workers)
|
||||
|
||||
def process_task_list_pool(self, task_list):
|
||||
with Pool() as pool:
|
||||
pool.map(self.pool_worker, task_list)
|
||||
|
||||
def process_task_list(self, args, task_list):
|
||||
if self.args.server is None:
|
||||
self.process_task_list_pool(task_list)
|
||||
else:
|
||||
asyncio.run(self.process_task_list_server(task_list))
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class Vosk
|
||||
def self.hi
|
||||
puts "Hello world!"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,12 @@
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "vosk"
|
||||
s.version = "0.3.43"
|
||||
s.summary = "Offline speech recognition API"
|
||||
s.description = "Vosk is an offline open source speech recognition toolkit. It enables speech recognition for 20+ languages and dialects - English, Indian English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish, Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino, Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech, Polish. More to come."
|
||||
s.authors = ["Alpha Cephei Inc"]
|
||||
s.email = "contact@alphacphei.com"
|
||||
s.files = ["lib/vosk.rb"]
|
||||
s.homepage =
|
||||
"https://rubygems.org/gems/vosk"
|
||||
s.license = "Apache 2.0"
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
See
|
||||
|
||||
https://github.com/Bear-03/vosk-rs
|
||||
|
||||
https://crates.io/crates/vosk
|
||||
+15
-2
@@ -418,14 +418,23 @@ bool Recognizer::GetSpkVector(Vector<BaseFloat> &out_xvector, int *num_spk_frame
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we can't align, we still need to prepare for MBR
|
||||
static void CopyLatticeForMbr(CompactLattice &lat, CompactLattice *lat_out)
|
||||
{
|
||||
*lat_out = lat;
|
||||
RmEpsilon(lat_out, true);
|
||||
fst::CreateSuperFinal(lat_out);
|
||||
TopSortCompactLatticeIfNeeded(lat_out);
|
||||
}
|
||||
|
||||
const char *Recognizer::MbrResult(CompactLattice &rlat)
|
||||
{
|
||||
|
||||
CompactLattice aligned_lat;
|
||||
if (model_->winfo_) {
|
||||
WordAlignLattice(rlat, *model_->trans_model_, *model_->winfo_, 0, &aligned_lat);
|
||||
} else {
|
||||
aligned_lat = rlat;
|
||||
CopyLatticeForMbr(rlat, &aligned_lat);
|
||||
}
|
||||
|
||||
MinimumBayesRisk mbr(aligned_lat);
|
||||
@@ -739,7 +748,11 @@ const char* Recognizer::PartialResult()
|
||||
CompactLattice aligned_lat;
|
||||
|
||||
clat = decoder_->GetLattice(decoder_->NumFramesInLattice(), false);
|
||||
WordAlignLatticePartial(clat, *model_->trans_model_, *model_->winfo_, 0, &aligned_lat);
|
||||
if (model_->winfo_) {
|
||||
WordAlignLatticePartial(clat, *model_->trans_model_, *model_->winfo_, 0, &aligned_lat);
|
||||
} else {
|
||||
CopyLatticeForMbr(clat, &aligned_lat);
|
||||
}
|
||||
|
||||
MinimumBayesRisk mbr(aligned_lat);
|
||||
const vector<BaseFloat> &conf = mbr.GetOneBestConfidences();
|
||||
|
||||
@@ -29,7 +29,7 @@ RUN cd /opt \
|
||||
&& git clone -b v3.2.1 --single-branch https://github.com/alphacep/clapack \
|
||||
&& echo ${OPENBLAS_ARGS} \
|
||||
&& make -C OpenBLAS ONLY_CBLAS=1 ${OPENBLAS_ARGS} HOSTCC=gcc USE_LOCKING=1 USE_THREAD=0 all \
|
||||
&& make -C OpenBLAS PREFIX=$(pwd)/OpenBLAS/install install \
|
||||
&& make -C OpenBLAS ${OPENBLAS_ARGS} HOSTCC=gcc USE_LOCKING=1 USE_THREAD=0 PREFIX=$(pwd)/OpenBLAS/install install \
|
||||
&& mkdir -p clapack/BUILD && cd clapack/BUILD && cmake .. \
|
||||
&& make -j 10 -C F2CLIBS \
|
||||
&& make -j 10 -C BLAS \
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
ARG DOCKCROSS_IMAGE=dockcross/manylinux2014-aarch64
|
||||
FROM ${DOCKCROSS_IMAGE}
|
||||
|
||||
LABEL description="A docker image for building portable Python linux binary wheels and Kaldi on other architectures"
|
||||
LABEL maintainer="contact@alphacephei.com"
|
||||
|
||||
RUN yum -y install \
|
||||
automake \
|
||||
autoconf \
|
||||
libtool \
|
||||
libffi-devel \
|
||||
&& yum clean all
|
||||
|
||||
ARG OPENBLAS_ARGS=
|
||||
RUN cd /opt \
|
||||
&& git clone -b vosk --single-branch https://github.com/alphacep/kaldi \
|
||||
&& cd kaldi/tools \
|
||||
&& git clone -b v0.3.20 --single-branch https://github.com/xianyi/OpenBLAS \
|
||||
&& git clone -b v3.2.1 --single-branch https://github.com/alphacep/clapack \
|
||||
&& echo ${OPENBLAS_ARGS} \
|
||||
&& make -C OpenBLAS ONLY_CBLAS=1 ${OPENBLAS_ARGS} HOSTCC=gcc USE_LOCKING=1 USE_THREAD=0 all \
|
||||
&& make -C OpenBLAS ${OPENBLAS_ARGS} HOSTCC=gcc USE_LOCKING=1 USE_THREAD=0 PREFIX=$(pwd)/OpenBLAS/install install \
|
||||
&& mkdir -p clapack/BUILD && cd clapack/BUILD && cmake .. \
|
||||
&& make -j 10 -C F2CLIBS \
|
||||
&& make -j 10 -C BLAS \
|
||||
&& make -j 10 -C SRC \
|
||||
&& find . -name "*.a" | xargs cp -t ../../OpenBLAS/install/lib \
|
||||
&& cd /opt/kaldi/tools \
|
||||
&& git clone --single-branch https://github.com/alphacep/openfst openfst \
|
||||
&& cd openfst \
|
||||
&& autoreconf -i \
|
||||
&& CFLAGS="-g -O3" ./configure --prefix=/opt/kaldi/tools/openfst --enable-static --enable-shared --enable-far --enable-ngram-fsts --enable-lookahead-fsts --with-pic --disable-bin --host=${CROSS_TRIPLE} --build=x86-linux-gnu \
|
||||
&& make -j 10 && make install \
|
||||
&& cd /opt/kaldi/src \
|
||||
&& sed -i "s:TARGET_ARCH=\"\`uname -m\`\":TARGET_ARCH=$(echo $CROSS_TRIPLE|cut -d - -f 1):g" configure \
|
||||
&& sed -i "s: -O1 : -O3 :g" makefiles/linux_openblas_arm.mk \
|
||||
&& ./configure --mathlib=OPENBLAS_CLAPACK --shared --use-cuda=no \
|
||||
&& make -j 10 online2 lm rnnlm \
|
||||
&& find /opt/kaldi -name "*.o" -exec rm {} \;
|
||||
@@ -9,6 +9,7 @@ RUN yum -y update && yum -y install \
|
||||
autoconf \
|
||||
libtool \
|
||||
cmake \
|
||||
libffi-devel \
|
||||
&& yum clean all
|
||||
|
||||
RUN cd /opt \
|
||||
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
docker build --build-arg="DOCKCROSS_IMAGE=dockcross/manylinux2014-aarch64" --build-arg="OPENBLAS_ARGS=TARGET=ARMV8" --file Dockerfile.dockcross-manylinux --tag alphacep/kaldi-dockcross-aarch64:latest .
|
||||
docker run --rm -v /home/shmyrev/travis/vosk-api/:/io alphacep/kaldi-dockcross-aarch64 /io/travis/build-wheels-dockcross.sh
|
||||
@@ -4,9 +4,13 @@ set -e
|
||||
set -x
|
||||
|
||||
docker build --build-arg="DOCKCROSS_IMAGE=alphacep/dockcross-linux-armv7" --build-arg="OPENBLAS_ARGS=TARGET=ARMV7" --file Dockerfile.dockcross --tag alphacep/kaldi-dockcross-armv7:latest .
|
||||
docker build --build-arg="DOCKCROSS_IMAGE=dockcross/linux-arm64" --build-arg="OPENBLAS_ARGS=TARGET=ARMV8" --file Dockerfile.dockcross --tag alphacep/kaldi-dockcross-arm64:latest .
|
||||
docker build --build-arg="DOCKCROSS_IMAGE=dockcross/linux-x86" --build-arg="OPENBLAS_ARGS=TARGET=CORE2\ DYNAMIC_ARCH=1" --file Dockerfile.dockcross --tag alphacep/kaldi-dockcross-x86:latest .
|
||||
docker build --build-arg="DOCKCROSS_IMAGE=dockcross/linux-riscv64" --build-arg="OPENBLAS_ARGS=TARGET=RISCV64_GENERIC\ ARCH=riscv64" --file Dockerfile.dockcross --tag alphacep/kaldi-dockcross-riscv:latest .
|
||||
|
||||
docker run --rm -v /home/shmyrev/travis/vosk-api/:/io alphacep/kaldi-dockcross-armv7 /io/travis/build-wheels-dockcross.sh
|
||||
docker run --rm -v /home/shmyrev/travis/vosk-api/:/io alphacep/kaldi-dockcross-arm64 /io/travis/build-wheels-dockcross.sh
|
||||
docker run --rm -v /home/shmyrev/travis/vosk-api/:/io alphacep/kaldi-dockcross-x86 /io/travis/build-wheels-dockcross.sh
|
||||
docker run --rm -v /home/shmyrev/travis/vosk-api/:/io alphacep/kaldi-dockcross-riscv /io/travis/build-wheels-dockcross.sh
|
||||
|
||||
# We use manylinux (Centos-based image) for aarch64 instead
|
||||
# docker build --build-arg="DOCKCROSS_IMAGE=dockcross/linux-arm64" --build-arg="OPENBLAS_ARGS=TARGET=ARMV8" --file Dockerfile.dockcross --tag alphacep/kaldi-dockcross-arm64:latest .
|
||||
# docker run --rm -v /home/shmyrev/travis/vosk-api/:/io alphacep/kaldi-dockcross-arm64 /io/travis/build-wheels-dockcross.sh
|
||||
|
||||
@@ -19,6 +19,9 @@ case $CROSS_TRIPLE in
|
||||
*i686-*)
|
||||
export VOSK_ARCHITECTURE=x86
|
||||
;;
|
||||
*riscv64-*)
|
||||
export VOSK_ARCHITECTURE=riscv64
|
||||
;;
|
||||
esac
|
||||
|
||||
# Copy library to output folder
|
||||
@@ -26,5 +29,5 @@ mkdir -p /io/wheelhouse/vosk-linux-$VOSK_ARCHITECTURE
|
||||
cp /opt/vosk-api/src/*.so /opt/vosk-api/src/vosk_api.h /io/wheelhouse/vosk-linux-$VOSK_ARCHITECTURE
|
||||
|
||||
# Build wheel
|
||||
python3 -m pip install requests tqdm
|
||||
python3 -m pip install requests tqdm srt wheel
|
||||
python3 -m pip wheel /opt/vosk-api/python --no-deps -w /io/wheelhouse
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vosk-js",
|
||||
"version": "0.3.41",
|
||||
"version": "0.3.43",
|
||||
"description": "Node binding for continuous voice recoginition through vosk-api.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Reference in New Issue
Block a user