From 1122954fea161cf40c104778c06b83dbc9c47880 Mon Sep 17 00:00:00 2001 From: yum Date: Wed, 21 Dec 2022 15:33:17 -0800 Subject: GUI: Add better logging interface Create printf-like interface for writing to wxTextCtrl objects. Also mask out PII. I wanted a way to not dox myself when recording demos, but I wound up making a second user on my PC to serve the same purpose. Maybe I'll delete the code later idk. --- GUI/GUI/GUI/Frame.cpp | 72 ++++++++------------ GUI/GUI/GUI/Frame.h | 2 +- GUI/GUI/GUI/GUI.vcxproj | 2 + GUI/GUI/GUI/GUI.vcxproj.filters | 6 ++ GUI/GUI/GUI/Logging.cpp | 17 +++++ GUI/GUI/GUI/Logging.h | 30 ++++++++ GUI/GUI/GUI/PythonWrapper.cpp | 147 ++++++++++++++++++++-------------------- GUI/README.md | 10 ++- 8 files changed, 164 insertions(+), 122 deletions(-) create mode 100644 GUI/GUI/GUI/Logging.cpp create mode 100644 GUI/GUI/GUI/Logging.h (limited to 'GUI') diff --git a/GUI/GUI/GUI/Frame.cpp b/GUI/GUI/GUI/Frame.cpp index 5c1fbeb..2ecc255 100644 --- a/GUI/GUI/GUI/Frame.cpp +++ b/GUI/GUI/GUI/Frame.cpp @@ -1,4 +1,5 @@ #include "Frame.h" +#include "Logging.h" #include "PythonWrapper.h" #include @@ -181,6 +182,8 @@ namespace { constexpr int kModelDefault = 2; // base.en } // namespace +using ::Logging::Log; + Frame::Frame() : wxFrame(nullptr, wxID_ANY, "TaSTT"), py_app_(nullptr), @@ -212,7 +215,7 @@ Frame::Frame() transcribe_out->SetMinSize(transcribe_out_sz); transcribe_out_ = transcribe_out; - transcribe_out_->AppendText(PythonWrapper::GetVersion() + "\n"); + Log(transcribe_out_, "{}\n", PythonWrapper::GetVersion()); auto* py_config_panel = new wxPanel(transcribe_panel, ID_PY_CONFIG_PANEL); { @@ -438,19 +441,15 @@ void Frame::OnNavbarUnity(wxCommandEvent& event) void Frame::OnSetupPython(wxCommandEvent& event) { - transcribe_out_->AppendText("Setting up Python virtual environment\n"); - transcribe_out_->AppendText("This could take several minutes, please be patient!\n"); - transcribe_out_->AppendText("This will download ~5GB of dependencies.\n"); + 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 ~5GB of dependencies.\n"); { std::string transcribe_out; - std::ostringstream transcribe_out_oss; - transcribe_out_oss << " Installing pip" << std::endl; - transcribe_out_->AppendText(transcribe_out_oss.str()); + Log(transcribe_out_, " Installing pip\n"); if (!PythonWrapper::InstallPip(&transcribe_out)) { - std::ostringstream transcribe_out_oss; - transcribe_out_oss << "Failed to install pip: " << transcribe_out; - transcribe_out_->AppendText(transcribe_out_oss.str()); + Log(transcribe_out_, "Failed to install pip: {}\n", transcribe_out); } } @@ -466,28 +465,21 @@ void Frame::OnSetupPython(wxCommandEvent& event) }; for (const auto& pip_dep : pip_deps) { - { - std::ostringstream transcribe_out_oss; - transcribe_out_oss << " Installing " << pip_dep << std::endl; - transcribe_out_->AppendText(transcribe_out_oss.str()); - } + Log(transcribe_out_, " Installing {}\n", pip_dep); std::string py_stdout, py_stderr; bool res = PythonWrapper::InvokeWithArgs({ "-m", "pip", "install", pip_dep }, &py_stdout, &py_stderr); if (!res) { - std::ostringstream transcribe_out_oss; - transcribe_out_oss << "Failed to install " << pip_dep << ": " << py_stderr << std::endl; - transcribe_out_->AppendText(transcribe_out_oss.str()); + Log(transcribe_out_, "Failed to install {}: {}\n", pip_dep, py_stderr); return; } } - transcribe_out_->AppendText("Python virtual environment successfully set up!\n"); + Log(transcribe_out_, "Python virtual environment successfully set up!\n"); } void Frame::OnDumpMics(wxCommandEvent& event) { - transcribe_out_->AppendText(PythonWrapper::DumpMics()); - transcribe_out_->AppendText("\n"); + Log(transcribe_out_, "{}\n", PythonWrapper::DumpMics()); } #define DEBUG @@ -553,22 +545,18 @@ void Frame::OnGenerateFX(wxCommandEvent& event) void Frame::OnAppStart(wxCommandEvent& event) { if (py_app_) { if (wxProcess::Exists(py_app_->GetPid())) { - transcribe_out_->AppendText("Transcription engine already running\n"); + Log(transcribe_out_, "Transcription engine already running\n"); return; } delete py_app_; py_app_ = nullptr; } - transcribe_out_->AppendText("Launching transcription engine\n"); + Log(transcribe_out_, "Launching transcription engine\n"); auto cb = [&](wxProcess* proc, int ret) -> void { - std::ostringstream transcribe_out_oss; - transcribe_out_oss << "Transcription engine exited with code " << ret << std::endl; - - DrainApp(proc, transcribe_out_oss); - - transcribe_out_->AppendText(transcribe_out_oss.str()); + Log(transcribe_out_, "Transcription engine exited with code {}\n", ret); + DrainApp(proc, transcribe_out_); return; }; @@ -590,7 +578,7 @@ void Frame::OnAppStart(wxCommandEvent& event) { kLangChoices[which_lang].ToStdString(), kModelChoices[which_model].ToStdString()); if (!p) { - transcribe_out_->AppendText("Failed to launch transcription engine\n"); + Log(transcribe_out_, "Failed to launch transcription engine\n"); return; } @@ -601,7 +589,7 @@ void Frame::OnAppStop(wxCommandEvent& event) { if (py_app_) { const long pid = py_app_->GetPid(); - transcribe_out_->AppendText("Stopping transcription engine...\n"); + Log(transcribe_out_, "Stopping transcription engine...\n"); // Closing stdout causes the app to exit. It takes it quite a while // to exit gracefully; be patient. @@ -615,11 +603,7 @@ void Frame::OnAppStop(wxCommandEvent& event) { wxMilliSleep(10); } - { - std::ostringstream oss; - DrainApp(py_app_, oss); - transcribe_out_->AppendText(oss.str()); - } + DrainApp(py_app_, transcribe_out_); // Now shut it down. bool first = true; @@ -627,39 +611,37 @@ void Frame::OnAppStop(wxCommandEvent& event) { while (wxProcess::Exists(pid)) { wxProcess::Kill(pid, wxSIGKILL); if (++loop_cnt % 100 == 0) { - transcribe_out_->AppendText("Waiting for transcription engine to exit"); + Log(transcribe_out_, "Waiting for transcription engine to exit\n"); } wxMilliSleep(10); } // Since we don't process the termination event, py_app_ deletes itself! py_app_ = nullptr; - transcribe_out_->AppendText("Stopped transcription engine\n"); + Log(transcribe_out_, "Stopped transcription engine\n"); } else { - transcribe_out_->AppendText("Transcription engine already stopped\n"); + Log(transcribe_out_, "Transcription engine already stopped\n"); } } void Frame::OnAppDrain(wxTimerEvent& event) { - std::ostringstream oss; - DrainApp(py_app_, oss); - transcribe_out_->AppendText(oss.str()); + DrainApp(py_app_, transcribe_out_); } -void Frame::DrainApp(wxProcess* proc, std::ostringstream& oss) { +void Frame::DrainApp(wxProcess* proc, wxTextCtrl* frame) { if (!proc) { return; } while (proc->IsInputAvailable()) { wxTextInputStream iss(*(proc->GetInputStream())); - oss << " " << iss.ReadLine() << std::endl; + Log(frame, " {}\n", iss.ReadLine()); } while (proc->IsErrorAvailable()) { wxTextInputStream iss(*(proc->GetErrorStream())); - oss << " " << iss.ReadLine() << std::endl; + Log(frame, " {}\n", iss.ReadLine()); } } diff --git a/GUI/GUI/GUI/Frame.h b/GUI/GUI/GUI/Frame.h index 1d847ca..9b94036 100644 --- a/GUI/GUI/GUI/Frame.h +++ b/GUI/GUI/GUI/Frame.h @@ -49,7 +49,7 @@ private: void OnAppStart(wxCommandEvent& event); void OnAppStop(wxCommandEvent& event); void OnAppDrain(wxTimerEvent& event); - void DrainApp(wxProcess* proc, std::ostringstream& oss); + void DrainApp(wxProcess* proc, wxTextCtrl *frame); void OnGenerateFX(wxCommandEvent& event); void LoadAndSetIcons(); diff --git a/GUI/GUI/GUI/GUI.vcxproj b/GUI/GUI/GUI/GUI.vcxproj index cd0e5f0..8327365 100644 --- a/GUI/GUI/GUI/GUI.vcxproj +++ b/GUI/GUI/GUI/GUI.vcxproj @@ -137,12 +137,14 @@ + + diff --git a/GUI/GUI/GUI/GUI.vcxproj.filters b/GUI/GUI/GUI/GUI.vcxproj.filters index 5118c26..348026a 100644 --- a/GUI/GUI/GUI/GUI.vcxproj.filters +++ b/GUI/GUI/GUI/GUI.vcxproj.filters @@ -27,6 +27,9 @@ Source Files + + Source Files + @@ -44,6 +47,9 @@ Header Files + + Header Files + diff --git a/GUI/GUI/GUI/Logging.cpp b/GUI/GUI/GUI/Logging.cpp new file mode 100644 index 0000000..6727ba1 --- /dev/null +++ b/GUI/GUI/GUI/Logging.cpp @@ -0,0 +1,17 @@ +#include "Logging.h" + +#include +#include + +std::string Logging::HidePII(const std::string&& str, + const std::string& replacement) { + try { + std::regex c_users("(C:\\\\Users\\\\)[a-zA-Z0-9_]+"); + std::string real_replacement = "$1" + replacement; + return std::regex_replace(str, c_users, real_replacement); + } + catch (const std::regex_error& e) { + wxLogFatalError(e.what()); + } + wxLogFatalError("Unhandled regex error (HidePII)"); +} diff --git a/GUI/GUI/GUI/Logging.h b/GUI/GUI/GUI/Logging.h new file mode 100644 index 0000000..95e7802 --- /dev/null +++ b/GUI/GUI/GUI/Logging.h @@ -0,0 +1,30 @@ +#pragma once + +#pragma once + +#include + +#ifndef WX_PRECOMP +#include +#endif + +#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 = "*****"); + + // 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)); + frame->AppendText(masked); + } +} + diff --git a/GUI/GUI/GUI/PythonWrapper.cpp b/GUI/GUI/GUI/PythonWrapper.cpp index 972982f..2e37994 100644 --- a/GUI/GUI/GUI/PythonWrapper.cpp +++ b/GUI/GUI/GUI/PythonWrapper.cpp @@ -1,3 +1,4 @@ +#include "Logging.h" #include "PythonWrapper.h" #include @@ -5,6 +6,8 @@ #include #include +using ::Logging::Log; + class PythonProcess : public wxProcess { public: PythonProcess(std::function&& exit_callback) : exit_cb_(exit_callback) { @@ -178,18 +181,14 @@ bool PythonWrapper::GenerateAnimator( { if (std::filesystem::exists(tastt_generated_dir_path)) { - std::ostringstream oss; - oss << "Erasing " << tastt_generated_dir_path << std::endl; - out->AppendText(oss.str()); + Log(out, "Erasing {}\n", tastt_generated_dir_path.string()); std::filesystem::remove_all(tastt_generated_dir_path); } - std::ostringstream oss; - oss << "Creating " << tastt_generated_dir_path << std::endl; - out->AppendText(oss.str()); + Log(out, "Creating {}\n", tastt_generated_dir_path.string()); std::filesystem::create_directories(tastt_generated_dir_path); } { - out->AppendText("Copying canned animations... "); + Log(out, "Copying canned animations... "); auto opts = std::filesystem::copy_options(); opts |= std::filesystem::copy_options::overwrite_existing; opts |= std::filesystem::copy_options::recursive; @@ -197,13 +196,13 @@ bool PythonWrapper::GenerateAnimator( std::filesystem::copy("Resources/Animations", tastt_animations_path, opts, error); if (error.value()) { wxLogError("Failed to copy animations: %s (%d)", error.message(), error.value()); - out->AppendText("failed!\n"); + Log(out, "failed!\n"); return false; } - out->AppendText("success!\n"); + Log(out, "success!\n"); } { - out->AppendText("Copying canned assets... "); + Log(out, "Copying canned assets... "); auto opts = std::filesystem::copy_options(); opts |= std::filesystem::copy_options::overwrite_existing; opts |= std::filesystem::copy_options::recursive; @@ -211,13 +210,13 @@ bool PythonWrapper::GenerateAnimator( std::filesystem::copy("Resources/UnityAssets", tastt_assets_path, opts, error); if (error.value()) { wxLogError("Failed to copy animations: %s (%d)", error.message(), error.value()); - out->AppendText("failed!\n"); + Log(out, "failed!\n"); return false; } - out->AppendText("success!\n"); + Log(out, "success!\n"); } { - out->AppendText("Copying canned shaders... "); + Log(out, "Copying canned shaders... "); auto opts = std::filesystem::copy_options(); opts |= std::filesystem::copy_options::overwrite_existing; opts |= std::filesystem::copy_options::recursive; @@ -225,13 +224,13 @@ bool PythonWrapper::GenerateAnimator( std::filesystem::copy("Resources/Shaders", tastt_shaders_path, opts, error); if (error.value()) { wxLogError("Failed to copy animations: %s (%d)", error.message(), error.value()); - out->AppendText("failed!\n"); + Log(out, "failed!\n"); return false; } - out->AppendText("success!\n"); + Log(out, "success!\n"); } { - out->AppendText("Copying canned fonts... "); + Log(out, "Copying canned fonts... "); auto opts = std::filesystem::copy_options(); opts |= std::filesystem::copy_options::overwrite_existing; opts |= std::filesystem::copy_options::recursive; @@ -239,83 +238,83 @@ bool PythonWrapper::GenerateAnimator( std::filesystem::copy("Resources/Fonts", tastt_fonts_path, opts, error); if (error.value()) { wxLogError("Failed to copy animations: %s (%d)", error.message(), error.value()); - out->AppendText("failed!\n"); + Log(out, "failed!\n"); return false; } - out->AppendText("success!\n"); + Log(out, "success!\n"); } { - out->AppendText("Generating guid.map... "); + Log(out, "Generating guid.map... "); std::string py_stdout, py_stderr; if (InvokeWithArgs({ libunity_path, "guid_map", "--project_root", unity_assets_path, "--save_to", guid_map_path.string() }, &py_stdout, &py_stderr)) { - out->AppendText("success!\n"); - out->AppendText(py_stdout.c_str()); + Log(out, "success!\n"); + Log(out, py_stdout.c_str()); if (!py_stdout.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } - out->AppendText(py_stderr.c_str()); + Log(out, py_stderr.c_str()); if (!py_stderr.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } } else { wxLogError("Failed to generate guid.map: %s", py_stderr.c_str()); - out->AppendText("failed!\n"); + Log(out, "failed!\n"); return false; } } { - out->AppendText("Generating animations... "); + Log(out, "Generating animations... "); std::string py_stdout, py_stderr; if (InvokeWithArgs({ libtastt_path, "gen_anims", "--gen_anim_dir", tastt_animations_path.string(), "--guid_map", guid_map_path.string() }, &py_stdout, &py_stderr)) { - out->AppendText("success!\n"); - out->AppendText(py_stdout.c_str()); + Log(out, "success!\n"); + Log(out, py_stdout.c_str()); if (!py_stdout.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } - out->AppendText(py_stderr.c_str()); + Log(out, py_stderr.c_str()); if (!py_stderr.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } } else { wxLogError("Failed to generate animations: %s", py_stderr.c_str()); - out->AppendText("failed!\n"); + Log(out, "failed!\n"); return false; } } { - out->AppendText("Generating FX layer... "); + Log(out, "Generating FX layer... "); std::string py_stdout, py_stderr; if (InvokeWithArgs({ libtastt_path, "gen_fx", "--fx_dest", tastt_fx0_path.string(), "--gen_anim_dir", tastt_animations_path.string(), "--guid_map", guid_map_path.string() }, &py_stdout, &py_stderr)) { - out->AppendText("success!\n"); - out->AppendText(py_stdout.c_str()); + Log(out, "success!\n"); + Log(out, py_stdout.c_str()); if (!py_stdout.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } - out->AppendText(py_stderr.c_str()); + Log(out, py_stderr.c_str()); if (!py_stderr.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } } else { wxLogError("Failed to generate FX layer: %s", py_stderr.c_str()); - out->AppendText("failed!\n"); + Log(out, "failed!\n"); return false; } } { - out->AppendText("Adding enable/disable toggle... "); + Log(out, "Adding enable/disable toggle... "); std::string py_stdout, py_stderr; if (InvokeWithArgs({ libunity_path, "add_toggle", "--fx0", tastt_fx0_path.string(), @@ -323,48 +322,48 @@ bool PythonWrapper::GenerateAnimator( "--gen_anim_dir", tastt_animations_path.string(), "--guid_map", guid_map_path.string() }, &py_stdout, &py_stderr)) { - out->AppendText("success!\n"); - out->AppendText(py_stdout.c_str()); + Log(out, "success!\n"); + Log(out, py_stdout.c_str()); if (!py_stdout.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } - out->AppendText(py_stderr.c_str()); + Log(out, py_stderr.c_str()); if (!py_stderr.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } } else { wxLogError("Failed to add enable/disable toggle: %s", py_stderr.c_str()); - out->AppendText("failed!\n"); + Log(out, "failed!\n"); return false; } } { - out->AppendText("Merging with user animator... "); + Log(out, "Merging with user animator... "); std::string py_stdout, py_stderr; if (InvokeWithArgs({ libunity_path, "merge", "--fx0", unity_animator_path, "--fx1", tastt_fx1_path.string(), "--fx_dest", tastt_fx2_path.string() }, &py_stdout, &py_stderr)) { - out->AppendText("success!\n"); - out->AppendText(py_stdout.c_str()); + Log(out, "success!\n"); + Log(out, py_stdout.c_str()); if (!py_stdout.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } - out->AppendText(py_stderr.c_str()); + Log(out, py_stderr.c_str()); if (!py_stderr.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } } else { wxLogError("Failed to merge animators: %s", py_stderr.c_str()); - out->AppendText("failed!\n"); + Log(out, "failed!\n"); return false; } } { - out->AppendText("Setting noop animations... "); + Log(out, "Setting noop animations... "); std::string py_stdout, py_stderr; if (InvokeWithArgs({ libunity_path, "set_noop_anim", "--fx0", tastt_fx2_path.string(), @@ -372,65 +371,65 @@ bool PythonWrapper::GenerateAnimator( "--gen_anim_dir", tastt_animations_path.string(), "--guid_map", guid_map_path.string() }, &py_stdout, &py_stderr)) { - out->AppendText("success!\n"); - out->AppendText(py_stdout.c_str()); + Log(out, "success!\n"); + Log(out, py_stdout.c_str()); if (!py_stdout.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } - out->AppendText(py_stderr.c_str()); + Log(out, py_stderr.c_str()); if (!py_stderr.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } } else { wxLogError("Failed to set noop animations: %s", py_stderr.c_str()); - out->AppendText("failed!\n"); + Log(out, "failed!\n"); return false; } } { - out->AppendText("Generating avatar parameters... "); + Log(out, "Generating avatar parameters... "); std::string py_stdout, py_stderr; if (InvokeWithArgs({ generate_params_path, "--old_params", unity_parameters_path, "--new_params", tastt_params_path.string()}, &py_stdout, &py_stderr)) { - out->AppendText("success!\n"); - out->AppendText(py_stdout.c_str()); + Log(out, "success!\n"); + Log(out, py_stdout.c_str()); if (!py_stdout.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } - out->AppendText(py_stderr.c_str()); + Log(out, py_stderr.c_str()); if (!py_stderr.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } } else { wxLogError("Failed to generate avatar parameters: %s", py_stderr.c_str()); - out->AppendText("failed!\n"); + Log(out, "failed!\n"); return false; } } { - out->AppendText("Generating avatar menu... "); + Log(out, "Generating avatar menu... "); std::string py_stdout, py_stderr; if (InvokeWithArgs({ generate_menu_path, "--old_menu", unity_menu_path, "--new_menu", tastt_menu_path.string()}, &py_stdout, &py_stderr)) { - out->AppendText("success!\n"); - out->AppendText(py_stdout.c_str()); + Log(out, "success!\n"); + Log(out, py_stdout.c_str()); if (!py_stdout.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } - out->AppendText(py_stderr.c_str()); + Log(out, py_stderr.c_str()); if (!py_stderr.empty()) { - out->AppendText("\n"); + Log(out, "\n"); } } else { wxLogError("Failed to generate avatar menu: %s", py_stderr.c_str()); - out->AppendText("failed!\n"); + Log(out, "failed!\n"); return false; } } diff --git a/GUI/README.md b/GUI/README.md index 079474d..f8cc3a1 100644 --- a/GUI/README.md +++ b/GUI/README.md @@ -1,10 +1,16 @@ ## Build instructions 0. Open Powershell. -1. Execute Libraries/fetch.ps1. -2. Install Visual Studio 2022. +1. Make sure you've downloaded submodules: +``` +$ git submodule init +$ git submodule update +``` +2. Execute Libraries/fetch.ps1. 3. Open Libraries/wx/build/msw/wx\_vc17.sln with Visual Studio 2022. 4. Build x64/Release. + 1. The build configuration is in the top. By default it's probably Debug/x64. + 2. To build: ctrl+shift+B 5. Open GUI/GUI.sln with Visual Studio 2022. 6. Build x64/Release. 7. Run package.ps1 from powershell. -- cgit v1.2.3