77
88#include < ios>
99#include < memory>
10+ #include < regex> // NOLINT
1011#include < sstream>
1112#include < string>
1213#include < utility>
2122#include " sherpa-onnx/csrc/offline-recognizer-impl.h"
2223#include " sherpa-onnx/csrc/pad-sequence.h"
2324#include " sherpa-onnx/csrc/symbol-table.h"
25+ #include " sherpa-onnx/csrc/utils.h"
26+ #include " ssentencepiece/csrc/ssentencepiece.h"
2427
2528namespace sherpa_onnx {
2629
@@ -207,6 +210,15 @@ class OfflineRecognizerCtcImpl : public OfflineRecognizerImpl {
207210 if (config_.decoding_method == " greedy_search" ) {
208211 decoder_ = std::make_unique<OfflineCtcGreedySearchDecoder>(blank_id);
209212 } else {
213+ if (!config_.model_config .bpe_vocab .empty ()) {
214+ bpe_encoder_ = std::make_unique<ssentencepiece::Ssentencepiece>(
215+ config_.model_config .bpe_vocab );
216+ }
217+
218+ if (!config_.hotwords_file .empty ()) {
219+ InitHotwords ();
220+ }
221+
210222 decoder_ = std::make_unique<OfflineCtcPrefixBeamSearchDecoder>(
211223 config_.max_active_paths , blank_id);
212224 }
@@ -219,9 +231,47 @@ class OfflineRecognizerCtcImpl : public OfflineRecognizerImpl {
219231 }
220232 }
221233
234+ std::unique_ptr<OfflineStream> CreateStream (
235+ const std::string &hotwords) const override {
236+ auto hws = std::regex_replace (hotwords, std::regex (" /" ), " \n " );
237+ std::istringstream is (hws);
238+ std::vector<std::vector<int32_t >> current;
239+ std::vector<float > current_scores;
240+ if (!EncodeHotwords (is, config_.model_config .modeling_unit , symbol_table_,
241+ bpe_encoder_.get (), ¤t, ¤t_scores)) {
242+ SHERPA_ONNX_LOGE (" Encode hotwords failed, skipping, hotwords are : %s" ,
243+ hotwords.c_str ());
244+ }
245+
246+ int32_t num_default_hws = hotwords_.size ();
247+ int32_t num_hws = current.size ();
248+
249+ current.insert (current.end (), hotwords_.begin (), hotwords_.end ());
250+
251+ if (!current_scores.empty () && !boost_scores_.empty ()) {
252+ current_scores.insert (current_scores.end (), boost_scores_.begin (),
253+ boost_scores_.end ());
254+ } else if (!current_scores.empty () && boost_scores_.empty ()) {
255+ current_scores.insert (current_scores.end (), num_default_hws,
256+ config_.hotwords_score );
257+ } else if (current_scores.empty () && !boost_scores_.empty ()) {
258+ current_scores.insert (current_scores.end (), num_hws,
259+ config_.hotwords_score );
260+ current_scores.insert (current_scores.end (), boost_scores_.begin (),
261+ boost_scores_.end ());
262+ } else {
263+ // Do nothing.
264+ }
265+
266+ auto context_graph = std::make_shared<ContextGraph>(
267+ current, config_.hotwords_score , current_scores);
268+ return std::make_unique<OfflineStream>(config_.feat_config , context_graph);
269+ }
270+
222271 std::unique_ptr<OfflineStream> CreateStream () const override {
223272 if (config_.model_config .omnilingual .model .empty ()) {
224- return std::make_unique<OfflineStream>(config_.feat_config );
273+ return std::make_unique<OfflineStream>(config_.feat_config ,
274+ hotwords_graph_);
225275 } else {
226276 return std::make_unique<OfflineStream>(OmnilingualAsrTag{});
227277 }
@@ -287,7 +337,7 @@ class OfflineRecognizerCtcImpl : public OfflineRecognizerImpl {
287337 -23 .025850929940457f );
288338 auto t = model_->Forward (std::move (x), std::move (x_length));
289339
290- auto results = decoder_->Decode (std::move (t[0 ]), std::move (t[1 ]));
340+ auto results = decoder_->Decode (std::move (t[0 ]), std::move (t[1 ]), ss, n );
291341
292342 int32_t frame_shift_ms = 10 ;
293343 for (int32_t i = 0 ; i != n; ++i) {
@@ -330,7 +380,9 @@ class OfflineRecognizerCtcImpl : public OfflineRecognizerImpl {
330380 x_length_shape.data (), x_length_shape.size ());
331381
332382 auto t = model_->Forward (std::move (x), std::move (x_length));
333- auto results = decoder_->Decode (std::move (t[0 ]), std::move (t[1 ]));
383+
384+ OfflineStream *ss[1 ] = {s};
385+ auto results = decoder_->Decode (std::move (t[0 ]), std::move (t[1 ]), ss, 1 );
334386 int32_t frame_shift_ms = 10 ;
335387
336388 if (!config_.model_config .omnilingual .model .empty ()) {
@@ -344,9 +396,60 @@ class OfflineRecognizerCtcImpl : public OfflineRecognizerImpl {
344396 s->SetResult (r);
345397 }
346398
399+ void InitHotwords () {
400+ // each line in hotwords_file contains space-separated words
401+
402+ std::ifstream is (config_.hotwords_file );
403+ if (!is) {
404+ SHERPA_ONNX_LOGE (" Open hotwords file failed: %s" ,
405+ config_.hotwords_file .c_str ());
406+ exit (-1 );
407+ }
408+
409+ if (!EncodeHotwords (is, config_.model_config .modeling_unit , symbol_table_,
410+ bpe_encoder_.get (), &hotwords_, &boost_scores_)) {
411+ SHERPA_ONNX_LOGE (
412+ " Failed to encode some hotwords, skip them already, see logs above "
413+ " for details." );
414+ }
415+ hotwords_graph_ = std::make_shared<ContextGraph>(
416+ hotwords_, config_.hotwords_score , boost_scores_);
417+ }
418+
419+ #if __ANDROID_API__ >= 9
420+ void InitHotwords (AAssetManager *mgr) {
421+ // each line in hotwords_file contains space-separated words
422+
423+ auto buf = ReadFile (mgr, config_.hotwords_file );
424+
425+ std::istringstream is (std::string (buf.begin (), buf.end ()));
426+
427+ if (!is) {
428+ SHERPA_ONNX_LOGE (" Open hotwords file failed: %s" ,
429+ config_.hotwords_file .c_str ());
430+ exit (-1 );
431+ }
432+
433+ if (!EncodeHotwords (is, config_.model_config .modeling_unit , symbol_table_,
434+ bpe_encoder_.get (), &hotwords_, &boost_scores_)) {
435+ SHERPA_ONNX_LOGE (
436+ " Failed to encode some hotwords, skip them already, see logs above "
437+ " for details." );
438+ }
439+ hotwords_graph_ = std::make_shared<ContextGraph>(
440+ hotwords_, config_.hotwords_score , boost_scores_);
441+ }
442+ #endif
443+
347444 private:
348445 OfflineRecognizerConfig config_;
349446 SymbolTable symbol_table_;
447+
448+ std::vector<std::vector<int32_t >> hotwords_;
449+ std::vector<float > boost_scores_;
450+ ContextGraphPtr hotwords_graph_;
451+ std::unique_ptr<ssentencepiece::Ssentencepiece> bpe_encoder_;
452+
350453 std::unique_ptr<OfflineCtcModel> model_;
351454 std::unique_ptr<OfflineCtcDecoder> decoder_;
352455};
0 commit comments