ductranminh
Committed by GitHub

Add context biasing for mobile (#568)

@@ -85,7 +85,7 @@ class SherpaOnnx( @@ -85,7 +85,7 @@ class SherpaOnnx(
85 acceptWaveform(ptr, samples, sampleRate) 85 acceptWaveform(ptr, samples, sampleRate)
86 86
87 fun inputFinished() = inputFinished(ptr) 87 fun inputFinished() = inputFinished(ptr)
88 - fun reset(recreate: Boolean = false) = reset(ptr, recreate = recreate) 88 + fun reset(recreate: Boolean = false, hotwords: String = "") = reset(ptr, recreate, hotwords)
89 fun decode() = decode(ptr) 89 fun decode() = decode(ptr)
90 fun isEndpoint(): Boolean = isEndpoint(ptr) 90 fun isEndpoint(): Boolean = isEndpoint(ptr)
91 fun isReady(): Boolean = isReady(ptr) 91 fun isReady(): Boolean = isReady(ptr)
@@ -93,6 +93,9 @@ class SherpaOnnx( @@ -93,6 +93,9 @@ class SherpaOnnx(
93 val text: String 93 val text: String
94 get() = getText(ptr) 94 get() = getText(ptr)
95 95
  96 + val tokens: Array<String>
  97 + get() = getTokens(ptr)
  98 +
96 private external fun delete(ptr: Long) 99 private external fun delete(ptr: Long)
97 100
98 private external fun new( 101 private external fun new(
@@ -107,10 +110,11 @@ class SherpaOnnx( @@ -107,10 +110,11 @@ class SherpaOnnx(
107 private external fun acceptWaveform(ptr: Long, samples: FloatArray, sampleRate: Int) 110 private external fun acceptWaveform(ptr: Long, samples: FloatArray, sampleRate: Int)
108 private external fun inputFinished(ptr: Long) 111 private external fun inputFinished(ptr: Long)
109 private external fun getText(ptr: Long): String 112 private external fun getText(ptr: Long): String
110 - private external fun reset(ptr: Long, recreate: Boolean) 113 + private external fun reset(ptr: Long, recreate: Boolean, hotwords: String)
111 private external fun decode(ptr: Long) 114 private external fun decode(ptr: Long)
112 private external fun isEndpoint(ptr: Long): Boolean 115 private external fun isEndpoint(ptr: Long): Boolean
113 private external fun isReady(ptr: Long): Boolean 116 private external fun isReady(ptr: Long): Boolean
  117 + private external fun getTokens(ptr: Long): Array<String>
114 118
115 companion object { 119 companion object {
116 init { 120 init {
@@ -120,7 +120,7 @@ class SherpaOnnx( @@ -120,7 +120,7 @@ class SherpaOnnx(
120 acceptWaveform(ptr, samples, sampleRate) 120 acceptWaveform(ptr, samples, sampleRate)
121 121
122 fun inputFinished() = inputFinished(ptr) 122 fun inputFinished() = inputFinished(ptr)
123 - fun reset(recreate: Boolean = false) = reset(ptr, recreate = recreate) 123 + fun reset(recreate: Boolean = false, hotwords: String = "") = reset(ptr, recreate, hotwords)
124 fun decode() = decode(ptr) 124 fun decode() = decode(ptr)
125 fun isEndpoint(): Boolean = isEndpoint(ptr) 125 fun isEndpoint(): Boolean = isEndpoint(ptr)
126 fun isReady(): Boolean = isReady(ptr) 126 fun isReady(): Boolean = isReady(ptr)
@@ -128,6 +128,9 @@ class SherpaOnnx( @@ -128,6 +128,9 @@ class SherpaOnnx(
128 val text: String 128 val text: String
129 get() = getText(ptr) 129 get() = getText(ptr)
130 130
  131 + val tokens: Array<String>
  132 + get() = getTokens(ptr)
  133 +
131 private external fun delete(ptr: Long) 134 private external fun delete(ptr: Long)
132 135
133 private external fun new( 136 private external fun new(
@@ -142,10 +145,11 @@ class SherpaOnnx( @@ -142,10 +145,11 @@ class SherpaOnnx(
142 private external fun acceptWaveform(ptr: Long, samples: FloatArray, sampleRate: Int) 145 private external fun acceptWaveform(ptr: Long, samples: FloatArray, sampleRate: Int)
143 private external fun inputFinished(ptr: Long) 146 private external fun inputFinished(ptr: Long)
144 private external fun getText(ptr: Long): String 147 private external fun getText(ptr: Long): String
145 - private external fun reset(ptr: Long, recreate: Boolean) 148 + private external fun reset(ptr: Long, recreate: Boolean, hotwords: String)
146 private external fun decode(ptr: Long) 149 private external fun decode(ptr: Long)
147 private external fun isEndpoint(ptr: Long): Boolean 150 private external fun isEndpoint(ptr: Long): Boolean
148 private external fun isReady(ptr: Long): Boolean 151 private external fun isReady(ptr: Long): Boolean
  152 + private external fun getTokens(ptr: Long): Array<String>
149 153
150 companion object { 154 companion object {
151 init { 155 init {
@@ -76,11 +76,24 @@ class SherpaOnnx { @@ -76,11 +76,24 @@ class SherpaOnnx {
76 76
77 bool IsReady() const { return recognizer_.IsReady(stream_.get()); } 77 bool IsReady() const { return recognizer_.IsReady(stream_.get()); }
78 78
79 - void Reset(bool recreate) {  
80 - if (recreate) {  
81 - stream_ = recognizer_.CreateStream(); 79 + // If keywords is an empty string, it just recreates the decoding stream
  80 + // If keywords is not empty, it will create a new decoding stream with
  81 + // the given keywords appended to the default keywords.
  82 + void Reset(bool recreate, const std::string &keywords = {}) {
  83 + if (keywords.empty()) {
  84 + if (recreate) {
  85 + stream_ = recognizer_.CreateStream();
  86 + } else {
  87 + recognizer_.Reset(stream_.get());
  88 + }
82 } else { 89 } else {
83 - recognizer_.Reset(stream_.get()); 90 + auto stream = recognizer_.CreateStream(keywords);
  91 + // Set new keywords failed, the stream_ will not be updated.
  92 + if (stream != nullptr) {
  93 + stream_ = std::move(stream);
  94 + } else {
  95 + SHERPA_ONNX_LOGE("Failed to set keywords: %s", keywords.c_str());
  96 + }
84 } 97 }
85 } 98 }
86 99
@@ -1509,9 +1522,12 @@ JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_SherpaOnnxOffline_delete( @@ -1509,9 +1522,12 @@ JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_SherpaOnnxOffline_delete(
1509 1522
1510 SHERPA_ONNX_EXTERN_C 1523 SHERPA_ONNX_EXTERN_C
1511 JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_SherpaOnnx_reset( 1524 JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_SherpaOnnx_reset(
1512 - JNIEnv *env, jobject /*obj*/, jlong ptr, jboolean recreate) { 1525 + JNIEnv *env, jobject /*obj*/,
  1526 + jlong ptr, jboolean recreate, jstring keywords) {
1513 auto model = reinterpret_cast<sherpa_onnx::SherpaOnnx *>(ptr); 1527 auto model = reinterpret_cast<sherpa_onnx::SherpaOnnx *>(ptr);
1514 - model->Reset(recreate); 1528 + const char *p_keywords = env->GetStringUTFChars(keywords, nullptr);
  1529 + model->Reset(recreate, p_keywords);
  1530 + env->ReleaseStringUTFChars(keywords, p_keywords);
1515 } 1531 }
1516 1532
1517 SHERPA_ONNX_EXTERN_C 1533 SHERPA_ONNX_EXTERN_C
@@ -188,7 +188,7 @@ class SherpaOnnxOnlineRecongitionResult { @@ -188,7 +188,7 @@ class SherpaOnnxOnlineRecongitionResult {
188 class SherpaOnnxRecognizer { 188 class SherpaOnnxRecognizer {
189 /// A pointer to the underlying counterpart in C 189 /// A pointer to the underlying counterpart in C
190 let recognizer: OpaquePointer! 190 let recognizer: OpaquePointer!
191 - let stream: OpaquePointer! 191 + var stream: OpaquePointer!
192 192
193 /// Constructor taking a model config 193 /// Constructor taking a model config
194 init( 194 init(
@@ -237,8 +237,23 @@ class SherpaOnnxRecognizer { @@ -237,8 +237,23 @@ class SherpaOnnxRecognizer {
237 237
238 /// Reset the recognizer, which clears the neural network model state 238 /// Reset the recognizer, which clears the neural network model state
239 /// and the state for decoding. 239 /// and the state for decoding.
240 - func reset() {  
241 - Reset(recognizer, stream) 240 + /// If hotwords is an empty string, it just recreates the decoding stream
  241 + /// If hotwords is not empty, it will create a new decoding stream with
  242 + /// the given hotWords appended to the default hotwords.
  243 + func reset(hotwords: String? = nil) {
  244 + guard let words = hotwords, !words.isEmpty else {
  245 + Reset(recognizer, stream)
  246 + return
  247 + }
  248 +
  249 + words.withCString { cString in
  250 + let newStream = CreateOnlineStreamWithHotwords(recognizer, cString)
  251 + // lock while release and replace stream
  252 + objc_sync_enter(self)
  253 + DestroyOnlineStream(stream)
  254 + stream = newStream
  255 + objc_sync_exit(self)
  256 + }
242 } 257 }
243 258
244 /// Signal that no more audio samples would be available. 259 /// Signal that no more audio samples would be available.