Update README.md
Browse files- .gitattributes +5 -0
- README.md +1 -1
- asr_server.py +21 -4
- models/SenseVoiceSmall/lib/cargs.h +162 -0
- models/SenseVoiceSmall/lib/libcargs.so +0 -0
- models/SenseVoiceSmall/lib/libonnxruntime.so +3 -0
- models/SenseVoiceSmall/lib/libonnxruntime.so.1 +3 -0
- models/SenseVoiceSmall/lib/libonnxruntime.so.1.23.2 +3 -0
- models/SenseVoiceSmall/lib/libsherpa-onnx-c-api.so +3 -0
- models/SenseVoiceSmall/lib/libsherpa-onnx-cxx-api.so +3 -0
- models/SenseVoiceSmall/lib/pkgconfig/espeak-ng.pc +11 -0
- stageflow/core/gateway.py +1 -1
- stageflow/units/speech_recognition.py +6 -4
.gitattributes
CHANGED
|
@@ -37,6 +37,11 @@ axllm filter=lfs diff=lfs merge=lfs -text
|
|
| 37 |
models/SenseVoiceSmall/ax650/model-10-seconds.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 38 |
models/SenseVoiceSmall/ax650/model-5-seconds.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 39 |
models/SenseVoiceSmall/bin/sherpa-onnx-offline filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
models/Vad/ax_model/vad.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 41 |
models/Vad/wav/vad_example.wav filter=lfs diff=lfs merge=lfs -text
|
| 42 |
models/melotts/decoder-zh.axmodel filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 37 |
models/SenseVoiceSmall/ax650/model-10-seconds.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 38 |
models/SenseVoiceSmall/ax650/model-5-seconds.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 39 |
models/SenseVoiceSmall/bin/sherpa-onnx-offline filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
models/SenseVoiceSmall/lib/libonnxruntime.so filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
models/SenseVoiceSmall/lib/libonnxruntime.so.1 filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
models/SenseVoiceSmall/lib/libonnxruntime.so.1.23.2 filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
models/SenseVoiceSmall/lib/libsherpa-onnx-c-api.so filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
models/SenseVoiceSmall/lib/libsherpa-onnx-cxx-api.so filter=lfs diff=lfs merge=lfs -text
|
| 45 |
models/Vad/ax_model/vad.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 46 |
models/Vad/wav/vad_example.wav filter=lfs diff=lfs merge=lfs -text
|
| 47 |
models/melotts/decoder-zh.axmodel filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
# Voice_Assistant.AXERA
|
| 2 |
|
| 3 |
-
ax650板端实时语音对话助手demo
|
| 4 |
|
| 5 |
## 特征
|
| 6 |
|
|
|
|
| 1 |
# Voice_Assistant.AXERA
|
| 2 |
|
| 3 |
+
ax650板端实时语音对话助手demo
|
| 4 |
|
| 5 |
## 特征
|
| 6 |
|
asr_server.py
CHANGED
|
@@ -43,10 +43,12 @@ _MIN_DURATION_MS = 500
|
|
| 43 |
|
| 44 |
|
| 45 |
def _model_for_duration(duration_seconds: float) -> Path:
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
|
|
|
|
|
|
| 50 |
|
| 51 |
|
| 52 |
@app.get("/health")
|
|
@@ -138,6 +140,21 @@ def main():
|
|
| 138 |
|
| 139 |
logger.info("ASR server ready (model_root=%s, provider=%s)", _MODEL_ROOT, _PROVIDER)
|
| 140 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
import uvicorn
|
| 142 |
uvicorn.run(app, host=args.host, port=args.port)
|
| 143 |
|
|
|
|
| 43 |
|
| 44 |
|
| 45 |
def _model_for_duration(duration_seconds: float) -> Path:
|
| 46 |
+
for seconds in (5, 10, 15, 20, 25, 30):
|
| 47 |
+
if duration_seconds <= seconds:
|
| 48 |
+
model = _MODEL_ROOT / "ax650" / f"model-{seconds}-seconds.axmodel"
|
| 49 |
+
if model.exists():
|
| 50 |
+
return model
|
| 51 |
+
return _MODEL_ROOT / "ax650" / "model-10-seconds.axmodel"
|
| 52 |
|
| 53 |
|
| 54 |
@app.get("/health")
|
|
|
|
| 140 |
|
| 141 |
logger.info("ASR server ready (model_root=%s, provider=%s)", _MODEL_ROOT, _PROVIDER)
|
| 142 |
|
| 143 |
+
# warm up: pre-load the model so the first real request is fast
|
| 144 |
+
_warmup_path = os.path.join(tempfile.gettempdir(), "_asr_warmup.wav")
|
| 145 |
+
try:
|
| 146 |
+
_warmup_audio = np.zeros(int(_SAMPLE_RATE * 0.5), dtype=np.float32) # 0.5s silence
|
| 147 |
+
sf.write(_warmup_path, _warmup_audio, _SAMPLE_RATE)
|
| 148 |
+
model_file = _MODEL_ROOT / "ax650" / "model-5-seconds.axmodel"
|
| 149 |
+
if model_file.exists():
|
| 150 |
+
cmd = [str(_SHERPA_BIN), f"--sense-voice-model={model_file}", f"--tokens={_TOKENS_FILE}", f"--provider={_PROVIDER}", _warmup_path]
|
| 151 |
+
t0 = time.time()
|
| 152 |
+
subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
| 153 |
+
logger.info("ASR warmup complete (%.1fs)", time.time() - t0)
|
| 154 |
+
os.remove(_warmup_path)
|
| 155 |
+
except Exception as e:
|
| 156 |
+
logger.warning("ASR warmup failed (non-fatal): %s", e)
|
| 157 |
+
|
| 158 |
import uvicorn
|
| 159 |
uvicorn.run(app, host=args.host, port=args.port)
|
| 160 |
|
models/SenseVoiceSmall/lib/cargs.h
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
/**
|
| 4 |
+
* This is a simple alternative cross-platform implementation of getopt, which
|
| 5 |
+
* is used to parse argument strings submitted to the executable (argc and argv
|
| 6 |
+
* which are received in the main function).
|
| 7 |
+
*/
|
| 8 |
+
|
| 9 |
+
#ifndef CAG_LIBRARY_H
|
| 10 |
+
#define CAG_LIBRARY_H
|
| 11 |
+
|
| 12 |
+
#include <stdbool.h>
|
| 13 |
+
#include <stddef.h>
|
| 14 |
+
#include <stdio.h>
|
| 15 |
+
|
| 16 |
+
#if defined(_WIN32) || defined(__CYGWIN__)
|
| 17 |
+
#define CAG_EXPORT __declspec(dllexport)
|
| 18 |
+
#define CAG_IMPORT __declspec(dllimport)
|
| 19 |
+
#elif __GNUC__ >= 4
|
| 20 |
+
#define CAG_EXPORT __attribute__((visibility("default")))
|
| 21 |
+
#define CAG_IMPORT __attribute__((visibility("default")))
|
| 22 |
+
#else
|
| 23 |
+
#define CAG_EXPORT
|
| 24 |
+
#define CAG_IMPORT
|
| 25 |
+
#endif
|
| 26 |
+
|
| 27 |
+
#if defined(CAG_SHARED)
|
| 28 |
+
#if defined(CAG_EXPORTS)
|
| 29 |
+
#define CAG_PUBLIC CAG_EXPORT
|
| 30 |
+
#else
|
| 31 |
+
#define CAG_PUBLIC CAG_IMPORT
|
| 32 |
+
#endif
|
| 33 |
+
#else
|
| 34 |
+
#define CAG_PUBLIC
|
| 35 |
+
#endif
|
| 36 |
+
|
| 37 |
+
#ifdef __cplusplus
|
| 38 |
+
extern "C" {
|
| 39 |
+
#endif
|
| 40 |
+
|
| 41 |
+
/**
|
| 42 |
+
* An option is used to describe a flag/argument option submitted when the
|
| 43 |
+
* program is run.
|
| 44 |
+
*/
|
| 45 |
+
typedef struct cag_option
|
| 46 |
+
{
|
| 47 |
+
const char identifier;
|
| 48 |
+
const char *access_letters;
|
| 49 |
+
const char *access_name;
|
| 50 |
+
const char *value_name;
|
| 51 |
+
const char *description;
|
| 52 |
+
} cag_option;
|
| 53 |
+
|
| 54 |
+
/**
|
| 55 |
+
* A context is used to iterate over all options provided. It stores the parsing
|
| 56 |
+
* state.
|
| 57 |
+
*/
|
| 58 |
+
typedef struct cag_option_context
|
| 59 |
+
{
|
| 60 |
+
const struct cag_option *options;
|
| 61 |
+
size_t option_count;
|
| 62 |
+
int argc;
|
| 63 |
+
char **argv;
|
| 64 |
+
int index;
|
| 65 |
+
int inner_index;
|
| 66 |
+
bool forced_end;
|
| 67 |
+
char identifier;
|
| 68 |
+
char *value;
|
| 69 |
+
} cag_option_context;
|
| 70 |
+
|
| 71 |
+
/**
|
| 72 |
+
* This is just a small macro which calculates the size of an array.
|
| 73 |
+
*/
|
| 74 |
+
#define CAG_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
| 75 |
+
|
| 76 |
+
/**
|
| 77 |
+
* @brief Prints all options to the terminal.
|
| 78 |
+
*
|
| 79 |
+
* This function prints all options to the terminal. This can be used to
|
| 80 |
+
* generate the output for a "--help" option.
|
| 81 |
+
*
|
| 82 |
+
* @param options The options which will be printed.
|
| 83 |
+
* @param option_count The option count which will be printed.
|
| 84 |
+
* @param destination The destination where the output will be printed.
|
| 85 |
+
*/
|
| 86 |
+
CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count,
|
| 87 |
+
FILE *destination);
|
| 88 |
+
|
| 89 |
+
/**
|
| 90 |
+
* @brief Prepare argument options context for parsing.
|
| 91 |
+
*
|
| 92 |
+
* This function prepares the context for iteration and initializes the context
|
| 93 |
+
* with the supplied options and arguments. After the context has been prepared,
|
| 94 |
+
* it can be used to fetch arguments from it.
|
| 95 |
+
*
|
| 96 |
+
* @param context The context which will be initialized.
|
| 97 |
+
* @param options The registered options which are available for the program.
|
| 98 |
+
* @param option_count The amount of options which are available for the
|
| 99 |
+
* program.
|
| 100 |
+
* @param argc The amount of arguments the user supplied in the main function.
|
| 101 |
+
* @param argv A pointer to the arguments of the main function.
|
| 102 |
+
*/
|
| 103 |
+
CAG_PUBLIC void cag_option_prepare(cag_option_context *context,
|
| 104 |
+
const cag_option *options, size_t option_count, int argc, char **argv);
|
| 105 |
+
|
| 106 |
+
/**
|
| 107 |
+
* @brief Fetches an option from the argument list.
|
| 108 |
+
*
|
| 109 |
+
* This function fetches a single option from the argument list. The context
|
| 110 |
+
* will be moved to that item. Information can be extracted from the context
|
| 111 |
+
* after the item has been fetched.
|
| 112 |
+
* The arguments will be re-ordered, which means that non-option arguments will
|
| 113 |
+
* be moved to the end of the argument list. After all options have been
|
| 114 |
+
* fetched, all non-option arguments will be positioned after the index of
|
| 115 |
+
* the context.
|
| 116 |
+
*
|
| 117 |
+
* @param context The context from which we will fetch the option.
|
| 118 |
+
* @return Returns true if there was another option or false if the end is
|
| 119 |
+
* reached.
|
| 120 |
+
*/
|
| 121 |
+
CAG_PUBLIC bool cag_option_fetch(cag_option_context *context);
|
| 122 |
+
|
| 123 |
+
/**
|
| 124 |
+
* @brief Gets the identifier of the option.
|
| 125 |
+
*
|
| 126 |
+
* This function gets the identifier of the option, which should be unique to
|
| 127 |
+
* this option and can be used to determine what kind of option this is.
|
| 128 |
+
*
|
| 129 |
+
* @param context The context from which the option was fetched.
|
| 130 |
+
* @return Returns the identifier of the option.
|
| 131 |
+
*/
|
| 132 |
+
CAG_PUBLIC char cag_option_get(const cag_option_context *context);
|
| 133 |
+
|
| 134 |
+
/**
|
| 135 |
+
* @brief Gets the value from the option.
|
| 136 |
+
*
|
| 137 |
+
* This function gets the value from the option, if any. If the option does not
|
| 138 |
+
* contain a value, this function will return NULL.
|
| 139 |
+
*
|
| 140 |
+
* @param context The context from which the option was fetched.
|
| 141 |
+
* @return Returns a pointer to the value or NULL if there is no value.
|
| 142 |
+
*/
|
| 143 |
+
CAG_PUBLIC const char *cag_option_get_value(const cag_option_context *context);
|
| 144 |
+
|
| 145 |
+
/**
|
| 146 |
+
* @brief Gets the current index of the context.
|
| 147 |
+
*
|
| 148 |
+
* This function gets the index within the argv arguments of the context. The
|
| 149 |
+
* context always points to the next item which it will inspect. This is
|
| 150 |
+
* particularly useful to inspect the original argument array, or to get
|
| 151 |
+
* non-option arguments after option fetching has finished.
|
| 152 |
+
*
|
| 153 |
+
* @param context The context from which the option was fetched.
|
| 154 |
+
* @return Returns the current index of the context.
|
| 155 |
+
*/
|
| 156 |
+
CAG_PUBLIC int cag_option_get_index(const cag_option_context *context);
|
| 157 |
+
|
| 158 |
+
#ifdef __cplusplus
|
| 159 |
+
} // extern "C"
|
| 160 |
+
#endif
|
| 161 |
+
|
| 162 |
+
#endif
|
models/SenseVoiceSmall/lib/libcargs.so
ADDED
|
Binary file (14.2 kB). View file
|
|
|
models/SenseVoiceSmall/lib/libonnxruntime.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b14fe799d56bb20f9175d707bc322d1395a38526ff9d0edd7eca1b7ab89d45cd
|
| 3 |
+
size 18762289
|
models/SenseVoiceSmall/lib/libonnxruntime.so.1
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b14fe799d56bb20f9175d707bc322d1395a38526ff9d0edd7eca1b7ab89d45cd
|
| 3 |
+
size 18762289
|
models/SenseVoiceSmall/lib/libonnxruntime.so.1.23.2
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b14fe799d56bb20f9175d707bc322d1395a38526ff9d0edd7eca1b7ab89d45cd
|
| 3 |
+
size 18762289
|
models/SenseVoiceSmall/lib/libsherpa-onnx-c-api.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2e0462c4f8f9ca1448ab5fb3526bc35cf06476e6c3f1975ece641c5fb5408e8b
|
| 3 |
+
size 7078544
|
models/SenseVoiceSmall/lib/libsherpa-onnx-cxx-api.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:47ce147df2081e3336c48a55ab1c3c99089edd61ecfeca67fb4d6a520297b061
|
| 3 |
+
size 135192
|
models/SenseVoiceSmall/lib/pkgconfig/espeak-ng.pc
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
prefix=/home/m5stack/Workspace/kaldi/sherpa-onnx/build-axera-linux-aarch64-ax650/install
|
| 2 |
+
exec_prefix=/home/m5stack/Workspace/kaldi/sherpa-onnx/build-axera-linux-aarch64-ax650/install
|
| 3 |
+
libdir=${exec_prefix}/lib
|
| 4 |
+
includedir=${prefix}/include
|
| 5 |
+
|
| 6 |
+
Name: espeak-ng
|
| 7 |
+
Description: espeak-ng is a multi-lingual software speech synthesizer
|
| 8 |
+
Version: 1.52.0.1
|
| 9 |
+
Requires:
|
| 10 |
+
Libs: -L${libdir} -lespeak-ng
|
| 11 |
+
Cflags: -I${includedir}
|
stageflow/core/gateway.py
CHANGED
|
@@ -224,7 +224,7 @@ def create_app(config_path):
|
|
| 224 |
return [
|
| 225 |
"python3", "asr_server.py",
|
| 226 |
"--model-root", str(asset_root / "SenseVoiceSmall"),
|
| 227 |
-
"--sherpa-bin", str(asset_root / "
|
| 228 |
"--provider", cfg.get("provider", "axera"),
|
| 229 |
"--host", "0.0.0.0", "--port", "8010",
|
| 230 |
]
|
|
|
|
| 224 |
return [
|
| 225 |
"python3", "asr_server.py",
|
| 226 |
"--model-root", str(asset_root / "SenseVoiceSmall"),
|
| 227 |
+
"--sherpa-bin", str(asset_root / "SenseVoiceSmall" / "bin" / "sherpa-onnx-offline"),
|
| 228 |
"--provider", cfg.get("provider", "axera"),
|
| 229 |
"--host", "0.0.0.0", "--port", "8010",
|
| 230 |
]
|
stageflow/units/speech_recognition.py
CHANGED
|
@@ -66,10 +66,12 @@ class SherpaSenseVoiceASR(ASR):
|
|
| 66 |
self.sherpa_bin.chmod(0o755)
|
| 67 |
|
| 68 |
def _model_for_duration(self, duration_seconds):
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
|
|
|
|
|
|
| 73 |
|
| 74 |
@staticmethod
|
| 75 |
def _clean_text(text):
|
|
|
|
| 66 |
self.sherpa_bin.chmod(0o755)
|
| 67 |
|
| 68 |
def _model_for_duration(self, duration_seconds):
|
| 69 |
+
for seconds in (5, 10, 15, 20, 25, 30):
|
| 70 |
+
if duration_seconds <= seconds:
|
| 71 |
+
model = self.root / "ax650" / f"model-{seconds}-seconds.axmodel"
|
| 72 |
+
if model.exists():
|
| 73 |
+
return model
|
| 74 |
+
return self.root / "ax650" / "model-10-seconds.axmodel"
|
| 75 |
|
| 76 |
@staticmethod
|
| 77 |
def _clean_text(text):
|