yum-archive/TaSTT-Whisper
High-performance GPGPU inference of OpenAI's Whisper automatic speech recognition (ASR) model
git clone https://git.yummers.dev/yum-archive/TaSTT-Whisper
f7d5741
master
1#define WIN32_LEAN_AND_MEAN 2 3#include <Unknwn.h> 4#include <windows.h> 5 6#include "Whisper/API/whisperWindows.h" 7 8#include <iostream> 9#include <locale> 10#include <set> 11#include <string> 12#include <string_view> 13 14using std::cout ; 15using std::cerr ; 16using std::endl ; 17using namespace Whisper ; 18 19struct Config { 20 std::wstring audio_path = L"input.wav" ; 21 std::wstring model_path = L"model.bin" ; 22eSamplingStrategy decode_method = eSamplingStrategy::BeamSearch ; 23}; 24 25bool hasArg (int argc ,int shift ,char * arg ) { 26if (shift + 1 >=argc ) { 27cerr <<"Error: " <<arg <<" is missing argument" <<endl ; 28return false; 29 } 30return true; 31} 32 33std::wstring cstrToWstr (char * c_str ) { 34int length = MultiByteToWideChar (CP_UTF8 ,0 ,c_str ,-1 ,NULL ,0 ); 35 std::wstring result (length ,0 ); 36MultiByteToWideChar (CP_UTF8 ,0 ,c_str ,-1 ,result .data (),result .size ()); 37return result ; 38} 39 40 41bool parseArgs (int argc ,char * argv [],Config & c ) { 42int shift = 1 ; 43while (shift < argc ) { 44if (std::string_view (argv [shift ])== "--audio_path" ) { 45if (!hasArg (argc ,shift ,argv [shift ])) { 46return false; 47 } 48c .audio_path = cstrToWstr (argv [shift + 1 ]); 49shift += 2 ; 50continue ; 51 } 52if (std::string_view (argv [shift ])== "--model_path" ) { 53if (!hasArg (argc ,shift ,argv [shift ])) { 54return false; 55 } 56c .model_path = cstrToWstr (argv [shift + 1 ]); 57shift += 2 ; 58continue ; 59 } 60if (std::string_view (argv [shift ])== "--decode_method" ) { 61if (!hasArg (argc ,shift ,argv [shift ])) { 62return false; 63 } 64 std::string_view decode_method (argv [shift + 1 ]); 65if (decode_method == "greedy" ) { 66cerr <<"Using greedy decode " <<endl ; 67c .decode_method = eSamplingStrategy::Greedy ; 68 } 69else if (decode_method == "beam" ) { 70cerr <<"Using beam decode " <<endl ; 71c .decode_method = eSamplingStrategy::BeamSearch ; 72 } 73else { 74cerr <<"Unsupported decode method: " <<decode_method <<endl ; 75return false; 76 } 77shift += 2 ; 78continue ; 79 } 80cerr <<"Unrecognized argument: \"" <<argv [shift ] <<'"' <<endl ; 81return false; 82 } 83return true; 84} 85 86int main (int argc ,char * argv []) 87{ 88Config c ; 89if (!parseArgs (argc ,argv ,c )) { 90cerr <<"Failed to parse args" ; 91return 1 ; 92 } 93 94iMediaFoundation * f = nullptr ; 95HRESULT err = initMediaFoundation (& f ); 96if (FAILED (err )) { 97cerr <<"Failed to init media foundation: " <<err <<endl ; 98return 1 ; 99 } 100 101Whisper ::iAudioBuffer * buffer = nullptr ; 102err = f -> loadAudioFile (c .audio_path .c_str (),/*stereo=*/ false,& buffer ); 103if (FAILED (err )) { 104cerr <<"Failed to load audio file 'input.wav': " <<err <<endl ; 105return 1 ; 106 } 107 108Whisper ::iModel * model = nullptr ; 109err = Whisper ::loadModel (c .model_path .c_str (), eModelImplementation::GPU ,/*flags=*/ 0 ,/*callbacks=*/ nullptr ,& model ); 110if (FAILED (err )) { 111cerr <<"Failed to open model 'model.bin': " <<err <<endl ; 112return 1 ; 113 } 114 115Whisper ::iContext * context = nullptr ; 116err = model -> createContext (& context ); 117if (FAILED (err )) { 118cerr <<"Failed to create context: " <<err <<endl ; 119return 1 ; 120 } 121 122Whisper ::sFullParams wparams {}; 123context -> fullDefaultParams (c .decode_method ,& wparams ); 124if (c .decode_method == eSamplingStrategy::BeamSearch ) { 125wparams .beam_search .beam_width = 5 ; 126wparams .beam_search .n_best = 5 ; 127 } 128wparams .language = Whisper ::makeLanguageKey ("en" ); 129wparams .n_max_text_ctx = 100 ; 130 131err = context -> runFull (wparams ,buffer ); 132if (FAILED (err )) { 133cerr <<"Failed to transcribe: " <<err <<endl ; 134return 1 ; 135 } 136 137Whisper ::iTranscribeResult * result = nullptr ; 138err = context -> getResults (eResultFlags::Tokens ,& result ); 139if (FAILED (err )) { 140cerr <<"Failed to get transcription results: " <<err <<endl ; 141return 1 ; 142 } 143 144 std::set < int > special_tokens ; 145 { 146Whisper ::SpecialTokens st ; 147err = model -> getSpecialTokens (st ); 148if (FAILED (err )) { 149cerr <<"Failed to get special tokens: " <<err <<endl ; 150 } 151special_tokens .insert (st .Not ); 152special_tokens .insert (st .PreviousWord ); 153special_tokens .insert (st .SentenceStart ); 154special_tokens .insert (st .TaskTranscribe ); 155special_tokens .insert (st .TaskTranslate ); 156special_tokens .insert (st .TranscriptionBegin ); 157special_tokens .insert (st .TranscriptionEnd ); 158special_tokens .insert (st .TranscriptionStart ); 159 } 160 161sTranscribeLength length ; 162err = result -> getSize (length ); 163if (FAILED (err )) { 164cerr <<"Failed to get transcription length: " <<err <<endl ; 165 } 166auto * segments = result -> getSegments (); 167auto * tokens = result -> getTokens (); 168bool is_metadata = false; 169for (int i = 0 ;i < length .countSegments ;i ++ ) { 170auto & segment = segments [i ]; 171for (int j = 0 ;j < segment .countTokens ;j ++ ) { 172const sToken & tok = tokens [segment .firstToken + j ]; 173if (special_tokens .contains (tok .id )) { 174continue ; 175 } 176 std::string_view tok_str (tok .text ); 177if (tok_str .starts_with ("[" )|| 178tok_str .starts_with (" [" )) { 179if (tok_str .ends_with ("]" )) { 180continue ; 181 } 182is_metadata = true; 183continue ; 184 } 185if (is_metadata && 186tok_str .ends_with ("]" )) { 187is_metadata = false; 188continue ; 189 } 190cout <<tok .text ; 191 } 192 } 193cout <<endl ; 194 195return 0 ; 196}