Skip to content

Commit 3807bec

Browse files
committed
update code after review
1 parent 92a3676 commit 3807bec

4 files changed

Lines changed: 10 additions & 73 deletions

File tree

c-api-examples/qwen3-asr-c-api.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ int32_t main() {
4848
qwen3.encoder = encoder;
4949
qwen3.decoder = decoder;
5050
qwen3.tokenizer = tokenizer;
51-
qwen3.hotwords = "";
5251
qwen3.max_total_len = 512;
5352
qwen3.max_new_tokens = 128;
5453
qwen3.temperature = 1e-6f;
5554
qwen3.top_p = 0.8f;
5655
qwen3.seed = 42;
56+
qwen3.hotwords = "";
5757

5858
SherpaOnnxOfflineModelConfig offline_model_config;
5959
memset(&offline_model_config, 0, sizeof(offline_model_config));

scripts/go/sherpa_onnx.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -862,15 +862,6 @@ func NewOfflineStream(recognizer *OfflineRecognizer) *OfflineStream {
862862
return stream
863863
}
864864

865-
// NewOfflineStreamWithHotwords creates a stream with per-utterance hotwords (Qwen3-ASR, transducer, etc.).
866-
func NewOfflineStreamWithHotwords(recognizer *OfflineRecognizer, hotwords string) *OfflineStream {
867-
cs := C.CString(hotwords)
868-
defer C.free(unsafe.Pointer(cs))
869-
stream := &OfflineStream{}
870-
stream.impl = C.SherpaOnnxCreateOfflineStreamWithHotwords(recognizer.impl, cs)
871-
return stream
872-
}
873-
874865
// Input audio samples for the offline stream.
875866
// Please only call it once. That is, input all samples at once.
876867
//

sherpa-onnx/c-api/c-api.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -991,8 +991,6 @@ typedef struct SherpaOnnxOfflineQwen3ASRModelConfig {
991991
const char *decoder;
992992
/** Path to the tokenizer directory (e.g. containing `vocab.json`). */
993993
const char *tokenizer;
994-
/** Optional Qwen3-ASR hotwords. */
995-
const char *hotwords;
996994
/** Maximum total sequence length supported by the model. */
997995
int32_t max_total_len;
998996
/** Maximum number of new tokens to generate. */
@@ -1003,6 +1001,8 @@ typedef struct SherpaOnnxOfflineQwen3ASRModelConfig {
10031001
float top_p;
10041002
/** Random seed for reproducible sampling. */
10051003
int32_t seed;
1004+
/** Optional Qwen3-ASR hotwords. */
1005+
const char *hotwords;
10061006
} SherpaOnnxOfflineQwen3ASRModelConfig;
10071007

10081008
/** @brief Configuration for a MedASR CTC model. */

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

Lines changed: 7 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
#include <algorithm>
88
#include <array>
9-
#include <cctype>
109
#include <cmath>
1110
#include <cstdint>
1211
#include <cstring>
@@ -31,6 +30,7 @@
3130
#include "sherpa-onnx/csrc/macros.h"
3231
#include "sherpa-onnx/csrc/math.h"
3332
#include "sherpa-onnx/csrc/onnx-utils.h"
33+
#include "sherpa-onnx/csrc/text-utils.h"
3434

3535
namespace sherpa_onnx {
3636

@@ -51,70 +51,16 @@ constexpr char kQwen3SystemPromptPrefix[] = "<|im_start|>system\n";
5151
constexpr char kQwen3SystemPromptSuffix[] =
5252
"<|im_end|>\n<|im_start|>user\n<|audio_start|>";
5353

54-
static std::string NormalizeQwen3AsrHotwordSlashes(std::string hw) {
55-
for (char &c : hw) {
56-
if (c == '/') {
57-
c = ' ';
58-
}
59-
}
60-
return hw;
61-
}
62-
63-
static inline void Qwen3TrimInplace(std::string *s) {
64-
if (!s) return;
65-
auto &str = *s;
66-
auto not_space = [](unsigned char c) { return !std::isspace(c); };
67-
str.erase(str.begin(), std::find_if(str.begin(), str.end(), not_space));
68-
str.erase(std::find_if(str.rbegin(), str.rend(), not_space).base(),
69-
str.end());
70-
}
71-
72-
static std::vector<std::string> Qwen3ParseHotwordsCsv(const std::string &csv) {
73-
std::vector<std::string> out;
74-
std::string cur;
75-
cur.reserve(csv.size());
76-
77-
for (size_t i = 0; i < csv.size(); ++i) {
78-
unsigned char ch = static_cast<unsigned char>(csv[i]);
79-
bool is_separator = false;
80-
if (ch == ',' || ch == ';' || ch == '\n' || ch == '\r' || ch == '\t') {
81-
is_separator = true;
82-
} else if (ch == 0xEF) {
83-
if (i + 2 < csv.size()) {
84-
unsigned char ch1 = static_cast<unsigned char>(csv[i + 1]);
85-
unsigned char ch2 = static_cast<unsigned char>(csv[i + 2]);
86-
if (ch1 == 0xBC && (ch2 == 0x8C || ch2 == 0x9B)) {
87-
is_separator = true;
88-
i += 2;
89-
} else if (ch1 >= 0x80 && ch1 <= 0xBF && ch2 >= 0x80 && ch2 <= 0xBF) {
90-
cur.push_back(csv[i]);
91-
cur.push_back(csv[i + 1]);
92-
cur.push_back(csv[i + 2]);
93-
i += 2;
94-
continue;
95-
}
96-
}
97-
}
98-
99-
if (is_separator) {
100-
Qwen3TrimInplace(&cur);
101-
if (!cur.empty()) out.push_back(cur);
102-
cur.clear();
103-
} else {
104-
cur.push_back(csv[i]);
105-
}
106-
}
107-
Qwen3TrimInplace(&cur);
108-
if (!cur.empty()) out.push_back(cur);
109-
return out;
110-
}
111-
54+
// Format hotwords for the Qwen3 chat template: ASCII comma-separated list
55+
// (e.g. "foo,bar,baz"); fields are trimmed, empty fields dropped, then joined
56+
// with spaces for the system prompt. Same delimiter convention as elsewhere
57+
// (comma-only); no alternate separators or '/' rewriting.
11258
static std::string Qwen3FormatHotwordsForPrompt(const std::string &csv) {
113-
std::vector<std::string> parts = Qwen3ParseHotwordsCsv(csv);
59+
const std::vector<std::string> parts = SplitStringAndTrim(csv, ',');
11460
std::string s;
11561
for (size_t i = 0; i < parts.size(); ++i) {
11662
if (i) s += ' ';
117-
s += NormalizeQwen3AsrHotwordSlashes(std::move(parts[i]));
63+
s += parts[i];
11864
}
11965
return s;
12066
}

0 commit comments

Comments
 (0)