Skip to content

Commit

Permalink
Revert "[runtime/binding] deprecate wenetruntime (wenet-e2e#2194)"
Browse files Browse the repository at this point in the history
This reverts commit 6638d68.
  • Loading branch information
Xsx93 authored Feb 23, 2024
1 parent 1a3633a commit e3ad39b
Show file tree
Hide file tree
Showing 20 changed files with 648 additions and 0 deletions.
57 changes: 57 additions & 0 deletions runtime/binding/python/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(wenet VERSION 0.1)

option(TORCH "whether to build with Torch" ON)
option(ONNX "whether to build with ONNX" OFF)
option(ITN "whether to use WeTextProcessing" ON)

set(CXX11_ABI OFF)
set(FST_HAVE_BIN OFF)
set(CMAKE_VERBOSE_MAKEFILE OFF)

include(FetchContent)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_EXTENSIONS OFF)
set(FETCHCONTENT_QUIET OFF)
get_filename_component(fc_base "fc_base" REALPATH BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(FETCHCONTENT_BASE_DIR ${fc_base})

list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)

if(NOT MSVC)
# Keep the same with openfst, -fPIC or -fpic
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread -fPIC")
else()
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
endif()

if(TORCH)
include(libtorch)
endif()
if(ONNX)
include(onnx)
endif()
include(openfst)
include(pybind11)

include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/kaldi
)

if(ITN)
include(wetextprocessing)
endif()

add_subdirectory(utils)
add_subdirectory(frontend)
add_subdirectory(post_processor)
add_subdirectory(kaldi) # kaldi: wfst based decoder
add_subdirectory(decoder)
add_subdirectory(api)

# wenet api
pybind11_add_module(_wenet cpp/binding.cc)
target_link_libraries(_wenet PRIVATE wenet_api)
2 changes: 2 additions & 0 deletions runtime/binding/python/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include README.md
recursive-include py *.*
114 changes: 114 additions & 0 deletions runtime/binding/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Python Binding

This is a python binding of WeNet.

WeNet is a production first and production ready end-to-end speech recognition toolkit.

The best things of the binding are:

1. Multiple languages supports, including English, Chinese. Other languages are in development.
2. Non-streaming and streaming API
3. N-best, contextual biasing, and timestamp supports, which are very important for speech productions.
4. Alignment support. You can get phone level alignments this tool, on developing.

## Install

Python 3.6+ is required.

``` sh
pip3 install wenetruntime
```

## Command-line usage

```
wenetruntime audio.wav
```

We support mainstream audio formats, such as wav, mp3, flac and so on.

You can specify the language using the `--language` option,
currently we support `en` (English) and `chs` (中文).

## Programming usage

Note:

1. For macOS, wenetruntime packed `libtorch.so`, so we can't import torch and wenetruntime at the same time.
2. For Windows and Linux, wenetruntime depends on torch. Please install and import the same version `torch` as wenetruntime.

### Non-streaming Usage

``` python
import sys
import wenetruntime as wenet

audio_file = sys.argv[1] # support wav, mp3, flac, etc
decoder = wenet.Decoder(lang='chs')
ans = decoder.decode(audio_file)
print(ans)
```

You can also specify the following parameter in `wenet.Decoder`

* `lang` (str): The language you used, `chs` for Chinese, and `en` for English.
* `model_dir` (str): is the `Runtime Model` directory, it contains the following files.
If not provided, official model for specific `lang` will be downloaded automatically.

* `final.zip`: runtime TorchScript ASR model.
* `units.txt`: modeling units file
* `TLG.fst`: optional, it means decoding with LM when `TLG.fst` is given.
* `words.txt`: optional, word level symbol table for decoding with `TLG.fst`

Please refer https://github.com/wenet-e2e/wenet/blob/main/docs/pretrained_models.md for the details of `Runtime Model`.

* `nbest` (int): Output the top-n best result.
* `enable_timestamp` (bool): Whether to enable the word level timestamp.
* `context` (List[str]): a list of context biasing words.
* `context_score` (float): context bonus score.
* `continuous_decoding` (bool): Whether to enable continuous(long) decoding.

For example:
``` python
decoder = wenet.Decoder(model_dir,
lang='chs',
nbest=5,
enable_timestamp=True,
context=['不忘初心', '牢记使命'],
context_score=3.0)
```

### Streaming Usage

``` python
import sys
import wave
import wenetruntime as wenet

test_wav = sys.argv[1]

with wave.open(test_wav, 'rb') as fin:
assert fin.getnchannels() == 1
wav = fin.readframes(fin.getnframes())

decoder = wenet.Decoder(lang='chs', streaming=True)
# We suppose the wav is 16k, 16bits, and decode every 0.5 seconds
interval = int(0.5 * 16000) * 2
for i in range(0, len(wav), interval):
last = False if i + interval < len(wav) else True
chunk_wav = wav[i: min(i + interval, len(wav))]
ans = decoder.decode(chunk_wav, last)
print(ans)
```

You can use the same parameters as we introduced above to control the behavior of `wenet.Decoder`


## Build on Your Local Machine

``` sh
git clone https://github.com/wenet-e2e/wenet.git
cd wenet/runtime/binding/python
python setup.py install
```

1 change: 1 addition & 0 deletions runtime/binding/python/api
1 change: 1 addition & 0 deletions runtime/binding/python/cmake
40 changes: 40 additions & 0 deletions runtime/binding/python/cpp/binding.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2022 Binbin Zhang([email protected])
//
// 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.

#include <pybind11/pybind11.h>

#include "api/wenet_api.h"

namespace py = pybind11;

PYBIND11_MODULE(_wenet, m) {
m.doc() = "wenet pybind11 plugin"; // optional module docstring
m.def("wenet_init", &wenet_init, py::return_value_policy::reference,
"wenet init");
m.def("wenet_free", &wenet_free, "wenet free");
m.def("wenet_reset", &wenet_reset, "wenet reset");
m.def("wenet_decode", &wenet_decode, py::return_value_policy::copy,
"wenet decode");
m.def("wenet_set_log_level", &wenet_set_log_level, "set log level");
m.def("wenet_set_nbest", &wenet_set_nbest, "set nbest");
m.def("wenet_set_timestamp", &wenet_set_timestamp, "set timestamp flag");
m.def("wenet_add_context", &wenet_add_context, "add one context word");
m.def("wenet_set_context_score", &wenet_set_context_score,
"set context bonus score");
m.def("wenet_set_language", &wenet_set_language, "set language");
m.def("wenet_set_continuous_decoding", &wenet_set_continuous_decoding,
"enable continuous decoding or not");
m.def("wenet_set_chunk_size", &wenet_set_chunk_size,
"set decoding chunk size");
}
1 change: 1 addition & 0 deletions runtime/binding/python/decoder
1 change: 1 addition & 0 deletions runtime/binding/python/frontend
1 change: 1 addition & 0 deletions runtime/binding/python/kaldi
1 change: 1 addition & 0 deletions runtime/binding/python/patch
1 change: 1 addition & 0 deletions runtime/binding/python/post_processor
92 changes: 92 additions & 0 deletions runtime/binding/python/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/usr/bin/env python3
# Copyright (c) 2020 Xiaomi Corporation (author: Fangjun Kuang)
# 2022 Binbin Zhang([email protected])

import glob
import os
import shutil
import sys

import setuptools
from setuptools.command.build_ext import build_ext


def cmake_extension(name, *args, **kwargs) -> setuptools.Extension:
kwargs["language"] = "c++"
sources = []
return setuptools.Extension(name, sources, *args, **kwargs)


class BuildExtension(build_ext):

def build_extension(self, ext: setuptools.extension.Extension):
os.makedirs(self.build_temp, exist_ok=True)
os.makedirs(self.build_lib, exist_ok=True)

cmake_args = os.environ.get("WENET_CMAKE_ARGS",
"-DCMAKE_BUILD_TYPE=Release")
if "PYTHON_EXECUTABLE" not in cmake_args:
print(f"Setting PYTHON_EXECUTABLE to {sys.executable}")
cmake_args += f" -DPYTHON_EXECUTABLE={sys.executable}"

src_dir = os.path.dirname(os.path.abspath(__file__))
os.system(f"cmake {cmake_args} -B {self.build_temp} -S {src_dir}")
ret = os.system(f"""
cmake --build {self.build_temp} --target _wenet --config Release
""")
if ret != 0:
raise Exception(
"\nBuild wenet failed. Please check the error message.\n"
"You can ask for help by creating an issue on GitHub.\n"
"\nClick:\n https://github.com/wenet-e2e/wenet/issues/new\n"
)

libs = []
for ext in ['so', 'pyd']:
libs.extend(
glob.glob(f"{self.build_temp}/**/_wenet*.{ext}",
recursive=True))
for ext in ['so', 'dylib', 'dll']:
libs.extend(
glob.glob(f"{self.build_temp}/**/*wenet_api.{ext}",
recursive=True))

for lib in libs:
print(f"Copying {lib} to {self.build_lib}/")
shutil.copy(f"{lib}", f"{self.build_lib}/")


def read_long_description():
with open("README.md", encoding="utf8") as f:
readme = f.read()
return readme


setuptools.setup(
name="wenetruntime",
version='1.14.0',
author="Binbin Zhang",
author_email="[email protected]",
packages=setuptools.find_packages(),
url="https://github.com/wenet-e2e/wenet",
long_description=read_long_description(),
long_description_content_type="text/markdown",
ext_modules=[cmake_extension("_wenet")],
cmdclass={"build_ext": BuildExtension},
zip_safe=False,
setup_requires=["tqdm"],
install_requires=["torch>=1.10.0", "librosa", "tqdm"] if "ONNX=ON"
not in os.environ.get("WENET_CMAKE_ARGS", "") else ["librosa", "tqdm"],
entry_points={
"console_scripts": [
"wenetruntime = wenetruntime.main:main",
]
},
classifiers=[
"Programming Language :: C++",
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
],
license="Apache licensed, as found in the LICENSE file",
)
1 change: 1 addition & 0 deletions runtime/binding/python/utils
2 changes: 2 additions & 0 deletions runtime/binding/python/wenetruntime/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .decoder import Decoder # noqa
from _wenet import wenet_set_log_level as set_log_level # noqa
4 changes: 4 additions & 0 deletions runtime/binding/python/wenetruntime/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from wenetruntime.main import main

if __name__ == "__main__":
main()
Loading

0 comments on commit e3ad39b

Please sign in to comment.