summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Evaluate/.gitignore10
-rw-r--r--Evaluate/.swpbin0 -> 12288 bytes
-rw-r--r--Evaluate/README.md18
-rw-r--r--Evaluate/evaluate.py54
-rw-r--r--Evaluate/setup.ps118
-rw-r--r--Whisper/MF/AudioBuffer.h1
-rw-r--r--Whisper/Whisper/ContextImpl.cpp2
-rw-r--r--Whisper/WhisperCLI/WhisperCLI.cpp196
-rw-r--r--Whisper/WhisperCLI/WhisperCLI.vcxproj143
-rw-r--r--Whisper/WhisperCLI/WhisperCLI.vcxproj.filters22
-rw-r--r--WhisperCpp.sln65
11 files changed, 525 insertions, 4 deletions
diff --git a/Evaluate/.gitignore b/Evaluate/.gitignore
new file mode 100644
index 0000000..c6d2776
--- /dev/null
+++ b/Evaluate/.gitignore
@@ -0,0 +1,10 @@
+# models
+*.bin
+# audio
+*.mp3
+*.wav
+# reference transcripts
+*.txt
+# binaries
+*.exe
+*.dll
diff --git a/Evaluate/.swp b/Evaluate/.swp
new file mode 100644
index 0000000..c1bc460
--- /dev/null
+++ b/Evaluate/.swp
Binary files differ
diff --git a/Evaluate/README.md b/Evaluate/README.md
new file mode 100644
index 0000000..91038f6
--- /dev/null
+++ b/Evaluate/README.md
@@ -0,0 +1,18 @@
+## Evaluation tool
+
+This directory holds code to evaluate the accuracy of transcriptions.
+
+Example usage (in Powershell):
+```
+python3 -m pip install -r requirements.txt
+python3 evaluate.py reference_transcript.txt
+./setup.ps1
+./WhisperCLI.exe \
+ --audio_path *.mp3 \
+ --model_path *.bin
+```
+
+* setup.ps1: Downloads whisper checkpoints and audio from librivox. Copies
+ WhisperCLI.exe to CWD.
+* evaluate.py: Computes Levenshtein distance between generated transcription
+ and "correct" transcription.
diff --git a/Evaluate/evaluate.py b/Evaluate/evaluate.py
new file mode 100644
index 0000000..5e8c85d
--- /dev/null
+++ b/Evaluate/evaluate.py
@@ -0,0 +1,54 @@
+import argparse
+import editdistance
+import jiwer
+import re
+import subprocess
+import sys
+import time
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("reference_path", type=str, help="Path to reference transcript")
+ parser.add_argument("audio_path", type=str, help="Path to audio file to transcribe")
+ parser.add_argument("model_path", type=str, help="Path to Whisper model to use")
+ parser.add_argument("decode_method", type=str, help="Decoding method. Either 'greedy' or 'beam'")
+ args = parser.parse_args()
+
+ cmd = "./WhisperCLI.exe"
+ cmd_args = [
+ "--audio_path", args.audio_path,
+ "--model_path", args.model_path,
+ "--decode_method", args.decode_method,
+ ]
+
+ t0 = time.time()
+ result = subprocess.run([cmd] + cmd_args, stdout=subprocess.PIPE)
+ t1 = time.time()
+
+ if result.returncode != 0:
+ print(f"Failed to transcribe: cmd returned {result.returncode}",
+ file=sys.stderr)
+
+ test_transcript = result.stdout.decode("utf-8")
+ with open(args.reference_path, "r") as f:
+ ref_transcript = f.read()
+
+ dist = editdistance.eval(ref_transcript, test_transcript)
+ wer_transform = jiwer.Compose([
+ jiwer.ToLowerCase(),
+ jiwer.RemoveWhiteSpace(replace_by_space=True),
+ jiwer.RemoveMultipleSpaces(),
+ jiwer.RemovePunctuation(),
+ jiwer.ReduceToListOfListOfWords(word_delimiter=" "),
+ ])
+ wer = jiwer.wer(
+ ref_transcript,
+ test_transcript,
+ truth_transform=wer_transform,
+ hypothesis_transform=wer_transform)
+
+ print(f"Duration: {t1 - t0}")
+ print(f"Levenshtein distance: {dist}")
+ print(f"Word error rate: {wer}")
+ print(f"Transcript: {test_transcript}")
+
diff --git a/Evaluate/setup.ps1 b/Evaluate/setup.ps1
new file mode 100644
index 0000000..95e2487
--- /dev/null
+++ b/Evaluate/setup.ps1
@@ -0,0 +1,18 @@
+
+cp ../x64/Debug/WhisperCLI.exe .
+cp ../x64/Debug/Whisper.dll .
+
+$MODEL_URL = "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-medium.bin"
+$MODEL_FILE = $(Split-Path -Path $MODEL_URL -Leaf)
+if (-Not (Test-Path $MODEL_FILE)) {
+ echo "Fetch model"
+ Invoke-WebRequest $MODEL_URL -OutFile $MODEL_FILE
+}
+
+#$AUDIO_URL = "https://www.archive.org/download/usconstitution_1610_librivox/constitution_01_unitedstates_64kb.mp3"
+$AUDIO_URL = "https://www.archive.org/download/usconstitution_1610_librivox/constitution_02_unitedstates_128kb.mp3"
+$AUDIO_FILE = $(Split-Path -Path $AUDIO_URL -Leaf)
+if (-Not (Test-Path $AUDIO_FILE)) {
+ echo "Fetch audio"
+ Invoke-WebRequest $AUDIO_URL -OutFile $AUDIO_FILE
+}
diff --git a/Whisper/MF/AudioBuffer.h b/Whisper/MF/AudioBuffer.h
index 63c4a8c..11b5ead 100644
--- a/Whisper/MF/AudioBuffer.h
+++ b/Whisper/MF/AudioBuffer.h
@@ -47,7 +47,6 @@ namespace Whisper
void dropFirst(size_t len)
{
- assert(len <= mono.size());
if (len >= mono.size()) {
mono.clear();
return;
diff --git a/Whisper/Whisper/ContextImpl.cpp b/Whisper/Whisper/ContextImpl.cpp
index 4e384ca..22347cf 100644
--- a/Whisper/Whisper/ContextImpl.cpp
+++ b/Whisper/Whisper/ContextImpl.cpp
@@ -837,12 +837,10 @@ HRESULT COMLIGHTCALL ContextImpl::runFullImpl( const sFullParams& params, const
// in ascending order, we're always copying from old or
// identical data.
for (int nth_beam = 0; nth_beam < ctx_.size(); nth_beam++) {
-#if 0
// Trivial optimization: only copy if beams differ.
if (nth_beam == best_beams_and_tokens[nth_beam].first) {
continue;
}
-#endif
ctx_[nth_beam] = ctx_[best_beams_and_tokens[nth_beam].first];
}
diff --git a/Whisper/WhisperCLI/WhisperCLI.cpp b/Whisper/WhisperCLI/WhisperCLI.cpp
new file mode 100644
index 0000000..af0a59f
--- /dev/null
+++ b/Whisper/WhisperCLI/WhisperCLI.cpp
@@ -0,0 +1,196 @@
+#define WIN32_LEAN_AND_MEAN
+
+#include <Unknwn.h>
+#include <windows.h>
+
+#include "Whisper/API/whisperWindows.h"
+
+#include <iostream>
+#include <locale>
+#include <set>
+#include <string>
+#include <string_view>
+
+using std::cout;
+using std::cerr;
+using std::endl;
+using namespace Whisper;
+
+struct Config {
+ std::wstring audio_path = L"input.wav";
+ std::wstring model_path = L"model.bin";
+ eSamplingStrategy decode_method = eSamplingStrategy::BeamSearch;
+};
+
+bool hasArg(int argc, int shift, char* arg) {
+ if (shift + 1 >= argc) {
+ cerr << "Error: " << arg << " is missing argument" << endl;
+ return false;
+ }
+ return true;
+}
+
+std::wstring cstrToWstr(char* c_str) {
+ int length = MultiByteToWideChar(CP_UTF8, 0, c_str, -1, NULL, 0);
+ std::wstring result(length, 0);
+ MultiByteToWideChar(CP_UTF8, 0, c_str, -1, result.data(), result.size());
+ return result;
+}
+
+
+bool parseArgs(int argc, char* argv[], Config& c) {
+ int shift = 1;
+ while (shift < argc) {
+ if (std::string_view(argv[shift]) == "--audio_path") {
+ if (!hasArg(argc, shift, argv[shift])) {
+ return false;
+ }
+ c.audio_path = cstrToWstr(argv[shift + 1]);
+ shift += 2;
+ continue;
+ }
+ if (std::string_view(argv[shift]) == "--model_path") {
+ if (!hasArg(argc, shift, argv[shift])) {
+ return false;
+ }
+ c.model_path = cstrToWstr(argv[shift + 1]);
+ shift += 2;
+ continue;
+ }
+ if (std::string_view(argv[shift]) == "--decode_method") {
+ if (!hasArg(argc, shift, argv[shift])) {
+ return false;
+ }
+ std::string_view decode_method(argv[shift + 1]);
+ if (decode_method == "greedy") {
+ cerr << "Using greedy decode " << endl;
+ c.decode_method = eSamplingStrategy::Greedy;
+ }
+ else if (decode_method == "beam") {
+ cerr << "Using beam decode " << endl;
+ c.decode_method = eSamplingStrategy::BeamSearch;
+ }
+ else {
+ cerr << "Unsupported decode method: " << decode_method << endl;
+ return false;
+ }
+ shift += 2;
+ continue;
+ }
+ cerr << "Unrecognized argument: \"" << argv[shift] << '"' << endl;
+ return false;
+ }
+ return true;
+}
+
+int main(int argc, char* argv[])
+{
+ Config c;
+ if (!parseArgs(argc, argv, c)) {
+ cerr << "Failed to parse args";
+ return 1;
+ }
+
+ iMediaFoundation* f = nullptr;
+ HRESULT err = initMediaFoundation(&f);
+ if (FAILED(err)) {
+ cerr << "Failed to init media foundation: " << err << endl;
+ return 1;
+ }
+
+ Whisper::iAudioBuffer* buffer = nullptr;
+ err = f->loadAudioFile(c.audio_path.c_str(), /*stereo=*/false, &buffer);
+ if (FAILED(err)) {
+ cerr << "Failed to load audio file 'input.wav': " << err << endl;
+ return 1;
+ }
+
+ Whisper::iModel* model = nullptr;
+ err = Whisper::loadModel(c.model_path.c_str(), eModelImplementation::GPU, /*flags=*/0, /*callbacks=*/nullptr, &model);
+ if (FAILED(err)) {
+ cerr << "Failed to open model 'model.bin': " << err << endl;
+ return 1;
+ }
+
+ Whisper::iContext* context = nullptr;
+ err = model->createContext(&context);
+ if (FAILED(err)) {
+ cerr << "Failed to create context: " << err << endl;
+ return 1;
+ }
+
+ Whisper::sFullParams wparams{};
+ context->fullDefaultParams(c.decode_method, &wparams);
+ if (c.decode_method == eSamplingStrategy::BeamSearch) {
+ wparams.beam_search.beam_width = 5;
+ wparams.beam_search.n_best = 5;
+ }
+ wparams.language = Whisper::makeLanguageKey("en");
+ wparams.n_max_text_ctx = 100;
+
+ err = context->runFull(wparams, buffer);
+ if (FAILED(err)) {
+ cerr << "Failed to transcribe: " << err << endl;
+ return 1;
+ }
+
+ Whisper::iTranscribeResult* result = nullptr;
+ err = context->getResults(eResultFlags::Tokens, &result);
+ if (FAILED(err)) {
+ cerr << "Failed to get transcription results: " << err << endl;
+ return 1;
+ }
+
+ std::set<int> special_tokens;
+ {
+ Whisper::SpecialTokens st;
+ err = model->getSpecialTokens(st);
+ if (FAILED(err)) {
+ cerr << "Failed to get special tokens: " << err << endl;
+ }
+ special_tokens.insert(st.Not);
+ special_tokens.insert(st.PreviousWord);
+ special_tokens.insert(st.SentenceStart);
+ special_tokens.insert(st.TaskTranscribe);
+ special_tokens.insert(st.TaskTranslate);
+ special_tokens.insert(st.TranscriptionBegin);
+ special_tokens.insert(st.TranscriptionEnd);
+ special_tokens.insert(st.TranscriptionStart);
+ }
+
+ sTranscribeLength length;
+ err = result->getSize(length);
+ if (FAILED(err)) {
+ cerr << "Failed to get transcription length: " << err << endl;
+ }
+ auto* segments = result->getSegments();
+ auto* tokens = result->getTokens();
+ bool is_metadata = false;
+ for (int i = 0; i < length.countSegments; i++) {
+ auto& segment = segments[i];
+ for (int j = 0; j < segment.countTokens; j++) {
+ const sToken& tok = tokens[segment.firstToken + j];
+ if (special_tokens.contains(tok.id)) {
+ continue;
+ }
+ std::string_view tok_str(tok.text);
+ if (tok_str.starts_with("[") ||
+ tok_str.starts_with(" [")) {
+ if (tok_str.ends_with("]")) {
+ continue;
+ }
+ is_metadata = true;
+ continue;
+ }
+ if (is_metadata &&
+ tok_str.ends_with("]")) {
+ is_metadata = false;
+ continue;
+ }
+ cout << tok.text;
+ }
+ }
+ cout << endl;
+
+ return 0;
+} \ No newline at end of file
diff --git a/Whisper/WhisperCLI/WhisperCLI.vcxproj b/Whisper/WhisperCLI/WhisperCLI.vcxproj
new file mode 100644
index 0000000..8295eee
--- /dev/null
+++ b/Whisper/WhisperCLI/WhisperCLI.vcxproj
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>16.0</VCProjectVersion>
+ <Keyword>Win32Proj</Keyword>
+ <ProjectGuid>{b561d29f-be1d-4a4f-acfc-4d075cbc9108}</ProjectGuid>
+ <RootNamespace>WhisperCLI</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir);</IncludePath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir);</IncludePath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <LanguageStandard>stdcpp20</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies);$(OutDir)Whisper.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="WhisperCLI.cpp" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Whisper/WhisperCLI/WhisperCLI.vcxproj.filters b/Whisper/WhisperCLI/WhisperCLI.vcxproj.filters
new file mode 100644
index 0000000..34bd24e
--- /dev/null
+++ b/Whisper/WhisperCLI/WhisperCLI.vcxproj.filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="WhisperCLI.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/WhisperCpp.sln b/WhisperCpp.sln
index 84d9a2f..9f50842 100644
--- a/WhisperCpp.sln
+++ b/WhisperCpp.sln
@@ -43,60 +43,123 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Readme.md = Readme.md
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PerfSummary", "Tools\PerfSummary\PerfSummary.csproj", "{8AC301F0-FEC9-4F26-83DD-DB32969CD510}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerfSummary", "Tools\PerfSummary\PerfSummary.csproj", "{8AC301F0-FEC9-4F26-83DD-DB32969CD510}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WhisperCLI", "Whisper\WhisperCLI\WhisperCLI.vcxproj", "{B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}"
+ ProjectSection(ProjectDependencies) = postProject
+ {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71} = {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}
+ EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{52F486E7-830C-45D8-BE47-E76B5AAB2772}.Debug|x64.ActiveCfg = Debug|x64
{52F486E7-830C-45D8-BE47-E76B5AAB2772}.Debug|x64.Build.0 = Debug|x64
+ {52F486E7-830C-45D8-BE47-E76B5AAB2772}.Debug|x86.ActiveCfg = Debug|x64
+ {52F486E7-830C-45D8-BE47-E76B5AAB2772}.Debug|x86.Build.0 = Debug|x64
{52F486E7-830C-45D8-BE47-E76B5AAB2772}.Release|x64.ActiveCfg = Release|x64
{52F486E7-830C-45D8-BE47-E76B5AAB2772}.Release|x64.Build.0 = Release|x64
+ {52F486E7-830C-45D8-BE47-E76B5AAB2772}.Release|x86.ActiveCfg = Release|x64
+ {52F486E7-830C-45D8-BE47-E76B5AAB2772}.Release|x86.Build.0 = Release|x64
{701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Debug|x64.ActiveCfg = Debug|x64
{701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Debug|x64.Build.0 = Debug|x64
+ {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Debug|x86.ActiveCfg = Debug|x64
+ {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Debug|x86.Build.0 = Debug|x64
{701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Release|x64.ActiveCfg = Release|x64
{701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Release|x64.Build.0 = Release|x64
+ {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Release|x86.ActiveCfg = Release|x64
+ {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Release|x86.Build.0 = Release|x64
{1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Debug|x64.ActiveCfg = Debug|x64
{1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Debug|x64.Build.0 = Debug|x64
+ {1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Debug|x86.ActiveCfg = Debug|x64
+ {1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Debug|x86.Build.0 = Debug|x64
{1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Release|x64.ActiveCfg = Release|x64
{1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Release|x64.Build.0 = Release|x64
+ {1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Release|x86.ActiveCfg = Release|x64
+ {1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Release|x86.Build.0 = Release|x64
{F213558F-FEA2-4F66-A07F-69727E9EC81D}.Debug|x64.ActiveCfg = Debug|Any CPU
{F213558F-FEA2-4F66-A07F-69727E9EC81D}.Debug|x64.Build.0 = Debug|Any CPU
+ {F213558F-FEA2-4F66-A07F-69727E9EC81D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F213558F-FEA2-4F66-A07F-69727E9EC81D}.Debug|x86.Build.0 = Debug|Any CPU
{F213558F-FEA2-4F66-A07F-69727E9EC81D}.Release|x64.ActiveCfg = Release|Any CPU
{F213558F-FEA2-4F66-A07F-69727E9EC81D}.Release|x64.Build.0 = Release|Any CPU
+ {F213558F-FEA2-4F66-A07F-69727E9EC81D}.Release|x86.ActiveCfg = Release|Any CPU
+ {F213558F-FEA2-4F66-A07F-69727E9EC81D}.Release|x86.Build.0 = Release|Any CPU
{0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Debug|x64.ActiveCfg = Debug|x64
{0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Debug|x64.Build.0 = Debug|x64
+ {0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Debug|x86.ActiveCfg = Debug|x64
+ {0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Debug|x86.Build.0 = Debug|x64
{0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Release|x64.ActiveCfg = Release|x64
+ {0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Release|x86.ActiveCfg = Release|x64
+ {0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Release|x86.Build.0 = Release|x64
{596F9770-9AEB-49D3-86CA-4200197DF12B}.Debug|x64.ActiveCfg = Debug|x64
{596F9770-9AEB-49D3-86CA-4200197DF12B}.Debug|x64.Build.0 = Debug|x64
+ {596F9770-9AEB-49D3-86CA-4200197DF12B}.Debug|x86.ActiveCfg = Debug|x64
+ {596F9770-9AEB-49D3-86CA-4200197DF12B}.Debug|x86.Build.0 = Debug|x64
{596F9770-9AEB-49D3-86CA-4200197DF12B}.Release|x64.ActiveCfg = Release|x64
{596F9770-9AEB-49D3-86CA-4200197DF12B}.Release|x64.Build.0 = Release|x64
+ {596F9770-9AEB-49D3-86CA-4200197DF12B}.Release|x86.ActiveCfg = Release|x64
+ {596F9770-9AEB-49D3-86CA-4200197DF12B}.Release|x86.Build.0 = Release|x64
{4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Debug|x64.ActiveCfg = Debug|Any CPU
{4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Debug|x64.Build.0 = Debug|Any CPU
+ {4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Debug|x86.Build.0 = Debug|Any CPU
{4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Release|x64.ActiveCfg = Release|Any CPU
{4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Release|x64.Build.0 = Release|Any CPU
+ {4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Release|x86.ActiveCfg = Release|Any CPU
+ {4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Release|x86.Build.0 = Release|Any CPU
{4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Debug|x64.ActiveCfg = Debug|x64
{4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Debug|x64.Build.0 = Debug|x64
+ {4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Debug|x86.ActiveCfg = Debug|x64
+ {4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Debug|x86.Build.0 = Debug|x64
{4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Release|x64.ActiveCfg = Release|x64
{4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Release|x64.Build.0 = Release|x64
+ {4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Release|x86.ActiveCfg = Release|x64
+ {4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Release|x86.Build.0 = Release|x64
{A49305C0-7022-45A6-89B4-4BD33138C98A}.Debug|x64.ActiveCfg = Debug|x64
{A49305C0-7022-45A6-89B4-4BD33138C98A}.Debug|x64.Build.0 = Debug|x64
+ {A49305C0-7022-45A6-89B4-4BD33138C98A}.Debug|x86.ActiveCfg = Debug|x64
+ {A49305C0-7022-45A6-89B4-4BD33138C98A}.Debug|x86.Build.0 = Debug|x64
{A49305C0-7022-45A6-89B4-4BD33138C98A}.Release|x64.ActiveCfg = Release|x64
+ {A49305C0-7022-45A6-89B4-4BD33138C98A}.Release|x86.ActiveCfg = Release|x64
+ {A49305C0-7022-45A6-89B4-4BD33138C98A}.Release|x86.Build.0 = Release|x64
{8478A77C-D851-4C63-9511-1770CC82D33E}.Debug|x64.ActiveCfg = Debug|x64
{8478A77C-D851-4C63-9511-1770CC82D33E}.Debug|x64.Build.0 = Debug|x64
+ {8478A77C-D851-4C63-9511-1770CC82D33E}.Debug|x86.ActiveCfg = Debug|x64
+ {8478A77C-D851-4C63-9511-1770CC82D33E}.Debug|x86.Build.0 = Debug|x64
{8478A77C-D851-4C63-9511-1770CC82D33E}.Release|x64.ActiveCfg = Release|x64
{8478A77C-D851-4C63-9511-1770CC82D33E}.Release|x64.Build.0 = Release|x64
+ {8478A77C-D851-4C63-9511-1770CC82D33E}.Release|x86.ActiveCfg = Release|x64
+ {8478A77C-D851-4C63-9511-1770CC82D33E}.Release|x86.Build.0 = Release|x64
{CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Debug|x64.ActiveCfg = Debug|x64
{CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Debug|x64.Build.0 = Debug|x64
+ {CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Debug|x86.ActiveCfg = Debug|x64
+ {CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Debug|x86.Build.0 = Debug|x64
{CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Release|x64.ActiveCfg = Release|x64
{CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Release|x64.Build.0 = Release|x64
+ {CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Release|x86.ActiveCfg = Release|x64
+ {CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Release|x86.Build.0 = Release|x64
{8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Debug|x64.ActiveCfg = Debug|Any CPU
{8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Debug|x64.Build.0 = Debug|Any CPU
+ {8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Debug|x86.Build.0 = Debug|Any CPU
{8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Release|x64.ActiveCfg = Release|Any CPU
{8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Release|x64.Build.0 = Release|Any CPU
+ {8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Release|x86.ActiveCfg = Release|Any CPU
+ {8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Release|x86.Build.0 = Release|Any CPU
+ {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Debug|x64.ActiveCfg = Debug|x64
+ {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Debug|x64.Build.0 = Debug|x64
+ {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Debug|x86.ActiveCfg = Debug|Win32
+ {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Debug|x86.Build.0 = Debug|Win32
+ {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Release|x64.ActiveCfg = Release|x64
+ {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Release|x64.Build.0 = Release|x64
+ {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Release|x86.ActiveCfg = Release|Win32
+ {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE