66
77#include < algorithm>
88#include < array>
9- #include < cctype>
109#include < cmath>
1110#include < cstdint>
1211#include < cstring>
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
3535namespace sherpa_onnx {
3636
@@ -51,70 +51,16 @@ constexpr char kQwen3SystemPromptPrefix[] = "<|im_start|>system\n";
5151constexpr 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.
11258static 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