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

KonstantinGUI to force specific version of the compute shaders670f889

master
5.2 KiB214 linesraw
1#include "stdafx.h"
2#include "LoadModelDlg.h"
3#include "Utils/miscUtils.h"
4#include "Utils/logger.h"
5#include "ModelAdvancedDlg.h"
6
7constexpr int progressMaxInteger = 1024 * 8;
8
9HRESULT LoadModelDlg::show()
10{
11	auto res = DoModal( nullptr );
12	if( res == -1 )
13		return HRESULT_FROM_WIN32( GetLastError() );
14	if( res == IDOK )
15	{
16		HRESULT hr = appState.lastScreenLoad();
17		switch( hr )
18		{
19		case SCREEN_TRANSCRIBE:
20		case SCREEN_CAPTURE:
21			return hr;
22		default:
23			return SCREEN_TRANSCRIBE;
24		}
25	}
26	return S_OK;
27}
28
29LRESULT LoadModelDlg::OnInitDialog( UINT nMessage, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
30{
31	// First DDX call, hooks up variables to controls.
32	DoDataExchange( false );
33
34	cbConsole.initialize( m_hWnd, IDC_CONSOLE, appState );
35	implPopulateCombobox( cbModelType, appState.source.impl );
36	modelPath.SetWindowTextW( appState.source.path );
37
38	HRESULT hr = work.create( this );
39	if( FAILED( hr ) )
40	{
41		CString text = L"CreateThreadpoolWork failed\n";
42		text += formatErrorMessage( hr );
43		::MessageBox( m_hWnd, text, L"Unable to load the model", MB_OK | MB_ICONWARNING );
44		return TRUE;
45	}
46
47	editorsWindows.reserve( 6 );
48	editorsWindows = { modelPath, cbModelType, GetDlgItem( IDC_BROWSE ), GetDlgItem( IDC_MODEL_ADV ), GetDlgItem( IDOK ), GetDlgItem( IDCANCEL ) };
49	pendingWindows.reserve( 2 );
50	pendingWindows = { GetDlgItem( IDC_PENDING_TEXT ), progressBar };
51
52	progressBar.SetRange32( 0, progressMaxInteger );
53	progressBar.SetStep( 1 );
54
55	appState.setupIcon( this );
56	ATLVERIFY( CenterWindow() );
57	if( !appState.source.found || !appState.automaticallyLoadModel )
58		return 0;
59
60	// AppState.findModelSource() method has located model parameters in registry;
61	// Post a notification identical to the "OK" button click event.
62	PostMessage( WM_COMMAND, IDOK, (LPARAM)( GetDlgItem( IDOK ).m_hWnd ) );
63
64	return 0;
65}
66
67LRESULT LoadModelDlg::OnBrowse( UINT, INT, HWND, BOOL& bHandled )
68{
69	bHandled = TRUE;
70
71	CString path;
72	modelPath.GetWindowText( path );
73	if( !getOpenFileName( m_hWnd, L"Select a GGML Model File", L"Binary files (*.bin)\0*.bin\0\0", path ) )
74		return 0;
75
76	modelPath.SetWindowText( path );
77	appState.source.path = path;
78	return 0;
79}
80
81LRESULT LoadModelDlg::validationError( LPCTSTR message )
82{
83	reportError( m_hWnd, message, L"Unable to load the model" );
84	return 0;
85}
86
87LRESULT LoadModelDlg::validationError( LPCTSTR message, HRESULT hr )
88{
89	reportError( m_hWnd, message, L"Unable to load the model", hr );
90	return 0;
91}
92
93void LoadModelDlg::setPending( bool nowPending )
94{
95	const BOOL enable = nowPending ? FALSE : TRUE;
96	for( HWND w : editorsWindows )
97		::EnableWindow( w, enable );
98
99	const int show = nowPending ? SW_NORMAL : SW_HIDE;
100	for( HWND w : pendingWindows )
101		::ShowWindow( w, show );
102
103	if( nowPending )
104		progressBar.SetMarquee( TRUE, 0 );
105	else
106		progressBar.SetMarquee( FALSE, 0 );
107}
108
109LRESULT LoadModelDlg::OnOk( UINT, INT, HWND, BOOL& bHandled )
110{
111	modelPath.GetWindowText( path );
112	if( path.GetLength() <= 0 )
113		return validationError( L"Please select a model GGML file" );
114
115	{
116		CAtlFile file;
117		HRESULT hr = file.Create( path, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING );
118		if( FAILED( hr ) )
119			return validationError( L"Unable to open the model file", hr );
120
121		ULONGLONG cb = 0;
122		file.GetSize( cb );
123		appState.source.sizeInBytes = cb;
124	}
125
126	impl = implGetValue( cbModelType );
127	if( impl == (Whisper::eModelImplementation)0 )
128		return validationError( L"Please select a model type" );
129
130	setPending( true );
131	work.post();
132	return 0;
133}
134
135void __stdcall LoadModelDlg::poolCallback() noexcept
136{
137	CComPtr<Whisper::iModel> model;
138	clearLastError();
139	loadError = L"";
140	Whisper::sLoadModelCallbacks lmcb;
141	lmcb.cancel = nullptr;
142	lmcb.progress = &LoadModelDlg::progressCallback;
143	lmcb.pv = this;
144	const uint32_t flags = appState.gpuFlagsLoad();
145	HRESULT hr = Whisper::loadModel( path, impl, flags, &lmcb, &model );
146	if( SUCCEEDED( hr ) )
147		appState.model = model;
148	else
149		getLastError( loadError );
150
151	this->PostMessage( WM_CALLBACK_STATUS, (WPARAM)hr );
152}
153
154HRESULT __stdcall LoadModelDlg::progressCallback( double val, void* pv ) noexcept
155{
156	LoadModelDlg& dialog = *(LoadModelDlg*)pv;
157	constexpr double mul = progressMaxInteger;
158	int pos = lround( mul * val );
159	dialog.progressBar.PostMessage( PBM_SETPOS, pos, 0 );
160	return S_OK;
161}
162
163LRESULT LoadModelDlg::OnCallbackStatus( UINT, WPARAM wParam, LPARAM, BOOL& bHandled )
164{
165	setPending( false );
166
167	bHandled = TRUE;
168	const HRESULT hr = (HRESULT)wParam;
169	if( FAILED( hr ) )
170	{
171		LPCTSTR failMessage = L"Error loading the model";
172		if( loadError.GetLength() > 0 )
173		{
174			CString tmp = failMessage;
175			tmp += L"\n";
176			tmp += loadError;
177			return validationError( tmp, hr );
178		}
179		else
180			return validationError( failMessage, hr );
181	}
182
183	appState.source.path = path;
184	appState.source.impl = impl;
185	appState.saveModelSource();
186
187	EndDialog( IDOK );
188	return 0;
189}
190
191LRESULT LoadModelDlg::OnHyperlink( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
192{
193	const UINT code = pnmh->code;
194	switch( code )
195	{
196	case NM_CLICK:
197	case NM_RETURN:
198		break;
199	default:
200		return 0;
201	}
202
203	PNMLINK pNMLink = (PNMLINK)pnmh;
204	LPCTSTR url = pNMLink->item.szUrl;
205	ShellExecute( NULL, L"open", url, NULL, NULL, SW_SHOW );
206	bHandled = TRUE;
207	return 0;
208}
209
210void LoadModelDlg::onModelAdvanced()
211{
212	ModelAdvancedDlg dlg{ appState };
213	dlg.show( m_hWnd );
214}