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

KonstantinBugfix, C# language projectionb188f58

master
4.5 KiB110 linesraw
1using ComLight;
2using System.Runtime.InteropServices;
3using System.Runtime.Intrinsics.X86;
4using Whisper.Internal;
5
6namespace Whisper
7{
8	/// <summary>Factory methods implemented by the C++ DLL</summary>
9	public static class Library
10	{
11		static Library()
12		{
13			if( Environment.OSVersion.Platform != PlatformID.Win32NT )
14				throw new ApplicationException( "This library requires Windows OS" );
15			if( !Environment.Is64BitProcess )
16				throw new ApplicationException( "This library only works in 64-bit processes" );
17			if( RuntimeInformation.ProcessArchitecture != Architecture.X64 )
18				throw new ApplicationException( "This library requires a processor with AMD64 instruction set" );
19			if( !Sse41.IsSupported )
20				throw new ApplicationException( "This library requires a CPU with SSE 4.1 support" );
21			NativeLogger.startup();
22		}
23
24		const string dll = "Whisper.dll";
25
26		[DllImport( dll, CallingConvention = RuntimeClass.defaultCallingConvention, PreserveSig = false )]
27		internal static extern void setupLogger( [In] ref sLoggerSetup setup );
28
29		[DllImport( dll, CallingConvention = RuntimeClass.defaultCallingConvention, PreserveSig = true )]
30		static extern int loadModel( [MarshalAs( UnmanagedType.LPWStr )] string path, eModelImplementation impl, eGpuModelFlags flags,
31			[In] ref sLoadModelCallbacks callbacks,
32			[MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof( Marshaler<iModel> ) )] out iModel model );
33
34		/// <summary>Load Whisper model from GGML file on disk</summary>
35		/// <remarks>Models are large, depending on user’s disk speed this might take a while, and this function blocks the calling thread.<br/>
36		/// Consider <see cref="loadModelAsync" /> instead.</remarks>
37		/// <seealso href="https://huggingface.co/datasets/ggerganov/whisper.cpp" />
38		public static iModel loadModel( string path, eGpuModelFlags flags = eGpuModelFlags.None, eModelImplementation impl = eModelImplementation.GPU )
39		{
40			iModel model;
41			sLoadModelCallbacks callbacks = default;
42			NativeLogger.prologue();
43			int hr = loadModel( path, impl, flags, ref callbacks, out model );
44			NativeLogger.throwForHR( hr );
45			return model;
46		}
47
48		/// <summary>Load Whisper model on a background thread, with optional progress reporting and cancellation</summary>
49		public static Task<iModel> loadModelAsync( string path, CancellationToken cancelToken, eGpuModelFlags flags = eGpuModelFlags.None, Action<double>? pfnProgress = null, eModelImplementation impl = eModelImplementation.GPU )
50		{
51			TaskCompletionSource<iModel> tcs = new TaskCompletionSource<iModel>();
52
53			WaitCallback wcb = delegate ( object? state )
54			{
55				try
56				{
57					sLoadModelCallbacks callbacks = new sLoadModelCallbacks( cancelToken, pfnProgress );
58
59					iModel model;
60					NativeLogger.prologue();
61					int hr = loadModel( path, impl, flags, ref callbacks, out model );
62					NativeLogger.throwForHR( hr );
63
64					tcs.SetResult( model );
65				}
66				catch( Exception ex )
67				{
68					tcs.SetException( ex );
69				}
70			};
71
72			ThreadPool.QueueUserWorkItem( wcb );
73			return tcs.Task;
74		}
75
76		[DllImport( dll, CallingConvention = RuntimeClass.defaultCallingConvention, PreserveSig = true )]
77		static extern int initMediaFoundation( [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof( Marshaler<iMediaFoundation> ) )] out iMediaFoundation mf );
78
79		/// <summary>Initialize Media Foundation runtime</summary>
80		public static iMediaFoundation initMediaFoundation()
81		{
82			iMediaFoundation mf;
83			NativeLogger.prologue();
84			int hr = initMediaFoundation( out mf );
85			NativeLogger.throwForHR( hr );
86			return mf;
87		}
88
89		// The .NET runtime uses UTF-16 for the strings, so we only need the Unicode version of this function.
90		// The native DLL exports both Unicode and ASCII versions.
91		[DllImport( dll, CallingConvention = RuntimeClass.defaultCallingConvention, PreserveSig = true )]
92		static extern uint findLanguageKeyW( [MarshalAs( UnmanagedType.LPWStr )] string lang );
93
94		/// <summary>Try to resolve language code string like <c>"en"</c>, <c>"pl"</c> or <c>"uk"</c> into the strongly-typed enum.</summary>
95		/// <remarks>The function is case-sensitive, <c>"EN"</c> or <c>"UK"</c> gonna fail.</remarks>
96		public static eLanguage? languageFromCode( string lang )
97		{
98			uint key = findLanguageKeyW( lang );
99			if( key != uint.MaxValue )
100				return (eLanguage)key;
101			return null;
102		}
103
104		/// <summary>Set up delegate to receive log messages from the C++ library</summary>
105		public static void setLogSink( eLogLevel lvl, eLoggerFlags flags = eLoggerFlags.SkipFormatMessage, pfnLogMessage? pfn = null )
106		{
107			NativeLogger.setup( lvl, flags, pfn );
108		}
109	}
110}