Skip to content

Commit 009ed2c

Browse files
authored
add WebAssembly for Kws (#648)
1 parent a628002 commit 009ed2c

14 files changed

+807
-8
lines changed

CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ option(SHERPA_ONNX_ENABLE_GPU "Enable ONNX Runtime GPU support" OFF)
2323
option(SHERPA_ONNX_ENABLE_WASM "Whether to enable WASM" OFF)
2424
option(SHERPA_ONNX_ENABLE_WASM_TTS "Whether to enable WASM for TTS" OFF)
2525
option(SHERPA_ONNX_ENABLE_WASM_ASR "Whether to enable WASM for ASR" OFF)
26+
option(SHERPA_ONNX_ENABLE_WASM_KWS "Whether to enable WASM for KWS" OFF)
2627
option(SHERPA_ONNX_ENABLE_WASM_NODEJS "Whether to enable WASM for NodeJS" OFF)
2728
option(SHERPA_ONNX_ENABLE_BINARY "Whether to build binaries" ON)
2829
option(SHERPA_ONNX_LINK_LIBSTDCPP_STATICALLY "True to link libstdc++ statically. Used only when BUILD_SHARED_LIBS is OFF on Linux" ON)
@@ -135,6 +136,10 @@ if(SHERPA_ONNX_ENABLE_WASM)
135136
add_definitions(-DSHERPA_ONNX_ENABLE_WASM=1)
136137
endif()
137138

139+
if(SHERPA_ONNX_ENABLE_WASM_KWS)
140+
add_definitions(-DSHERPA_ONNX_ENABLE_WASM_KWS=1)
141+
endif()
142+
138143
if(NOT CMAKE_CXX_STANDARD)
139144
set(CMAKE_CXX_STANDARD 14 CACHE STRING "The C++ version to be used.")
140145
endif()

build-wasm-simd-kws.sh

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env bash
2+
3+
if [ x"$EMSCRIPTEN" == x"" ]; then
4+
if ! command -v emcc &> /dev/null; then
5+
echo "Please install emscripten first"
6+
echo ""
7+
echo "You can use the following commands to install it:"
8+
echo ""
9+
echo "git clone https://github.com/emscripten-core/emsdk.git"
10+
echo "cd emsdk"
11+
echo "git pull"
12+
echo "./emsdk install latest"
13+
echo "./emsdk activate latest"
14+
echo "source ./emsdk_env.sh"
15+
exit 1
16+
else
17+
EMSCRIPTEN=$(dirname $(realpath $(which emcc)))
18+
fi
19+
fi
20+
21+
export EMSCRIPTEN=$EMSCRIPTEN
22+
echo "EMSCRIPTEN: $EMSCRIPTEN"
23+
if [ ! -f $EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake ]; then
24+
echo "Cannot find $EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake"
25+
echo "Please make sure you have installed emsdk correctly"
26+
exit 1
27+
fi
28+
29+
mkdir -p build-wasm-simd-kws
30+
pushd build-wasm-simd-kws
31+
32+
export SHERPA_ONNX_IS_USING_BUILD_WASM_SH=ON
33+
34+
cmake \
35+
-DCMAKE_INSTALL_PREFIX=./install \
36+
-DCMAKE_BUILD_TYPE=Release \
37+
-DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake \
38+
\
39+
-DSHERPA_ONNX_ENABLE_PYTHON=OFF \
40+
-DSHERPA_ONNX_ENABLE_TESTS=OFF \
41+
-DSHERPA_ONNX_ENABLE_CHECK=OFF \
42+
-DBUILD_SHARED_LIBS=OFF \
43+
-DSHERPA_ONNX_ENABLE_PORTAUDIO=OFF \
44+
-DSHERPA_ONNX_ENABLE_JNI=OFF \
45+
-DSHERPA_ONNX_ENABLE_C_API=ON \
46+
-DSHERPA_ONNX_ENABLE_WEBSOCKET=OFF \
47+
-DSHERPA_ONNX_ENABLE_GPU=OFF \
48+
-DSHERPA_ONNX_ENABLE_WASM=ON \
49+
-DSHERPA_ONNX_ENABLE_WASM_KWS=ON \
50+
-DSHERPA_ONNX_ENABLE_BINARY=OFF \
51+
-DSHERPA_ONNX_LINK_LIBSTDCPP_STATICALLY=OFF \
52+
..
53+
make -j8
54+
make install
55+
56+
ls -lh install/bin/wasm

sherpa-onnx/c-api/c-api.cc

+3-4
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ SherpaOnnxKeywordSpotter* CreateKeywordSpotter(
481481
SherpaOnnxKeywordSpotter* spotter = new SherpaOnnxKeywordSpotter;
482482

483483
spotter->impl =
484-
std::make_unique<sherpa_onnx::KeywordSpotter>(spotter_config);
484+
std::make_unique<sherpa_onnx::KeywordSpotter>(spotter_config);
485485

486486
return spotter;
487487
}
@@ -493,7 +493,7 @@ void DestroyKeywordSpotter(SherpaOnnxKeywordSpotter* spotter) {
493493
SherpaOnnxOnlineStream* CreateKeywordStream(
494494
const SherpaOnnxKeywordSpotter* spotter) {
495495
SherpaOnnxOnlineStream* stream =
496-
new SherpaOnnxOnlineStream(spotter->impl->CreateStream());
496+
new SherpaOnnxOnlineStream(spotter->impl->CreateStream());
497497
return stream;
498498
}
499499

@@ -512,7 +512,7 @@ void DecodeMultipleKeywordStreams(
512512
int32_t n) {
513513
std::vector<sherpa_onnx::OnlineStream*> ss(n);
514514
for (int32_t i = 0; i != n; ++i) {
515-
ss[i] = streams[i]->impl.get();
515+
ss[i] = streams[i]->impl.get();
516516
}
517517
spotter->impl->DecodeStreams(ss.data(), n);
518518
}
@@ -593,7 +593,6 @@ void DestroyKeywordResult(const SherpaOnnxKeywordResult *r) {
593593
}
594594
}
595595

596-
597596
// ============================================================
598597
// For VAD
599598
// ============================================================

sherpa-onnx/csrc/keyword-spotter-transducer-impl.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -266,15 +266,22 @@ class KeywordSpotterTransducerImpl : public KeywordSpotterImpl {
266266
}
267267

268268
void InitKeywords() {
269+
#ifdef SHERPA_ONNX_ENABLE_WASM_KWS
270+
// Due to the limitations of the wasm file system,
271+
// the keyword_file variable is directly parsed as a string of keywords
272+
// if WASM KWS on
273+
std::istringstream is(config_.keywords_file);
274+
InitKeywords(is);
275+
#else
269276
// each line in keywords_file contains space-separated words
270-
271277
std::ifstream is(config_.keywords_file);
272278
if (!is) {
273279
SHERPA_ONNX_LOGE("Open keywords file failed: %s",
274280
config_.keywords_file.c_str());
275281
exit(-1);
276282
}
277283
InitKeywords(is);
284+
#endif
278285
}
279286

280287
#if __ANDROID_API__ >= 9

sherpa-onnx/csrc/keyword-spotter.cc

+7
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,17 @@ bool KeywordSpotterConfig::Validate() const {
9494
SHERPA_ONNX_LOGE("Please provide --keywords-file.");
9595
return false;
9696
}
97+
98+
#ifndef SHERPA_ONNX_ENABLE_WASM_KWS
99+
// due to the limitations of the wasm file system,
100+
// keywords file will be packaged into the sherpa-onnx-wasm-kws-main.data file
101+
// Solution: take keyword_file variable is directly
102+
// parsed as a string of keywords
97103
if (!std::ifstream(keywords_file.c_str()).good()) {
98104
SHERPA_ONNX_LOGE("Keywords file %s does not exist.", keywords_file.c_str());
99105
return false;
100106
}
107+
#endif
101108

102109
return model_config.Validate();
103110
}

sherpa-onnx/csrc/transducer-keyword-decoder.cc

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,14 @@
22
//
33
// Copyright (c) 2023-2024 Xiaomi Corporation
44

5-
#include "sherpa-onnx/csrc/transducer-keyword-decoder.h"
6-
75
#include <algorithm>
86
#include <cmath>
9-
#include <cstring>
107
#include <utility>
118
#include <vector>
129

1310
#include "sherpa-onnx/csrc/log.h"
1411
#include "sherpa-onnx/csrc/onnx-utils.h"
12+
#include "sherpa-onnx/csrc/transducer-keyword-decoder.h"
1513

1614
namespace sherpa_onnx {
1715

wasm/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ if(SHERPA_ONNX_ENABLE_WASM_ASR)
66
add_subdirectory(asr)
77
endif()
88

9+
if(SHERPA_ONNX_ENABLE_WASM_KWS)
10+
add_subdirectory(kws)
11+
endif()
12+
913
if(SHERPA_ONNX_ENABLE_WASM_NODEJS)
1014
add_subdirectory(nodejs)
1115
endif()

wasm/kws/CMakeLists.txt

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
if(NOT $ENV{SHERPA_ONNX_IS_USING_BUILD_WASM_SH})
2+
message(FATAL_ERROR "Please use ./build-wasm-simd-kws.sh to build for wasm KWS")
3+
endif()
4+
5+
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/assets/decoder-epoch-12-avg-2-chunk-16-left-64.onnx")
6+
message(WARNING "${CMAKE_CURRENT_SOURCE_DIR}/assets/decoder-epoch-12-avg-2-chunk-16-left-64.onnx does not exist")
7+
message(FATAL_ERROR "Please read ${CMAKE_CURRENT_SOURCE_DIR}/assets/README.md before you continue")
8+
endif()
9+
10+
set(exported_functions
11+
AcceptWaveform
12+
CreateKeywordSpotter
13+
DestroyKeywordSpotter
14+
CreateKeywordStream
15+
DecodeKeywordStream
16+
GetKeywordResult
17+
DestroyKeywordResult
18+
IsKeywordStreamReady
19+
InputFinished
20+
)
21+
set(mangled_exported_functions)
22+
foreach(x IN LISTS exported_functions)
23+
list(APPEND mangled_exported_functions "_${x}")
24+
endforeach()
25+
26+
list(JOIN mangled_exported_functions "," all_exported_functions)
27+
28+
include_directories(${CMAKE_SOURCE_DIR})
29+
set(MY_FLAGS "-s FORCE_FILESYSTEM=1 -s INITIAL_MEMORY=512MB -s ALLOW_MEMORY_GROWTH=1")
30+
string(APPEND MY_FLAGS " -sSTACK_SIZE=10485760 ")
31+
string(APPEND MY_FLAGS " -sEXPORTED_FUNCTIONS=[_CopyHeap,_malloc,_free,${all_exported_functions}] ")
32+
string(APPEND MY_FLAGS "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/assets@. ")
33+
string(APPEND MY_FLAGS " -sEXPORTED_RUNTIME_METHODS=['ccall','stringToUTF8','setValue','getValue','lengthBytesUTF8','UTF8ToString'] ")
34+
message(STATUS "MY_FLAGS: ${MY_FLAGS}")
35+
36+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MY_FLAGS}")
37+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MY_FLAGS}")
38+
set(CMAKE_EXECUTBLE_LINKER_FLAGS "${CMAKE_EXECUTBLE_LINKER_FLAGS} ${MY_FLAGS}")
39+
40+
add_executable(sherpa-onnx-wasm-kws-main sherpa-onnx-wasm-main-kws.cc)
41+
target_link_libraries(sherpa-onnx-wasm-kws-main sherpa-onnx-c-api)
42+
install(TARGETS sherpa-onnx-wasm-kws-main DESTINATION bin/wasm)
43+
44+
install(
45+
FILES
46+
"sherpa-onnx-kws.js"
47+
"app.js"
48+
"index.html"
49+
"$<TARGET_FILE_DIR:sherpa-onnx-wasm-kws-main>/sherpa-onnx-wasm-kws-main.js"
50+
"$<TARGET_FILE_DIR:sherpa-onnx-wasm-kws-main>/sherpa-onnx-wasm-kws-main.wasm"
51+
"$<TARGET_FILE_DIR:sherpa-onnx-wasm-kws-main>/sherpa-onnx-wasm-kws-main.data"
52+
DESTINATION
53+
bin/wasm
54+
)

0 commit comments

Comments
 (0)