1010
1111#include " sherpa-onnx/csrc/file-utils.h"
1212#include " sherpa-onnx/csrc/macros.h"
13+ #include " sherpa-onnx/csrc/text-utils.h"
1314
1415namespace sherpa_onnx {
1516
17+ static bool IsQnnModelLibFile (const std::string &filename) {
18+ return EndsWith (filename, " .so" );
19+ }
20+
21+ static bool IsQnnWhisperArtifact (const OfflineWhisperModelConfig &config) {
22+ return IsQnnModelLibFile (config.encoder ) ||
23+ IsQnnModelLibFile (config.decoder ) ||
24+ !config.qnn_config .context_binary .empty ();
25+ }
26+
27+ static bool ValidateQnnContextBinaries (const std::string &context_binary,
28+ std::vector<std::string> &filenames) {
29+ filenames.clear ();
30+
31+ if (context_binary.empty ()) {
32+ return true ;
33+ }
34+
35+ SplitStringToVector (context_binary, " ," , true , &filenames);
36+ if (filenames.size () != 2 ) {
37+ SHERPA_ONNX_LOGE (
38+ " For offline whisper with QNN, you should provide 2 context "
39+ " binaries separated by commas (encoder,decoder). Given '%s'" ,
40+ context_binary.c_str ());
41+ return false ;
42+ }
43+
44+ return true ;
45+ }
46+
1647void OfflineWhisperModelConfig::Register (ParseOptions *po) {
1748 po->Register (" whisper-encoder" , &encoder,
1849 " Path to onnx encoder of whisper, e.g., tiny-encoder.onnx, "
@@ -59,17 +90,71 @@ void OfflineWhisperModelConfig::Register(ParseOptions *po) {
5990 " --whisper-enable-token-timestamps for both segment-level and "
6091 " token-level "
6192 " timestamps. Default: false." );
93+
94+ std::string prefix = " whisper" ;
95+ ParseOptions p (prefix, po);
96+ qnn_config.Register (&p);
6297}
6398
6499bool OfflineWhisperModelConfig::Validate () const {
100+ bool uses_qnn = IsQnnWhisperArtifact (*this );
101+
102+ if (uses_qnn) {
103+ std::vector<std::string> context_binaries;
104+ if (!ValidateQnnContextBinaries (qnn_config.context_binary ,
105+ context_binaries)) {
106+ return false ;
107+ }
108+
109+ bool need_model_libs = context_binaries.empty ();
110+ for (const auto &name : context_binaries) {
111+ if (!FileExists (name)) {
112+ need_model_libs = true ;
113+ break ;
114+ }
115+ }
116+
117+ if (need_model_libs) {
118+ if (!EndsWith (encoder, " .so" ) || !EndsWith (decoder, " .so" )) {
119+ SHERPA_ONNX_LOGE (
120+ " For offline whisper with QNN, encoder/decoder should be "
121+ " *.so when context binaries are missing. Given encoder: '%s', "
122+ " decoder: '%s'" ,
123+ encoder.c_str (), decoder.c_str ());
124+ return false ;
125+ }
126+
127+ if (!FileExists (encoder)) {
128+ SHERPA_ONNX_LOGE (" whisper encoder: '%s' does not exist" ,
129+ encoder.c_str ());
130+ return false ;
131+ }
132+
133+ if (!FileExists (decoder)) {
134+ SHERPA_ONNX_LOGE (" whisper decoder: '%s' does not exist" ,
135+ decoder.c_str ());
136+ return false ;
137+ }
138+ }
139+
140+ for (const auto &name : context_binaries) {
141+ if (FileExists (name) && !EndsWith (name, " .bin" )) {
142+ SHERPA_ONNX_LOGE (" QNN context binary should end with .bin. Given '%s'" ,
143+ name.c_str ());
144+ return false ;
145+ }
146+ }
147+
148+ return qnn_config.Validate ();
149+ }
150+
65151 if (encoder.empty ()) {
66152 SHERPA_ONNX_LOGE (" Please provide --whisper-encoder" );
67153 return false ;
68154 }
69155
70156 if (!FileExists (encoder)) {
71- SHERPA_ONNX_LOGE (" whisper encoder file '%s' does not exist" ,
72- encoder.c_str ());
157+ SHERPA_ONNX_LOGE (" whisper encoder: '%s' does not exist" , encoder.c_str ());
73158 return false ;
74159 }
75160
@@ -79,16 +164,14 @@ bool OfflineWhisperModelConfig::Validate() const {
79164 }
80165
81166 if (!FileExists (decoder)) {
82- SHERPA_ONNX_LOGE (" whisper decoder file '%s' does not exist" ,
83- decoder.c_str ());
167+ SHERPA_ONNX_LOGE (" whisper decoder: '%s' does not exist" , decoder.c_str ());
84168 return false ;
85169 }
86170
87171 if (task != " translate" && task != " transcribe" ) {
88172 SHERPA_ONNX_LOGE (
89173 " --whisper-task supports only translate and transcribe. Given: %s" ,
90174 task.c_str ());
91-
92175 return false ;
93176 }
94177
@@ -107,7 +190,11 @@ std::string OfflineWhisperModelConfig::ToString() const {
107190 os << " enable_token_timestamps="
108191 << (enable_token_timestamps ? " True" : " False" ) << " , " ;
109192 os << " enable_segment_timestamps="
110- << (enable_segment_timestamps ? " True" : " False" ) << " )" ;
193+ << (enable_segment_timestamps ? " True" : " False" ) << " , " ;
194+ if (!qnn_config.backend_lib .empty ()) {
195+ os << " qnn_config=" << qnn_config.ToString () << " , " ;
196+ }
197+ os << " )" ;
111198
112199 return os.str ();
113200}
0 commit comments