Skip to content

Commit 565d097

Browse files
committed
Fix Qwen3ASR hotwords handling
1 parent 178cee0 commit 565d097

2 files changed

Lines changed: 40 additions & 41 deletions

File tree

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
1-
// Copyright (c) 2026 Xiaomi Corporation
2-
//
3-
// This file shows how to use a Qwen3 ASR model for speech recognition.
4-
//
5-
// You can find the model doc at
6-
// https://k2-fsa.github.io/sherpa/onnx/qwen3-asr.html
7-
using SherpaOnnx;
8-
9-
class NonStreamingQwen3Asr
10-
{
11-
static void Main(string[] args)
12-
{
13-
// please download model files from
14-
// https://github.com/k2-fsa/sherpa-onnx/releases/tag/asr-models
15-
var config = new OfflineRecognizerConfig();
16-
config.ModelConfig.Qwen3Asr.ConvFrontend = "./sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25/conv_frontend.onnx";
17-
config.ModelConfig.Qwen3Asr.Encoder = "./sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25/encoder.int8.onnx";
18-
config.ModelConfig.Qwen3Asr.Decoder = "./sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25/decoder.int8.onnx";
19-
config.ModelConfig.Qwen3Asr.Tokenizer = "./sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25/tokenizer";
20-
config.ModelConfig.Qwen3Asr.Hotwords = "";
21-
config.ModelConfig.Tokens = "";
22-
config.ModelConfig.Debug = 1;
23-
var recognizer = new OfflineRecognizer(config);
24-
25-
var testWaveFilename = "./sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25/test_wavs/raokouling.wav";
26-
var reader = new WaveReader(testWaveFilename);
27-
var stream = recognizer.CreateStream();
28-
stream.AcceptWaveform(reader.SampleRate, reader.Samples);
29-
recognizer.Decode(stream);
30-
var text = stream.Result.Text;
31-
Console.WriteLine("Text: {0}", text);
32-
}
33-
}
1+
// Copyright (c) 2026 Xiaomi Corporation
2+
//
3+
// This file shows how to use a Qwen3 ASR model for speech recognition.
4+
//
5+
// You can find the model doc at
6+
// https://k2-fsa.github.io/sherpa/onnx/qwen3-asr
7+
using SherpaOnnx;
8+
9+
class NonStreamingQwen3Asr
10+
{
11+
static void Main(string[] args)
12+
{
13+
// please download model files from
14+
// https://github.com/k2-fsa/sherpa-onnx/releases/tag/asr-models
15+
var config = new OfflineRecognizerConfig();
16+
config.ModelConfig.Qwen3Asr.ConvFrontend = "./sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25/conv_frontend.onnx";
17+
config.ModelConfig.Qwen3Asr.Encoder = "./sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25/encoder.int8.onnx";
18+
config.ModelConfig.Qwen3Asr.Decoder = "./sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25/decoder.int8.onnx";
19+
config.ModelConfig.Qwen3Asr.Tokenizer = "./sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25/tokenizer";
20+
config.ModelConfig.Qwen3Asr.Hotwords = "";
21+
config.ModelConfig.Tokens = "";
22+
config.ModelConfig.Debug = 1;
23+
var recognizer = new OfflineRecognizer(config);
24+
25+
var testWaveFilename = "./sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25/test_wavs/raokouling.wav";
26+
var reader = new WaveReader(testWaveFilename);
27+
var stream = recognizer.CreateStream();
28+
stream.AcceptWaveform(reader.SampleRate, reader.Samples);
29+
recognizer.Decode(stream);
30+
var text = stream.Result.Text;
31+
Console.WriteLine("Text: {0}", text);
32+
}
33+
}

sherpa-onnx/csrc/offline-recognizer-qwen3-asr-impl.cc

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,8 @@ OfflineRecognitionResult OfflineRecognizerQwen3ASRImpl::GenerateText(
709709
// Optional per-stream hotwords via SetOption("hotwords", comma-separated
710710
// CSV).
711711
const std::string hotwords = Qwen3FormatHotwordsForPrompt(
712-
stream->HasOption("hotwords") ? stream->GetOption("hotwords") : "");
712+
stream->HasOption("hotwords") ? stream->GetOption("hotwords")
713+
: qwen3_config.hotwords);
713714

714715
std::string language;
715716
if (stream->HasOption("language")) {
@@ -981,20 +982,18 @@ OfflineRecognitionResult OfflineRecognizerQwen3ASRImpl::GenerateText(
981982
std::vector<int64_t> cleaned_ids = generated_ids;
982983
if (!generated_ids.empty()) {
983984
const size_t prefix_window = std::min<size_t>(16, generated_ids.size());
984-
auto asr_text_it = std::find(generated_ids.begin(),
985-
generated_ids.begin() + prefix_window,
986-
asr_text_token_id_);
985+
auto asr_text_it =
986+
std::find(generated_ids.begin(), generated_ids.begin() + prefix_window,
987+
asr_text_token_id_);
987988

988989
// Only strip a leading scaffold prefix recognized by token ID.
989990
if (asr_text_it != generated_ids.begin() + prefix_window &&
990991
asr_text_it != generated_ids.begin()) {
991992
std::vector<int64_t> prefix_ids(generated_ids.begin(),
992993
std::next(asr_text_it));
993994
std::string prefix_text = tokenizer_->Decode(prefix_ids);
994-
if (prefix_text.rfind("language ", 0) == 0 &&
995-
prefix_text.size() >= 10 &&
996-
prefix_text.compare(prefix_text.size() - 10, 10, "<asr_text>") ==
997-
0) {
995+
if (prefix_text.rfind("language ", 0) == 0 && prefix_text.size() >= 10 &&
996+
prefix_text.compare(prefix_text.size() - 10, 10, "<asr_text>") == 0) {
998997
cleaned_ids.assign(std::next(asr_text_it), generated_ids.end());
999998
}
1000999
}

0 commit comments

Comments
 (0)