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
8c4603c
master
1// https://github.com/Const-me/vis_avs_dx/blob/master/avs_dx/DxVisuals/Interop/ConsoleLogger.cpp 2#include "stdafx.h" 3#include "DebugConsole.h" 4#include "miscUtils.h" 5#include "../AppState.h" 6#include "logger.h" 7 8namespace 9{ 10using Whisper ::eLogLevel ; 11 12constexpr uint16_t defaultAttributes = FOREGROUND_RED |FOREGROUND_GREEN |FOREGROUND_BLUE ; 13 14inline uint16_t textAttributes (eLogLevel lvl ) 15 { 16switch (lvl ) 17 { 18case eLogLevel::Error : 19return FOREGROUND_RED |FOREGROUND_INTENSITY ; 20case eLogLevel::Warning : 21return FOREGROUND_RED |FOREGROUND_GREEN |FOREGROUND_INTENSITY ; 22case eLogLevel::Info : 23return FOREGROUND_GREEN |FOREGROUND_INTENSITY ; 24case eLogLevel::Debug : 25return FOREGROUND_BLUE |FOREGROUND_INTENSITY ; 26 } 27return defaultAttributes ; 28 } 29 30// Background stuff: accumulate messages in a small buffer, in case user will want to see them in the console. 31// Ideally, we should accumulate them in a more efficient data structure, maybe a circular buffer. 32// However, we don't have that many messages per second, this simple solution that uses std::deque is probably good enough for the job. 33static constexpr uint16_t bufferSize = 64 ; 34 35using Lock = CComCritSecLock < CComAutoCriticalSection > ; 36#define LOCK () Lock __lock{ critSec } 37 38 thread_localCStringA threadError ; 39} 40 41HRESULT DebugConsole ::Entry ::HANDLE hConsole ,CString & tempString )const 42{ 43if ( !SetConsoleTextAttribute (hConsole ,textAttributes (level ) ) ) 44return getLastHr (); 45 46makeUtf16 (tempString ,message ); 47tempString += L"\r\n" ; 48if ( !WriteConsoleW (hConsole ,tempString , (DWORD )tempString .GetLength (),nullptr ,nullptr ) ) 49return getLastHr (); 50return S_OK ; 51} 52 53void clearLastError () 54{ 55threadError = "" ; 56} 57 58bool getLastError (CString & rdi ) 59{ 60if (threadError .GetLength () <=0 ) 61 { 62rdi = L"" ; 63return false; 64 } 65else 66 { 67makeUtf16 (rdi ,threadError ); 68threadError = "" ; 69return true; 70 } 71} 72 73inline void DebugConsole ::logSink (eLogLevel lvl ,const char * message ) 74{ 75LOCK (); 76 77// Add to the buffer 78while (buffer .size () >=bufferSize ) 79buffer .pop_front (); 80buffer .emplace_back (Entry {lvl ,message } ); 81 82// If the console window is shown, print there, too. 83if (output ) 84buffer .rbegin ()-> output ,tempString ); 85} 86 87void __stdcallDebugConsole ::logSinkStatic (void * context ,eLogLevel lvl ,const char * message ) 88{ 89if (lvl == eLogLevel::Error ) 90threadError = message ; 91 92DebugConsole * con = (DebugConsole * )context ; 93con -> logSink (lvl ,message ); 94} 95 96HRESULT DebugConsole ::initialize (Whisper ::eLogLevel level ) 97{ 98if (nullptr != pGlobalInstance ) 99return HRESULT_FROM_WIN32 (ERROR_ALREADY_INITIALIZED ); 100pGlobalInstance = this ; 101 102Whisper ::sLoggerSetup setup ; 103setup .sink = & logSinkStatic ; 104setup .context = this ; 105setup .level = level ; 106setup .flags = Whisper ::eLoggerFlags::SkipFormatMessage ; 107return Whisper ::setupLogger (setup ); 108} 109 110DebugConsole ::~DebugConsole () 111{ 112hide (); 113 114Whisper ::sLoggerSetup setup ; 115memset (& setup ,0 ,sizeof (setup ) ); 116Whisper ::setupLogger (setup ); 117 118pGlobalInstance = nullptr ; 119} 120 121DebugConsole * DebugConsole ::pGlobalInstance = nullptr ; 122 123void DebugConsole ::windowClosed () 124{ 125LOCK (); 126if (FreeConsole () ) 127 { 128// Apparently, FreeConsole already closes that handle: https://stackoverflow.com/q/12676312/126995 129output .Detach (); 130 } 131output .Close (); 132 133for (CButton * b :checkboxes ) 134 { 135if ( !* b ) 136continue ; 137if ( !b -> IsWindow () ) 138continue ; 139PostMessage (* b ,BM_SETCHECK ,BST_UNCHECKED ,0 ); 140 } 141} 142 143BOOL __stdcallDebugConsole ::consoleHandlerRoutine (DWORD dwCtrlType ) 144{ 145switch (dwCtrlType ) 146 { 147case CTRL_CLOSE_EVENT : 148case CTRL_C_EVENT : 149case CTRL_BREAK_EVENT : 150pGlobalInstance -> windowClosed (); 151return TRUE; 152 } 153return TRUE; 154} 155 156HRESULT DebugConsole ::show () 157{ 158HWND hWnd = GetConsoleWindow (); 159if (nullptr != hWnd ) 160 { 161ShowWindow (hWnd ,SW_RESTORE ); 162SetForegroundWindow (hWnd ); 163return S_FALSE ; 164 } 165 166if ( !AllocConsole () ) 167return getLastHr (); 168 169output .Close (); 170output .Attach (GetStdHandle (STD_OUTPUT_HANDLE ) ); 171if ( !output ) 172return getLastHr (); 173 174constexpr UINT cp = CP_UTF8 ; 175if (IsValidCodePage (cp ) ) 176SetConsoleOutputCP (cp ); 177 178// Enable ANSI color coding 179DWORD mode = 0 ; 180if ( !GetConsoleMode (output ,& mode ) ) 181return getLastHr (); 182if (0 == (mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING ) ) 183 { 184mode |=ENABLE_VIRTUAL_TERMINAL_PROCESSING ; 185if ( !SetConsoleMode (output ,mode ) ) 186return getLastHr (); 187 } 188 189SetConsoleTitle (L"Whisper Desktop Debug Console" ); 190 191SetConsoleCtrlHandler (& consoleHandlerRoutine , TRUE ); 192 193// Disable close command in the sys.menu of the new console, otherwise the whole process will quit: https://stackoverflow.com/a/12015131/126995 194HWND hwnd = ::GetConsoleWindow (); 195if (hwnd != nullptr ) 196 { 197HMENU hMenu = ::GetSystemMenu (hwnd , FALSE ); 198if (hMenu != NULL ) 199DeleteMenu (hMenu ,SC_CLOSE ,MF_BYCOMMAND ); 200 } 201 202// Print old log entries 203for (const auto & e :buffer ) 204CHECK (e .output ,tempString ) ); 205 206const CStringA msg = "Press Control+C or Control+Break to close this window\r\n" ; 207if ( !SetConsoleTextAttribute (output ,FOREGROUND_RED |FOREGROUND_GREEN |FOREGROUND_BLUE |FOREGROUND_INTENSITY ) ) 208return getLastHr (); 209if ( !WriteConsoleA (output ,cstr (msg ),msg .GetLength (),nullptr ,nullptr ) ) 210return getLastHr (); 211 212return S_OK ; 213} 214 215HRESULT DebugConsole ::hide () 216{ 217LOCK (); 218if ( !output ) 219return S_FALSE ; 220windowClosed (); 221return S_OK ; 222} 223 224void DebugConsole ::addCheckbox (CButton & cb ) 225{ 226checkboxes .emplace (& cb ); 227} 228void DebugConsole ::removeCheckbox (CButton & cb ) 229{ 230checkboxes .erase (& cb ); 231} 232 233HRESULT ConsoleCheckbox ::initialize (HWND dialog ,int idc ,AppState & state ) 234{ 235control = GetDlgItem (dialog ,idc ); 236assert (control ); 237 238console = & state .console ; 239if (state .console .isVisible () ) 240control .SetCheck (BST_CHECKED ); 241 242state .console .addCheckbox (control ); 243return S_OK ; 244} 245 246void ConsoleCheckbox ::click () 247{ 248const int state = control .GetCheck (); 249if (state == BST_CHECKED ) 250console -> show (); 251else 252console -> hide (); 253} 254 255void ConsoleCheckbox ::ensureChecked () 256{ 257const int state = control .GetCheck (); 258if (state == BST_CHECKED ) 259return ; 260control .SetCheck (BST_CHECKED ); 261console -> show (); 262} 263 264void DebugConsole ::log (eLogLevel lvl ,const char * pszFormat ,va_list args ) 265{ 266LOCK (); 267// Add to the buffer 268while (buffer .size () >=bufferSize ) 269buffer .pop_front (); 270 271tempStringA .FormatV (pszFormat ,args ); 272buffer .emplace_back (Entry {lvl ,tempStringA } ); 273 274// If the console window is shown, print there, too. 275if (output ) 276buffer .rbegin ()-> output ,tempString ); 277} 278 279void DebugConsole ::logMessage (eLogLevel lvl ,const char * pszFormat ,va_list args ) 280{ 281if (nullptr == pGlobalInstance ) 282return ; 283pGlobalInstance -> log (lvl ,pszFormat ,args ); 284} 285 286void logMessage (Whisper ::eLogLevel lvl ,const char8_t * pczFormat ,va_list args ) 287{ 288DebugConsole ::logMessage (lvl , (const char * )pczFormat ,args ); 289}