From 4539f87e36cb3ca554e1e174c19206b552107c57 Mon Sep 17 00:00:00 2001 From: yum Date: Wed, 23 Jul 2025 22:53:08 -0700 Subject: Delete unused files --- GUI/.gitignore | 14 - GUI/GUI/.gitignore | 5 - GUI/GUI/GUI.sln | 31 - GUI/GUI/GUI/.gitignore | 9 - GUI/GUI/GUI/App.cpp | 11 - GUI/GUI/GUI/App.h | 13 - GUI/GUI/GUI/BrowserSource.cpp | 87 -- GUI/GUI/GUI/BrowserSource.h | 28 - GUI/GUI/GUI/Config.cpp | 230 ---- GUI/GUI/GUI/Config.h | 100 -- GUI/GUI/GUI/ConfigMarshal.h | 161 --- GUI/GUI/GUI/Frame.cpp | 2757 --------------------------------------- GUI/GUI/GUI/Frame.h | 134 -- GUI/GUI/GUI/GUI.rc | Bin 2798 -> 0 bytes GUI/GUI/GUI/GUI.vcxproj | 196 --- GUI/GUI/GUI/GUI.vcxproj.filters | 124 -- GUI/GUI/GUI/GUI.vcxproj.user | 13 - GUI/GUI/GUI/HTTPMapper.cpp | 69 - GUI/GUI/GUI/HTTPMapper.h | 35 - GUI/GUI/GUI/HTTPParser.cpp | 217 --- GUI/GUI/GUI/HTTPParser.h | 51 - GUI/GUI/GUI/Logging.cpp | 121 -- GUI/GUI/GUI/Logging.h | 50 - GUI/GUI/GUI/PythonWrapper.cpp | 894 ------------- GUI/GUI/GUI/PythonWrapper.h | 98 -- GUI/GUI/GUI/Resources/logo.ico | Bin 4314 -> 0 bytes GUI/GUI/GUI/ScopeGuard.h | 32 - GUI/GUI/GUI/Transcript.cpp | 44 - GUI/GUI/GUI/Transcript.h | 31 - GUI/GUI/GUI/Util.h | 20 - GUI/GUI/GUI/WebCommon.h | 8 - GUI/GUI/GUI/WebServer.cpp | 217 --- GUI/GUI/GUI/WebServer.h | 56 - GUI/GUI/GUI/main.cpp | 10 - GUI/GUI/GUI/resource.h | 15 - GUI/Libraries/.gitignore | 5 - GUI/Libraries/fetch.ps1 | 31 - GUI/README.md | 93 -- GUI/package.ps1 | 150 --- 39 files changed, 6160 deletions(-) delete mode 100644 GUI/.gitignore delete mode 100644 GUI/GUI/.gitignore delete mode 100644 GUI/GUI/GUI.sln delete mode 100644 GUI/GUI/GUI/.gitignore delete mode 100644 GUI/GUI/GUI/App.cpp delete mode 100644 GUI/GUI/GUI/App.h delete mode 100644 GUI/GUI/GUI/BrowserSource.cpp delete mode 100644 GUI/GUI/GUI/BrowserSource.h delete mode 100644 GUI/GUI/GUI/Config.cpp delete mode 100644 GUI/GUI/GUI/Config.h delete mode 100644 GUI/GUI/GUI/ConfigMarshal.h delete mode 100644 GUI/GUI/GUI/Frame.cpp delete mode 100644 GUI/GUI/GUI/Frame.h delete mode 100644 GUI/GUI/GUI/GUI.rc delete mode 100644 GUI/GUI/GUI/GUI.vcxproj delete mode 100644 GUI/GUI/GUI/GUI.vcxproj.filters delete mode 100644 GUI/GUI/GUI/GUI.vcxproj.user delete mode 100644 GUI/GUI/GUI/HTTPMapper.cpp delete mode 100644 GUI/GUI/GUI/HTTPMapper.h delete mode 100644 GUI/GUI/GUI/HTTPParser.cpp delete mode 100644 GUI/GUI/GUI/HTTPParser.h delete mode 100644 GUI/GUI/GUI/Logging.cpp delete mode 100644 GUI/GUI/GUI/Logging.h delete mode 100644 GUI/GUI/GUI/PythonWrapper.cpp delete mode 100644 GUI/GUI/GUI/PythonWrapper.h delete mode 100644 GUI/GUI/GUI/Resources/logo.ico delete mode 100644 GUI/GUI/GUI/ScopeGuard.h delete mode 100644 GUI/GUI/GUI/Transcript.cpp delete mode 100644 GUI/GUI/GUI/Transcript.h delete mode 100644 GUI/GUI/GUI/Util.h delete mode 100644 GUI/GUI/GUI/WebCommon.h delete mode 100644 GUI/GUI/GUI/WebServer.cpp delete mode 100644 GUI/GUI/GUI/WebServer.h delete mode 100644 GUI/GUI/GUI/main.cpp delete mode 100644 GUI/GUI/GUI/resource.h delete mode 100644 GUI/Libraries/.gitignore delete mode 100644 GUI/Libraries/fetch.ps1 delete mode 100644 GUI/README.md delete mode 100644 GUI/package.ps1 (limited to 'GUI') diff --git a/GUI/.gitignore b/GUI/.gitignore deleted file mode 100644 index 727e4ae..0000000 --- a/GUI/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# ignore generated package files -TaSTT -TaSTT.zip - -# ignore net-fetched dependencies -PortableGit* -Python* -python-* -UwwwuPP -Profanity -curl - -# Frequently created during development -freeze.txt diff --git a/GUI/GUI/.gitignore b/GUI/GUI/.gitignore deleted file mode 100644 index 7082b1d..0000000 --- a/GUI/GUI/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Don't check in build artifacts -x64 -x86 -# Ignore visual studio cruft -.vs diff --git a/GUI/GUI/GUI.sln b/GUI/GUI/GUI.sln deleted file mode 100644 index 5ef5534..0000000 --- a/GUI/GUI/GUI.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.4.33122.133 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GUI", "GUI\GUI.vcxproj", "{E17AD8B1-0565-459B-B8D0-2024CC6C5CD4}" -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 - {E17AD8B1-0565-459B-B8D0-2024CC6C5CD4}.Debug|x64.ActiveCfg = Debug|x64 - {E17AD8B1-0565-459B-B8D0-2024CC6C5CD4}.Debug|x64.Build.0 = Debug|x64 - {E17AD8B1-0565-459B-B8D0-2024CC6C5CD4}.Debug|x86.ActiveCfg = Debug|Win32 - {E17AD8B1-0565-459B-B8D0-2024CC6C5CD4}.Debug|x86.Build.0 = Debug|Win32 - {E17AD8B1-0565-459B-B8D0-2024CC6C5CD4}.Release|x64.ActiveCfg = Release|x64 - {E17AD8B1-0565-459B-B8D0-2024CC6C5CD4}.Release|x64.Build.0 = Release|x64 - {E17AD8B1-0565-459B-B8D0-2024CC6C5CD4}.Release|x86.ActiveCfg = Release|Win32 - {E17AD8B1-0565-459B-B8D0-2024CC6C5CD4}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {FA0FE5DA-8B30-47E0-9715-792C7CA1D5F8} - EndGlobalSection -EndGlobal diff --git a/GUI/GUI/GUI/.gitignore b/GUI/GUI/GUI/.gitignore deleted file mode 100644 index 75f9933..0000000 --- a/GUI/GUI/GUI/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -# Don't check in build artifacts -x64 -x86 -# No .rc generated files -GUI.APS -# No fetched files -ryml.h -whisper/ -oatpp/ diff --git a/GUI/GUI/GUI/App.cpp b/GUI/GUI/GUI/App.cpp deleted file mode 100644 index 94a01a4..0000000 --- a/GUI/GUI/GUI/App.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "App.h" -#include "Frame.h" - -bool MyApp::OnInit() -{ - Frame* frame = new Frame(); - - frame->Show(true); - - return true; -} diff --git a/GUI/GUI/GUI/App.h b/GUI/GUI/GUI/App.h deleted file mode 100644 index fe6eeec..0000000 --- a/GUI/GUI/GUI/App.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -#ifndef WX_PRECOMP -#include -#endif - -class MyApp : public wxApp -{ -public: - virtual bool OnInit(); -}; diff --git a/GUI/GUI/GUI/BrowserSource.cpp b/GUI/GUI/GUI/BrowserSource.cpp deleted file mode 100644 index fce1bee..0000000 --- a/GUI/GUI/GUI/BrowserSource.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "BrowserSource.h" -#include "Logging.h" -#include "ScopeGuard.h" -#include "WebCommon.h" -#include "WebServer.h" - -using ::Logging::Log; - -BrowserSource::BrowserSource(uint16_t port, wxTextCtrl *out, Transcript *transcript) - : port_(port), out_(out), transcript_(transcript) -{} - -void BrowserSource::Run(volatile bool* run) -{ - WebServer::WebServer ws(out_, port_); - - ws.RegisterPathHandler("GET", "/", - [&](int& status_code, std::string& payload, - WebServer::ContentType& type) -> void { - auto html_path = std::filesystem::path("Resources/BrowserSource/index.html"); - - std::ifstream html_ifs(html_path); - std::vector resp(4096 * 16, 0); - html_ifs.read(resp.data(), resp.size()); - - std::string html(resp.data()); - resp.clear(); - - size_t pos = 0; - std::string key = "%PORT%"; - std::string value = std::to_string(port_); - while ((pos = html.find("%PORT%", pos)) != std::string::npos) { - html.replace(pos, key.size(), value); - pos += value.size(); - } - - status_code = 200; - payload = html; - type = WebServer::HTML; - }); - - ws.RegisterPathHandler("GET", "/api/transcript", - [&](int& status_code, std::string& payload, - WebServer::ContentType& type) -> void { - status_code = 200; - - std::ostringstream transcript_oss; - std::vector transcript = transcript_->Get(); - // Hack: escape transcription to work inside JSON blob. - for (auto& segment : transcript) { - size_t pos; - while ((pos = segment.find('"')) != std::string::npos) { - segment[pos] = '\''; - } - transcript_oss << segment; - } - - std::ostringstream preview_oss; - std::vector preview = transcript_->GetPreview(); - // Hack: escape transcription to work inside JSON blob. - for (auto& segment : preview) { - size_t pos; - while ((pos = segment.find('"')) != std::string::npos) { - segment[pos] = '\''; - } - preview_oss << segment; - } - - bool is_final = transcript_->IsFinalized(); - - std::ostringstream resp_oss; - resp_oss << "{"; - resp_oss << "\"transcript\":\"" << transcript_oss.str() << "\","; - resp_oss << "\"preview\":\"" << preview_oss.str() << "\","; - resp_oss << "\"is_final\":" << std::to_string(is_final ? 1 : 0) << ""; - resp_oss << "}"; - payload = resp_oss.str(); - type = WebServer::JSON; - - //Log(out_, "Serving transcript to port {}: {}\n", port_, transcript_oss.str()); - }); - - if (!ws.Run(run)) { - Log(out_, "Failed to launch browser source!\n"); - } - return; -} diff --git a/GUI/GUI/GUI/BrowserSource.h b/GUI/GUI/GUI/BrowserSource.h deleted file mode 100644 index fe732ba..0000000 --- a/GUI/GUI/GUI/BrowserSource.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -#ifndef WX_PRECOMP -#include -#endif - -#include "Transcript.h" - -#include - -#include -#include - -class BrowserSource -{ -public: - BrowserSource(uint16_t port, wxTextCtrl *out, Transcript *transcript); - - void Run(volatile bool* run); - -private: - const uint16_t port_; - wxTextCtrl* const out_; - Transcript* const transcript_; -}; - diff --git a/GUI/GUI/GUI/Config.cpp b/GUI/GUI/GUI/Config.cpp deleted file mode 100644 index 948b1af..0000000 --- a/GUI/GUI/GUI/Config.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#include - -#ifndef WX_PRECOMP -#include -#endif - -#include "Config.h" -#include "ConfigMarshal.h" -#include "Logging.h" - -#include -#include -#include - -using ::Logging::Log; - -bool Config::Serialize(const std::filesystem::path& path, - const ConfigMarshal& cm) { - // If there's an old config, delete it. - struct stat tmpstat; - if (stat(path.string().c_str(), &tmpstat) == 0) { - if (::_unlink(path.string().c_str())) { - Log(out_, "Failed to delete old config at {}: {}\n", - path.string().c_str(), strerror(errno)); - return false; - } - } - - // Write the config to a tmp file. If we crash in the middle of this, it - // doesn't matter, since the next process will just overwrite it. - std::filesystem::path tmp_path = path; - - if (stat(tmp_path.string().c_str(), &tmpstat) == 0) { - if (::_unlink(tmp_path.string().c_str())) { - Log(out_, "Failed to delete old tmp config at {}: {}\n", - tmp_path.string().c_str(), strerror(errno)); - return false; - } - } - - if (!cm.Save(tmp_path)) { - Log(out_, "Failed to save config to {}\n", tmp_path.string()); - return false; - } - - // File renames within the same filesystem are atomic, so there's no risk - // of leaving a corrupt file on disk. - if (rename(tmp_path.string().c_str(), path.string().c_str()) != 0) { - Log(out_, "Failed to save config to {}: {}\n", path.string().c_str(), - strerror(errno)); - return false; - } - - return true; -} - -bool Config::Deserialize(const std::filesystem::path& path, - ConfigMarshal& cm) { - return cm.Load(path); -} - -AppConfig::AppConfig(wxTextCtrl* out) - : Config(out), - - microphone("index"), - language("english"), - language_target("Do not translate"), - model("small.en"), - model_translation("nllb-200-distilled-600M"), - button("left joystick"), - prio("normal"), - compute_type("float16"), - - enable_local_beep(true), - enable_orig_lang(true), - enable_browser_src(false), - browser_src_port(8097), - commit_fuzz_threshold(4), - use_cpu(false), - use_flash_attention(false), - use_builtin(true), - enable_uwu_filter(false), - remove_trailing_period(false), - enable_uppercase_filter(false), - enable_lowercase_filter(false), - enable_profanity_filter(false), - enable_debug_mode(false), - reset_on_toggle(true), - enable_previews(true), - enable_lock_at_spawn(true), - gpu_idx(0), - min_silence_duration_ms(250), - max_speech_duration_s(10), - reset_after_silence_s(15), - transcription_loop_delay_ms(100), - keybind("ctrl+x"), - - chars_per_sync(10), - bytes_per_char(1), - rows(4), - cols(40), - texture_sz(512), - - assets_path(), - fx_path(), - params_path(), - menu_path(), - unity_generated_dir("TaSTT_Generated"), - clear_osc(true), - enable_phonemes(false) -{} - -bool AppConfig::Serialize(const std::filesystem::path& path) { - ConfigMarshal cm(out_); - - cm.Set("microphone", microphone); - cm.Set("language", language); - cm.Set("language_target", language_target); - cm.Set("model", model); - cm.Set("model_translation", model_translation); - cm.Set("button", button); - cm.Set("prio", prio); - cm.Set("compute_type", compute_type); - - cm.Set("enable_local_beep", enable_local_beep); - cm.Set("enable_orig_lang", enable_orig_lang); - cm.Set("enable_browser_src", enable_browser_src); - cm.Set("browser_src_port", browser_src_port); - cm.Set("commit_fuzz_threshold", commit_fuzz_threshold); - cm.Set("use_cpu", use_cpu); - cm.Set("use_flash_attention", use_flash_attention); - cm.Set("use_builtin", use_builtin); - cm.Set("enable_uwu_filter", enable_uwu_filter); - cm.Set("remove_trailing_period", remove_trailing_period); - cm.Set("enable_uppercase_filter", enable_uppercase_filter); - cm.Set("enable_lowercase_filter", enable_lowercase_filter); - cm.Set("enable_profanity_filter", enable_profanity_filter); - cm.Set("enable_debug_mode", enable_debug_mode); - cm.Set("reset_on_toggle", reset_on_toggle); - cm.Set("enable_previews", enable_previews); - cm.Set("enable_lock_at_spawn", enable_lock_at_spawn); - cm.Set("gpu_idx", gpu_idx); - cm.Set("min_silence_duration_ms", min_silence_duration_ms); - cm.Set("max_speech_duration_s", max_speech_duration_s); - cm.Set("reset_after_silence_s", reset_after_silence_s); - cm.Set("transcription_loop_delay_ms", transcription_loop_delay_ms); - cm.Set("keybind", keybind); - - cm.Set("chars_per_sync", chars_per_sync); - cm.Set("bytes_per_char", bytes_per_char); - cm.Set("rows", rows); - cm.Set("cols", cols); - cm.Set("texture_sz", texture_sz); - - cm.Set("assets_path", assets_path); - cm.Set("fx_path", fx_path); - cm.Set("params_path", params_path); - cm.Set("menu_path", menu_path); - cm.Set("unity_generated_dir", unity_generated_dir); - cm.Set("clear_osc", clear_osc); - cm.Set("enable_phonemes", enable_phonemes); - - return Config::Serialize(path, cm); -} - -bool AppConfig::Deserialize(const std::filesystem::path& path) { - std::error_code err; - if (!std::filesystem::exists(path, err)) { - *this = AppConfig(out_); - return true; - } - - ConfigMarshal cm(out_); - if (!Config::Deserialize(path, cm)) { - Log(out_, "Deserialization failed at {}\n", path.string()); - return false; - } - - AppConfig c(out_); - cm.Get("microphone", c.microphone); - cm.Get("language", c.language); - cm.Get("language_target", c.language_target); - cm.Get("model", c.model); - cm.Get("model_translation", c.model_translation); - cm.Get("button", c.button); - cm.Get("prio", c.prio); - cm.Get("compute_type", c.compute_type); - - cm.Get("enable_local_beep", c.enable_local_beep); - cm.Get("enable_orig_lang", c.enable_orig_lang); - cm.Get("enable_browser_src", c.enable_browser_src); - cm.Get("browser_src_port", c.browser_src_port); - cm.Get("commit_fuzz_threshold", c.commit_fuzz_threshold); - cm.Get("use_cpu", c.use_cpu); - cm.Get("use_flash_attention", c.use_flash_attention); - cm.Get("use_builtin", c.use_builtin); - cm.Get("enable_uwu_filter", c.enable_uwu_filter); - cm.Get("remove_trailing_period", c.remove_trailing_period); - cm.Get("enable_uppercase_filter", c.enable_uppercase_filter); - cm.Get("enable_lowercase_filter", c.enable_lowercase_filter); - cm.Get("enable_profanity_filter", c.enable_profanity_filter); - cm.Get("enable_debug_mode", c.enable_debug_mode); - cm.Get("reset_on_toggle", c.reset_on_toggle); - cm.Get("enable_previews", c.enable_previews); - cm.Get("enable_lock_at_spawn", c.enable_lock_at_spawn); - cm.Get("gpu_idx", c.gpu_idx); - cm.Get("min_silence_duration_ms", c.min_silence_duration_ms); - cm.Get("max_speech_duration_s", c.max_speech_duration_s); - cm.Get("reset_after_silence_s", c.reset_after_silence_s); - cm.Get("transcription_loop_delay_ms", c.transcription_loop_delay_ms); - cm.Get("keybind", c.keybind); - - cm.Get("chars_per_sync", c.chars_per_sync); - cm.Get("bytes_per_char", c.bytes_per_char); - cm.Get("rows", c.rows); - cm.Get("cols", c.cols); - cm.Get("texture_sz", c.texture_sz); - - cm.Get("assets_path", c.assets_path); - cm.Get("fx_path", c.fx_path); - cm.Get("params_path", c.params_path); - cm.Get("menu_path", c.menu_path); - cm.Get("unity_generated_dir", c.unity_generated_dir); - cm.Get("clear_osc", c.clear_osc); - cm.Get("enable_phonemes", c.enable_phonemes); - - *this = std::move(c); - return true; -} - diff --git a/GUI/GUI/GUI/Config.h b/GUI/GUI/GUI/Config.h deleted file mode 100644 index 48b49a2..0000000 --- a/GUI/GUI/GUI/Config.h +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once - -#include - -#ifndef WX_PRECOMP -#include -#endif - -#include "ConfigMarshal.h" - -#include - -// Represents a disk-backed configuration. Knows how to save to disk -// (Serialize) and restore from disk (Deserialize). -class Config { -public: - Config(wxTextCtrl* out) : out_(out) {} - - virtual ~Config() {} - - virtual bool Serialize(const std::filesystem::path& path) = 0; - - virtual bool Deserialize(const std::filesystem::path& path) = 0; - -protected: - virtual bool Serialize(const std::filesystem::path& path, - const ConfigMarshal& cm); - - virtual bool Deserialize(const std::filesystem::path& path, - ConfigMarshal& cm); - - wxTextCtrl* out_; -}; - -// Represents the configurable fields for the GUI. Used by both the -// Transcription panel and the Unity panel. -class AppConfig : public Config { -public: - virtual ~AppConfig() {} - - AppConfig(wxTextCtrl* out); - - bool Serialize(const std::filesystem::path& path) override; - - bool Deserialize(const std::filesystem::path& path) override; - - // The default path at which configs are serialized. - static constexpr char kConfigPath[] = "Resources/app_config.yml"; - - // Transcription-specific settings. - std::string microphone; - std::string language; - std::string language_target; - std::string model; - std::string model_translation; - std::string button; - std::string prio; - std::string compute_type; - - bool enable_local_beep; - bool enable_orig_lang; - bool enable_browser_src; - int browser_src_port; - int commit_fuzz_threshold; - bool use_cpu; - bool use_flash_attention; - bool use_builtin; - bool enable_uwu_filter; - bool remove_trailing_period; - bool enable_uppercase_filter; - bool enable_lowercase_filter; - bool enable_profanity_filter; - bool enable_debug_mode; - bool reset_on_toggle; - bool enable_previews; - bool enable_lock_at_spawn; - int gpu_idx; - int min_silence_duration_ms; - int max_speech_duration_s; - int reset_after_silence_s; - int transcription_loop_delay_ms; - std::string keybind; - - // Unity and transcription shared settings. - int chars_per_sync; - int bytes_per_char; - int rows; - int cols; - int texture_sz; - - // Unity-specific settings. - std::string assets_path; - std::string fx_path; - std::string params_path; - std::string menu_path; - std::string unity_generated_dir; - bool clear_osc; - bool enable_phonemes; -}; - diff --git a/GUI/GUI/GUI/ConfigMarshal.h b/GUI/GUI/GUI/ConfigMarshal.h deleted file mode 100644 index 0f40ed4..0000000 --- a/GUI/GUI/GUI/ConfigMarshal.h +++ /dev/null @@ -1,161 +0,0 @@ -#pragma once - -#include - -#ifndef WX_PRECOMP -#include -#endif - -#include "Logging.h" - -#include -#include -#include -#include -#include -#include - -class ConfigMarshal -{ -public: - ConfigMarshal(wxTextCtrl* const out) - : out_(out) - {} - - bool Save(const std::filesystem::path& path) const { - std::ostringstream oss; - for (const auto& [k, v] : kv_str_) { - oss << k << ": " << v << std::endl; - } - for (const auto& [k, v] : kv_int_) { - oss << k << ": " << std::to_string(v) << std::endl; - } - for (const auto& [k, v] : kv_float_) { - oss << k << ": " << std::to_string(v) << std::endl; - } - - std::ofstream ofs(path.string()); - ofs << oss.str(); - ofs.close(); - - return true; - } - - bool Load(const std::filesystem::path& path) { - std::ifstream ifs(path.string()); - std::string line; - while (std::getline(ifs, line)) { - int n_words = 0; - - std::string delim = ": "; - size_t delim_pos = line.find(delim, 0); - if (delim_pos == std::string::npos) { - Logging::Log(out_, "Invalid config file: line {} has no delimiter\n", line); - return false; - } - std::string key = line.substr(0, delim_pos); - std::string val = line.substr(delim_pos + delim.length()); - - try { - size_t pos; - int val_i = std::stoi(val, &pos); - if (pos == val.length()) { - // The entire value is an int -> interpret as an int. Corollary: users - // can't store ints as strings! - kv_int_[key] = val_i; - continue; - } - } - catch (const std::invalid_argument&) {} - catch (const std::out_of_range&) {} - - try { - size_t pos; - float val_f = std::stof(val, &pos); - if (pos == val.length()) { - // The entire value is a float -> interpret as a float. Corollary: users - // can't store floats as strings! - kv_float_[key] = val_f; - continue; - } - } - catch (const std::invalid_argument&) {} - catch (const std::out_of_range&) {} - - kv_str_[key] = val; - } - return true; - } - - template - bool Set(const std::string& key, const T& value) { - if constexpr (std::is_same_v) { - kv_str_[key] = value; - return true; - } - if constexpr (std::is_same_v || std::is_same_v) { - kv_int_[key] = static_cast(value); - return true; - } - if constexpr (std::is_same_v) { - kv_float_[key] = value; - return true; - } - Logging::Log(out_, "ConfigMarshal unsupported type: {}\n", typeid(T).name()); - return false; - } - - template - bool Get(const std::string& key, T& value) const { - if constexpr (std::is_same_v) { - auto iter = kv_str_.find(key); - if (iter == kv_str_.end()) { - // Edge case: string may be represented entirely as an int, so - // it was parsed out as an int. - auto iter = kv_int_.find(key); - if (iter == kv_int_.end()) { - Logging::Log(out_, "Config contains no field named `{}`\n", key); - return false; - } - value = std::to_string(iter->second); - return true; - } - value = iter->second; - return true; - } - if constexpr (std::is_same_v) { - auto iter = kv_float_.find(key); - if (iter == kv_float_.end()) { - Logging::Log(out_, "Config contains no field named `{}`\n", key); - return false; - } - value = iter->second; - return true; - } - if constexpr (std::is_same_v || std::is_same_v) { - auto iter = kv_int_.find(key); - if (iter == kv_int_.end()) { - Logging::Log(out_, "Config contains no field named `{}`\n", key); - return false; - } - if constexpr (std::is_same_v) { - if (iter->second < 0 || iter->second > 1) { - Logging::Log(out_, "Config field {} is out of boolean range: {}\n", key, iter->second); - return false; - } - } - value = static_cast(iter->second); - return true; - } - Logging::Log(out_, "ConfigMarshal unsupported type: {}\n", typeid(T).name()); - return false; - } - - -private: - wxTextCtrl* out_; - - std::map kv_str_; - std::map kv_int_; - std::map kv_float_; -}; diff --git a/GUI/GUI/GUI/Frame.cpp b/GUI/GUI/GUI/Frame.cpp deleted file mode 100644 index 697e18a..0000000 --- a/GUI/GUI/GUI/Frame.cpp +++ /dev/null @@ -1,2757 +0,0 @@ -#include "BrowserSource.h" -#include "Frame.h" -#include "Logging.h" -#include "PythonWrapper.h" -#include "ScopeGuard.h" -#include "Util.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Does `lhs_type lhs = rhs`, where rhs returns `std::optional`. -// If the optional doesn't return a value, this returns. -// TODO(yum) do this without creating a named temporary. -// Example: -// ASSIGN_OR_RETURN(int, foo, 1) -#define ASSIGN_OR_RETURN_VOID(lhs_type, lhs, rhs) \ - std::optional lhs ## _tmp = rhs; \ - if (!lhs ## _tmp.has_value()) return; \ - lhs_type lhs = std::move(lhs ## _tmp).value() - -#define ASSIGN_OR_RETURN_BOOL(lhs_type, lhs, rhs) \ - std::optional lhs ## _tmp = rhs; \ - if (!lhs ## _tmp.has_value()) return false; \ - lhs_type lhs = std::move(lhs ## _tmp).value() - -using ::Logging::DrainAsyncOutput; -using ::Logging::Log; - -namespace { - enum FrameIds { - ID_MAIN_PANEL, - ID_NAVBAR, - ID_NAVBAR_BUTTON_TRANSCRIBE, - ID_NAVBAR_BUTTON_UNITY, - ID_NAVBAR_BUTTON_DEBUG, - ID_PY_PANEL, - ID_PY_CONFIG_PANEL, - ID_PY_APP_CONFIG_PANEL_PAIRS, - ID_PY_DUMP_MICS_BUTTON, - ID_PY_APP_DRAIN, - ID_PY_APP_START_BUTTON, - ID_PY_APP_STOP_BUTTON, - ID_TRANSCRIBE_OUT, - ID_PY_APP_MIC, - ID_PY_APP_MIC_PANEL, - ID_PY_APP_LANG, - ID_PY_APP_TRANSLATE_TARGET, - ID_PY_APP_LANG_PANEL, - ID_PY_APP_MODEL, - ID_PY_APP_MODEL_TRANSLATION, - ID_PY_APP_CHARS_PER_SYNC, - ID_PY_APP_BYTES_PER_CHAR, - ID_PY_APP_BUTTON, - ID_PY_APP_PRIO, - ID_PY_APP_COMPUTE_TYPE, - ID_PY_APP_MODEL_PANEL, - ID_PY_APP_ENABLE_LOCAL_BEEP, - ID_PY_APP_ENABLE_ORIG_LANG, - ID_PY_APP_ENABLE_BROWSER_SRC, - ID_PY_APP_USE_CPU, - ID_PY_APP_USE_BUILTIN, - ID_PY_APP_ENABLE_UWU_FILTER, - ID_PY_APP_REMOVE_TRAILING_PERIOD, - ID_PY_APP_ENABLE_UPPERCASE_FILTER, - ID_PY_APP_ENABLE_LOWERCASE_FILTER, - ID_PY_APP_ENABLE_PROFANITY_FILTER, - ID_PY_APP_ENABLE_DEBUG_MODE, - ID_PY_APP_RESET_ON_TOGGLE, - ID_PY_APP_ENABLE_PREVIEWS, - ID_PY_APP_ENABLE_LOCK_AT_SPAWN, - ID_PY_APP_ROWS, - ID_PY_APP_COLS, - ID_PY_APP_GPU_IDX, - ID_PY_APP_MIN_SILENCE_DURATION_MS, - ID_PY_APP_MAX_SPEECH_DURATION_S, - ID_PY_APP_RESET_AFTER_SILENCE_S, - ID_PY_APP_TRANSCRIPTION_LOOP_DELAY_MS, - ID_PY_APP_KEYBIND, - ID_PY_APP_BROWSER_SRC_PORT, - ID_PY_APP_COMMIT_FUZZ_THRESHOLD, - ID_UNITY_PANEL, - ID_UNITY_CONFIG_PANEL, - ID_UNITY_OUT, - ID_UNITY_ASSETS_FILE_PICKER, - ID_UNITY_ANIMATOR_FILE_PICKER, - ID_UNITY_PARAMETERS_FILE_PICKER, - ID_UNITY_MENU_FILE_PICKER, - ID_UNITY_CONFIG_PANEL_PAIRS, - ID_UNITY_ANIMATOR_GENERATED_DIR, - ID_UNITY_ANIMATOR_GENERATED_NAME, - ID_UNITY_PARAMETERS_GENERATED_NAME, - ID_UNITY_MENU_GENERATED_NAME, - ID_UNITY_BUTTON_GEN_ANIMATOR, - ID_UNITY_BUTTON_AUTO_REFRESH, - ID_UNITY_BUTTON_AUTO_REFRESH_STOP, - ID_UNITY_CHARS_PER_SYNC, - ID_UNITY_BYTES_PER_CHAR, - ID_UNITY_ROWS, - ID_UNITY_COLS, - ID_UNITY_TEXTURE_SZ, - ID_UNITY_CLEAR_OSC, - ID_UNITY_ENABLE_PHONEMES, - ID_DEBUG_PANEL, - ID_DEBUG_OUT, - ID_DEBUG_CONFIG_PANEL, - ID_DEBUG_BUTTON_CLEAR_PIP, - ID_DEBUG_BUTTON_LIST_PIP, - ID_DEBUG_BUTTON_RESET_VENV, - ID_DEBUG_BUTTON_CLEAR_OSC, - ID_DEBUG_BUTTON_BACKUP_VENV, - ID_DEBUG_BUTTON_RESTORE_VENV, - ID_DEBUG_BUTTON_SETUP_VENV, - }; - - const wxString kMicChoices[] = { - "index", - "beyond", - "focusrite", - "motu", - // ok now this is epic - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "15", - "16", - "17", - "18", - "19", - }; - const size_t kNumMicChoices = sizeof(kMicChoices) / sizeof(kMicChoices[0]); - constexpr int kMicDefault = 0; // index - - // lifted from whisper/tokenizer.py - const wxString kLangChoices[] = { - "english", - "afrikaans", - "albanian", - "amharic", - "arabic", - "armenian", - "assamese", - "azerbaijani", - "bashkir", - "basque", - "belarusian", - "bengali", - "bosnian", - "breton", - "bulgarian", - "catalan", - "chinese", - "croatian", - "czech", - "danish", - "dutch", - "estonian", - "faroese", - "finnish", - "french", - "galician", - "georgian", - "german", - "greek", - "gujarati", - "haitian creole", - "hausa", - "hawaiian", - "hebrew", - "hindi", - "hungarian", - "icelandic", - "indonesian", - "italian", - "japanese", - "javanese", - "kannada", - "kazakh", - "khmer", - "korean", - "lao", - "latin", - "latvian", - "lingala", - "lithuanian", - "luxembourgish", - "macedonian", - "malagasy", - "malay", - "malayalam", - "maltese", - "maori", - "marathi", - "mongolian", - "myanmar", - "nepali", - "norwegian", - "nynorsk", - "occitan", - "pashto", - "persian", - "polish", - "portuguese", - "punjabi", - "romanian", - "russian", - "sanskrit", - "serbian", - "shona", - "sindhi", - "sinhala", - "slovak", - "slovenian", - "somali", - "spanish", - "sundanese" - "swahili", - "swedish", - "tagalog", - "tajik", - "tamil", - "tatar", - "telugu", - "thai", - "tibetan", - "turkish", - "turkmen", - "ukrainian", - "urdu", - "uzbek", - "vietnamese", - "welsh", - "yiddish", - "yoruba", - }; - const size_t kNumLangChoices = sizeof(kLangChoices) / sizeof(kLangChoices[0]); - constexpr int kLangDefault = 0; // english - - const wxString kLangTargetChoices[] = { - "Do not translate", - "Acehnese(Arabic script) | ace_Arab", - "Acehnese(Latin script) | ace_Latn", - "Afrikaans | afr_Latn", - "Akan | aka_Latn", - "Amharic | amh_Ethi", - "Armenian | hye_Armn", - "Assamese | asm_Beng", - "Asturian | ast_Latn", - "Awadhi | awa_Deva", - "Ayacucho Quechua | quy_Latn", - "Balinese | ban_Latn", - "Bambara | bam_Latn", - "Banjar(Arabic script) | bjn_Arab", - "Banjar(Latin script) | bjn_Latn", - "Bashkir | bak_Cyrl", - "Basque | eus_Latn", - "Belarusian | bel_Cyrl", - "Bemba | bem_Latn", - "Bengali | ben_Beng", - "Bhojpuri | bho_Deva", - "Bosnian | bos_Latn", - "Buginese | bug_Latn", - "Bulgarian | bul_Cyrl", - "Burmese | mya_Mymr", - "Catalan | cat_Latn", - "Cebuano | ceb_Latn", - "Central Atlas Tamazight | tzm_Tfng", - "Central Aymara | ayr_Latn", - "Central Kanuri(Arabic script) | knc_Arab", - "Central Kanuri(Latin script) | knc_Latn", - "Central Kurdish | ckb_Arab", - "Chhattisgarhi | hne_Deva", - "Chinese(Simplified) | zho_Hans", - "Chinese(Traditional) | zho_Hant", - "Chokwe | cjk_Latn", - "Crimean Tatar | crh_Latn", - "Croatian | hrv_Latn", - "Czech | ces_Latn", - "Danish | dan_Latn", - "Dari | prs_Arab", - "Dutch | nld_Latn", - "Dyula | dyu_Latn", - "Dzongkha | dzo_Tibt", - "Eastern Panjabi | pan_Guru", - "Eastern Yiddish | ydd_Hebr", - "Egyptian Arabic | arz_Arab", - "English | eng_Latn", - "Esperanto | epo_Latn", - "Estonian | est_Latn", - "Ewe | ewe_Latn", - "Faroese | fao_Latn", - "Fijian | fij_Latn", - "Finnish | fin_Latn", - "Fon | fon_Latn", - "French | fra_Latn", - "Friulian | fur_Latn", - "Galician | glg_Latn", - "Ganda | lug_Latn", - "Georgian | kat_Geor", - "German | deu_Latn", - "Greek | ell_Grek", - "Guarani | grn_Latn", - "Gujarati | guj_Gujr", - "Haitian Creole | hat_Latn", - "Halh Mongolian | khk_Cyrl", - "Hausa | hau_Latn", - "Hebrew | heb_Hebr", - "Hindi | hin_Deva", - "Hungarian | hun_Latn", - "Icelandic | isl_Latn", - "Igbo | ibo_Latn", - "Ilocano | ilo_Latn", - "Indonesian | ind_Latn", - "Irish | gle_Latn", - "Italian | ita_Latn", - "Japanese | jpn_Jpan", - "Javanese | jav_Latn", - "Jingpho | kac_Latn", - "Kabiyè | kbp_Latn", - "Kabuverdianu | kea_Latn", - "Kabyle | kab_Latn", - "Kamba | kam_Latn", - "Kannada | kan_Knda", - "Kashmiri(Arabic script) | kas_Arab", - "Kashmiri(Devanagari script) | kas_Deva", - "Kazakh | kaz_Cyrl", - "Khmer | khm_Khmr", - "Kikongo | kon_Latn", - "Kikuyu | kik_Latn", - "Kimbundu | kmb_Latn", - "Kinyarwanda | kin_Latn", - "Korean | kor_Hang", - "Kyrgyz | kir_Cyrl", - "Lao | lao_Laoo", - "Latgalian | ltg_Latn", - "Ligurian | lij_Latn", - "Limburgish | lim_Latn", - "Lingala | lin_Latn", - "Lithuanian | lit_Latn", - "Lombard | lmo_Latn", - "Luba - Kasai | lua_Latn", - "Luo | luo_Latn", - "Luxembourgish | ltz_Latn", - "Macedonian | mkd_Cyrl", - "Magahi | mag_Deva", - "Maithili | mai_Deva", - "Malayalam | mal_Mlym", - "Maltese | mlt_Latn", - "Maori | mri_Latn", - "Marathi | mar_Deva", - "Meitei(Bengali script) | mni_Beng", - "Mesopotamian Arabic | acm_Arab", - "Minangkabau(Arabic script) | min_Arab", - "Minangkabau(Latin script) | min_Latn", - "Mizo | lus_Latn", - "Modern Standard Arabic | arb_Arab", - "Modern Standard Arabic(Romanized) | arb_Latn", - "Moroccan Arabic | ary_Arab", - "Mossi | mos_Latn", - "Najdi Arabic | ars_Arab", - "Nepali | npi_Deva", - "Nigerian Fulfulde | fuv_Latn", - "North Azerbaijani | azj_Latn", - "North Levantine Arabic | apc_Arab", - "Northern Kurdish | kmr_Latn", - "Northern Sotho | nso_Latn", - "Northern Uzbek | uzn_Latn", - "Norwegian Bokmål | nob_Latn", - "Norwegian Nynorsk | nno_Latn", - "Nuer | nus_Latn", - "Nyanja | nya_Latn", - "Occitan | oci_Latn", - "Odia | ory_Orya", - "Pangasinan | pag_Latn", - "Papiamento | pap_Latn", - "Plateau Malagasy | plt_Latn", - "Polish | pol_Latn", - "Portuguese | por_Latn", - "Romanian | ron_Latn", - "Rundi | run_Latn", - "Russian | rus_Cyrl", - "Samoan | smo_Latn", - "Sango | sag_Latn", - "Sanskrit | san_Deva", - "Santali | sat_Olck", - "Sardinian | srd_Latn", - "Scottish Gaelic | gla_Latn", - "Serbian | srp_Cyrl", - "Shan | shn_Mymr", - "Shona | sna_Latn", - "Sicilian | scn_Latn", - "Silesian | szl_Latn", - "Sindhi | snd_Arab", - "Sinhala | sin_Sinh", - "Slovak | slk_Latn", - "Slovenian | slv_Latn", - "Somali | som_Latn", - "South Azerbaijani | azb_Arab", - "South Levantine Arabic | ajp_Arab", - "Southern Pashto | pbt_Arab", - "Southern Sotho | sot_Latn", - "Southwestern Dinka | dik_Latn", - "Spanish | spa_Latn", - "Standard Latvian | lvs_Latn", - "Standard Malay | zsm_Latn", - "Standard Tibetan | bod_Tibt", - "Sundanese | sun_Latn", - "Swahili | swh_Latn", - "Swati | ssw_Latn", - "Swedish | swe_Latn", - "Ta'izzi - Adeni Arabic | acq_Arab", - "Tagalog | tgl_Latn", - "Tajik | tgk_Cyrl", - "Tamasheq(Latin script) | taq_Latn", - "Tamasheq(Tifinagh script) | taq_Tfng", - "Tamil | tam_Taml", - "Tatar | tat_Cyrl", - "Telugu | tel_Telu", - "Thai | tha_Thai", - "Tigrinya | tir_Ethi", - "Tok Pisin | tpi_Latn", - "Tosk Albanian | als_Latn", - "Tsonga | tso_Latn", - "Tswana | tsn_Latn", - "Tumbuka | tum_Latn", - "Tunisian Arabic | aeb_Arab", - "Turkish | tur_Latn", - "Turkmen | tuk_Latn", - "Twi | twi_Latn", - "Ukrainian | ukr_Cyrl", - "Umbundu | umb_Latn", - "Urdu | urd_Arab", - "Uyghur | uig_Arab", - "Venetian | vec_Latn", - "Vietnamese | vie_Latn", - "Waray | war_Latn", - "Welsh | cym_Latn", - "West Central Oromo | gaz_Latn", - "Western Persian | pes_Arab", - "Wolof | wol_Latn", - "Xhosa | xho_Latn", - "Yoruba | yor_Latn", - "Yue Chinese | yue_Hant", - "Zulu | zul_Latn", - }; - const size_t kNumLangTargetChoices = sizeof(kLangTargetChoices) / sizeof(kLangTargetChoices[0]); - constexpr int kLangTargetDefault = 0; // do not translate - - // lifted from whisper/__init__.py - const wxString kModelChoices[] = { - "tiny.en", - "tiny", - "base.en", - "base", - "distil-small.en", - "small.en", - "small", - "distil-medium.en", - "medium.en", - "medium", - "large-v1", - "distil-large-v2", - "large-v2", - "distil-large-v3", - "large-v3", - "large-v3-turbo", - }; - const size_t kNumModelChoices = sizeof(kModelChoices) / sizeof(kModelChoices[0]); - constexpr int kModelDefault = 2; // base.en - - const wxString kModelTranslationChoices[] = { - "nllb-200-distilled-600M", - "nllb-200-distilled-1.3B", - }; - const size_t kNumModelTranslationChoices = sizeof(kModelTranslationChoices) / sizeof(kModelTranslationChoices[0]); - constexpr int kModelTranslationDefault = 2; // base.en - - const wxString kCharsPerSync[] = { - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "15", - "16", - "17", - "18", - "19", - "20", - "21", - "22", - "23", - "24", - }; - const size_t kNumCharsPerSync = sizeof(kCharsPerSync) / sizeof(kCharsPerSync[0]); - // 20 chars per sync is a good balance between parameter space and speed: - // 20 * 8 + 25 = 185 bits, leaving 71 bits for other systems. - constexpr int kCharsDefault = kNumCharsPerSync - 5; - - const wxString kBytesPerChar[] = { - "1", - "2", - }; - const size_t kNumBytesPerChar = sizeof(kBytesPerChar) / sizeof(kBytesPerChar[0]); - // Sorry international users. Optimize for English speakers, by default. - constexpr int kBytesDefault = 0; - - const wxString kButton[] = { - "left thumbstick", - "left a", - "left b", - "right thumbstick", - "right a", - "right b", - }; - const size_t kNumButtons = sizeof(kButton) / sizeof(kButton[0]); - constexpr int kButtonDefault = 0; - - const wxString kPrio[] = { - "idle", - "below normal", - "normal", - "above normal", - "high", - "realtime", - }; - const size_t kNumPrios = sizeof(kPrio) / sizeof(kPrio[0]); - constexpr int kPrioDefault = 0; - - const wxString kComputeType[] = { - "int8", - "int8_float32", - "int8_float16", - "int8_bfloat16", - "int16", - "float16", - "bfloat16", - "float32", - }; - const size_t kNumComputeTypes = sizeof(kComputeType) / sizeof(kComputeType[0]); - constexpr int kComputeTypeDefault = 4; - - const wxString kDecodeMethods[] = { - "greedy", - "beam", - }; - const size_t kNumDecodeMethods = sizeof(kDecodeMethods) / sizeof(kDecodeMethods[0]); - constexpr int kDecodeMethodDefault = 0; - - // Given the string value of a dropdown menu's entry, find its index. If no - // entry matches, return `default_index`. - int GetDropdownChoiceIndex(const wxString menu[], - const size_t num_menu_entries, const std::string& entry, - const int default_index) { - for (int i = 0; i < num_menu_entries; i++) { - if (entry == menu[i]) { - return i; - } - } - return default_index; - } - - std::optional stoiInRange(wxTextCtrl* out, const std::string& int_s, const std::string int_name, int min, int max) { - int res; - try { - res = std::stoi(int_s); - } - catch (const std::invalid_argument&) { - Log(out, "Could not parse {} \"{}\" as an integer: invalid\n", - int_name, int_s); - return {}; - } - catch (const std::out_of_range&) { - Log(out, "Could not parse {} \"{}\" as an integer: out of " - "range\n", int_name, int_s); - return {}; - } - if (res < min || res > max) { - Log(out, "Int argument {} is out of the allowed range [{},{}]\n", - int_name, min, max); - return {}; - } - return res; - } - -} // namespace - -Frame::Frame() - : wxFrame(nullptr, wxID_ANY, "TaSTT"), - run_py_app_(false), - py_app_drain_(this, ID_PY_APP_DRAIN) -{ - app_c_ = std::make_unique(nullptr); - - // Initialize futures so that valid() returns true. We use this as a proxy - // to tell whether they're still executing. - { - auto p = std::promise(); - py_app_ = p.get_future(); - p.set_value(true); - } - { - auto p = std::promise(); - obs_app_ = p.get_future(); - p.set_value(true); - } - { - auto p = std::promise(); - unity_app_ = p.get_future(); - p.set_value(true); - } - { - auto p = std::promise(); - unity_auto_refresh_ = p.get_future(); - p.set_value(true); - } - { - auto p = std::promise(); - dump_mics_ = p.get_future(); - p.set_value(true); - } - { - auto p = std::promise(); - env_proc_ = p.get_future(); - p.set_value(true); - } - { - auto p = std::promise(); - reset_venv_proc_ = p.get_future(); - p.set_value(); - } - - auto* main_panel = new wxPanel(this, ID_MAIN_PANEL); - main_panel_ = main_panel; - { - auto* navbar = new wxPanel(main_panel, ID_NAVBAR); - { - auto* navbar_button_transcribe = new wxButton(navbar, - ID_NAVBAR_BUTTON_TRANSCRIBE, "Transcription"); - auto* navbar_button_unity = new wxButton(navbar, - ID_NAVBAR_BUTTON_UNITY, "Unity"); - auto* navbar_button_debug = new wxButton(navbar, - ID_NAVBAR_BUTTON_DEBUG, "Debug"); - - auto* sizer = new wxBoxSizer(wxVERTICAL); - navbar->SetSizer(sizer); - - sizer->Add(navbar_button_transcribe, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(navbar_button_unity, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(navbar_button_debug, /*proportion=*/0, - /*flags=*/wxEXPAND); - } - - auto* transcribe_panel = new wxPanel(main_panel, ID_PY_PANEL); - transcribe_panel_ = transcribe_panel; - { - const auto transcribe_out_sz = wxSize(/*x_px=*/480, /*y_px=*/160); - auto* transcribe_out = new wxTextCtrl(transcribe_panel, - ID_TRANSCRIBE_OUT, wxEmptyString, wxDefaultPosition, - transcribe_out_sz, wxTE_MULTILINE | wxTE_READONLY); - transcribe_out->SetMinSize(transcribe_out_sz); - transcribe_out_ = transcribe_out; - - Log(transcribe_out_, "{}\n", PythonWrapper::GetVersion()); - - auto* py_config_panel = new wxPanel(transcribe_panel, - ID_PY_CONFIG_PANEL); - { - auto* py_dump_mics_button = new wxButton(py_config_panel, - ID_PY_DUMP_MICS_BUTTON, "List input devices"); - py_dump_mics_button->SetToolTip( - "List the microphones (and input devices) attached to " - "your computer. To use a microphone, enter the number " - "to its left in the 'Microphone' dropdown."); - auto* py_app_config_panel_pairs = new wxPanel(py_config_panel, - ID_PY_APP_CONFIG_PANEL_PAIRS); - { - auto* py_app_mic = new wxChoice(py_app_config_panel_pairs, - ID_PY_APP_MIC, wxDefaultPosition, - wxDefaultSize, kNumMicChoices, kMicChoices); - py_app_mic->SetToolTip( - "Select which microphone to listen to when " - "transcribing. To get list microphones and get their " - "numbers, click 'List input devices'."); - py_app_mic_ = py_app_mic; - - auto* py_app_lang = new wxChoice(py_app_config_panel_pairs, - ID_PY_APP_LANG, wxDefaultPosition, wxDefaultSize, - kNumLangChoices, kLangChoices); - py_app_lang->SetToolTip("Select which language you will " - "speak in."); - py_app_lang_ = py_app_lang; - - auto* py_app_translate_target = new wxChoice(py_app_config_panel_pairs, - ID_PY_APP_TRANSLATE_TARGET, wxDefaultPosition, wxDefaultSize, - kNumLangTargetChoices, kLangTargetChoices); - py_app_translate_target->SetToolTip("Select which " - "language to translate to. This is the language " - "that will appear in game. " - "If using a language with non-ASCII characters (i.e. " - "not English), make sure you have 'bytes per char' " - "set to 2."); - py_app_translate_target_ = py_app_translate_target; - - auto* py_app_model = new wxChoice( - py_app_config_panel_pairs, ID_PY_APP_MODEL, - wxDefaultPosition, wxDefaultSize, kNumModelChoices, - kModelChoices); - py_app_model->SetToolTip("Select which version of " - "the transcription model to use. 'base' is a good " - "choice for most users. 'small' is slightly more " - "accurate, slower, and uses more VRAM. The *.en " - "models are fine-tuned English language models, and " - "don't work for other languages."); - py_app_model_ = py_app_model; - - auto* py_app_model_translation = new wxChoice( - py_app_config_panel_pairs, ID_PY_APP_MODEL_TRANSLATION, - wxDefaultPosition, wxDefaultSize, kNumModelTranslationChoices, - kModelTranslationChoices); - py_app_model_translation->SetToolTip("Select which " - "version of the translation model to use. 600M params " - "uses 4.1 GB of memory, while 1.3B uses ~7GB of " - "memory. If 'Translate to' is set to 'Do not " - "translate', this does nothing."); - py_app_model_translation_ = py_app_model_translation; - - auto* py_app_chars_per_sync = new wxChoice( - py_app_config_panel_pairs, ID_PY_APP_CHARS_PER_SYNC, - wxDefaultPosition, wxDefaultSize, kNumCharsPerSync, - kCharsPerSync); - py_app_chars_per_sync->SetToolTip( - "VRChat syncs avatar parameters roughly 5 times per " - "second. We use this to send text to the box. By " - "sending more characters per sync, the box will be " - "faster, but you'll use more avatar parameters."); - py_app_chars_per_sync_ = py_app_chars_per_sync; - - auto* py_app_bytes_per_char = new wxChoice( - py_app_config_panel_pairs, ID_PY_APP_BYTES_PER_CHAR, - wxDefaultPosition, wxDefaultSize, kNumBytesPerChar, - kBytesPerChar); - py_app_bytes_per_char->SetToolTip( - "If you speak a language that uses non-ASCII " - "characters (i.e. not English), set this to 2."); - py_app_bytes_per_char_ = py_app_bytes_per_char; - - auto* py_app_button = new wxChoice(py_app_config_panel_pairs, - ID_PY_APP_BUTTON, wxDefaultPosition, - wxDefaultSize, kNumButtons, kButton); - py_app_button->SetToolTip( - "You will use this button in game to start and stop " - "transcription. Set it to a button you're not using " - "for anything else!"); - py_app_button_ = py_app_button; - - auto* py_app_prio = new wxChoice(py_app_config_panel_pairs, - ID_PY_APP_PRIO, wxDefaultPosition, - wxDefaultSize, kNumPrios, kPrio); - py_app_prio->SetToolTip( - "The priority level at which the transcription process runs."); - py_app_prio_ = py_app_prio; - - auto* py_app_compute_type = new wxChoice(py_app_config_panel_pairs, - ID_PY_APP_COMPUTE_TYPE, wxDefaultPosition, - wxDefaultSize, kNumComputeTypes, kComputeType); - py_app_compute_type->SetToolTip( - "The compute type to use for GPU inference. Ignored " - "if CPU mode is enabled."); - py_app_compute_type_ = py_app_compute_type; - - auto* py_app_rows = new wxTextCtrl(py_app_config_panel_pairs, - ID_PY_APP_ROWS, std::to_string(app_c_->rows), - wxDefaultPosition, wxDefaultSize, /*style=*/0); - py_app_rows->SetToolTip( - "The number of rows on the text box."); - py_app_rows_ = py_app_rows; - - auto* py_app_cols = new wxTextCtrl(py_app_config_panel_pairs, - ID_PY_APP_COLS, std::to_string(app_c_->cols), - wxDefaultPosition, wxDefaultSize, /*style=*/0); - py_app_cols->SetToolTip( - "The number of columns on the text box."); - py_app_cols_ = py_app_cols; - - auto* py_app_gpu_idx = new wxTextCtrl( - py_app_config_panel_pairs, ID_PY_APP_GPU_IDX, - std::to_string(app_c_->gpu_idx), wxDefaultPosition, - wxDefaultSize, /*style=*/0); - py_app_gpu_idx->SetToolTip( - "The index of the GPU to use. 0 is usually your CPU's " - "onboard GPU (if you have one), 1 is usually your " - "discrete GPU."); - py_app_gpu_idx_ = py_app_gpu_idx; - - auto* py_app_min_silence_duration_ms = new wxTextCtrl( - py_app_config_panel_pairs, ID_PY_APP_MIN_SILENCE_DURATION_MS, - std::to_string(app_c_->min_silence_duration_ms), wxDefaultPosition, - wxDefaultSize, /*style=*/0); - py_app_min_silence_duration_ms->SetToolTip( - "The minimum duration, in milliseconds, of a silence " - "used to segment speech."); - py_app_min_silence_duration_ms_ = py_app_min_silence_duration_ms; - - auto* py_app_max_speech_duration_s = new wxTextCtrl( - py_app_config_panel_pairs, ID_PY_APP_MAX_SPEECH_DURATION_S, - std::to_string(app_c_->max_speech_duration_s), wxDefaultPosition, - wxDefaultSize, /*style=*/0); - py_app_max_speech_duration_s->SetToolTip( - "The maximum duration, in seconds, of any segment of " - "speech. Continuous speech longer than this is split " - "at the last pause lasting longer than 100 " - "milliseconds."); - py_app_max_speech_duration_s_ = py_app_max_speech_duration_s; - - auto* py_app_reset_after_silence_s = new wxTextCtrl( - py_app_config_panel_pairs, ID_PY_APP_RESET_AFTER_SILENCE_S, - std::to_string(app_c_->reset_after_silence_s), wxDefaultPosition, - wxDefaultSize, /*style=*/0); - py_app_reset_after_silence_s->SetToolTip( - "If you pause for at least this long between " - "sentences, the transcript before the pause will be " - "removed. To disable this feature, set it to -1."); - py_app_reset_after_silence_s_ = py_app_reset_after_silence_s; - - auto* py_app_transcription_loop_delay_ms = new wxTextCtrl( - py_app_config_panel_pairs, ID_PY_APP_TRANSCRIPTION_LOOP_DELAY_MS, - std::to_string(app_c_->transcription_loop_delay_ms), wxDefaultPosition, - wxDefaultSize, /*style=*/0); - py_app_transcription_loop_delay_ms->SetToolTip( - "The amount of time, in milliseconds, that the " - "application will sleep between every subsequent " - "transcription."); - py_app_transcription_loop_delay_ms_ = py_app_transcription_loop_delay_ms; - - auto* py_app_keybind = new wxTextCtrl( - py_app_config_panel_pairs, ID_PY_APP_KEYBIND, - app_c_->keybind, wxDefaultPosition, - wxDefaultSize, /*style=*/0); - py_app_keybind->SetToolTip( - "The keybind to use to toggle the STT when in desktop " - "mode. To dismiss the STT, double press the keybind " - "quickly."); - py_app_keybind_ = py_app_keybind; - - auto* py_app_browser_src_port = new wxTextCtrl( - py_app_config_panel_pairs, ID_PY_APP_BROWSER_SRC_PORT, - std::to_string(app_c_->browser_src_port), wxDefaultPosition, - wxDefaultSize, /*style=*/0); - py_app_browser_src_port->SetToolTip( - "The port to send the transcript to when `Enable " - "browser source` is enabled. To preview, go to " - "localhost:$PORT in your browser, where $PORT is the " - "value you configure here."); - py_app_browser_src_port_ = py_app_browser_src_port; - - auto* sizer = new wxFlexGridSizer(/*cols=*/2); - py_app_config_panel_pairs->SetSizer(sizer); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Microphone:")); - sizer->Add(py_app_mic, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Spoken language:")); - sizer->Add(py_app_lang, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Transcription model:")); - sizer->Add(py_app_model, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Translate to:")); - sizer->Add(py_app_translate_target, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Translation model:")); - sizer->Add(py_app_model_translation, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Characters per sync:")); - sizer->Add(py_app_chars_per_sync, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Bytes per character:")); - sizer->Add(py_app_bytes_per_char, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Button:")); - sizer->Add(py_app_button, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Process priority:")); - sizer->Add(py_app_prio, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"GPU compute type:")); - sizer->Add(py_app_compute_type, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Desktop keybind:")); - sizer->Add(py_app_keybind, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Text box rows:")); - sizer->Add(py_app_rows, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Text box columns:")); - sizer->Add(py_app_cols, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"GPU index:")); - sizer->Add(py_app_gpu_idx, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Minimum silence duration (ms):")); - sizer->Add(py_app_min_silence_duration_ms, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Maximum speech duration (s):")); - sizer->Add(py_app_max_speech_duration_s, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Reset after silence (s):")); - sizer->Add(py_app_reset_after_silence_s, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Transcription loop delay (ms):")); - sizer->Add(py_app_transcription_loop_delay_ms, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(py_app_config_panel_pairs, - wxID_ANY, /*label=*/"Browser source port:")); - sizer->Add(py_app_browser_src_port, /*proportion=*/0, - /*flags=*/wxEXPAND); - } - - auto* py_app_enable_browser_src = new wxCheckBox(py_config_panel, - ID_PY_APP_ENABLE_BROWSER_SRC, "Enable browser source"); - py_app_enable_browser_src->SetValue(app_c_->enable_browser_src); - py_app_enable_browser_src->SetToolTip( - "Stream transcript to a browser source. To preview, go to " - "localhost:8097, or whatever port you configured."); - py_app_enable_browser_src_ = py_app_enable_browser_src; - - auto* py_app_enable_local_beep = new wxCheckBox(py_config_panel, - ID_PY_APP_ENABLE_LOCAL_BEEP, "Enable local beep"); - py_app_enable_local_beep->SetValue(app_c_->enable_local_beep); - py_app_enable_local_beep->SetToolTip( - "By default, TaSTT will play a sound (audible only to " - "you) when it begins transcription and when it stops. " - "Uncheck this to disable that behavior." - ); - py_app_enable_local_beep_ = py_app_enable_local_beep; - - auto* py_app_enable_orig_lang = new wxCheckBox(py_config_panel, - ID_PY_APP_ENABLE_ORIG_LANG, "Translation shows original language"); - py_app_enable_orig_lang->SetValue(app_c_->enable_orig_lang); - py_app_enable_orig_lang->SetToolTip( - "When translation is enabled, this checkbox determines whether " - "the original language is shown in parentheses after the " - "translated text - c'est comme ça. ( like this)." - ); - py_app_enable_orig_lang_ = py_app_enable_orig_lang; - - auto* py_app_use_cpu = new wxCheckBox(py_config_panel, - ID_PY_APP_USE_CPU, "Use CPU"); - py_app_use_cpu->SetValue(app_c_->use_cpu); - py_app_use_cpu->SetToolTip( - "If checked, the transcription engine will run on your " - "CPU instead of your GPU. This is typically much slower " - "and should only be used if you aren't able to use your " - "GPU." - ); - py_app_use_cpu_ = py_app_use_cpu; - - auto* py_app_use_builtin = new wxCheckBox(py_config_panel, - ID_PY_APP_USE_BUILTIN, "Use built-in chatbox"); - py_app_use_builtin->SetValue(app_c_->use_builtin); - py_app_use_builtin->SetToolTip( - "If checked, text will be sent to the built-in text box " - "instead of one attached to the current avatar." - ); - py_app_use_builtin_ = py_app_use_builtin; - - auto* py_app_enable_uwu_filter = new wxCheckBox(py_config_panel, - ID_PY_APP_ENABLE_UWU_FILTER, "Enable uwu filter :3"); - py_app_enable_uwu_filter->SetValue(app_c_->enable_uwu_filter); - py_app_enable_uwu_filter->SetToolTip( - "If checked, transcribed text will be passed through an " - "uwu filter." - ); - py_app_enable_uwu_filter_ = py_app_enable_uwu_filter; - - auto* py_app_remove_trailing_period = new wxCheckBox(py_config_panel, - ID_PY_APP_REMOVE_TRAILING_PERIOD, "Remove trailing period"); - py_app_remove_trailing_period->SetValue(app_c_->remove_trailing_period); - py_app_remove_trailing_period->SetToolTip( - "If checked, transcriptions will never end with a period." - ); - py_app_remove_trailing_period_ = py_app_remove_trailing_period; - - auto* py_app_enable_uppercase_filter = new wxCheckBox(py_config_panel, - ID_PY_APP_ENABLE_UPPERCASE_FILTER, "Enable uppercase filter"); - py_app_enable_uppercase_filter->SetValue(app_c_->enable_uppercase_filter); - py_app_enable_uppercase_filter->SetToolTip( - "If checked, transcribed text will be converted to UPPERCASE." - ); - py_app_enable_uppercase_filter_ = py_app_enable_uppercase_filter; - - auto* py_app_enable_lowercase_filter = new wxCheckBox(py_config_panel, - ID_PY_APP_ENABLE_LOWERCASE_FILTER, "Enable lowercase filter"); - py_app_enable_lowercase_filter->SetValue(app_c_->enable_lowercase_filter); - py_app_enable_lowercase_filter->SetToolTip( - "If checked, transcribed text will be converted to lowercase." - ); - py_app_enable_lowercase_filter_ = py_app_enable_lowercase_filter; - - auto* py_app_enable_profanity_filter = new wxCheckBox(py_config_panel, - ID_PY_APP_ENABLE_PROFANITY_FILTER, "Enable profanity filter"); - py_app_enable_profanity_filter->SetValue(app_c_->enable_profanity_filter); - py_app_enable_profanity_filter->SetToolTip( - "If checked, profane words in your transcript will have " - "their vowels replaced with asterisks. Currently only " - "English is supported." - ); - py_app_enable_profanity_filter_ = py_app_enable_profanity_filter; - - auto* py_app_enable_debug_mode = new wxCheckBox(py_config_panel, - ID_PY_APP_ENABLE_DEBUG_MODE, "Enable debug mode"); - py_app_enable_debug_mode->SetValue(app_c_->enable_debug_mode); - py_app_enable_debug_mode->SetToolTip( - "If checked, the transcription engine will print out " - "additional information. Use this if you're debugging a " - "technical issue." - ); - py_app_enable_debug_mode_ = py_app_enable_debug_mode; - - auto* py_app_reset_on_toggle = new wxCheckBox(py_config_panel, - ID_PY_APP_RESET_ON_TOGGLE, "Reset transcript on toggle"); - py_app_reset_on_toggle->SetValue(app_c_->reset_on_toggle); - py_app_reset_on_toggle->SetToolTip( - "If checked, the transcript will be reset (cleared) every " - "time that transcription is toggled on. Only affects " - "keyboard controls, not the VR controls." - ); - py_app_reset_on_toggle_ = py_app_reset_on_toggle; - - auto* py_app_enable_previews = new wxCheckBox(py_config_panel, - ID_PY_APP_ENABLE_PREVIEWS, "Enable previews"); - py_app_enable_previews->SetValue(app_c_->enable_previews); - py_app_enable_previews->SetToolTip( - "If checked, audio that has not yet stabilized will also " - "be transcribed and shown. Turn this off if you're on a " - "resource-constrained system or if transcription is " - "running slowly." - ); - py_app_enable_previews_ = py_app_enable_previews; - - auto* py_app_enable_lock_at_spawn = new wxCheckBox(py_config_panel, - ID_PY_APP_ENABLE_LOCK_AT_SPAWN, "Lock chatbox at spawn"); - py_app_enable_lock_at_spawn->SetValue(app_c_->enable_lock_at_spawn); - py_app_enable_lock_at_spawn->SetToolTip( - "If checked, the custom chatbox will be locked in world " - "space when spawned. This minimizes the visual " - "disruption for other players."); - py_app_enable_lock_at_spawn_ = py_app_enable_lock_at_spawn; - - // Hack: Add newlines before and after the button text to make - // the buttons bigger, and easier to click from inside VR. - auto* py_app_start_button = new wxButton(py_config_panel, - ID_PY_APP_START_BUTTON, "\nBegin transcribing\n\n"); - auto* py_app_stop_button = new wxButton(py_config_panel, - ID_PY_APP_STOP_BUTTON, "\nStop transcribing\n\n"); - - auto* sizer = new wxBoxSizer(wxVERTICAL); - py_config_panel->SetSizer(sizer); - sizer->Add(py_dump_mics_button, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_config_panel_pairs, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_reset_on_toggle, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_enable_previews, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_enable_lock_at_spawn, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_enable_browser_src, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_enable_local_beep, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_enable_orig_lang, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_use_cpu, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_use_builtin, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_enable_uwu_filter, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_remove_trailing_period, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_enable_uppercase_filter, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_enable_lowercase_filter, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_enable_profanity_filter, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_enable_debug_mode, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_start_button, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(py_app_stop_button, /*proportion=*/0, - /*flags=*/wxEXPAND); - } - - auto* sizer = new wxBoxSizer(wxHORIZONTAL); - transcribe_panel->SetSizer(sizer); - sizer->Add(py_config_panel, /*proportion=*/0, /*flags=*/wxEXPAND); - sizer->Add(transcribe_out, /*proportion=*/1, /*flags=*/wxEXPAND); - } - - auto* unity_panel = new wxPanel(main_panel, ID_UNITY_PANEL); - unity_panel_ = unity_panel; - { - const auto unity_out_sz = wxSize(/*x_px=*/480, /*y_px=*/160); - auto* unity_out = new wxTextCtrl(unity_panel, ID_UNITY_OUT, - wxEmptyString, - wxDefaultPosition, - unity_out_sz, wxTE_MULTILINE | wxTE_READONLY); - unity_out->SetMinSize(unity_out_sz); - unity_out_ = unity_out; - - auto* unity_config_panel = new wxPanel(unity_panel, - ID_UNITY_CONFIG_PANEL); - { - auto* unity_config_panel_pairs = new wxPanel(unity_config_panel, - ID_UNITY_CONFIG_PANEL_PAIRS); - { - auto* unity_assets_file_picker = new wxDirPickerCtrl( - unity_config_panel_pairs, - ID_UNITY_ASSETS_FILE_PICKER, - /*path=*/app_c_->assets_path, - /*message=*/"Unity Assets folder" - ); - unity_assets_file_picker->SetToolTip( - "The path to the Assets folder for your avatar's " - "Unity project. Example:\n" - "C:\\Users\\yum\\unity\\kumadan\\Assets"); - unity_assets_file_picker_ = unity_assets_file_picker; - - auto* unity_animator_file_picker = new wxFilePickerCtrl( - unity_config_panel_pairs, - ID_UNITY_ANIMATOR_FILE_PICKER, - /*path=*/app_c_->fx_path, - /*message=*/"FX controller path", - /*wildcard=*/wxFileSelectorDefaultWildcardStr, - /*pos=*/wxDefaultPosition, - /*size=*/wxDefaultSize - ); - unity_animator_file_picker->SetToolTip( - "The path to your avatar's FX layer. You can find " - "this in your avatar descriptor. Example:\n" - "C:\\Users\\yum\\unity\\kumadan\\Assets\\kumadan_fx.controller"); - unity_animator_file_picker_ = unity_animator_file_picker; - - auto* unity_parameters_file_picker = new wxFilePickerCtrl( - unity_config_panel_pairs, - ID_UNITY_PARAMETERS_FILE_PICKER, - /*path=*/app_c_->params_path, - /*message=*/"Avatar parameters path", - /*wildcard=*/wxFileSelectorDefaultWildcardStr, - /*pos=*/wxDefaultPosition, - /*size=*/wxDefaultSize - ); - unity_parameters_file_picker->SetToolTip( - "The path to your avatar's parameters. You can find " - "this in your avatar descriptor. Example:\n" - "C:\\Users\\yum\\unity\\kumadan\\Assets\\kumadan_parameters.asset"); - unity_parameters_file_picker_ = - unity_parameters_file_picker; - - auto* unity_menu_file_picker = new wxFilePickerCtrl( - unity_config_panel_pairs, - ID_UNITY_MENU_FILE_PICKER, - /*path=*/app_c_->menu_path, - /*message=*/"Avatar menu path", - /*wildcard=*/wxFileSelectorDefaultWildcardStr, - /*pos=*/wxDefaultPosition, - /*size=*/wxDefaultSize - ); - unity_menu_file_picker->SetToolTip( - "The path to your avatar's menu. You can find " - "this in your avatar descriptor. Example:\n" - "C:\\Users\\yum\\unity\\kumadan\\Assets\\kumadan_menu.asset"); - unity_menu_file_picker_ = unity_menu_file_picker; - - auto* unity_animator_generated_dir = new wxTextCtrl( - unity_config_panel_pairs, - ID_UNITY_ANIMATOR_GENERATED_DIR, - wxEmptyString, wxDefaultPosition, wxDefaultSize, - /*style=*/0); - unity_animator_generated_dir->AppendText("TaSTT_Generated"); - unity_animator_generated_dir->SetToolTip( - "TaSTT will create a bunch of files " - "(animations, shaders, etc.) to drive the text box. " - "It places them in this folder, which it creates " - "under your Unity project's Assets folder. Any data " - "inside this folder may be overwritten!"); - unity_animator_generated_dir_ = - unity_animator_generated_dir; - - auto* unity_animator_generated_name = new wxTextCtrl( - unity_config_panel_pairs, - ID_UNITY_ANIMATOR_GENERATED_NAME, - wxEmptyString, wxDefaultPosition, wxDefaultSize, - wxTE_READONLY); - unity_animator_generated_name->AppendText("TaSTT.controller"); - unity_animator_generated_name->SetToolTip( - "The name of the FX layer that TaSTT generates. " - "It will be placed inside the generated assets " - "folder. Put this on your avatar descriptor when " - "you're done!"); - unity_animator_generated_name_ = unity_animator_generated_name; - - auto* unity_parameters_generated_name = new wxTextCtrl( - unity_config_panel_pairs, - ID_UNITY_PARAMETERS_GENERATED_NAME, - wxEmptyString, wxDefaultPosition, wxDefaultSize, - wxTE_READONLY); - unity_parameters_generated_name->AppendText( - "TaSTT_Parameters.asset"); - unity_parameters_generated_name->SetToolTip( - "The name of the parameters file that TaSTT generates. " - "It will be placed inside the generated assets " - "folder. Put this on your avatar descriptor when " - "you're done!"); - unity_parameters_generated_name_ = - unity_parameters_generated_name; - - auto* unity_menu_generated_name = new wxTextCtrl( - unity_config_panel_pairs, - ID_UNITY_MENU_GENERATED_NAME, - wxEmptyString, wxDefaultPosition, wxDefaultSize, - wxTE_READONLY); - unity_menu_generated_name->AppendText("TaSTT_Menu.asset"); - unity_menu_generated_name->SetToolTip( - "The name of the menu file that TaSTT generates. " - "It will be placed inside the generated assets " - "folder. Put this on your avatar descriptor when " - "you're done!"); - unity_menu_generated_name_ = unity_menu_generated_name; - - auto* unity_chars_per_sync = new wxChoice( - unity_config_panel_pairs, - ID_UNITY_CHARS_PER_SYNC, wxDefaultPosition, - wxDefaultSize, kNumCharsPerSync, kCharsPerSync); - unity_chars_per_sync->SetToolTip( - "VRChat syncs avatar parameters roughly 5 times per " - "second. We use this to send text to the box. By " - "sending more characters per sync, the box will be " - "faster, but you'll use more avatar parameters."); - unity_chars_per_sync_ = unity_chars_per_sync; - - auto* unity_bytes_per_char = new wxChoice( - unity_config_panel_pairs, - ID_UNITY_BYTES_PER_CHAR, wxDefaultPosition, - wxDefaultSize, kNumBytesPerChar, kBytesPerChar); - unity_bytes_per_char->SetToolTip( - "If you speak a language that uses non-ASCII " - "characters (i.e. not English), set this to 2."); - unity_bytes_per_char_ = unity_bytes_per_char; - - auto* unity_rows = new wxTextCtrl(unity_config_panel_pairs, - ID_UNITY_ROWS, std::to_string(app_c_->rows), - wxDefaultPosition, wxDefaultSize, /*style=*/0); - unity_rows->SetToolTip( - "The number of rows on the text box."); - unity_rows_ = unity_rows; - - auto* unity_cols = new wxTextCtrl(unity_config_panel_pairs, - ID_UNITY_COLS, std::to_string(app_c_->cols), - wxDefaultPosition, wxDefaultSize, /*style=*/0); - unity_cols->SetToolTip( - "The number of columns on the text box."); - unity_cols_ = unity_cols; - - auto* unity_texture_sz = new wxTextCtrl(unity_config_panel_pairs, - ID_UNITY_TEXTURE_SZ, std::to_string(app_c_->texture_sz), - wxDefaultPosition, wxDefaultSize, /*style=*/0); - unity_texture_sz->SetToolTip( - "The size of the textures holding text glyphs."); - unity_texture_sz_ = unity_texture_sz; - - auto* sizer = new wxFlexGridSizer(/*cols=*/2); - unity_config_panel_pairs->SetSizer(sizer); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"Unity Assets folder:")); - sizer->Add(unity_assets_file_picker); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"FX controller:")); - sizer->Add(unity_animator_file_picker); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"Avatar parameters:")); - sizer->Add(unity_parameters_file_picker); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"Avatar menu:")); - sizer->Add(unity_menu_file_picker); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"Generated assets folder:")); - sizer->Add(unity_animator_generated_dir); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"Generated FX controller:")); - sizer->Add(unity_animator_generated_name); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"Generated parameters:")); - sizer->Add(unity_parameters_generated_name); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"Generated menu:")); - sizer->Add(unity_menu_generated_name); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"Characters per sync:")); - sizer->Add(unity_chars_per_sync, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"Bytes per character:")); - sizer->Add(unity_bytes_per_char, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"Text box rows:")); - sizer->Add(unity_rows, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"Text box columns:")); - sizer->Add(unity_cols, /*proportion=*/0, - /*flags=*/wxEXPAND); - - sizer->Add(new wxStaticText(unity_config_panel_pairs, - wxID_ANY, /*label=*/"Texture size:")); - sizer->Add(unity_texture_sz, /*proportion=*/0, - /*flags=*/wxEXPAND); - } - - auto* clear_osc = new wxCheckBox(unity_config_panel, - ID_UNITY_CLEAR_OSC, "Clear OSC configs"); - clear_osc->SetValue(app_c_->clear_osc); - clear_osc->SetToolTip( - "If checked, VRChat's OSC configs will be cleared. " - "VRC SDK has a bug where parameters added to an " - "existing avatar are not added to the avatar's OSC " - "config. By clearing configs, VRC SDK is forced to " - "regenerate them. The regenerated config will include " - "the STT parameters. Check this if you are updating " - "an existing avatar."); - unity_clear_osc_ = clear_osc; - - auto* enable_phonemes = new wxCheckBox(unity_config_panel, - ID_UNITY_ENABLE_PHONEMES, "Enable phonemes"); - enable_phonemes->SetValue(app_c_->enable_phonemes); - enable_phonemes->SetToolTip( - "If checked, the chatbox will be created with 5 audio " - "sources for each English vowel sound: a, e, i, o, and u. " - "Whenever a page of data is sent into the game, any " - "vowels will have the corresponding audio source enabled. " - "This uses 6 parameter bits."); - unity_enable_phonemes_ = enable_phonemes; - - auto* unity_button_gen_fx = new wxButton(unity_config_panel, - ID_UNITY_BUTTON_GEN_ANIMATOR, "Generate avatar assets"); - unity_button_gen_fx->SetWindowStyleFlag(wxBU_EXACTFIT); - - auto* unity_button_auto_refresh = new wxButton(unity_config_panel, - ID_UNITY_BUTTON_AUTO_REFRESH, "Begin auto generating assets on change"); - unity_button_auto_refresh->SetWindowStyleFlag(wxBU_EXACTFIT); - unity_button_auto_refresh->SetToolTip( - "When the configured FX controller, parameters, or menu " - "change (as determined by its hash changing), " - "automatically regenerate TaSTT assets." - ); - - auto* unity_button_auto_refresh_stop = new wxButton(unity_config_panel, - ID_UNITY_BUTTON_AUTO_REFRESH_STOP, - "Stop auto generating assets on change"); - unity_button_auto_refresh_stop->SetWindowStyleFlag(wxBU_EXACTFIT); - unity_button_auto_refresh_stop->SetToolTip( - "Stop auto-generating TaSTT assets on change."); - - auto* sizer = new wxBoxSizer(wxVERTICAL); - unity_config_panel->SetSizer(sizer); - sizer->Add(unity_config_panel_pairs); - sizer->Add(clear_osc); - sizer->Add(enable_phonemes); - sizer->Add(unity_button_gen_fx, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(unity_button_auto_refresh, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(unity_button_auto_refresh_stop, /*proportion=*/0, - /*flags=*/wxEXPAND); - } - - auto* sizer = new wxBoxSizer(wxHORIZONTAL); - unity_panel->SetSizer(sizer); - sizer->Add(unity_config_panel, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(unity_out, /*proportion=*/1, /*flags=*/wxEXPAND); - } - unity_panel_->Hide(); - - auto* debug_panel = new wxPanel(main_panel, ID_DEBUG_PANEL); - debug_panel_ = debug_panel; - { - const auto debug_out_sz = wxSize(/*x_px=*/480, /*y_px=*/160); - auto* debug_out = new wxTextCtrl(debug_panel, ID_DEBUG_OUT, - wxEmptyString, - wxDefaultPosition, - debug_out_sz, wxTE_MULTILINE | wxTE_READONLY); - debug_out->SetMinSize(debug_out_sz); - debug_out_ = debug_out; - - auto* debug_config_panel = new wxPanel(debug_panel, - ID_DEBUG_CONFIG_PANEL); - { - auto* debug_button_list_pip = new wxButton(debug_config_panel, - ID_DEBUG_BUTTON_LIST_PIP, "List pip packages"); - debug_button_list_pip->SetToolTip( - "List the packages (and versions) installed in the " - "virtual environment by pip. Also list the contents " - "of the pip cache."); - debug_button_list_pip->SetWindowStyleFlag(wxBU_EXACTFIT); - - auto* debug_button_clear_pip = new wxButton(debug_config_panel, - ID_DEBUG_BUTTON_CLEAR_PIP, "Clear pip cache"); - // The real explanation: we install a special version of torch - // using --extra-index-url, and I'm like 99% sure that pip - // doesn't correctly detect that we want this version instead - // of the normal version. - debug_button_clear_pip->SetToolTip( - "TaSTT uses a piece of software called pip to install " - "Python dependencies. To enable reusing packages across " - "different Python projects, pip installs packages in a " - "system-wide cache. Sometimes the contents of this cache " - "can get stale (it's complicated) and clearing the cache " - "can fix issues."); - debug_button_clear_pip->SetWindowStyleFlag(wxBU_EXACTFIT); - - auto* debug_button_reset_venv = new wxButton( - debug_config_panel, ID_DEBUG_BUTTON_RESET_VENV, - "Reset python virtual environment"); - debug_button_reset_venv->SetToolTip( - "Uninstall all Python packages installed into the virtual " - "environment. Do this after clearing pip!"); - debug_button_reset_venv->SetWindowStyleFlag(wxBU_EXACTFIT); - - auto* debug_button_clear_osc = new wxButton(debug_config_panel, - ID_DEBUG_BUTTON_CLEAR_OSC, "Clear OSC configs"); - debug_button_clear_osc->SetToolTip( - "No idea if this actually does anything valuable yet. I " - "think making certain animator changes (s.a. turning on " - "multi-byte character encoding) require you to reset " - "(i.e. delete) your OSC config. This button deletes all " - "your OSC configs."); - debug_button_clear_osc->SetWindowStyleFlag(wxBU_EXACTFIT); - - auto* debug_button_backup_venv = new wxButton( - debug_config_panel, ID_DEBUG_BUTTON_BACKUP_VENV, - "Back up virtual env"); - debug_button_backup_venv->SetToolTip( - "Back up the virtual environment to " - "~/Downloads/TaSTT_venv"); - debug_button_backup_venv->SetWindowStyleFlag(wxBU_EXACTFIT); - - auto* debug_button_restore_venv = new wxButton( - debug_config_panel, ID_DEBUG_BUTTON_RESTORE_VENV, - "Restore virtual env"); - debug_button_restore_venv->SetToolTip( - "Restore the virtual environment from " - "~/Downloads/TaSTT_venv"); - debug_button_restore_venv->SetWindowStyleFlag(wxBU_EXACTFIT); - - auto* debug_button_setup_venv = new wxButton( - debug_config_panel, ID_DEBUG_BUTTON_SETUP_VENV, - "Set up virtual env"); - debug_button_setup_venv->SetToolTip( - "Reinstall packages to the virtual environment"); - debug_button_setup_venv->SetWindowStyleFlag(wxBU_EXACTFIT); - - auto* sizer = new wxBoxSizer(wxVERTICAL); - debug_config_panel->SetSizer(sizer); - sizer->Add(debug_button_list_pip, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(debug_button_clear_pip, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(debug_button_reset_venv, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(debug_button_clear_osc, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(debug_button_backup_venv, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(debug_button_restore_venv, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(debug_button_setup_venv, /*proportion=*/0, - /*flags=*/wxEXPAND); - } - - auto* sizer = new wxBoxSizer(wxHORIZONTAL); - debug_panel->SetSizer(sizer); - sizer->Add(debug_config_panel, /*proportion=*/0, - /*flags=*/wxEXPAND); - sizer->Add(debug_out, /*proportion=*/1, /*flags=*/wxEXPAND); - } - debug_panel_->Hide(); - - auto* sizer = new wxBoxSizer(wxHORIZONTAL); - main_panel->SetSizer(sizer); - sizer->Add(navbar, /*proportion=*/0, /*flags=*/wxEXPAND); - sizer->Add(transcribe_panel, /*proportion=*/1, /*flags=*/wxEXPAND); - sizer->Add(unity_panel, /*proportion=*/1, /*flags=*/wxEXPAND); - sizer->Add(debug_panel, /*proportion=*/1, /*flags=*/wxEXPAND); - } - - // Now that transcribe_out_ has been created, we can deserialize. - app_c_ = std::make_unique(transcribe_out_); - app_c_->Deserialize(AppConfig::kConfigPath); - - Bind(wxEVT_CLOSE_WINDOW, &Frame::OnExit, this); - Bind(wxEVT_BUTTON, &Frame::OnNavbarTranscribe, this, - ID_NAVBAR_BUTTON_TRANSCRIBE); - Bind(wxEVT_BUTTON, &Frame::OnNavbarUnity, this, ID_NAVBAR_BUTTON_UNITY); - Bind(wxEVT_BUTTON, &Frame::OnNavbarDebug, this, ID_NAVBAR_BUTTON_DEBUG); - Bind(wxEVT_BUTTON, &Frame::OnAppStart, this, ID_PY_APP_START_BUTTON); - Bind(wxEVT_BUTTON, &Frame::OnAppStop, this, ID_PY_APP_STOP_BUTTON); - Bind(wxEVT_TIMER, &Frame::OnAppDrain, this, ID_PY_APP_DRAIN); - Bind(wxEVT_BUTTON, &Frame::OnDumpMics, this, ID_PY_DUMP_MICS_BUTTON); - Bind(wxEVT_BUTTON, &Frame::OnGenerateFX, this, - ID_UNITY_BUTTON_GEN_ANIMATOR); - Bind(wxEVT_BUTTON, &Frame::OnUnityAutoRefresh, this, - ID_UNITY_BUTTON_AUTO_REFRESH); - Bind(wxEVT_BUTTON, &Frame::OnUnityAutoRefreshStop, this, - ID_UNITY_BUTTON_AUTO_REFRESH_STOP); - Bind(wxEVT_BUTTON, &Frame::OnListPip, this, ID_DEBUG_BUTTON_LIST_PIP); - Bind(wxEVT_BUTTON, &Frame::OnClearPip, this, ID_DEBUG_BUTTON_CLEAR_PIP); - Bind(wxEVT_BUTTON, &Frame::OnListPip, this, ID_DEBUG_BUTTON_LIST_PIP); - Bind(wxEVT_BUTTON, &Frame::OnResetVenv, this, ID_DEBUG_BUTTON_RESET_VENV); - Bind(wxEVT_BUTTON, &Frame::OnClearOSC, this, ID_DEBUG_BUTTON_CLEAR_OSC); - Bind(wxEVT_BUTTON, &Frame::OnBackupVenv, this, ID_DEBUG_BUTTON_BACKUP_VENV); - Bind(wxEVT_BUTTON, &Frame::OnRestoreVenv, this, - ID_DEBUG_BUTTON_RESTORE_VENV); - Bind(wxEVT_BUTTON, &Frame::OnSetupVenv, this, - ID_DEBUG_BUTTON_SETUP_VENV); - Bind(wxEVT_CHOICE, &Frame::OnUnityParamChange, this, - ID_UNITY_CHARS_PER_SYNC); - Bind(wxEVT_CHOICE, &Frame::OnUnityParamChange, this, - ID_UNITY_BYTES_PER_CHAR); - Bind(wxEVT_CHECKBOX, &Frame::OnUnityParamChange, this, - ID_UNITY_ENABLE_PHONEMES); - - // wx needs this to be able to load PNGs. - wxImage::AddHandler(&png_handler_); - LoadAndSetIcons(); - - // Make tooltips show up for longer. - wxToolTip::SetAutoPop(/*milliseconds=*/ 10 * 1000); - - // Initialize input fields using AppConfig. - ApplyConfigToInputFields(); - - Resize(); - OnUnityParamChangeImpl(); - - // Every 100 milliseconds we drain output from the Python app. - py_app_drain_.Start(/*milliseconds=*/100); -} - -void Frame::ApplyConfigToInputFields() -{ - // Transcription panel - auto* py_app_mic = static_cast(FindWindowById(ID_PY_APP_MIC)); - int mic_idx = GetDropdownChoiceIndex(kMicChoices, - kNumMicChoices, app_c_->microphone, kMicDefault); - py_app_mic->SetSelection(mic_idx); - - auto* py_app_lang = static_cast(FindWindowById(ID_PY_APP_LANG)); - int lang_idx = GetDropdownChoiceIndex(kLangChoices, - kNumLangChoices, app_c_->language, kLangDefault); - py_app_lang->SetSelection(lang_idx); - - auto* py_app_translate_target = static_cast(FindWindowById(ID_PY_APP_TRANSLATE_TARGET)); - int translate_target_idx = GetDropdownChoiceIndex(kLangTargetChoices, - kNumLangTargetChoices, app_c_->language_target, kLangTargetDefault); - py_app_translate_target->SetSelection(translate_target_idx); - - auto* py_app_model = static_cast(FindWindowById(ID_PY_APP_MODEL)); - int model_idx = GetDropdownChoiceIndex(kModelChoices, - kNumModelChoices, app_c_->model, kModelDefault); - py_app_model->SetSelection(model_idx); - - auto* py_app_model_translation = static_cast(FindWindowById(ID_PY_APP_MODEL_TRANSLATION)); - int model_translation_idx = GetDropdownChoiceIndex(kModelTranslationChoices, - kNumModelTranslationChoices, app_c_->model_translation, kModelTranslationDefault); - py_app_model_translation->SetSelection(model_translation_idx); - - auto* py_app_chars_per_sync = static_cast(FindWindowById(ID_PY_APP_CHARS_PER_SYNC)); - int chars_idx = GetDropdownChoiceIndex(kCharsPerSync, - kNumCharsPerSync, std::to_string(app_c_->chars_per_sync), - kCharsDefault); - py_app_chars_per_sync->SetSelection(chars_idx); - - auto* py_app_bytes_per_char = static_cast(FindWindowById(ID_PY_APP_BYTES_PER_CHAR)); - int bytes_idx = GetDropdownChoiceIndex(kBytesPerChar, - kNumBytesPerChar, std::to_string(app_c_->bytes_per_char), - kBytesDefault); - py_app_bytes_per_char->SetSelection(bytes_idx); - - auto* py_app_button = static_cast(FindWindowById(ID_PY_APP_BUTTON)); - int button_idx = GetDropdownChoiceIndex(kButton, - kNumButtons, app_c_->button, kButtonDefault); - py_app_button->SetSelection(button_idx); - - auto* py_app_prio = static_cast(FindWindowById(ID_PY_APP_PRIO)); - int prio_idx = GetDropdownChoiceIndex(kPrio, - kNumPrios, app_c_->prio, kPrioDefault); - py_app_prio->SetSelection(prio_idx); - - auto* py_app_compute_type = static_cast(FindWindowById(ID_PY_APP_COMPUTE_TYPE)); - int compute_type_idx = GetDropdownChoiceIndex(kComputeType, - kNumComputeTypes, app_c_->compute_type, kComputeTypeDefault); - py_app_compute_type->SetSelection(compute_type_idx); - - auto* py_app_desktop_keybind = static_cast(FindWindowById(ID_PY_APP_KEYBIND)); - py_app_desktop_keybind->Clear(); - py_app_desktop_keybind->AppendText(app_c_->keybind); - - auto* py_app_desktop_browser_src_port = static_cast(FindWindowById(ID_PY_APP_BROWSER_SRC_PORT)); - py_app_desktop_browser_src_port->Clear(); - py_app_desktop_browser_src_port->AppendText(std::to_string(app_c_->browser_src_port)); - - auto* py_app_rows = static_cast(FindWindowById(ID_PY_APP_ROWS)); - py_app_rows->Clear(); - py_app_rows->AppendText(std::to_string(app_c_->rows)); - - auto* py_app_cols = static_cast(FindWindowById(ID_PY_APP_COLS)); - py_app_cols->Clear(); - py_app_cols->AppendText(std::to_string(app_c_->cols)); - - auto* py_app_gpu_idx = static_cast(FindWindowById(ID_PY_APP_GPU_IDX)); - py_app_gpu_idx->Clear(); - py_app_gpu_idx->AppendText(std::to_string(app_c_->gpu_idx)); - - auto* py_app_min_silence_duration_ms = static_cast(FindWindowById(ID_PY_APP_MIN_SILENCE_DURATION_MS)); - py_app_min_silence_duration_ms->Clear(); - py_app_min_silence_duration_ms->AppendText(std::to_string(app_c_->min_silence_duration_ms)); - - auto* py_app_max_speech_duration_s = static_cast(FindWindowById(ID_PY_APP_MAX_SPEECH_DURATION_S)); - py_app_max_speech_duration_s->Clear(); - py_app_max_speech_duration_s->AppendText(std::to_string(app_c_->max_speech_duration_s)); - - auto* py_app_reset_after_silence_s = static_cast(FindWindowById(ID_PY_APP_RESET_AFTER_SILENCE_S)); - py_app_reset_after_silence_s->Clear(); - py_app_reset_after_silence_s->AppendText(std::to_string(app_c_->reset_after_silence_s)); - - auto* py_app_transcription_loop_delay_ms = static_cast(FindWindowById(ID_PY_APP_TRANSCRIPTION_LOOP_DELAY_MS)); - py_app_transcription_loop_delay_ms->Clear(); - py_app_transcription_loop_delay_ms->AppendText(std::to_string(app_c_->transcription_loop_delay_ms)); - - auto* py_app_enable_local_beep = static_cast(FindWindowById(ID_PY_APP_ENABLE_LOCAL_BEEP)); - py_app_enable_local_beep->SetValue(app_c_->enable_local_beep); - - auto* py_app_enable_orig_lang = static_cast(FindWindowById(ID_PY_APP_ENABLE_ORIG_LANG)); - py_app_enable_orig_lang->SetValue(app_c_->enable_orig_lang); - - auto* py_app_enable_browser_src = static_cast(FindWindowById(ID_PY_APP_ENABLE_BROWSER_SRC)); - py_app_enable_browser_src->SetValue(app_c_->enable_browser_src); - - auto* py_app_use_cpu = static_cast(FindWindowById(ID_PY_APP_USE_CPU)); - py_app_use_cpu->SetValue(app_c_->use_cpu); - - auto* py_app_use_builtin = static_cast(FindWindowById(ID_PY_APP_USE_BUILTIN)); - py_app_use_builtin->SetValue(app_c_->use_builtin); - - auto* py_app_enable_uwu_filter = static_cast(FindWindowById(ID_PY_APP_ENABLE_UWU_FILTER)); - py_app_enable_uwu_filter->SetValue(app_c_->enable_uwu_filter); - - auto* py_app_remove_trailing_period = static_cast(FindWindowById(ID_PY_APP_REMOVE_TRAILING_PERIOD)); - py_app_remove_trailing_period->SetValue(app_c_->remove_trailing_period); - - auto* py_app_enable_uppercase_filter = static_cast(FindWindowById(ID_PY_APP_ENABLE_UPPERCASE_FILTER)); - py_app_enable_uppercase_filter->SetValue(app_c_->enable_uppercase_filter); - - auto* py_app_enable_lowercase_filter = static_cast(FindWindowById(ID_PY_APP_ENABLE_LOWERCASE_FILTER)); - py_app_enable_lowercase_filter->SetValue(app_c_->enable_lowercase_filter); - - auto* py_app_enable_profanity_filter = static_cast(FindWindowById(ID_PY_APP_ENABLE_PROFANITY_FILTER)); - py_app_enable_profanity_filter->SetValue(app_c_->enable_profanity_filter); - - auto* py_app_enable_debug_mode = static_cast(FindWindowById(ID_PY_APP_ENABLE_DEBUG_MODE)); - py_app_enable_debug_mode->SetValue(app_c_->enable_debug_mode); - - auto* py_app_reset_on_toggle = static_cast(FindWindowById(ID_PY_APP_RESET_ON_TOGGLE)); - py_app_reset_on_toggle->SetValue(app_c_->reset_on_toggle); - - auto* py_app_enable_previews = static_cast(FindWindowById(ID_PY_APP_ENABLE_PREVIEWS)); - py_app_enable_previews->SetValue(app_c_->enable_previews); - - auto* py_app_enable_lock_at_spawn = static_cast(FindWindowById(ID_PY_APP_ENABLE_LOCK_AT_SPAWN)); - py_app_enable_lock_at_spawn->SetValue(app_c_->enable_lock_at_spawn); - - // Unity panel - auto* unity_assets_path = static_cast(FindWindowById(ID_UNITY_ASSETS_FILE_PICKER)); - unity_assets_path->SetPath(app_c_->assets_path); - - auto* unity_animator_path = static_cast(FindWindowById(ID_UNITY_ANIMATOR_FILE_PICKER)); - unity_animator_path->SetPath(app_c_->fx_path); - - auto* unity_params_path = static_cast(FindWindowById(ID_UNITY_PARAMETERS_FILE_PICKER)); - unity_params_path->SetPath(app_c_->params_path); - - auto* unity_menu_path = static_cast(FindWindowById(ID_UNITY_MENU_FILE_PICKER)); - unity_menu_path->SetPath(app_c_->menu_path); - - auto* unity_generated_dir = static_cast(FindWindowById(ID_UNITY_ANIMATOR_GENERATED_DIR)); - unity_generated_dir->Clear(); - unity_generated_dir->AppendText(app_c_->unity_generated_dir); - - auto* unity_chars_per_sync = static_cast(FindWindowById(ID_UNITY_CHARS_PER_SYNC)); - unity_chars_per_sync->SetSelection(chars_idx); - - auto* unity_bytes_per_char = static_cast(FindWindowById(ID_UNITY_BYTES_PER_CHAR)); - unity_bytes_per_char->SetSelection(bytes_idx); - - auto* unity_rows = static_cast(FindWindowById(ID_UNITY_ROWS)); - unity_rows->Clear(); - unity_rows->AppendText(std::to_string(app_c_->rows)); - - auto* unity_cols = static_cast(FindWindowById(ID_UNITY_COLS)); - unity_cols->Clear(); - unity_cols->AppendText(std::to_string(app_c_->cols)); - - auto* unity_texture_sz = static_cast(FindWindowById(ID_UNITY_TEXTURE_SZ)); - unity_texture_sz->Clear(); - unity_texture_sz->AppendText(std::to_string(app_c_->texture_sz)); - - auto* unity_clear_osc = static_cast(FindWindowById(ID_UNITY_CLEAR_OSC)); - unity_clear_osc->SetValue(app_c_->clear_osc); - - auto* unity_enable_phonemes = static_cast(FindWindowById(ID_UNITY_ENABLE_PHONEMES)); - unity_enable_phonemes->SetValue(app_c_->enable_phonemes); -} - -void Frame::OnExit(wxCloseEvent& event) -{ - OnAppStop(); - OnUnityAutoRefreshStop(); - event.Skip(); -} - -void Frame::OnNavbarTranscribe(wxCommandEvent& event) -{ - transcribe_panel_->Hide(); - unity_panel_->Hide(); - debug_panel_->Hide(); - - // Initialize input fields using AppConfig. - ApplyConfigToInputFields(); - - transcribe_panel_->Show(); - Resize(); -} - -void Frame::OnNavbarUnity(wxCommandEvent& event) -{ - transcribe_panel_->Hide(); - unity_panel_->Hide(); - debug_panel_->Hide(); - - // Initialize input fields using AppConfig. - ApplyConfigToInputFields(); - - unity_panel_->Show(); - Resize(); -} - -void Frame::OnNavbarDebug(wxCommandEvent& event) -{ - transcribe_panel_->Hide(); - unity_panel_->Hide(); - debug_panel_->Hide(); - - // Initialize input fields using AppConfig. - ApplyConfigToInputFields(); - - debug_panel_->Show(); - Resize(); -} - -bool FindDirectoryByPrefix(wxTextCtrl* out, const std::string& prefix, std::filesystem::path& path) { - std::error_code ec; - // Find directory starting with "cudnn" - for (const auto& entry : - std::filesystem::directory_iterator(".", ec)) { - if (ec) { - Log(out, "Failed to iterate cwd: {}\n", - ec.message()); - return false; - } - - if (entry.is_directory(ec) && - !ec && - entry.path().filename().string().starts_with(prefix)) { - path = entry.path(); - return true; - } - } - return false; -} - -void Frame::EnsureVirtualEnv(bool block, bool force) -{ - auto status = env_proc_.wait_for(std::chrono::seconds(0)); - if (status != std::future_status::ready) { - Log(transcribe_out_, "Virtual environment setup already running\n"); - return; - } - - static const std::filesystem::path venv_flag = std::filesystem::current_path() / ".venv_is_set_up"; - if (!force && std::filesystem::exists(venv_flag)) { - std::ifstream venv_flag_ifs(venv_flag); - std::string venv_flag_ts_str; - std::getline(venv_flag_ifs, venv_flag_ts_str); - - int64_t venv_flag_ts; - bool is_valid = false; - try { - venv_flag_ts = std::stol(venv_flag_ts_str); - is_valid = true; - } - catch (const std::invalid_argument&) { - Log(transcribe_out_, "Could not venv flag timestamp \"{}\" as long " - "- will re-setup venv"); - } - catch (const std::out_of_range&) { - Log(transcribe_out_, "Could not venv flag timestamp \"{}\" as long " - "- will re-setup venv"); - } - return; - } - - env_proc_ = std::move(std::async(std::launch::async, [&]() { - Log(transcribe_out_, "Setting up Python virtual environment\n"); - Log(transcribe_out_, "This could take several minutes, please be " - "patient!\n"); - Log(transcribe_out_, "This will download ~1GB of dependencies.\n"); - - { - Log(transcribe_out_, " Installing pip\n"); - auto out_cb = [&](const std::string& out, const std::string& err) { - Log(transcribe_out_, "{}", out); - Log(transcribe_out_, "{}", err); - }; - if (!PythonWrapper::InstallPip(std::move(out_cb))) { - Log(transcribe_out_, "Failed to install pip!\n"); - return false; - } - } - - Log(transcribe_out_, " Installing python dependencies\n"); - auto out_cb = [&](const std::string& out, const std::string& err) { - Log(transcribe_out_, "{}", out); - Log(transcribe_out_, "{}", err); - }; - if (!PythonWrapper::InvokeWithArgs(*app_c_, - { - "-u", // Unbuffered output - "-m pip", - "install", - "-r Resources/Scripts/requirements_frozen.txt", - }, out_cb)) { - Log(transcribe_out_, "Failed to launch environment setup thread!\n"); - return false; - } - - Log(transcribe_out_, " Fetching CuDNN\n"); - if (!PythonWrapper::InvokeWithArgs(*app_c_, - { - "-m wget", - "https://developer.download.nvidia.com/compute/cudnn/redist/cudnn/windows-x86_64/cudnn-windows-x86_64-9.5.1.17_cuda12-archive.zip" - }, out_cb)) { - } - Log(transcribe_out_, " Unzipping CuDNN\n"); - if (!PythonWrapper::InvokeWithArgs(*app_c_, - { - "-m zipfile -e", - "cudnn-windows-x86_64-9.5.1.17_cuda12-archive.zip", - "." - }, out_cb)) { - } - Log(transcribe_out_, " Installing CuDNN\n"); - { - std::filesystem::path cudnn_dir; - if (!FindDirectoryByPrefix(transcribe_out_, "cudnn", cudnn_dir)) { - Log(transcribe_out_, "Failed to find unzipped cudnn " - "directory\n"); - return false; - } - std::error_code ec; - const std::filesystem::path dest_dir = "Resources/Scripts"; - for (const auto& entry : - std::filesystem::recursive_directory_iterator(cudnn_dir, ec)) { - if (ec) { - Log(transcribe_out_, "Failed to iterate cudnn dir: {}\n", - ec.message()); - return false; - } - if (!entry.is_regular_file(ec)) { - continue; - } - if (ec) { - Log(transcribe_out_, "Skipping unrecognized file type " - "{}: {}\n", entry.path().string(), ec.message()); - continue; - } - if (entry.path().extension() != ".dll") { - continue; - } - std::filesystem::path dest = - dest_dir / entry.path().filename(); - // Remove destination - std::filesystem::remove(dest, ec); - if (ec) { - Log(transcribe_out_, "Failed to delete old CuDNN .dll: {}\n", - ec.message()); - return false; - } - // Rename file - std::filesystem::rename(entry.path(), dest, ec); - if (ec) { - Log(transcribe_out_, "Failed to move CuDNN .dll: {}\n", - ec.message()); - } - } - // Delete cudnn dir - std::filesystem::remove_all(cudnn_dir, ec); - if (ec) { - Log(transcribe_out_, "Failed to remove old CuDNN dir: {}\n", - ec.message()); - } - } - - Log(transcribe_out_, "Successfully set up virtual environment!\n"); - - std::ofstream venv_flag_ofs(venv_flag); - auto now = std::chrono::system_clock::now(); - const int64_t seconds_since_epoch = std::chrono::duration_cast(now.time_since_epoch()).count(); - venv_flag_ofs << std::to_string(seconds_since_epoch); - - return true; - })); - - if (block) { - // Spinning prevents the GUI from hanging. - while (true) { - auto status = env_proc_.wait_for(std::chrono::milliseconds(1)); - if (status == std::future_status::ready) { - break; - } - } - } -} - -void Frame::OnDumpMics(wxCommandEvent& event) -{ - auto status = dump_mics_.wait_for(std::chrono::seconds(0)); - if (status != std::future_status::ready) { - Log(transcribe_out_, "Mic dump already running\n"); - return; - } - dump_mics_ = std::move(std::async(std::launch::async, [&]() { - EnsureVirtualEnv(/*block=*/true); - Log(transcribe_out_, "Getting mics...\n"); - Log(transcribe_out_, "{}\n", PythonWrapper::DumpMics()); - return true; - })); -} - -bool GetUserPath(wxTextCtrl* out, - const std::string& raw, std::filesystem::path& clean, - const std::string& err_prefix = "", bool must_exist = true) { - clean = raw; - if (must_exist && !std::filesystem::exists(clean)) { - std::ostringstream oss; - oss << err_prefix << ": User-provided path does not exist at " - << clean << std::endl; - Log(out, oss.str().c_str()); - return false; - } - return true; -} - -void Frame::OnGenerateFX(wxCommandEvent& event) -{ - auto status = unity_app_.wait_for(std::chrono::seconds(0)); - if (status != std::future_status::ready) { - Log(unity_out_, "Unity process already running\n"); - return; - } - - unity_app_ = std::move(std::async(std::launch::async, [&]() { - Log(unity_out_, "Generating animator\n"); - - EnsureVirtualEnv(/*block=*/true); - - std::filesystem::path unity_assets_path; - if (!GetUserPath(unity_out_, - unity_assets_file_picker_->GetPath().ToStdString(), - unity_assets_path, - "Cannot generate FX layer: Failed to validate assets directory")) { - return false; - } - std::filesystem::path unity_animator_path; - if (!GetUserPath(unity_out_, - unity_animator_file_picker_->GetPath().ToStdString(), - unity_animator_path, - "Cannot generate FX layer: Failed to validate animator directory")) { - return false; - } - std::filesystem::path unity_parameters_path; - if (!GetUserPath(unity_out_, - unity_parameters_file_picker_->GetPath().ToStdString(), - unity_parameters_path, - "Cannot generate FX layer: Failed to validate parameters directory")) { - return false; - } - std::filesystem::path unity_menu_path; - if (!GetUserPath(unity_out_, unity_menu_file_picker_->GetPath().ToStdString(), - unity_menu_path, - "Cannot generate FX layer: Failed to validate menu directory")) { - return false; - } - - std::string unity_animator_generated_dir = - unity_animator_generated_dir_->GetLineText(0).ToStdString(); - std::string unity_animator_generated_name = - unity_animator_generated_name_->GetLineText(0).ToStdString(); - std::string unity_parameters_generated_name = - unity_parameters_generated_name_->GetLineText(0).ToStdString(); - std::string unity_menu_generated_name = - unity_menu_generated_name_->GetLineText(0).ToStdString(); - - int chars_per_sync_idx = unity_chars_per_sync_->GetSelection(); - if (chars_per_sync_idx == wxNOT_FOUND) { - chars_per_sync_idx = kCharsDefault; - } - int bytes_per_char_idx = unity_bytes_per_char_->GetSelection(); - if (bytes_per_char_idx == wxNOT_FOUND) { - bytes_per_char_idx = kBytesDefault; - } - - ASSIGN_OR_RETURN_BOOL(int, rows, stoiInRange(transcribe_out_, unity_rows_->GetValue().ToStdString(), "rows", 1, 10)); - ASSIGN_OR_RETURN_BOOL(int, cols, stoiInRange(transcribe_out_, unity_cols_->GetValue().ToStdString(), "cols", 1, 120)); - ASSIGN_OR_RETURN_BOOL(int, texture_sz, stoiInRange(transcribe_out_, unity_texture_sz_->GetValue().ToStdString(), "texture_sz", 128, 8192)); - ASSIGN_OR_RETURN_BOOL(int, chars_per_sync, stoiInRange(transcribe_out_, kCharsPerSync[chars_per_sync_idx].ToStdString(), "chars_per_sync", 1, 24)); - ASSIGN_OR_RETURN_BOOL(int, bytes_per_char, stoiInRange(transcribe_out_, kBytesPerChar[bytes_per_char_idx].ToStdString(), "bytes_per_char", 1, 2)); - - app_c_->assets_path = unity_assets_path.string(); - app_c_->fx_path = unity_animator_path.string(); - app_c_->params_path = unity_parameters_path.string(); - app_c_->menu_path = unity_menu_path.string(); - app_c_->unity_generated_dir = unity_animator_generated_dir; - app_c_->bytes_per_char = bytes_per_char; - app_c_->chars_per_sync = chars_per_sync; - app_c_->rows = rows; - app_c_->cols = cols; - app_c_->texture_sz = texture_sz; - app_c_->clear_osc = unity_clear_osc_->GetValue(); - app_c_->enable_phonemes = unity_enable_phonemes_->GetValue(); - app_c_->Serialize(AppConfig::kConfigPath); - - std::string out; - if (!PythonWrapper::GenerateAnimator( - *app_c_, - std::string(AppConfig::kConfigPath), - unity_animator_generated_dir, - unity_animator_generated_name, - unity_parameters_generated_name, - unity_menu_generated_name, - unity_out_)) { - Log(unity_out_, "Failed to generate animator:\n%s\n", out.c_str()); - } - return true; - })); -} - -// Return a non-cryptographic hash of the file at `path`. -std::string hash_non_crypto(const std::string& path) { - std::ifstream file_ifs(path, std::ios::binary); - if (!file_ifs) { - std::cerr << "Could not open the file: " << path << '\n'; - return 0; - } - - // Read all bytes from the file into a vector - std::vector data((std::istreambuf_iterator(file_ifs)), - std::istreambuf_iterator()); - - // Compute the hash as a sum of all bytes - uint32_t hash = std::accumulate(data.begin(), data.end(), 0); - - std::stringstream ss; - ss << std::hex << hash; - return ss.str(); -} - -void Frame::OnUnityAutoRefresh(wxCommandEvent& event) -{ - auto status = unity_auto_refresh_.wait_for(std::chrono::seconds(0)); - if (status != std::future_status::ready) { - Log(unity_out_, "Auto refresh thread already running\n"); - return; - } - - run_unity_auto_refresh_ = true; - - unity_auto_refresh_ = std::move(std::async(std::launch::async, [&]() { - std::string fx_hash_prev; - std::string params_hash_prev; - std::string menu_hash_prev; - while (run_unity_auto_refresh_) { - std::this_thread::sleep_for(std::chrono::seconds(3)); - - std::filesystem::path unity_animator_path; - if (!GetUserPath(unity_out_, - unity_animator_file_picker_->GetPath().ToStdString(), - unity_animator_path, - "Cannot auto-refresh FX layer: Failed to validate animator directory")) { - return false; - } - std::filesystem::path unity_parameters_path; - if (!GetUserPath(unity_out_, - unity_parameters_file_picker_->GetPath().ToStdString(), - unity_parameters_path, - "Cannot auto-refresh FX layer: Failed to validate parameters directory")) { - return false; - } - std::filesystem::path unity_menu_path; - if (!GetUserPath(unity_out_, unity_menu_file_picker_->GetPath().ToStdString(), - unity_menu_path, - "Cannot auto-refresh FX layer: Failed to validate menu directory")) { - return false; - } - - if (fx_hash_prev.empty() || params_hash_prev.empty() || menu_hash_prev.empty()) { - Log(unity_out_, "Generating initial hash of animator, parameters and menu\n"); - fx_hash_prev = hash_non_crypto(unity_animator_path.string()); - params_hash_prev = hash_non_crypto(unity_parameters_path.string()); - menu_hash_prev = hash_non_crypto(unity_menu_path.string()); - continue; - } - - const std::string fx_hash = hash_non_crypto(unity_animator_path.string()); - const std::string params_hash = hash_non_crypto(unity_parameters_path.string()); - const std::string menu_hash = hash_non_crypto(unity_menu_path.string()); - - if (fx_hash.empty() || params_hash.empty() || menu_hash.empty()) { - Log(unity_out_, "Failed to hash animator ({}, {}), parameters ({}, {}), or menu ({}, {})\n", - unity_animator_path.string(), fx_hash, - unity_parameters_path.string(), params_hash, - unity_menu_path.string(), menu_hash); - continue; - } - - if (fx_hash != fx_hash_prev || - params_hash != params_hash_prev || - menu_hash != menu_hash_prev) { - Log(unity_out_, "Detected change in animator ({}), params ({}), or menu ({}), regenerating unity assets\n", - fx_hash != fx_hash_prev ? "CHANGED" : "NO_CHANGE", - params_hash != params_hash_prev ? "CHANGED" : "NO_CHANGE", - menu_hash != menu_hash_prev ? "CHANGED" : "NO_CHANGE"); - OnGenerateFX(event); - fx_hash_prev = fx_hash; - params_hash_prev = params_hash; - menu_hash_prev = menu_hash; - } - } - Log(unity_out_, "Stopping unity asset auto-generation\n"); - return true; - })); -} - -void Frame::OnUnityAutoRefreshStop() { - run_unity_auto_refresh_ = false; - auto status = unity_auto_refresh_.wait_for(std::chrono::seconds(0)); - if (status == std::future_status::ready) { - Log(transcribe_out_, "Auto-refresh thread already stopped.\n"); - } - else { - unity_auto_refresh_.wait(); - Log(transcribe_out_, "Stopped transcription engine\n"); - } -} - -void Frame::OnUnityAutoRefreshStop(wxCommandEvent& event) { - OnUnityAutoRefreshStop(); -} - -void Frame::OnListPip(wxCommandEvent& event) -{ - Log(debug_out_, "Listing pip packages... "); - PythonWrapper::InvokeWithArgs(*app_c_, { - "-m pip", - "list", - }, "Failed to list pip packages", debug_out_); - - Log(debug_out_, "Listing pip cache... "); - PythonWrapper::InvokeWithArgs(*app_c_, { - "-m pip", - "cache", - "list", - }, "Failed to list pip cache", debug_out_); -} - -void Frame::OnClearPip(wxCommandEvent& event) -{ - Log(debug_out_, "Clearing pip cache... "); - PythonWrapper::InvokeWithArgs(*app_c_, { - "-m pip", - "cache", - "purge", - }, "Failed to clear pip cache", debug_out_); -} - -void Frame::OnResetVenv(wxCommandEvent& event) -{ - auto status = reset_venv_proc_.wait_for(std::chrono::seconds(0)); - if (status != std::future_status::ready) { - Log(debug_out_, "Virtual environment reset already running\n"); - return; - } - - /* - Equivalent shell: - python -m pip freeze > venv_pkgs.txt - python -m pip uninstall -r venv_pkgs.txt - rm venv_pkgs.txt - */ - - reset_venv_proc_ = std::move(std::async(std::launch::async, [&]() { - Log(debug_out_, "Resetting virtual environment...\n"); - - { - std::stringstream pkg_list_ss; - auto out_cb = [&](const std::string& out, const std::string& err) { - Log(debug_out_, "{}", out); - Log(debug_out_, "{}", err); - pkg_list_ss << out; - }; - auto in_cb = [&](std::string& in) {}; - Log(debug_out_, "Freezing packages...\n"); - if (!PythonWrapper::InvokeWithArgs(*app_c_, { "-m pip freeze" }, out_cb, in_cb)) { - Log(debug_out_, "failed!\n"); - return; - } - - std::stringstream pkg_list_ss2; - std::string pkg_line; - while (std::getline(pkg_list_ss, pkg_line)) { - if (pkg_line.find("future") != std::string::npos) { - continue; - } - pkg_list_ss2 << pkg_line << std::endl; - } - - std::ofstream pkgs_ofs("venv_pkgs.txt"); - pkgs_ofs << pkg_list_ss2.str(); - pkgs_ofs.close(); - } - - // For now, leave venv_pkgs.txt on disk for better debuggability. - //ScopeGuard venv_pkgs_cleanup([]() { std::filesystem::remove("venv_pkgs.txt"); }); - - { - auto out_cb = [&](const std::string& out, const std::string& err) { - Log(debug_out_, "{}", out); - Log(debug_out_, "{}", err); - }; - auto in_cb = [&](std::string& in) {}; - Log(debug_out_, "Uninstalling packages...\n"); - if (!PythonWrapper::InvokeWithArgs(*app_c_, { "-m pip uninstall -y -r venv_pkgs.txt" }, out_cb, in_cb)) { - Log(debug_out_, "failed!\n"); - return; - } - } - - Log(debug_out_, "Virtual environment reset done!\n"); - })); -} - -void Frame::OnClearOSC(wxCommandEvent& event) -{ - std::filesystem::path osc_path = "C:/Users"; - osc_path /= wxGetUserName().ToStdString(); - osc_path /= "AppData/LocalLow/VRChat/vrchat/OSC"; - osc_path = osc_path.lexically_normal(); - Log(debug_out_, "OSC configs are stored at {}\n", osc_path.string()); - - if (!std::filesystem::is_directory(osc_path)) { - Log(debug_out_, "OSC configs do not exist at {}, assuming already " - "deleted!\n", osc_path.string()); - return; - } - - Log(debug_out_, "Deleting OSC configs... "); - std::error_code err; - if (std::filesystem::remove_all(osc_path, err)) { - Log(debug_out_, "success!\n"); - } - else { - wxLogError("Failed to delete OSC configs: %s", err.message()); - Log(debug_out_, "failed!\n"); - } -} - -void Frame::OnBackupVenv(wxCommandEvent& event) -{ - std::filesystem::path venv_path = "C:/Users"; - venv_path /= wxGetUserName().ToStdString(); - venv_path /= "Downloads/TaSTT_venv"; - venv_path = venv_path.lexically_normal(); - Log(debug_out_, "Backing up virtual environment to {}\n", - venv_path.string()); - - if (std::filesystem::is_directory(venv_path)) { - Log(debug_out_, "Old backup found, removing... "); - std::error_code err; - if (!std::filesystem::remove_all(venv_path, err)) { - wxLogError("Failed to remove old virtual environment backup: %s", - err.message()); - Log(debug_out_, "failed!\n"); - return; - } - Log(debug_out_, "success!\n"); - } - - Log(debug_out_, "Copying venv... "); - auto opts = std::filesystem::copy_options(); - opts |= std::filesystem::copy_options::overwrite_existing; - opts |= std::filesystem::copy_options::recursive; - std::error_code error; - std::filesystem::copy("Resources/Python", venv_path, opts, error); - if (error.value()) { - wxLogError("Failed to back up virtual environment: %s (%d)", - error.message(), error.value()); - Log(debug_out_, "failed!\n"); - return; - } - Log(debug_out_, "success!\n"); -} - -void Frame::OnRestoreVenv(wxCommandEvent& event) -{ - std::filesystem::path venv_path = "C:/Users"; - venv_path /= wxGetUserName().ToStdString(); - venv_path /= "Downloads/TaSTT_venv"; - venv_path = venv_path.lexically_normal(); - Log(debug_out_, "Restoring virtual environment from {}\n", - venv_path.string()); - - if (!std::filesystem::is_directory(venv_path)) { - wxLogError("Virtual environment backup does not exist at %s", - venv_path.string()); - Log(debug_out_, "Failed!\n"); - } - - if (std::filesystem::is_directory("Resources/Python")) { - Log(debug_out_, "Removing active virtual environment... "); - std::error_code err; - if (!std::filesystem::remove_all("Resources/Python", err)) { - wxLogError("Failed to remove active virtual environment: %s", - err.message()); - Log(debug_out_, "failed!\n"); - return; - } - Log(debug_out_, "success!\n"); - } - - Log(debug_out_, "Copying venv... "); - auto opts = std::filesystem::copy_options(); - opts |= std::filesystem::copy_options::overwrite_existing; - opts |= std::filesystem::copy_options::recursive; - std::error_code error; - std::filesystem::copy(venv_path, "Resources/Python", opts, error); - if (error.value()) { - wxLogError("Failed to copy venv: %s (%d)", error.message(), - error.value()); - Log(debug_out_, "failed!\n"); - return; - } - Log(debug_out_, "success!\n"); - - Log(debug_out_, "Setting up virtual env to ensure consistency. Most " - "packages should not be re-acquired. Output is printed to the " - "transcription panel.\n"); - EnsureVirtualEnv(/*block=*/false); -} - -void Frame::OnSetupVenv(wxCommandEvent& event) -{ - Log(debug_out_, "Setting up virtual environment. Output is printed to the " - "transcription panel.\n"); - EnsureVirtualEnv(/*block=*/false, /*force=*/true); -} - -void Frame::OnUnityParamChangeImpl() { - int chars_per_sync_idx = unity_chars_per_sync_->GetSelection(); - if (chars_per_sync_idx == wxNOT_FOUND) { - chars_per_sync_idx = kCharsDefault; - } - ASSIGN_OR_RETURN_VOID(int, chars_per_sync, stoiInRange(transcribe_out_, kCharsPerSync[chars_per_sync_idx].ToStdString(), "chars_per_sync", 1, 24)); - int bytes_per_char_idx = unity_bytes_per_char_->GetSelection(); - if (bytes_per_char_idx == wxNOT_FOUND) { - bytes_per_char_idx = kBytesDefault; - } - ASSIGN_OR_RETURN_VOID(int, bytes_per_char, stoiInRange(transcribe_out_, kBytesPerChar[bytes_per_char_idx].ToStdString(), "bytes_per_char", 1, 2)); - - // Used to select which region is being updated. - int select_bits = 8; - // Used to update the active region. - int layer_bits = (chars_per_sync * bytes_per_char) * 8; - // Used to control the size of the board. - int scale_bits = 8; - // These are all the misc bits we use: - // 1. dummy (we should get rid of this one) - // 2. show - // 3. disable - // 4. lock - // 5. clear - int misc_bits = 5; - - int phoneme_bits = 0; - if (unity_enable_phonemes_->GetValue()) { - phoneme_bits = 6; - } - - int total_bits = select_bits + layer_bits + scale_bits + misc_bits + phoneme_bits; - - Log(unity_out_, "This configuration will use {} bits of avatar parameter space:\n", total_bits); - Log(unity_out_, " {} bits coming from ({} characters per sync) * ({} bytes per character)\n", layer_bits, chars_per_sync, bytes_per_char); - Log(unity_out_, " {} bits coming from fixed overheads\n", select_bits + scale_bits + misc_bits); - if (phoneme_bits > 0) { - Log(unity_out_, " {} bits coming from phonemes\n", phoneme_bits); - } -} - -void Frame::OnUnityParamChange(wxCommandEvent& event) { - OnUnityParamChangeImpl(); -} - -void Frame::OnAppStart(wxCommandEvent& event) { - auto status = py_app_.wait_for(std::chrono::seconds(0)); - if (status != std::future_status::ready) { - Log(transcribe_out_, "Transcription engine already running\n"); - return; - } - - status = obs_app_.wait_for(std::chrono::seconds(0)); - if (status != std::future_status::ready) { - Log(transcribe_out_, "Transcription engine (OBS server) already running\n"); - return; - } - - Log(transcribe_out_, "Launching transcription engine\n"); - - int which_mic = py_app_mic_->GetSelection(); - if (which_mic == wxNOT_FOUND) { - which_mic = kMicDefault; - } - int which_lang = py_app_lang_->GetSelection(); - if (which_lang == wxNOT_FOUND) { - which_lang = kLangDefault; - } - int which_translate_target = py_app_translate_target_->GetSelection(); - if (which_translate_target == wxNOT_FOUND) { - which_translate_target = kLangDefault; - } - int which_model = py_app_model_->GetSelection(); - if (which_model == wxNOT_FOUND) { - which_model = kModelDefault; - } - int which_model_translation = py_app_model_translation_->GetSelection(); - if (which_model_translation == wxNOT_FOUND) { - which_model_translation = kModelTranslationDefault; - } - int chars_per_sync_idx = py_app_chars_per_sync_->GetSelection(); - if (chars_per_sync_idx == wxNOT_FOUND) { - chars_per_sync_idx = kCharsDefault; - } - int bytes_per_char_idx = py_app_bytes_per_char_->GetSelection(); - if (bytes_per_char_idx == wxNOT_FOUND) { - bytes_per_char_idx = kBytesDefault; - } - int button_idx = py_app_button_->GetSelection(); - if (button_idx == wxNOT_FOUND) { - button_idx = kButtonDefault; - } - int prio_idx = py_app_prio_->GetSelection(); - if (prio_idx == wxNOT_FOUND) { - prio_idx = kPrioDefault; - } - int compute_type_idx = py_app_compute_type_->GetSelection(); - if (compute_type_idx == wxNOT_FOUND) { - compute_type_idx = kComputeTypeDefault; - } - - const bool enable_local_beep = py_app_enable_local_beep_->GetValue(); - const bool enable_orig_lang = py_app_enable_orig_lang_->GetValue(); - const bool enable_browser_src = py_app_enable_browser_src_->GetValue(); - const bool use_cpu = py_app_use_cpu_->GetValue(); - const bool use_builtin = py_app_use_builtin_->GetValue(); - const bool enable_uwu_filter = py_app_enable_uwu_filter_->GetValue(); - const bool remove_trailing_period = py_app_remove_trailing_period_->GetValue(); - const bool enable_uppercase_filter = py_app_enable_uppercase_filter_->GetValue(); - const bool enable_lowercase_filter = py_app_enable_lowercase_filter_->GetValue(); - const bool enable_profanity_filter = py_app_enable_profanity_filter_->GetValue(); - const bool enable_debug_mode = py_app_enable_debug_mode_->GetValue(); - const bool reset_on_toggle = py_app_reset_on_toggle_->GetValue(); - const bool enable_previews = py_app_enable_previews_->GetValue(); - const bool enable_lock_at_spawn = py_app_enable_lock_at_spawn_->GetValue(); - - ASSIGN_OR_RETURN_VOID(int, rows, stoiInRange(transcribe_out_, py_app_rows_->GetValue().ToStdString(), "rows", 1, 10)); - ASSIGN_OR_RETURN_VOID(int, cols, stoiInRange(transcribe_out_, py_app_cols_->GetValue().ToStdString(), "cols", 1, 120)); - ASSIGN_OR_RETURN_VOID(int, chars_per_sync, stoiInRange(transcribe_out_, kCharsPerSync[chars_per_sync_idx].ToStdString(), "chars_per_sync", 1, 24)); - ASSIGN_OR_RETURN_VOID(int, bytes_per_char, stoiInRange(transcribe_out_, kBytesPerChar[bytes_per_char_idx].ToStdString(), "bytes_per_char", 1, 2)); - ASSIGN_OR_RETURN_VOID(int, gpu_idx, stoiInRange(transcribe_out_, py_app_gpu_idx_->GetValue().ToStdString(), "gpu_idx", 0, 10)); - ASSIGN_OR_RETURN_VOID(int, min_silence_duration_ms, stoiInRange(transcribe_out_, py_app_min_silence_duration_ms_->GetValue().ToStdString(), "min_silence_duration_ms", 50, 5000)); - ASSIGN_OR_RETURN_VOID(int, max_speech_duration_s, stoiInRange(transcribe_out_, py_app_max_speech_duration_s_->GetValue().ToStdString(), "max_speech_duration_s", 1, 30)); - ASSIGN_OR_RETURN_VOID(int, reset_after_silence_s, stoiInRange(transcribe_out_, py_app_reset_after_silence_s_->GetValue().ToStdString(), "reset_after_silence_s", -1, 30)); - ASSIGN_OR_RETURN_VOID(int, transcription_loop_delay_ms, stoiInRange(transcribe_out_, py_app_transcription_loop_delay_ms_->GetValue().ToStdString(), "transcription_loop_delay_ms", 0, 10000)); - ASSIGN_OR_RETURN_VOID(int, browser_src_port, stoiInRange(transcribe_out_, py_app_browser_src_port_->GetValue().ToStdString(), "browser_src_port", 1024, 65535)); - - std::string keybind = py_app_keybind_->GetValue().ToStdString(); - - app_c_->microphone = kMicChoices[which_mic].ToStdString(); - app_c_->language = kLangChoices[which_lang].ToStdString(); - app_c_->language_target = kLangTargetChoices[which_translate_target].ToStdString(); - app_c_->model = kModelChoices[which_model].ToStdString(); - app_c_->model_translation = kModelTranslationChoices[which_model_translation].ToStdString(); - app_c_->chars_per_sync = chars_per_sync; - app_c_->bytes_per_char = bytes_per_char; - app_c_->button = kButton[button_idx].ToStdString(); - app_c_->prio = kPrio[prio_idx].ToStdString(); - app_c_->compute_type = kComputeType[compute_type_idx].ToStdString(); - app_c_->rows = rows; - app_c_->cols = cols; - app_c_->enable_local_beep = enable_local_beep; - app_c_->enable_orig_lang = enable_orig_lang; - app_c_->enable_browser_src = enable_browser_src; - app_c_->browser_src_port = browser_src_port; - app_c_->use_cpu = use_cpu; - app_c_->use_builtin = use_builtin; - app_c_->enable_uwu_filter = enable_uwu_filter; - app_c_->remove_trailing_period = remove_trailing_period; - app_c_->enable_uppercase_filter = enable_uppercase_filter; - app_c_->enable_lowercase_filter = enable_lowercase_filter; - app_c_->enable_profanity_filter = enable_profanity_filter; - app_c_->enable_debug_mode = enable_debug_mode; - app_c_->reset_on_toggle = reset_on_toggle; - app_c_->enable_previews = enable_previews; - app_c_->enable_lock_at_spawn = enable_lock_at_spawn; - app_c_->gpu_idx = gpu_idx; - app_c_->min_silence_duration_ms = min_silence_duration_ms; - app_c_->max_speech_duration_s = max_speech_duration_s; - app_c_->reset_after_silence_s = reset_after_silence_s; - app_c_->transcription_loop_delay_ms = transcription_loop_delay_ms; - app_c_->keybind = keybind; - app_c_->Serialize(AppConfig::kConfigPath); - - auto out_cb = [&](const std::string& out, const std::string& err) { - Log(transcribe_out_, "{}", out); - Log(transcribe_out_, "{}", err); - - std::istringstream out_iss(out); - std::string out_line; - while (std::getline(out_iss, out_line)) { - if (out_line.starts_with("Finalized: 1")) { - transcript_.SetFinalized(true); - } - else if (out_line.starts_with("Finalized: 0")) { - transcript_.SetFinalized(false); - } - - std::regex pattern("^Transcript: "); - if (std::regex_search(out_line, pattern)) { - std::string filtered_transcript = std::regex_replace(out_line, pattern, ""); - filtered_transcript.erase(std::remove_if(filtered_transcript.begin(), filtered_transcript.end(), [](char c) { - return c == '\n' || c == '\r'; - }), filtered_transcript.end()); - //Log(transcribe_out_, "Got transcription line! Transcript: \"{}\"", filtered_transcript); - transcript_.Set(std::move(filtered_transcript)); - } - - pattern = std::regex("^Preview: "); - if (std::regex_search(out_line, pattern)) { - std::string filtered_transcript = std::regex_replace(out_line, pattern, ""); - filtered_transcript.erase(std::remove_if(filtered_transcript.begin(), filtered_transcript.end(), [](char c) { - return c == '\n' || c == '\r'; - }), filtered_transcript.end()); - //Log(transcribe_out_, "Got transcription line! Transcript: \"{}\"", filtered_transcript); - transcript_.SetPreview(std::move(filtered_transcript)); - } - } - }; - auto in_cb = [&](std::string& in) { - if (!run_py_app_) { - std::ostringstream oss; - oss << "exit" << std::endl; - in = oss.str(); - } - }; - auto run_cb = [&]() { - return run_py_app_; - }; - run_py_app_ = true; - auto prestart_cb = [this]() -> void { - EnsureVirtualEnv(/*block=*/true); - }; - -#if 0 - obs_app_ = std::async(std::launch::async, - [this, enable_browser_src, browser_src_port]() -> bool { - if (enable_browser_src) { - BrowserSource browser_src(browser_src_port, transcribe_out_, &transcript_); - browser_src.Run(&run_py_app_); - } - return true; - }); -#endif - const std::string config_path(AppConfig::kConfigPath); - py_app_ = std::move(PythonWrapper::StartApp(*app_c_, - config_path, transcribe_out_, - std::move(out_cb), std::move(in_cb), std::move(run_cb), - std::move(prestart_cb))); - Log(transcribe_out_, "py app valid: {}\n", py_app_.valid()); -} - -void Frame::OnAppStop() { - run_py_app_ = false; - auto status = py_app_.wait_for(std::chrono::seconds(0)); - if (status == std::future_status::ready) { - Log(transcribe_out_, "Transcription engine already stopped\n"); - } - else { - py_app_.wait(); - Log(transcribe_out_, "Stopped transcription engine\n"); - } - status = obs_app_.wait_for(std::chrono::seconds(0)); - if (status == std::future_status::ready) { - Log(transcribe_out_, "Browser source already stopped\n"); - } - else { - obs_app_.wait(); - Log(transcribe_out_, "Stopped browser source\n"); - } - transcript_.Clear(); -} - -void Frame::OnAppStop(wxCommandEvent& event) { - OnAppStop(); -} - -void Frame::OnAppDrain(wxTimerEvent& event) { - Logging::kThreadLogger.Drain(); -} - -void Frame::LoadAndSetIcons() { - const char* icons[] = { - "Resources/Images/logo.png", - "Resources/Images/logo_16x16.png", - "Resources/Images/logo_32x32.png", - }; - wxIconBundle icon_bundle; - for (const auto& icon_path : icons) { - if (!std::filesystem::exists(icon_path)) { - wxLogFatalError("Logo is missing from %s", icon_path); - } - icon_bundle.AddIcon(icon_path, wxBITMAP_TYPE_PNG); - } - SetIcons(icon_bundle); -} - -void Frame::Resize() -{ - auto frame_sz = GetBestSize(); - auto panel_sz = main_panel_->GetBestSize(); - - //auto ideal_sz = panel_sz; - //ideal_sz.x += frame_sz.x; - //ideal_sz.y += frame_sz.y; - - this->SetSize(panel_sz); -} - diff --git a/GUI/GUI/GUI/Frame.h b/GUI/GUI/GUI/Frame.h deleted file mode 100644 index 7e5c7c7..0000000 --- a/GUI/GUI/GUI/Frame.h +++ /dev/null @@ -1,134 +0,0 @@ -#pragma once - -#include -#include - -#ifndef WX_PRECOMP -#include -#endif - -#include "Config.h" -#include "Transcript.h" - -#include -#include - -class Frame : public wxFrame -{ -public: - Frame(); - -private: - wxPNGHandler png_handler_; - - wxPanel* main_panel_; - wxPanel* transcribe_panel_; - wxPanel* unity_panel_; - wxPanel* debug_panel_; - - wxTextCtrl* transcribe_out_; - wxTextCtrl* unity_out_; - wxTextCtrl* debug_out_; - - wxTextCtrl* unity_animator_generated_dir_; - wxTextCtrl* unity_animator_generated_name_; - wxTextCtrl* unity_parameters_generated_name_; - wxTextCtrl* unity_menu_generated_name_; - - wxTextCtrl* py_app_rows_; - wxTextCtrl* py_app_cols_; - wxTextCtrl* py_app_gpu_idx_; - wxTextCtrl* py_app_min_silence_duration_ms_; - wxTextCtrl* py_app_max_speech_duration_s_; - wxTextCtrl* py_app_reset_after_silence_s_; - wxTextCtrl* py_app_transcription_loop_delay_ms_; - wxTextCtrl* py_app_keybind_; - wxTextCtrl* py_app_browser_src_port_; - wxTextCtrl* py_app_commit_fuzz_threshold_; - wxTextCtrl* unity_rows_; - wxTextCtrl* unity_cols_; - wxTextCtrl* unity_texture_sz_; - - wxDirPickerCtrl* unity_assets_file_picker_; - wxFilePickerCtrl* unity_animator_file_picker_; - wxFilePickerCtrl* unity_parameters_file_picker_; - wxFilePickerCtrl* unity_menu_file_picker_; - - wxChoice* py_app_mic_; - wxChoice* py_app_lang_; - wxChoice* py_app_translate_target_; - wxChoice* py_app_model_; - wxChoice* py_app_model_translation_; - // TODO(yum) figure out how to deduplicate these objects - wxChoice* py_app_chars_per_sync_; - wxChoice* py_app_bytes_per_char_; - wxChoice* py_app_button_; - wxChoice* py_app_prio_; - wxChoice* py_app_compute_type_; - wxChoice* unity_chars_per_sync_; - wxChoice* unity_bytes_per_char_; - - wxCheckBox* py_app_enable_local_beep_; - wxCheckBox* py_app_enable_orig_lang_; - wxCheckBox* py_app_enable_browser_src_; - wxCheckBox* py_app_use_cpu_; - wxCheckBox* py_app_use_builtin_; - wxCheckBox* py_app_enable_uwu_filter_; - wxCheckBox* py_app_remove_trailing_period_; - wxCheckBox* py_app_enable_uppercase_filter_; - wxCheckBox* py_app_enable_lowercase_filter_; - wxCheckBox* py_app_enable_profanity_filter_; - wxCheckBox* py_app_enable_debug_mode_; - wxCheckBox* py_app_reset_on_toggle_; - wxCheckBox* py_app_enable_previews_; - wxCheckBox* py_app_enable_lock_at_spawn_; - wxCheckBox* unity_clear_osc_; - wxCheckBox* unity_enable_phonemes_; - - std::future py_app_; - std::future obs_app_; - Transcript transcript_; - bool run_py_app_; - bool run_unity_auto_refresh_; - std::future unity_app_; - std::future unity_auto_refresh_; - std::future dump_mics_; - std::future env_proc_; - std::future reset_venv_proc_; - - wxTimer py_app_drain_; - - std::unique_ptr app_c_; - - // Initialize GUI input fields using `app_c_`. - void ApplyConfigToInputFields(); - // Ensure that virtual env is set up. - void EnsureVirtualEnv(bool block, bool force = false); - - void OnExit(wxCloseEvent& event); - void OnNavbarTranscribe(wxCommandEvent& event); - void OnNavbarUnity(wxCommandEvent& event); - void OnNavbarDebug(wxCommandEvent& event); - void OnDumpMics(wxCommandEvent& event); - void OnAppStart(wxCommandEvent& event); - void OnAppStop(); - void OnAppStop(wxCommandEvent& event); - void OnAppDrain(wxTimerEvent& event); - void OnGenerateFX(wxCommandEvent& event); - void OnUnityAutoRefresh(wxCommandEvent& event); - void OnUnityAutoRefreshStop(); - void OnUnityAutoRefreshStop(wxCommandEvent& event); - void OnUnityParamChangeImpl(); - void OnUnityParamChange(wxCommandEvent& event); - void OnListPip(wxCommandEvent& event); - void OnClearPip(wxCommandEvent& event); - void OnResetVenv(wxCommandEvent& event); - void OnClearOSC(wxCommandEvent& event); - void OnBackupVenv(wxCommandEvent& event); - void OnRestoreVenv(wxCommandEvent& event); - void OnSetupVenv(wxCommandEvent& event); - - void LoadAndSetIcons(); - void Resize(); -}; - diff --git a/GUI/GUI/GUI/GUI.rc b/GUI/GUI/GUI/GUI.rc deleted file mode 100644 index 01c922a..0000000 Binary files a/GUI/GUI/GUI/GUI.rc and /dev/null differ diff --git a/GUI/GUI/GUI/GUI.vcxproj b/GUI/GUI/GUI/GUI.vcxproj deleted file mode 100644 index e5874c4..0000000 --- a/GUI/GUI/GUI/GUI.vcxproj +++ /dev/null @@ -1,196 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {e17ad8b1-0565-459b-b8d0-2024cc6c5cd4} - GUI - 10.0 - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - false - - - Application - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(ProjectDir)/whisper;$(ProjectDir)/oatpp - $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir) - - - $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(ProjectDir)/whisper;$(ProjectDir)/oatpp - $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir) - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - MultiThreaded - - - Windows - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - MultiThreaded - - - Windows - true - true - true - kernel32.lib;user32.lib;gdi32.lib;comdlg32.lib;winspool.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;advapi32.lib;version.lib;comctl32.lib;rpcrt4.lib;ws2_32.lib;wininet.lib;winmm.lib;Whisper.lib;%(AdditionalDependencies) - - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - MultiThreadedDebug - - - Windows - true - kernel32.lib;user32.lib;gdi32.lib;comdlg32.lib;winspool.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;advapi32.lib;version.lib;comctl32.lib;rpcrt4.lib;ws2_32.lib;wininet.lib;winmm.lib;Whisper.lib;%(AdditionalDependencies) - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - MultiThreaded - - - Windows - true - true - true - kernel32.lib;user32.lib;gdi32.lib;comdlg32.lib;winspool.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;advapi32.lib;version.lib;comctl32.lib;rpcrt4.lib;ws2_32.lib;wininet.lib;winmm.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/GUI/GUI/GUI/GUI.vcxproj.filters b/GUI/GUI/GUI/GUI.vcxproj.filters deleted file mode 100644 index 10069e8..0000000 --- a/GUI/GUI/GUI/GUI.vcxproj.filters +++ /dev/null @@ -1,124 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {a0953f26-cbc5-43b7-86c6-2d4b1030b13f} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - WebServer - - - WebServer - - - WebServer - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - WebServer - - - WebServer - - - WebServer - - - WebServer - - - Header Files - - - - - Resource Files - - - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - \ No newline at end of file diff --git a/GUI/GUI/GUI/GUI.vcxproj.user b/GUI/GUI/GUI/GUI.vcxproj.user deleted file mode 100644 index 052eb16..0000000 --- a/GUI/GUI/GUI/GUI.vcxproj.user +++ /dev/null @@ -1,13 +0,0 @@ - - - - TaSTT.exe - $(ProjectDir)/../../TaSTT/ - WindowsLocalDebugger - - - TaSTT.exe - $(ProjectDir)/../../TaSTT/ - WindowsLocalDebugger - - \ No newline at end of file diff --git a/GUI/GUI/GUI/HTTPMapper.cpp b/GUI/GUI/GUI/HTTPMapper.cpp deleted file mode 100644 index c9884ae..0000000 --- a/GUI/GUI/GUI/HTTPMapper.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "HTTPMapper.h" - -#include -#include - -namespace { - // Source: RFC 2616 section 6.1.1 - const std::map kStatusCodeToString{ - {100, "Continue" }, - {101, "Switching Protocols"}, - {200, "OK"}, - {201, "Created"}, - {202, "Accepted"}, - {203, "Non-Authoritative Information"}, - {204, "No Content"}, - {205, "Reset Content"}, - {206, "Partial Content"}, - {300, "Multiple Choices"}, - {301, "Moved Permanently"}, - {302, "Found"}, - {303, "See Other"}, - {304, "Not Modified"}, - {305, "Use Proxy"}, - {307, "Temporary Redirect"}, - {400, "Bad Request"}, - {401, "Unauthorized"}, - {402, "Payment Required"}, - {403, "Forbidden"}, - {404, "Not Found"}, - {405, "Method Not Allowed"}, - {406, "Not Acceptable"}, - }; -} - -namespace WebServer { - std::string HTTPMapper::Map(const int status_code, - const std::string& payload, const ContentType type) { - switch (type) { - case HTML: - return HTTPMapperHTML().Map(status_code, payload); - case JSON: - return HTTPMapperJSON().Map(status_code, payload); - } - } - - std::string HTTPMapperHTML::Map(const int status_code, - const std::string& payload) { - std::ostringstream oss; - // This might throw and crash the app, but that's ok, just don't use an unsupported code. - oss << "HTTP/1.1 " << status_code << " " << kStatusCodeToString.at(status_code) << "\r\n"; - oss << "Content-Type: text/html\r\n"; - oss << "Content-Length: " << std::to_string(payload.size()) << "\r\n"; - oss << "\r\n"; - oss << payload; - return oss.str(); - } - - std::string HTTPMapperJSON::Map(const int status_code, - const std::string& payload) { - std::ostringstream oss; - // This might throw and crash the app, but that's ok, just don't use an unsupported code. - oss << "HTTP/1.1 " << status_code << " " << kStatusCodeToString.at(status_code) << "\r\n"; - oss << "Content-Type: application/json\r\n"; - oss << "Content-Length: " << std::to_string(payload.size()) << "\r\n"; - oss << "\r\n"; - oss << payload; - return oss.str(); - } -} \ No newline at end of file diff --git a/GUI/GUI/GUI/HTTPMapper.h b/GUI/GUI/GUI/HTTPMapper.h deleted file mode 100644 index 4086fe9..0000000 --- a/GUI/GUI/GUI/HTTPMapper.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "WebCommon.h" - -#include - -namespace WebServer { - - class HTTPMapper { - public: - HTTPMapper() {} - virtual ~HTTPMapper() {} - - std::string Map(int status_code, - const std::string& payload, ContentType type); - }; - - class HTTPMapperHTML : public HTTPMapper { - public: - HTTPMapperHTML() {} - virtual ~HTTPMapperHTML() {} - - std::string Map(int status_code, - const std::string& payload); - }; - - class HTTPMapperJSON : public HTTPMapper { - public: - HTTPMapperJSON() {} - virtual ~HTTPMapperJSON() {} - - std::string Map(int status_code, - const std::string& payload); - }; -} diff --git a/GUI/GUI/GUI/HTTPParser.cpp b/GUI/GUI/GUI/HTTPParser.cpp deleted file mode 100644 index 3e15afa..0000000 --- a/GUI/GUI/GUI/HTTPParser.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include "HTTPParser.h" -#include "ScopeGuard.h" - -#include - -namespace WebServer { - HTTPParser::HTTPParser() {} - - namespace { - constexpr const char kLineDelim[] = "\r\n"; - constexpr const char kHeadersDelim[] = "\r\n\r\n"; - constexpr const char kRfcSP[] = " "; - constexpr const char kRfcHT[] = "\t"; - constexpr const char kRfcLWS[] = " \t\r\n"; - }; - - bool HTTPParser::Parse(const std::string& raw_http, std::string& err) { - std::ostringstream err_oss; - ScopeGuard err_oss_flush([&]() { err += err_oss.str(); }); - - ParserState state = PARSER_STATE_START_LINE; - size_t pos = 0; - while (pos < raw_http.length()) { - size_t end; - switch (state) { - case PARSER_STATE_START_LINE: - end = raw_http.find(kLineDelim, pos); - break; - case PARSER_STATE_HEADERS: - end = raw_http.find(kHeadersDelim, pos); - break; - case PARSER_STATE_PAYLOAD: - end = raw_http.length(); - break; - } - ScopeGuard advance_pos([&]() { pos = end + 1; }); - if (end == std::string::npos) { - err_oss << "Failed to parse HTTP in state " << state << ": No delimiter!" << std::endl; - return false; - } - std::string_view segment(raw_http.data() + pos, end - pos); - if (!ParseSegment(segment, state, err)) { - return false; - } - } - return true; - } - - const std::string& HTTPParser::GetMethod() const { - return method_; - } - - const std::string& HTTPParser::GetPath() const { - return path_; - } - - bool HTTPParser::GetHeader(const std::string& header, std::string& value) const { - auto iter = headers_.find(header); - if (iter == headers_.end()) { - return false; - } - value = iter->second; - return true; - } - - const std::map& HTTPParser::GetHeaders() const { - return headers_; - } - - const std::string& HTTPParser::GetPayload() const { - return payload_; - } - - bool HTTPParser::ParseSegment( - const std::string_view segment, - ParserState& state, - std::string& err) { - std::ostringstream err_oss; - ScopeGuard err_oss_flush([&]() { err += err_oss.str(); }); - switch (state) { - case PARSER_STATE_START_LINE: - return ParseStartLine(segment, state, err); - case PARSER_STATE_HEADERS: - return ParseHeaders(segment, state, err); - case PARSER_STATE_PAYLOAD: - return ParsePayload(segment, state, err); - } - } - - enum StartLineParserState { - START_LINE_PARSER_STATE_METHOD, - START_LINE_PARSER_STATE_PATH, - START_LINE_PARSER_STATE_VERSION, - START_LINE_PARSER_STATE_END, - }; - // Source: RFC 2616 section 5.1.1. - bool HTTPParser::ParseStartLine( - const std::string_view segment, - ParserState& state, - std::string& err) { - std::ostringstream err_oss; - ScopeGuard err_oss_flush([&]() { err += err_oss.str(); }); - - // Request-Line = Method SP Request-URI SP HTTP-Version CRLF - // SP == space. - // Thus we expect to see exactly three space-delimited chunks. - StartLineParserState cur_state = START_LINE_PARSER_STATE_METHOD; - size_t pos = 0; - while (pos < segment.length()) { - size_t end = segment.find(' ', pos); - if (end == std::string::npos) { - end = segment.length(); - } - ScopeGuard advance_pos([&]() { pos = end + 1; }); - - std::string_view cur_segment(segment.data() + pos, end - pos); - switch (cur_state) { - case START_LINE_PARSER_STATE_METHOD: - method_ = cur_segment; - cur_state = START_LINE_PARSER_STATE_PATH; - continue; - case START_LINE_PARSER_STATE_PATH: - path_ = cur_segment; - cur_state = START_LINE_PARSER_STATE_VERSION; - continue; - case START_LINE_PARSER_STATE_VERSION: - // TODO(yum) check this - cur_state = START_LINE_PARSER_STATE_END; - continue; - case START_LINE_PARSER_STATE_END: - err_oss << "Invalid start line: has too many parts: " << segment << std::endl; - return false; - } - } - if (cur_state != START_LINE_PARSER_STATE_END) { - err_oss << "Invalid start line: missing parts: " << segment << std::endl; - return false; - } - - state = PARSER_STATE_HEADERS; - return true; - } - - // Source: RFC 2616 section 4.2. - bool HTTPParser::ParseHeaders( - const std::string_view segment, - ParserState& state, - std::string& err) { - std::ostringstream err_oss; - ScopeGuard err_oss_flush([&]() { err += err_oss.str(); }); - - // From the RFC: - // message-header = field-name ":" [ field-value ] - // field-name = token - // field-value = *(field-content | LWS) - // field-content = - // Takewaways: - // * field-name is guaranteed to not be preceded by whitespace - // * field-name is guaranteed to be followed by ":" - // * field-value may be preceded by LWS - // * multi-line field-values are guaranteed to start with either ' ' - // or '\t' - size_t pos = 0; - std::string key, value; - while (pos < segment.length()) { - // Divide into lines. - size_t end = segment.find(kLineDelim, pos); - if (end == std::string::npos) { - end = segment.length(); - } - ScopeGuard advance_pos([&]() { pos = end + 1; }); - - std::string_view line = segment.substr(pos, end - pos); - if (line.empty()) { - continue; - } - - // Lengthen the current line to cover multi-line header. - while (end + 1 < segment.length() && - (segment[end + 1] == ' ' || segment[end + 1] == '\t')) { - end = segment.find("\r\n", end + 1); - } - - size_t sep = line.find(':'); - if (sep == std::string::npos) { - err_oss << "Invalid header: No ':' delimiter: " << segment << std::endl; - return false; - } - - std::string_view key = line.substr(0, sep); - size_t key_start = key.find_first_not_of(kRfcLWS); - size_t key_end = key.find_last_not_of(kRfcLWS); - key = key.substr(key_start, (key_end - key_start) + 1); - // Value may contain interspersed LWS (linear whitespace). - // Could scrub it out, but not necessary for our purposes. - std::string_view value = line.substr(sep + 1); - size_t value_start = value.find_first_not_of(kRfcLWS); - size_t value_end = value.find_last_not_of(kRfcLWS); - value = value.substr(value_start, (value_end - value_start) + 1); - - headers_[std::string(key)] = value; - } - - state = PARSER_STATE_PAYLOAD; - return true; - } - - bool HTTPParser::ParsePayload( - const std::string_view segment, - ParserState& state, - std::string& err) { - payload_ = segment; - return true; - } -} diff --git a/GUI/GUI/GUI/HTTPParser.h b/GUI/GUI/GUI/HTTPParser.h deleted file mode 100644 index 7fcfe0e..0000000 --- a/GUI/GUI/GUI/HTTPParser.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include - -namespace WebServer { - - // A simple HTTP/1.1 message parser based on RFC 2616. - class HTTPParser - { - public: - HTTPParser(); - - bool Parse(const std::string& raw_http, std::string& err); - - const std::string& GetMethod() const; - const std::string& GetPath() const; - bool GetHeader(const std::string& header, std::string& value) const; - const std::map& GetHeaders() const; - const std::string& GetPayload() const; - - private: - enum ParserState { - PARSER_STATE_START_LINE, - PARSER_STATE_HEADERS, - PARSER_STATE_PAYLOAD, - }; - - bool ParseSegment( - const std::string_view segment, - ParserState& state, - std::string& err); - bool ParseStartLine( - const std::string_view segment, - ParserState& state, - std::string& err); - bool ParseHeaders( - const std::string_view segment, - ParserState& state, - std::string& err); - bool ParsePayload( - const std::string_view segment, - ParserState& state, - std::string& err); - - std::string method_; - std::string path_; - std::map headers_; - std::string payload_; - }; -} diff --git a/GUI/GUI/GUI/Logging.cpp b/GUI/GUI/GUI/Logging.cpp deleted file mode 100644 index 6983a40..0000000 --- a/GUI/GUI/GUI/Logging.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "Logging.h" - -#include - -#ifndef WX_PRECOMP -#include -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include - -Logging::ThreadLogger Logging::kThreadLogger = Logging::ThreadLogger(); - -Logging::ThreadLogger::ThreadLogger() {} - -void Logging::ThreadLogger::Append(wxTextCtrl* frame, const std::string&& message) -{ - std::scoped_lock l(mu_); - auto entry = messages_.find(frame); - if (entry == messages_.end()) { - messages_[frame] = { std::move(message) }; - } - else { - messages_[frame].push_back(message); - } -} - -void Logging::ThreadLogger::Drain() -{ - std::scoped_lock l(mu_); - const std::filesystem::path log_path("Resources/log.txt"); - std::ofstream log_ofs(log_path, std::ios_base::app); - for (const auto& [frame, messages] : messages_) { - for (const auto& message : messages) { - if (frame) { - frame->AppendText(message); - } - else { - wxLogError("%s", message); - } - log_ofs << message; - } - - // Constrain wxTextCtrl's to a few hundred lines to keep memory usage / - // general snappiness in check. - if (frame) { - constexpr int kHalfMaxChars = 50 * 1000; - int nchars; - while ((nchars = frame->GetLastPosition()) > kHalfMaxChars) { - wxString allText = frame->GetValue(); - wxArrayString lines = wxStringTokenize(allText, "\n"); - // Keep only the last kHalfMaxLines lines. - size_t nlines = lines.GetCount(); - size_t linesToRemove = nlines / 2; - - // Remove lines from the beginning - lines.RemoveAt(0, linesToRemove); - - // Join the lines back into a single string - wxString newText = wxJoin(lines, '\n'); - - // Update the text in the wxTextCtrl - frame->Clear(); - frame->AppendText(newText); - } - } - } - log_ofs.close(); - messages_.clear(); - - // Drop first 50% of lines in file if larger than 1 MB. - if (std::filesystem::file_size(log_path) > 1024 * 1024) { - std::vector lines; - std::ifstream log_ifs(log_path); - std::string line; - while (std::getline(log_ifs, line)) { - lines.push_back(std::move(line)); - } - log_ofs = std::ofstream(log_path); - for (int i = lines.size() / 2; i < lines.size(); i++) { - log_ofs << lines[i]; - } - } -} - -std::string Logging::HidePII(const std::string&& str, - const std::string& replacement) { - try { - std::regex c_users("([A-Za-z]:\\\\+[Uu]sers\\\\+)[a-zA-Z0-9_ ]+"); - std::string real_replacement = "$1" + replacement; - return std::regex_replace(str, c_users, real_replacement); - } - catch (const std::exception& e) { - wxLogFatalError(e.what()); - } - wxLogFatalError("Unhandled regex error (HidePII)"); - return ""; // Compiler thinks we can get here (we can't) and prints a warning. -} - -void Logging::DrainAsyncOutput(wxProcess* proc, wxTextCtrl* frame) { - if (!proc) { - return; - } - - while (proc->IsInputAvailable()) { - wxTextInputStream iss(*(proc->GetInputStream())); - Log(frame, " {}\n", iss.ReadLine().ToStdString()); - } - - while (proc->IsErrorAvailable()) { - wxTextInputStream iss(*(proc->GetErrorStream())); - Log(frame, " {}\n", iss.ReadLine().ToStdString()); - } -} diff --git a/GUI/GUI/GUI/Logging.h b/GUI/GUI/GUI/Logging.h deleted file mode 100644 index 193617a..0000000 --- a/GUI/GUI/GUI/Logging.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#pragma once - -#include - -#ifndef WX_PRECOMP -#include -#endif - -#include -#include - -#include -#include -#include - -namespace Logging { - // Remove personally identifying information (PII) from str. - // - // For example, this translates "C:/Users/foo/Desktop" to "C:/Users/*****/Desktop". - std::string HidePII(const std::string&& str, const std::string& replacement = "*****"); - - class ThreadLogger { - public: - ThreadLogger(); - - void Append(wxTextCtrl* frame, const std::string&& message); - void Drain(); - private: - std::mutex mu_; - std::unordered_map> messages_; - }; - - extern ThreadLogger kThreadLogger; - - // Provides a simple Python format()-like interface to wxTextCtrl. - // Ex: Log(my_textctrl_, "{}\n", "Hello, world!"); - template - void Log(wxTextCtrl* frame, std::string_view format, Args&&... args) { - const std::string raw = std::vformat(format, std::make_format_args(args...)); - const std::string masked = HidePII(std::move(raw)); - const std::string decoded = wxString::FromUTF8(masked).ToStdString(); - - kThreadLogger.Append(frame, std::move(decoded)); - } - - void DrainAsyncOutput(wxProcess* proc, wxTextCtrl* frame); -} - diff --git a/GUI/GUI/GUI/PythonWrapper.cpp b/GUI/GUI/GUI/PythonWrapper.cpp deleted file mode 100644 index 765a283..0000000 --- a/GUI/GUI/GUI/PythonWrapper.cpp +++ /dev/null @@ -1,894 +0,0 @@ -// Import rand_s() WIN32 API. -#define _CRT_RAND_S -// Silence security warnings caused by importing stdlib.h before wx. -#define _CRT_SECURE_NO_WARNINGS - -#include - -#include "Logging.h" -#include "PythonWrapper.h" -#include "ScopeGuard.h" -#include "Util.h" -#include "Config.h" - -#include -#include - -#include -#include -#include - -using ::Logging::Log; - -namespace { - constexpr const char kEmotesPickle[] = "Resources/Fonts/Bitmaps/emotes.map"; -} // namespace - -class PythonProcess : public wxProcess { -public: - PythonProcess(std::function&& exit_callback) : exit_cb_(exit_callback) { - Redirect(); - } - - virtual void OnTerminate(int pid, int status) wxOVERRIDE { - exit_cb_(this, status); - } - -private: - const std::function exit_cb_; -}; - -wxProcess* PythonWrapper::InvokeAsyncWithArgs(std::vector&& args, - std::function&& exit_callback) { - std::ostringstream cmd_oss; - cmd_oss << "Resources/Python/python.exe"; - for (const auto& arg : args) { - cmd_oss << " " << arg; - } - - auto *p = new PythonProcess(std::move(exit_callback)); - int pid = wxExecute(cmd_oss.str(), wxEXEC_ASYNC, p); - - if (!pid) { - delete p; - p = nullptr; - } - - return p; -} - -std::string GetWin32ErrMsg() { - DWORD error = GetLastError(); - LPSTR err_msg = nullptr; - FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&err_msg, - 0, - NULL - ); - ScopeGuard err_msg_cleanup([&]() { LocalFree(err_msg); }); - return std::to_string(error) + ": " + err_msg; -} - - -std::string DrainWin32Pipe(const HANDLE pipe) { - DWORD bytes_avail; - std::ostringstream oss; - if (PeekNamedPipe( - pipe, - nullptr, // buffer to read into - 0, // buffer size - nullptr, // bytes read - &bytes_avail, - nullptr // bytes left in this message - )) { - DWORD cur_bytes_read = 0; - DWORD sum_bytes_read = 0; - std::vector buf(4096, 0); - while (sum_bytes_read < bytes_avail && - ReadFile(pipe, buf.data(), buf.size() - 1, &cur_bytes_read, NULL) && - cur_bytes_read > 0) { - oss << std::string(buf.data(), cur_bytes_read); - sum_bytes_read += cur_bytes_read; - } - } - return oss.str(); -} - -bool PythonWrapper::InvokeCommandWithArgs( - const AppConfig& app_c, - const std::string& cmd, - std::vector&& args, - const std::function&& out_cb, - const std::function&& in_cb, - const std::function&& run_cb) { - std::ostringstream cmd_oss; - cmd_oss << cmd; - for (const auto& arg : args) { - cmd_oss << " " << arg; - } - - HANDLE stdout_read{}; - HANDLE stdout_write{}; - SECURITY_ATTRIBUTES stdout_sec_attr{}; - stdout_sec_attr.nLength = sizeof(stdout_sec_attr); - stdout_sec_attr.bInheritHandle = TRUE; - if (!CreatePipe(&stdout_read, &stdout_write, &stdout_sec_attr, 0)) { - std::ostringstream err_oss; - err_oss << "Error while executing python command \"" << cmd_oss.str() - << "\": Failed to create stdout pipe: " << GetWin32ErrMsg() << std::endl; - out_cb("", err_oss.str()); - return false; - } - ScopeGuard stdout_cleanup([&]() { - if (stdout_read) { - CloseHandle(stdout_read); - } - if (stdout_write) { - CloseHandle(stdout_write); - } - }); - SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0); - - HANDLE stderr_read{}; - HANDLE stderr_write{}; - SECURITY_ATTRIBUTES stderr_sec_attr{}; - stderr_sec_attr.nLength = sizeof(stderr_sec_attr); - stderr_sec_attr.bInheritHandle = TRUE; - - if (!CreatePipe(&stderr_read, &stderr_write, &stderr_sec_attr, 0)) { - std::ostringstream err_oss; - err_oss << "Error while executing python command \"" << cmd_oss.str() - << "\": Failed to create stderr pipe: " << GetWin32ErrMsg() << std::endl; - out_cb("", err_oss.str()); - return false; - } - ScopeGuard stderr_cleanup([&]() { - if (stderr_read) { - CloseHandle(stderr_read); - } - if (stderr_write) { - CloseHandle(stderr_write); - } - }); - SetHandleInformation(stderr_read, HANDLE_FLAG_INHERIT, 0); - - HANDLE stdin_read{}; - HANDLE stdin_write{}; - SECURITY_ATTRIBUTES stdin_sec_attr{}; - stdin_sec_attr.nLength = sizeof(stdin_sec_attr); - stdin_sec_attr.bInheritHandle = TRUE; - - if (!CreatePipe(&stdin_read, &stdin_write, &stdin_sec_attr, 0)) { - std::ostringstream err_oss; - err_oss << "Error while executing python command \"" << cmd_oss.str() - << "\": Failed to create stdin pipe: " << GetWin32ErrMsg() << std::endl; - out_cb("", err_oss.str()); - return false; - } - ScopeGuard stdin_cleanup([&]() { - if (stdin_read) { - CloseHandle(stdin_read); - } - if (stdin_write) { - CloseHandle(stdin_write); - } - }); - SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0); - - STARTUPINFOA si{}; - si.cb = sizeof(si); - si.hStdOutput = stdout_write; - si.hStdError = stderr_write; - si.hStdInput = stdin_read; - si.dwFlags |= STARTF_USESTDHANDLES; - si.dwFlags |= STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - PROCESS_INFORMATION pi{}; - std::string env; - - { - std::vector buf(4096 * 8, 0); - DWORD len = GetEnvironmentVariableA("PATH", buf.data(), buf.size() - 1); - if (len > 0) { - env = std::string("PATH=") + buf.data(); - } - else { - std::ostringstream err_oss; - err_oss << "Error while executing python command \"" << cmd_oss.str() - << "\": Failed to get PATH env variable: " << GetWin32ErrMsg() << std::endl; - out_cb("", err_oss.str()); - return false; - } - - // Add git to PATH - std::filesystem::path git_path = - (std::filesystem::current_path() / - "Resources/PortableGit/bin").lexically_normal(); - if (env.find(git_path.string()) == std::string::npos) { - env += ";" + git_path.string(); - - // Add updated PATH to current process's environment - if (!SetEnvironmentVariableA("PATH", env.c_str())) { - std::ostringstream err_oss; - err_oss << "Error while executing python command \"" - << cmd_oss.str() - << "\": Failed to add git to PATH: " << GetWin32ErrMsg() - << std::endl; - out_cb("", err_oss.str()); - return false; - } - } - - // Add python scripts to PATH - std::filesystem::path py_bin = (std::filesystem::current_path() / - "Resources/Python/Scripts").lexically_normal(); - if (env.find(py_bin.string()) == std::string::npos) { - env += ";" + py_bin.string(); - - // Add updated PATH to current process's environment - if (!SetEnvironmentVariableA("PATH", env.c_str())) { - std::ostringstream err_oss; - err_oss << "Error while executing python command \"" - << cmd_oss.str() - << "\": Failed to add python scripts to PATH: " - << GetWin32ErrMsg() << std::endl; - out_cb("", err_oss.str()); - return false; - } - } - - // Add scripts to PATH - std::filesystem::path dll_bin = (std::filesystem::current_path() / - "Resources/Scripts").lexically_normal(); - if (env.find(dll_bin.string()) == std::string::npos) { - env += ";" + dll_bin.string(); - - // Add updated PATH to current process's environment - if (!SetEnvironmentVariableA("PATH", env.c_str())) { - std::ostringstream err_oss; - err_oss << "Error while executing python command \"" - << cmd_oss.str() - << "\": Failed to add python scripts to PATH: " - << GetWin32ErrMsg() << std::endl; - out_cb("", err_oss.str()); - return false; - } - } - } - - std::string cmd_str = cmd_oss.str(); - if (!CreateProcessA(NULL, // application name - cmd_str.data(), - NULL, // process attributes - NULL, // thread attributes - TRUE, // whether to inherit parent's handles - 0, // creation flags - //env.data(), - nullptr, // environment variables - std::filesystem::current_path().string().c_str(), // current directory - &si, - &pi)) { - std::ostringstream err_oss; - err_oss << "Error while executing python command \"" << cmd_oss.str() - << "\": Failed to launch process: " << GetWin32ErrMsg(); - out_cb("", err_oss.str()); - return false; - } - ScopeGuard pi_cleanup([&] { - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - }); - - std::map prio_stoi = { - {"above normal", ABOVE_NORMAL_PRIORITY_CLASS}, - {"below normal", BELOW_NORMAL_PRIORITY_CLASS}, - {"normal", NORMAL_PRIORITY_CLASS}, - {"idle", IDLE_PRIORITY_CLASS}, - {"high", HIGH_PRIORITY_CLASS}, - {"realtime", REALTIME_PRIORITY_CLASS}, - }; - if (!SetPriorityClass(pi.hProcess, prio_stoi[app_c.prio])) { - std::ostringstream err_oss; - err_oss << "Error while executing python command \"" << cmd_oss.str() - << "\": Failed to reduce priority class: " << GetWin32ErrMsg(); - out_cb("", err_oss.str()); - return false; - } - - // While the process is running, drain output and send input every 10 ms. - DWORD timeout_ms = 10; - DWORD ret = WAIT_TIMEOUT; - while (run_cb() && ret == WAIT_TIMEOUT) { - DWORD ret = WaitForSingleObject(pi.hProcess, timeout_ms); - if (ret != WAIT_TIMEOUT) { - break; - } - std::ostringstream stdout_oss, stderr_oss; - stdout_oss << DrainWin32Pipe(stdout_read); - stderr_oss << DrainWin32Pipe(stderr_read); - out_cb(stdout_oss.str(), stderr_oss.str()); - - std::string input; - in_cb(input); - if (input.size()) { - DWORD cur_bytes_write = 0; - DWORD sum_bytes_write = 0; - std::vector buf(4096, 0); - while (sum_bytes_write < input.size() && - WriteFile(stdin_write, input.data() + sum_bytes_write, - input.size() - sum_bytes_write, &cur_bytes_write, NULL)) { - sum_bytes_write += cur_bytes_write; - } - } - } - if (!run_cb()) { - DWORD timeout_ms = 1000 * 10; - DWORD ret = WaitForSingleObject(pi.hProcess, timeout_ms); - - if (ret == WAIT_TIMEOUT) { - std::ostringstream stderr_oss; - stderr_oss << "Timed out waiting for graceful exit, killing process"; - out_cb("", stderr_oss.str()); - - TerminateProcess(pi.hProcess, 0); - } - } - - std::ostringstream stdout_oss, stderr_oss; - DWORD exit_code; - if (!GetExitCodeProcess(pi.hProcess, &exit_code)) { - stderr_oss << "Failed to get exit code: " << GetWin32ErrMsg(); - } - if (exit_code != 0) { - stderr_oss << "Command exited with code " << exit_code << ": " - << GetWin32ErrMsg(); - } - - // Close write ends of pipes. If we don't do this, the last read will block forever. - CloseHandle(stdout_write); - stdout_write = 0; - CloseHandle(stderr_write); - stderr_write = 0; - - stdout_oss << DrainWin32Pipe(stdout_read); - stderr_oss << DrainWin32Pipe(stderr_read); - out_cb(stdout_oss.str(), stderr_oss.str()); - - return exit_code == 0; -} - -bool PythonWrapper::InvokeCommandWithArgs( - const AppConfig& app_c, - const std::string& cmd, - std::vector&& args, - std::string* py_stdout, std::string* py_stderr) { - - std::ostringstream out_oss, err_oss; - auto out_cb = [&](const std::string& out, const std::string& err) { - out_oss << out; - err_oss << err; - }; - bool ret = InvokeCommandWithArgs(app_c, cmd, std::move(args), std::move(out_cb)); - if (py_stderr) { - *py_stderr = err_oss.str(); - } - *py_stdout = out_oss.str(); - return ret; -} - -bool PythonWrapper::InvokeWithArgs( - const AppConfig& app_c, - std::vector&& args, - std::string* py_stdout, std::string* py_stderr) { - return InvokeCommandWithArgs(app_c, "Resources/Python/python.exe", - std::move(args), py_stdout, py_stderr); -} - -bool PythonWrapper::InvokeWithArgs( - const AppConfig& app_c, - std::vector&& args, - const std::string&& err_msg, - wxTextCtrl* const out) { - std::string py_stdout, py_stderr; - if (InvokeWithArgs(app_c, std::move(args), &py_stdout, &py_stderr)) { - Log(out, "success!\n"); - Log(out, py_stdout.c_str()); - if (!py_stdout.empty()) { - Log(out, "\n"); - } - Log(out, py_stderr.c_str()); - if (!py_stderr.empty()) { - Log(out, "\n"); - } - return true; - } - else { - Log(out, "failed!\n"); - Log(out, "Error: {}: {}\n", err_msg, py_stderr); - return false; - } -} - -bool PythonWrapper::InvokeWithArgs( - const AppConfig& app_c, - std::vector&& args, - const std::function&& out_cb, - const std::function&& in_cb, - const std::function&& run_cb) { - return InvokeCommandWithArgs(app_c, - "Resources/Python/python.exe", - std::move(args), std::move(out_cb), std::move(in_cb), std::move(run_cb)); -} - - -std::string PythonWrapper::GetVersion() { - std::string py_stdout, py_stderr; - bool ok = InvokeWithArgs(AppConfig(nullptr), { "--version" }, &py_stdout, &py_stderr); - if (!ok) { - wxLogError("Failed to get python version: %s", py_stderr.c_str()); - } - return py_stdout; -} - -std::string PythonWrapper::DumpMics() { - std::string py_stdout, py_stderr; - const std::string dump_mics_path = "Resources/Scripts/dump_mic_devices.py"; - bool ok = InvokeWithArgs(AppConfig(nullptr), { dump_mics_path }, &py_stdout, &py_stderr); - if (!ok) { - wxLogError("Failed to dump mic devices: %s", py_stderr.c_str()); - } - return py_stdout; -} - -bool PythonWrapper::InstallPip(std::string* out, std::string* err) { - std::ostringstream out_oss, err_oss; - auto out_cb = [&](const std::string& out, const std::string& err) { - out_oss << out; - err_oss << err; - }; - bool ret = InstallPip(std::move(out_cb)); - *out = out_oss.str(); - if (err) { - *err = err_oss.str(); - } - return ret; -} - -bool PythonWrapper::InstallPip( - const std::function&& out_cb, - const std::function&& in_cb, - const std::function&& run_cb) { - std::filesystem::path pip_flag = "Resources/Python/.pip_installed"; - if (std::filesystem::exists(pip_flag)) { - out_cb("Pip flag exists, already installed\n", ""); - return true; - } - - std::string pip_path = "Resources/Python/get-pip.py"; - if (!InvokeWithArgs(AppConfig(nullptr), { pip_path }, std::move(out_cb), std::move(in_cb), - std::move(run_cb))) { - return false; - } - - // Create the flag file so subsstd::chrono::milliseconds(100));equent calls don't reinstall. - std::ofstream flag_ofs(pip_path); - flag_ofs.close(); - - return true; -} - -std::future PythonWrapper::StartApp( - const AppConfig& app_c, - const std::string& config_path, - wxTextCtrl *out, - const std::function&& out_cb, - const std::function&& in_cb, - const std::function&& run_cb, - const std::function&& prestart_cb) { - - return std::move(std::async(std::launch::async, - []( - const AppConfig app_c, - const std::string config_path, - wxTextCtrl *out, - const std::function&& out_cb, - const std::function&& in_cb, - const std::function&& run_cb, - const std::function&& prestart_cb) -> bool { - prestart_cb(); - - Log(out, "DEBUG::{}:: config_path: {}\n", __func__, config_path); - - return InvokeWithArgs( - app_c, - { - "-u", // Unbuffered output - "Resources/Scripts/transcribe_v2.py", - "--config", config_path, - }, - std::move(out_cb), - std::move(in_cb), - std::move(run_cb)); - }, app_c, config_path, out, std::move(out_cb), std::move(in_cb), - std::move(run_cb), std::move(prestart_cb))); -} - -bool PythonWrapper::GenerateAnimator( - const AppConfig& config, - const std::string& config_path, - const std::string& unity_animator_generated_dir, - const std::string& unity_animator_generated_name, - const std::string& unity_parameters_generated_name, - const std::string& unity_menu_generated_name, - wxTextCtrl* out) { - // Python script locations - std::string remove_audio_srcs_path = "Resources/Scripts/remove_audio_sources.py"; - std::string set_texture_sz_path = "Resources/Scripts/set_texture_sz.py"; - std::string libunity_path = "Resources/Scripts/libunity.py"; - std::string libtastt_path = "Resources/Scripts/libtastt.py"; - std::string generate_emotes_path = "Resources/Scripts/emotes_v2.py"; - std::string generate_params_path = "Resources/Scripts/generate_params.py"; - std::string generate_menu_path = "Resources/Scripts/generate_menu.py"; - std::string generate_shader_path = "Resources/Scripts/generate_shader.py"; - std::string shader_template_path = "Resources/Shaders/TaSTT_template.shader"; - std::string shader_lighting_template_path = "Resources/Shaders/STT_generated_template.cginc"; - std::string shader_path = "Resources/Shaders/TaSTT.shader"; - std::string shader_lighting_path = "Resources/Shaders/STT_generated.cginc"; - - // Generated directory locations - std::filesystem::path tastt_generated_dir_path = - std::filesystem::path(config.assets_path) / unity_animator_generated_dir; - std::filesystem::path guid_map_path = - tastt_generated_dir_path / "guid.map"; - std::filesystem::path tastt_animations_path = - tastt_generated_dir_path / "Animations"; - std::filesystem::path tastt_assets_path = - tastt_generated_dir_path / "UnityAssets"; - std::filesystem::path tastt_sounds_path = - tastt_generated_dir_path / "Sounds"; - std::filesystem::path tastt_shaders_path = - tastt_generated_dir_path / "Shaders"; - std::filesystem::path tastt_fonts_path = - tastt_generated_dir_path / "Fonts"; - std::filesystem::path tastt_params_path = - tastt_generated_dir_path / unity_parameters_generated_name; - std::filesystem::path tastt_menu_path = - tastt_generated_dir_path / unity_menu_generated_name; - // These are intermediate animators. We apply several transformations before - // arriving at the final animator. - std::filesystem::path tastt_fx0_path = - tastt_generated_dir_path / "FX0.controller"; - std::filesystem::path tastt_fx1_path = - tastt_generated_dir_path / "FX1.controller"; - // This is the final animator. - std::filesystem::path tastt_animator_path = - tastt_generated_dir_path / unity_animator_generated_name; - - const int texture_rows = (config.bytes_per_char == 1 ? 8 : 64); - const int texture_cols = (config.bytes_per_char == 1 ? 16 : 128); - { - Log(out, "Generating shader for {}x{} board (pass 0)...", config.rows, config.cols); - if (!InvokeWithArgs(AppConfig(nullptr), { generate_shader_path, - "--bytes_per_char", std::to_string(config.bytes_per_char), - "--board_rows", std::to_string(config.rows), - "--board_cols", std::to_string(config.cols), - "--texture_rows", std::to_string(texture_rows), - "--texture_cols", std::to_string(texture_cols), - "--shader_template", shader_template_path, - "--shader_path", shader_path }, - "Failed to generate shader", out)) { - return false; - } - } - { - Log(out, "Generating shader for {}x{} board (pass 1)...", config.rows, config.cols); - - std::string py_stdout, py_stderr; - if (!InvokeWithArgs(AppConfig(nullptr), { generate_shader_path, - "--bytes_per_char", std::to_string(config.bytes_per_char), - "--board_rows", std::to_string(config.rows), - "--board_cols", std::to_string(config.cols), - "--texture_rows", std::to_string(texture_rows), - "--texture_cols", std::to_string(texture_cols), - "--shader_template", shader_lighting_template_path, - "--shader_path", shader_lighting_path }, - "Failed to generate shader", out)) { - return false; - } - } -#if 0 - { - Log(out, "Generating emotes... "); - - std::string py_stdout, py_stderr; - if (InvokeWithArgs(AppConfig(nullptr), { generate_emotes_path, - "Resources/Fonts/Emotes/", - /*board_aspect_ratio=*/ std::to_string(6), - /*texture_aspect_ratio=*/ std::to_string(2), - "Resources/Fonts/Bitmaps/emotes.png", - kEmotesPickle - }, - &py_stdout, &py_stderr)) { - Log(out, "success!\n"); - Log(out, py_stdout.c_str()); - if (!py_stdout.empty()) { - Log(out, "\n"); - } - Log(out, py_stderr.c_str()); - if (!py_stderr.empty()) { - Log(out, "\n"); - } - } - else { - Log(out, "failed!\n"); - Log(out, "stdout: {}\n", py_stdout.c_str()); - Log(out, "stderr: {}\n", py_stderr.c_str()); - return false; - } - } -#endif - { - Log(out, "Creating {}\n", tastt_generated_dir_path.string()); - std::filesystem::create_directories(tastt_generated_dir_path); - } - { - Log(out, "Copying canned animations... "); - auto opts = std::filesystem::copy_options(); - opts |= std::filesystem::copy_options::overwrite_existing; - opts |= std::filesystem::copy_options::recursive; - std::error_code error; - std::filesystem::copy("Resources/Animations", tastt_animations_path, opts, error); - if (error.value()) { - Log(out, "failed!\n"); - Log(out, "Error: {} ({})\n", error.message(), error.value()); - return false; - } - Log(out, "success!\n"); - } - { - Log(out, "Copying canned assets... "); - auto opts = std::filesystem::copy_options(); - opts |= std::filesystem::copy_options::overwrite_existing; - opts |= std::filesystem::copy_options::recursive; - std::error_code error; - std::filesystem::copy("Resources/UnityAssets", tastt_assets_path, opts, error); - if (error.value()) { - Log(out, "failed!\n"); - Log(out, "Error: {} ({})\n", error.message(), error.value()); - return false; - } - Log(out, "success!\n"); - } - if (!config.enable_phonemes) { - std::string prefab_path = (std::filesystem::path(tastt_assets_path) / "World Constraint.prefab").string(); - Log(out, "Remove audio sources from prefab at {}\n", prefab_path); - Log(out, "Removing audio sources from prefab... "); - if (!InvokeWithArgs(AppConfig(nullptr), { remove_audio_srcs_path, - "--prefab", Quote(prefab_path) - }, - "Failed to remove audio sources", out)) { - return false; - } - Log(out, "succes!\n"); - } - { - Log(out, "Copying canned sounds... "); - auto opts = std::filesystem::copy_options(); - opts |= std::filesystem::copy_options::overwrite_existing; - opts |= std::filesystem::copy_options::recursive; - std::error_code error; - std::filesystem::copy("Resources/Sounds", tastt_sounds_path, opts, error); - if (error.value()) { - Log(out, "failed!\n"); - Log(out, "Error: {} ({})\n", error.message(), error.value()); - return false; - } - Log(out, "success!\n"); - } - { - Log(out, "Copying canned shaders... "); - auto opts = std::filesystem::copy_options(); - opts |= std::filesystem::copy_options::overwrite_existing; - opts |= std::filesystem::copy_options::recursive; - std::error_code error; - std::filesystem::copy("Resources/Shaders", tastt_shaders_path, opts, error); - if (error.value()) { - Log(out, "failed!\n"); - Log(out, "Error: {} ({})\n", error.message(), error.value()); - return false; - } - Log(out, "success!\n"); - } - { - Log(out, "Deleting shader templates... "); - try { - if (std::filesystem::exists(tastt_shaders_path) && std::filesystem::is_directory(tastt_shaders_path)) { - for (const auto& entry : std::filesystem::directory_iterator(tastt_shaders_path)) { - if (entry.is_regular_file()) { - if (entry.path().stem().string().ends_with("_template")) { - std::filesystem::remove(entry.path()); - } - } - } - } - } - catch (const std::exception& e) { - Log(out, "failed!\n"); - Log(out, "Error: {}\n", e.what()); - } - Log(out, "success!\n"); - } - { - Log(out, "Copying canned fonts... "); - auto opts = std::filesystem::copy_options(); - opts |= std::filesystem::copy_options::overwrite_existing; - opts |= std::filesystem::copy_options::recursive; - std::error_code error; - std::filesystem::copy("Resources/Fonts", tastt_fonts_path, opts, error); - if (error.value()) { - Log(out, "failed!\n"); - Log(out, "Error: {} ({})\n", error.message(), error.value()); - return false; - } - Log(out, "success!\n"); - } - if (config.bytes_per_char == 1) { - Log(out, "Applying texture memory optimization for English speakers... "); - std::error_code err; - for (int i = 0; i < 8; i++) { - std::filesystem::remove(tastt_fonts_path / ("Bitmaps/font-" + std::to_string(i) + ".png"), err); - if (err.value()) { - Log(out, "failed!\n"); - Log(out, "Error removing unicode texture: {} ({})\n", err.message(), err.value()); - return false; - } - std::filesystem::remove(tastt_fonts_path / ("Bitmaps/font-" + std::to_string(i) + ".png.meta"), err); - if (err.value()) { - Log(out, "failed!\n"); - Log(out, "Error removing unicode texture: {} ({})\n", err.message(), err.value()); - return false; - } - } - std::filesystem::remove(tastt_fonts_path / "Bitmaps/emotes.png", err); - if (err.value()) { - Log(out, "failed!\n"); - Log(out, "Error removing emotes texture: {} ({})\n", err.message(), err.value()); - return false; - } - - Log(out, "success!\n"); - } - else { - std::error_code err; - std::filesystem::remove(tastt_fonts_path / ("Bitmaps/font-ascii.png"), err); - if (err.value()) { - Log(out, "failed!\n"); - Log(out, "Error removing unicode texture: {} ({})\n", err.message(), err.value()); - return false; - } - std::filesystem::remove(tastt_fonts_path / ("Bitmaps/font-ascii.png.meta"), err); - if (err.value()) { - Log(out, "failed!\n"); - Log(out, "Error removing unicode texture: {} ({})\n", err.message(), err.value()); - return false; - } - } - { - Log(out, "Setting texture sizes... "); - std::filesystem::path fonts_dir = tastt_fonts_path / "Bitmaps"; - for (const auto& entry : std::filesystem::recursive_directory_iterator(fonts_dir)) { - Log(out, "Entry get {}\n", entry.path().string()); - Log(out, "Setting size to {}\n", config.texture_sz); - if (entry.is_regular_file() && entry.path().extension() == ".meta") { - if (!InvokeWithArgs(AppConfig(nullptr), { set_texture_sz_path, - "--meta", Quote(entry.path().string()), - "--size", std::to_string(config.texture_sz)}, - "Failed to set texture size", out)) { - return false; - } - } - } - Log(out, "succes!\n"); - } - { - Log(out, "Generating guid.map... "); - if (!InvokeWithArgs(AppConfig(nullptr), { libunity_path, "guid_map", - "--project_root", Quote(config.assets_path), - "--save_to", Quote(guid_map_path), }, - "Failed to generate guid.map", out)) { - return false; - } - } - { - Log(out, "Generating animations... "); - if (!InvokeWithArgs(AppConfig(nullptr), { libtastt_path, "gen_anims", - "--gen_anim_dir", Quote(tastt_animations_path), - "--guid_map", Quote(guid_map_path), - "--config", Quote(config_path) }, - "Failed to generate animations", out)) { - return false; - } - } - { - Log(out, "Generating FX layer... "); - if (!InvokeWithArgs(AppConfig(nullptr), { libtastt_path, "gen_fx", - "--fx_dest", Quote(tastt_fx0_path), - "--gen_anim_dir", Quote(tastt_animations_path), - "--guid_map", Quote(guid_map_path), - "--config", Quote(config_path) }, - "Failed to generate FX layer", out)) { - return false; - } - } - { - Log(out, "Merging with user animator... "); - if (!InvokeWithArgs(AppConfig(nullptr), { libunity_path, "merge", - "--fx0", Quote(config.fx_path), - "--fx1", Quote(tastt_fx0_path), - "--fx_dest", Quote(tastt_fx1_path), }, - "Failed to merge animators", out)) { - return false; - } - } - { - Log(out, "Setting noop animations... "); - if (!InvokeWithArgs(AppConfig(nullptr), { libunity_path, "set_noop_anim", - "--fx0", Quote(tastt_fx1_path), - "--fx_dest", Quote(tastt_animator_path), - "--gen_anim_dir", Quote(tastt_animations_path), - "--guid_map", Quote(guid_map_path), }, - "Failed to set noop animations", out)) { - return false; - } - } - { - Log(out, "Generating avatar parameters... "); - if (!InvokeWithArgs(AppConfig(nullptr), { generate_params_path, - "--old_params", Quote(config.params_path), - "--new_params", Quote(tastt_params_path), - "--config", Quote(config_path) }, - "Failed to generate avatar parameters", out)) { - return false; - } - } - { - Log(out, "Generating avatar menu... "); - if (!InvokeWithArgs(AppConfig(nullptr), { generate_menu_path, - "--old_menu", Quote(config.menu_path), - "--new_menu", Quote(tastt_menu_path) }, - "Failed to generate avatar menu", out)) { - return false; - } - } - if (config.clear_osc) { - std::filesystem::path osc_path = "C:/Users"; - osc_path /= wxGetUserName().ToStdString(); - osc_path /= "AppData/LocalLow/VRChat/vrchat/OSC"; - osc_path = osc_path.lexically_normal(); - Log(out, "OSC configs are stored at {}\n", osc_path.string()); - Log(out, "Clearing OSC configs... "); - - if (std::filesystem::is_directory(osc_path)) { - std::error_code err; - if (std::filesystem::remove_all(osc_path, err)) { - Log(out, "success!\n"); - } - else { - Log(out, "failed!\n"); - Log(out, "Error: {} ({})\n", err.message(), err.value()); - } - } - else { - Log(out, "OSC configs do not exist at {}, assuming already " - "cleared!\n", osc_path.string()); - } - } - - Log(out, "Done!\n"); - return true; -} - diff --git a/GUI/GUI/GUI/PythonWrapper.h b/GUI/GUI/GUI/PythonWrapper.h deleted file mode 100644 index b5fe518..0000000 --- a/GUI/GUI/GUI/PythonWrapper.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include - -#ifndef WX_PRECOMP -#include -#endif - -#include - -#include "Config.h" - -#include -#include -#include -#include - -/* - * This class wraps interactions with the embedded Python interpreter. -*/ -namespace PythonWrapper -{ - // Invoke the interpreter asynchronously with the given arguments. - // When the process exits, `exit_callback` runs. - // The caller is responsible for deleting wxProcess. - wxProcess* InvokeAsyncWithArgs(std::vector&& args, - std::function&& exit_callback); - - // Invoke a command on the shell with arguments. - // On error, sets `out` to an error message and returns false. - bool InvokeCommandWithArgs( - const AppConfig& app_c, - const std::string& cmd, - std::vector&& args, - std::string* py_stdout, - std::string* py_stderr = NULL); - - // Invoke a command on the shell with arguments. - // On error, sets `out` to an error message and returns false. - bool InvokeCommandWithArgs( - const AppConfig& app_c, - const std::string& cmd, - std::vector&& args, - const std::function&& out_cb, - const std::function&& in_cb = [](std::string&) {}, - const std::function&& run_cb = []() { return true; }); - - // Invoke the interpreter with arguments. - // On error, sets `out` to an error message and returns false. - bool InvokeWithArgs( - const AppConfig& app_c, - std::vector&& args, std::string* py_stdout, - std::string* py_stderr = NULL); - - bool InvokeWithArgs( - const AppConfig& app_c, - std::vector&& args, - const std::string&& err_msg, wxTextCtrl* out); - - bool InvokeWithArgs( - const AppConfig& app_c, - std::vector&& args, - const std::function&& out_cb, - const std::function&& in_cb = [](std::string&) {}, - const std::function&& run_cb = []() { return true; }); - - // Execute python --version. - std::string GetVersion(); - - // Executes dump_mic_devices.py. - std::string DumpMics(); - - // Execute get-pip.py. - bool InstallPip( - const std::function&& out_cb, - const std::function&& in_cb = [](std::string&) {}, - const std::function&& run_cb = []() { return true; }); - bool InstallPip(std::string* out, std::string* err = nullptr); - - std::future StartApp( - const AppConfig& app_c, - const std::string& config_path, - wxTextCtrl *out, - const std::function&& out_cb, - const std::function&& in_cb = [](std::string&) {}, - const std::function&& run_cb = []() { return true; }, - const std::function&& prestart_cb = []() {}); - - bool GenerateAnimator( - const AppConfig& config, - const std::string& config_path, - const std::string& unity_animator_generated_dir, - const std::string& unity_animator_generated_name, - const std::string& unity_parameters_generated_name, - const std::string& unity_menu_generated_name, - wxTextCtrl* out); -}; - diff --git a/GUI/GUI/GUI/Resources/logo.ico b/GUI/GUI/GUI/Resources/logo.ico deleted file mode 100644 index aca1b5a..0000000 Binary files a/GUI/GUI/GUI/Resources/logo.ico and /dev/null differ diff --git a/GUI/GUI/GUI/ScopeGuard.h b/GUI/GUI/GUI/ScopeGuard.h deleted file mode 100644 index 601061c..0000000 --- a/GUI/GUI/GUI/ScopeGuard.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include - -class ScopeGuard { -public: - ScopeGuard(std::function&& cb) : cb_(std::move(cb)), active_(true) {} - ~ScopeGuard() { - Invoke(); - } - - ScopeGuard() = delete; - ScopeGuard(ScopeGuard&) = delete; - ScopeGuard(const ScopeGuard&) = delete; - ScopeGuard(ScopeGuard&&) = delete; - ScopeGuard& operator=(ScopeGuard&) = delete; - ScopeGuard& operator=(const ScopeGuard&) = delete; - - void Cancel() { active_ = false; } - - void Invoke() { - if (active_) { - cb_(); - active_ = false; - } - } - -private: - const std::function cb_; - bool active_; -}; diff --git a/GUI/GUI/GUI/Transcript.cpp b/GUI/GUI/GUI/Transcript.cpp deleted file mode 100644 index 11bab31..0000000 --- a/GUI/GUI/GUI/Transcript.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "Transcript.h" - -void Transcript::Append(std::string&& segment) { - std::scoped_lock l(mu_); - segments_.push_back(std::move(segment)); -} - -void Transcript::Set(std::string&& segment) { - std::scoped_lock l(mu_); - segments_.clear(); - segments_.push_back(std::move(segment)); -} - -void Transcript::SetPreview(std::string&& segment) { - std::scoped_lock l(mu_); - previews_.clear(); - previews_.push_back(std::move(segment)); -} - -void Transcript::Clear() { - std::scoped_lock l(mu_); - segments_.clear(); - previews_.clear(); -} - -std::vector Transcript::Get() { - std::scoped_lock l(mu_); - return segments_; -} - -std::vector Transcript::GetPreview() { - std::scoped_lock l(mu_); - return previews_; -} - -void Transcript::SetFinalized(bool is_finalized) { - // Accessing anything smaller than a word is always atomic. - is_finalized_ = is_finalized; -} - -bool Transcript::IsFinalized() { - // Accessing anything smaller than a word is always atomic. - return is_finalized_; -} diff --git a/GUI/GUI/GUI/Transcript.h b/GUI/GUI/GUI/Transcript.h deleted file mode 100644 index 1c18afe..0000000 --- a/GUI/GUI/GUI/Transcript.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include -#include -#include - -// Simple thread-safe class to share transcription data between layers. -class Transcript { -public: - Transcript() = default; - - void Append(std::string&& segment); - void Set(std::string&& segment); - void SetPreview(std::string&& segment); - void Clear(); - - // Indicate whether the transcript is "finalized", i.e. the transcription - // engine has committed the entirety of the transcript and will no longer - // change it. - void SetFinalized(bool is_finalized); - - std::vector Get(); - std::vector GetPreview(); - bool IsFinalized(); - -private: - std::mutex mu_; - std::vector segments_; - std::vector previews_; - bool is_finalized_{ false }; -}; diff --git a/GUI/GUI/GUI/Util.h b/GUI/GUI/GUI/Util.h deleted file mode 100644 index 594972e..0000000 --- a/GUI/GUI/GUI/Util.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include -#include - -// Wrap the filesystem path in quotes, escaping intermediate quotes with \\. -inline std::string Quote(const std::filesystem::path& p) { - std::ostringstream oss; - oss << std::quoted(p.string()); - return oss.str(); -} - -inline std::string Unquote(const std::string& s) { - std::istringstream iss(s); - - std::string result; - iss >> quoted(result); - - return result; -} diff --git a/GUI/GUI/GUI/WebCommon.h b/GUI/GUI/GUI/WebCommon.h deleted file mode 100644 index 6e18bb2..0000000 --- a/GUI/GUI/GUI/WebCommon.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace WebServer { - enum ContentType { - HTML, - JSON, - }; -}; diff --git a/GUI/GUI/GUI/WebServer.cpp b/GUI/GUI/GUI/WebServer.cpp deleted file mode 100644 index 2b589c6..0000000 --- a/GUI/GUI/GUI/WebServer.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include - -#ifndef WX_PRECOMP -#include -#endif - -#include "HTTPMapper.h" -#include "HTTPParser.h" -#include "ScopeGuard.h" -#include "WebServer.h" - -#include -#include -#include - -using ::Logging::Log; - -namespace WebServer { - WebServer::WebServer(wxTextCtrl* out, uint16_t port) - : out_(out), port_(port) - { - default_handler_ = - [](int& status_code, std::string& payload, - ContentType& type) -> void { - status_code = 404; - payload = "404: No route to URI"; - type = HTML; - }; - } - - bool WebServer::RegisterPathHandler(const std::string& method, - const std::string& path, handler_t&& handler) { - dispatch_key_t key = GetDispatchKey(method, path); - if (dispatch_map_.contains(key)) { - Log(out_, "Failed to register path handler at {} {}: " - "Handler already exists!\n", method, path); - return false; - } - - dispatch_map_[key] = std::move(handler); - return true; - } - - void WebServer::RegisterDefaultHandler(handler_t&& handler) { - default_handler_ = std::move(handler); - } - - bool WebServer::Run(volatile bool* run) { - WSADATA wsaData; - int result = WSAStartup(/*version=*/MAKEWORD(2, 2), &wsaData); - if (result) { - Log(out_, "Failed to start winsock: {}\n", result); - return false; - } - ScopeGuard wsa_cleanup([]() { WSACleanup(); }); - - SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock == INVALID_SOCKET) { - Log(out_, "Failed to create socket: {}\n", WSAGetLastError()); - return false; - } - ScopeGuard sock_cleanup([sock]() { closesocket(sock); }); - - sockaddr_in saddr; - saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr = INADDR_ANY; - saddr.sin_port = htons(port_); - if (bind(sock, (sockaddr*)&saddr, sizeof(saddr)) == SOCKET_ERROR) { - Log(out_, "Failed to bind to port {}: {}\n", port_, WSAGetLastError()); - return false; - } - - int optval = 1; - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof(optval)) == SOCKET_ERROR) { - Log(out_, "Failed to setsockopt(SO_REUSEADDR): {}", WSAGetLastError()); - return 1; - } - - u_long enable_nonblock = 1; - if (ioctlsocket(sock, FIONBIO, &enable_nonblock) == SOCKET_ERROR) { - Log(out_, "Failed to enable non-blocking socket: {}\n", WSAGetLastError()); - return false; - } - - if (listen(sock, SOMAXCONN) == SOCKET_ERROR) { - Log(out_, "Failed to listen on port {}: {}\n", port_, WSAGetLastError()); - return false; - } - - Log(out_, "Server running on port {}\n", port_); - - sockaddr_in peer_addr; - int accept_cnt = 0; - while (*run) { - int peer_addr_sz = sizeof(peer_addr); - SOCKET csock = accept(sock, (sockaddr*)&peer_addr, &peer_addr_sz); - if (csock == INVALID_SOCKET) { - int err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - continue; - } - Log(out_, "Accept failed: {}\n", WSAGetLastError()); - return false; - } - - // Periodically cull dead connections to prevent runaway memory usage. - ++accept_cnt; - if (accept_cnt % 10 == 0) { - std::vector> alive_conn; - for (int i = 0; i < connections_.size(); i++) { - if (connections_[i].valid()) { - continue; - } - alive_conn.push_back(std::move(connections_[i])); - } - //Log(out_, "Culled {} dead connections\n", connections_.size() - alive_conn.size()); - connections_ = std::move(alive_conn); - accept_cnt = 0; // Prevent overflow - } - - wxTextCtrl* out = out_; - const auto& dispatch_map = dispatch_map_; - const auto& default_handler = default_handler_; - connections_.push_back(std::async(std::launch::async, - [csock, peer_addr, out, run, dispatch_map, default_handler]() -> void { - ScopeGuard csock_cleanup([csock]() { closesocket(csock); }); - char peer_ip_str[INET_ADDRSTRLEN]{}; - inet_ntop(AF_INET, &peer_addr.sin_addr, peer_ip_str, sizeof(peer_ip_str)); - //Log(out, "Connection get: peer: {}:{}\n", peer_ip_str, ntohs(peer_addr.sin_port)); - - std::string buf(4096 * 16, 0); - int cur_bytes_read = 0; - int sum_bytes_read = 0; - - // Drain socket until we see a valid HTTP message. - while (*run) { - cur_bytes_read = recv(csock, buf.data() + sum_bytes_read, - buf.size() - (1 + sum_bytes_read), /*flags=*/0); - if (cur_bytes_read == SOCKET_ERROR) { - if (WSAGetLastError() == WSAEWOULDBLOCK) { - // Client may try to keep the connection open, - // so see if there's a complete request in the - // buffer. If so, terminate the recv loop. - HTTPParser p; - std::string err; - if (p.Parse(buf, err)) { - // In general we should verify that we got a - // full message, but since we only need to - // support GET, this is unnecessary. - cur_bytes_read = 0; - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - continue; - } - break; - } - sum_bytes_read += cur_bytes_read; - if (cur_bytes_read == 0) { - break; - } - } - if (cur_bytes_read == SOCKET_ERROR) { - Log(out, "Failed to read client socket: {}\n", WSAGetLastError()); - return; - } - // Edge case: Server was stopped in the middle of serving a request. - if (!*run) { - return; - } - buf.resize(sum_bytes_read); - - // Parse HTTP. Expect this to succeed, since we only exit the loop once the - // request parses. - // TODO(yum) this repeats work! The loop already parsed the request. - HTTPParser p; - std::string err; - if (!p.Parse(buf, err)) { - Log(out, "Failed to parse client request: {}\n", err); - Log(out, "Offending request:\n{}\n", buf); - return; - } - - // Find the dispatch handler for the requested method and path. - dispatch_key_t dispatch_key = GetDispatchKey(p.GetMethod(), p.GetPath()); - auto iter = dispatch_map.find(dispatch_key); - handler_t handler; - if (iter == dispatch_map.end()) { - handler = default_handler; - } else { - handler = iter->second; - } - - // Generate a response. - int status_code; - std::string payload; - ContentType type; - handler(status_code, payload, type); - std::string response = HTTPMapper().Map(status_code, payload, type); - - // Send the response. - if (send(csock, response.data(), response.size(), /*flags=*/0) == SOCKET_ERROR) { - Log(out, "Failed to send response to client: {}\n", WSAGetLastError()); - return; - } - - // Implicitly close the connection by exiting scope. We - // completely ignore keep-alive requests for now. Browsers - // should handle this well, there are many reasons why - // keep-alive requests may be ignored, such as transient - // network failures. - })); - } - return true; - } -} diff --git a/GUI/GUI/GUI/WebServer.h b/GUI/GUI/GUI/WebServer.h deleted file mode 100644 index e476ba9..0000000 --- a/GUI/GUI/GUI/WebServer.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include - -#ifndef WX_PRECOMP -#include -#endif - -#include - -#include -#include -#include -#include -#include -#include - -#include "Logging.h" -#include "WebCommon.h" - -namespace WebServer { - class WebServer { - public: - WebServer(wxTextCtrl *out, std::uint16_t port); - - typedef std::function handler_t; - - bool RegisterPathHandler(const std::string& method, - const std::string& path, handler_t&& handler); - void RegisterDefaultHandler(handler_t&& handler); - - bool Run(volatile bool* run); - - private: - // Dispatch requests by mapping from (method, path) to handler. - // Dispatch key is (method, path) in that order. - typedef std::tuple dispatch_key_t; - static inline dispatch_key_t GetDispatchKey(const std::string& method, const std::string& path) - { - return dispatch_key_t(method, path); - } - - typedef std::map dispatch_map_t; - dispatch_map_t dispatch_map_; - handler_t default_handler_; - - wxTextCtrl* const out_; - const uint16_t port_; - - std::vector> connections_; - }; -} - diff --git a/GUI/GUI/GUI/main.cpp b/GUI/GUI/GUI/main.cpp deleted file mode 100644 index d9303f5..0000000 --- a/GUI/GUI/GUI/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "App.h" - -#include - -#ifndef WX_PRECOMP -#include -#endif - -wxIMPLEMENT_APP(MyApp); - diff --git a/GUI/GUI/GUI/resource.h b/GUI/GUI/GUI/resource.h deleted file mode 100644 index f10e004..0000000 --- a/GUI/GUI/GUI/resource.h +++ /dev/null @@ -1,15 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by GUI.rc -// - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 106 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/GUI/Libraries/.gitignore b/GUI/Libraries/.gitignore deleted file mode 100644 index 26be5d9..0000000 --- a/GUI/Libraries/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Don't check in anything we fetch -wx -rapidyaml -whisper -oatpp diff --git a/GUI/Libraries/fetch.ps1 b/GUI/Libraries/fetch.ps1 deleted file mode 100644 index f558d3f..0000000 --- a/GUI/Libraries/fetch.ps1 +++ /dev/null @@ -1,31 +0,0 @@ -param( - [switch]$overwrite = $False, - [string]$release = "Release" -) - -echo "Overwrite: $overwrite" -echo "Release: $release" - -Set-PSDebug -trace 0 - -$WX_3_2_1_URL = "https://github.com/wxWidgets/wxWidgets/releases/download/v3.2.1/wxWidgets-3.2.1.zip" -$WX_URL = $WX_3_2_1_URL -$WX_FILE = $(Split-Path -Path $WX_URL -Leaf) - -pushd $PSScriptRoot - -# WX -if ((Test-Path wx) -And ($overwrite)) { - rm -Recurse wx -} - -if (-Not (Test-Path wx)) { - mkdir wx - pushd wx > $null - Invoke-WebRequest $WX_URL -OutFile $WX_FILE - Expand-Archive $WX_FILE -DestinationPath . - popd > $null -} - -popd > $null # $PSScriptRoot - diff --git a/GUI/README.md b/GUI/README.md deleted file mode 100644 index 39d3292..0000000 --- a/GUI/README.md +++ /dev/null @@ -1,93 +0,0 @@ -## Build instructions - -0. Install build dependencies: cmake, git, python3, Visual Studio Community - 2022 - 0.0. When installing Visual Studio, make sure `Desktop development with C++` - is selected. - 0.1. Make sure Windows is using Python 3.10.9. From Powershell, the command - `python.exe --version` should show that it's using 3.10.9. Direct link: - https://www.python.org/ftp/python/3.10.9/python-3.10.9-amd64.exe -1. Open Powershell. -2. Make sure you've downloaded submodules: -``` -$ git submodule init -$ git submodule update -``` -3. Execute Libraries/fetch.ps1. This will take 2-3 minutes. - 3.0. If you can't run the script, run `Set-ExecutionPolicyPolicy - Unrestricted` in an admin instance of powershell. Heed the warning, - this is a security risk! Never run code from someone you don't trust - unless you've carefully audited it. -4. Open `Libraries/wx/build/msw/wx_vc17.sln` with Visual Studio 2022. -5. Select every project in the Solution Explorer except for `_custom_build`. -6. Right click, select Properties, go to C/C++, Code Generation, and set - Runtime Library to Multi-threaded (/MT). Make sure this applies to the - configuration x64/Release. Click Apply. -7. Build x64/Release. - 1. The build configuration is in the top. By default it's probably Debug/x64. - 2. To build: ctrl+shift+B - 3. If you saw an error in 7.1, rerun Libraries/fetch.ps1. -8. Open GUI/GUI.sln with Visual Studio 2022. -9. Build x64/Release. -10. Run package.ps1 from powershell. - 10.0. If you're not creating a redistributable release, use this command - instead (it's way faster): `package.ps1 -skip_zip`. - 10.1. When PortableGit creates a window, wait for it to complete, then press - then press enter in Powershell. - 10.2. The first time you run this it'll take a long time since it has to - fetch a few large packages. Subsequent invocations will be much faster - since it won't reacquire anything already downloaded. On my connection, - it took 90 minutes to finish downloading, mostly because Google Drive - downloads are slower than dirt. - -## High level design - -* The GUI is written using wxWidgets. -* Python executes core business logic. With libraries like faster\_whisper - available, this provides a nice balance between flexibility and performance. -* To skirt licensing complexity, we distribute an embedded python - that's hacked up to allow installing packages via pip. We use this - to install packages at runtime (like a net installer), so we don't - actually distribute all our transitive dependencies. This also keeps - the initial package size small. - -## C++ Style - -Follow the Google C++ style guide. This is not absolutely strict but -it will be used to settle arguments. - -https://google.github.io/styleguide/cppguide.html - -This should get you 80% of the way there: - -* When in doubt, use K&R style -* 2 space indents -* Class members `look_like_this_` -* Functions and methods `LookLikeThis()` -* Local variables `look_like_this` -* Global constexprs `kLookLikeThis` - -Consistent style reduces cognitive burden. Follow it for the benefit of -your peers. - -## How the embedded python environment works - -I'm distributing an embeddable version of python from the official -python website. It's modified so that packages are installed under -Python/Lib/site-packages, instead of the usual filesystem paths. - -To bootstrap pip & fetch the dependencies needed: - -``` -cd TaSTT -./Resources/Python/python.exe Resources/Python/get-pip.py -./Resources/Python/python.exe -m pip install $YOUR\_PACKAGE\_HERE -``` - -The `future` package imports extra modules, and the embedded python -search path needs to be told where that is. For that reason, we also -redistribute the `future` package in source format. - -This is logically what the GUI does internally when it creates the -python environment. - diff --git a/GUI/package.ps1 b/GUI/package.ps1 deleted file mode 100644 index 697f1a2..0000000 --- a/GUI/package.ps1 +++ /dev/null @@ -1,150 +0,0 @@ -param( - [switch]$skip_zip = $false, - [string]$release = "Release", - [string]$install_pip = $true -) - -echo "Skip zip: $skip_zip" -echo "Release: $release" -echo "Install pip: $install_pip" - -$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8' - -$install_dir = "TaSTT" - -if (Test-Path $install_dir) { - rm -Recurse -Force $install_dir -} - -$py_dir = "Python" - -if (Test-Path $py_dir) { - rm -Recurse $py_dir -} -if (-Not (Test-Path $py_dir)) { - echo "Fetching python" - - $PYTHON_3_10_9_URL = "https://www.python.org/ftp/python/3.10.9/python-3.10.9-embed-amd64.zip" - $PYTHON_URL = $PYTHON_3_10_9_URL - $PYTHON_FILE = $(Split-Path -Path $PYTHON_URL -Leaf) - - if (-Not (Test-Path $PYTHON_FILE)) { - Invoke-WebRequest $PYTHON_URL -OutFile $PYTHON_FILE - } - - mkdir Python - Expand-Archive $PYTHON_FILE -DestinationPath Python - - echo "../Scripts" >> Python/python310._pth - echo "import site" >> Python/python310._pth -} - -$pip_path = "$py_dir/get-pip.py" - -if (Test-Path $pip_path) { - rm -Force $pip_path -} - -if (-Not (Test-Path $pip_path)) { - echo "Fetching pip" - - $PIP_URL = "https://bootstrap.pypa.io/get-pip.py" - $PIP_FILE = $(Split-Path -Path $PIP_URL -Leaf) - - if (-Not (Test-Path $PIP_FILE)) { - Invoke-WebRequest $PIP_URL -OutFile $PIP_FILE - } - - mv $PIP_FILE $pip_path -} - -if ($install_pip) { - ./Python/python.exe Python/get-pip.py - - echo "Installing future" - echo "Assuming host has python 3.10.9 installed" # TODO test for this - python -m pip install future==0.18.2 --target Python/Lib/site-packages -} - -$git_dir = "PortableGit" - -if (-Not (Test-Path $git_dir)) { - echo "Fetching PortableGit" - - # When it's time to update this, get the latest version from here: - # https://git-scm.com/download/win - $GIT_2_39_0_URL = "https://github.com/git-for-windows/git/releases/download/v2.39.0.windows.2/PortableGit-2.39.0.2-64-bit.7z.exe" - $GIT_URL = $GIT_2_39_0_URL - $GIT_FILE = $(Split-Path -Path $GIT_URL -Leaf) - - if (-Not (Test-Path $GIT_FILE)) { - Invoke-WebRequest $GIT_URL -OutFile $GIT_FILE - } - & "./$GIT_FILE" - - Read-Host -Prompt "Press enter once PortableGit is installed at $pwd\PortableGit" -} - -if (-Not (Test-Path UwwwuPP)) { - git clone https://github.com/yum-food/UwwwuPP - pushd UwwwuPP > $null - git submodule update --init --recursive - - mkdir build - pushd build > $null - - cmake.exe .. - cmake.exe --build . - - popd > $null - popd > $null -} - -if (-Not (Test-Path Profanity)) { - mkdir Profanity - pushd Profanity > $null - - $repo = "List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words" - git clone https://github.com/LDNOOBW/$repo - - mkdir Profanity - cp $repo/LICENSE Profanity/ - cp $repo/en Profanity/ - - echo "Source: https://github.com/LDNOOBW/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words" > Profanity/AUTHOR - - popd > $null -} - -if (-Not (Test-Path "silero-vad")) { - git clone "https://github.com/snakers4/silero-vad" -} - -mkdir $install_dir > $null -mkdir $install_dir/Resources > $null -cp -Recurse ../Animations TaSTT/Resources/Animations -mkdir TaSTT/Resources/Fonts -cp -Recurse ../Fonts/Bitmaps TaSTT/Resources/Fonts/Bitmaps -cp -Recurse ../Fonts/Emotes TaSTT/Resources/Fonts/Emotes -cp -Recurse Python TaSTT/Resources/Python -cp -Recurse PortableGit TaSTT/Resources/PortableGit -cp -Recurse ../Scripts TaSTT/Resources/Scripts -mkdir TaSTT/Resources/Images -cp ../Images/logo*.png TaSTT/Resources/Images/ -cp -Recurse ../Shaders TaSTT/Resources/Shaders -cp -Recurse ../Sounds TaSTT/Resources/Sounds -cp -Recurse ../UnityAssets TaSTT/Resources/UnityAssets -cp -Recurse ../BrowserSource TaSTT/Resources/BrowserSource -cp GUI/x64/$release/GUI.exe TaSTT/TaSTT.exe -mkdir TaSTT/Resources/Models -cp "silero-vad/files/silero_vad.onnx" TaSTT/Resources/Models/ -cp "silero-vad/LICENSE" TaSTT/Resources/Models/silero_vad.onnx.LICENSE -mkdir TaSTT/Resources/Uwu -cp UwwwuPP/build/Src/Debug/Uwwwu.exe TaSTT/Resources/Uwu/ -cp UwwwuPP/LICENSE TaSTT/Resources/Uwu/ -cp -r Profanity/Profanity TaSTT/Resources/Profanity - -if (-Not $skip_zip) { - Compress-Archive -Path "$install_dir" -DestinationPath "$install_dir.zip" -Force -} - -- cgit v1.2.3