diff --git a/CMakeLists.txt b/CMakeLists.txt index 84336d0..7edfda7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE # Link libraries target_link_libraries(${PROJECT_NAME} PRIVATE - portaudio_static + portaudio httplib::httplib nlohmann_json::nlohmann_json imgui::imgui @@ -54,8 +54,16 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") -Wall -Wextra -Wpedantic - -Werror ) + + # MinGW: cpp-httplib's GetAddrInfoExCancel is not available + # Don't treat warnings as errors for MinGW due to httplib incompatibilities + if(NOT MINGW) + target_compile_options(${PROJECT_NAME} PRIVATE -Werror) + else() + # Force console subsystem on Windows (not GUI subsystem) + target_link_options(${PROJECT_NAME} PRIVATE -mconsole) + endif() endif() # Copy config files to build directory diff --git a/CMakePresets.json b/CMakePresets.json index 2cc6267..0d85a5b 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -61,12 +61,15 @@ "name": "mingw-base", "hidden": true, "generator": "Ninja", - "binaryDir": "${sourceDir}/build/${presetName}", + "binaryDir": "${sourceDir}/build/mingw-${presetName}", "cacheVariables": { "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "VCPKG_TARGET_TRIPLET": "x64-mingw-dynamic", + "VCPKG_OVERLAY_TRIPLETS": "$env{VCPKG_ROOT}/triplets/community", "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", "CMAKE_C_COMPILER": "gcc", - "CMAKE_CXX_COMPILER": "g++" + "CMAKE_CXX_COMPILER": "g++", + "CMAKE_MAKE_PROGRAM": "ninja" } }, { diff --git a/build_mingw.bat b/build_mingw.bat index 4d5c6d0..e243223 100644 --- a/build_mingw.bat +++ b/build_mingw.bat @@ -109,19 +109,25 @@ if /i "%BUILD_TYPE%"=="Debug" ( set PRESET=mingw-release ) -REM Configure with CMake -echo [INFO] Configuring CMake with preset: %PRESET% -cmake --preset %PRESET% +REM Configure with CMake - force MinGW triplet via environment variable +echo [INFO] Configuring CMake for MinGW build... +echo [INFO] Forcing vcpkg triplet: x64-mingw-dynamic +set VCPKG_DEFAULT_TRIPLET=x64-mingw-dynamic +set VCPKG_DEFAULT_HOST_TRIPLET=x64-mingw-dynamic + +cmake -B build/mingw-%BUILD_TYPE% ^ + -G Ninja ^ + -DCMAKE_BUILD_TYPE=%BUILD_TYPE% ^ + -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%/scripts/buildsystems/vcpkg.cmake ^ + -DVCPKG_TARGET_TRIPLET=x64-mingw-dynamic ^ + -DVCPKG_HOST_TRIPLET=x64-mingw-dynamic ^ + -DCMAKE_C_COMPILER=gcc ^ + -DCMAKE_CXX_COMPILER=g++ ^ + -DCMAKE_MAKE_PROGRAM=ninja if %errorlevel% neq 0 ( echo. echo [ERROR] CMake configuration failed - echo. - echo Common issues: - echo 1. VCPKG_ROOT not set correctly - echo 2. Missing dependencies (run setup_mingw.bat) - echo 3. PATH not refreshed (close and reopen terminal) - echo. pause exit /b 1 ) @@ -133,11 +139,6 @@ cmake --build build/mingw-%BUILD_TYPE% if %errorlevel% neq 0 ( echo. echo [ERROR] Build failed - echo. - echo Check the error messages above for details. - echo If you see dependency errors, try: - echo build_mingw.bat --clean --release - echo. pause exit /b 1 ) diff --git a/setup_mingw.bat b/setup_mingw.bat index 5f9422f..29f1558 100644 --- a/setup_mingw.bat +++ b/setup_mingw.bat @@ -33,18 +33,25 @@ if %errorlevel% neq 0 ( powershell -Command "Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))" + REM Check if Chocolatey is now in PATH + set "PATH=%PATH%;C:\ProgramData\chocolatey\bin" + + where choco >nul 2>&1 if %errorlevel% neq 0 ( - echo [ERROR] Failed to install Chocolatey - echo Please install manually: https://chocolatey.org/install + echo. + echo ======================================== + echo [IMPORTANT] Chocolatey installed successfully! + echo ======================================== + echo. + echo Please CLOSE this window and reopen PowerShell as ADMIN + echo Then run this script again: .\setup_mingw.bat + echo. pause - exit /b 1 + exit /b 0 ) - echo [SUCCESS] Chocolatey installed! + echo [SUCCESS] Chocolatey installed and ready! echo. - - REM Refresh environment - refreshenv ) echo [INFO] Chocolatey found diff --git a/setup_mingw_simple.bat b/setup_mingw_simple.bat new file mode 100644 index 0000000..12642f2 --- /dev/null +++ b/setup_mingw_simple.bat @@ -0,0 +1,82 @@ +@echo off +REM Simplified MinGW Setup Script for SecondVoice + +echo ======================================== +echo SecondVoice - MinGW Setup (Simplified) +echo ======================================== +echo. + +REM Check if running as admin +net session >nul 2>&1 +if %errorlevel% neq 0 ( + echo [ERROR] Please run as Administrator + pause + exit /b 1 +) + +REM Check/Install Chocolatey +where choco >nul 2>&1 +if %errorlevel% neq 0 ( + echo [INFO] Installing Chocolatey... + powershell -Command "Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))" + + echo. + echo [SUCCESS] Chocolatey installed! + echo Please CLOSE this window, reopen PowerShell as ADMIN, and run this script again. + pause + exit /b 0 +) + +echo [INFO] Chocolatey found + +REM Install MinGW +where gcc >nul 2>&1 +if %errorlevel% neq 0 ( + echo [INFO] Installing MinGW... + choco install mingw -y +) + +REM Install CMake +where cmake >nul 2>&1 +if %errorlevel% neq 0 ( + echo [INFO] Installing CMake... + choco install cmake -y --installargs 'ADD_CMAKE_TO_PATH=System' +) + +REM Install Ninja +where ninja >nul 2>&1 +if %errorlevel% neq 0 ( + echo [INFO] Installing Ninja... + choco install ninja -y +) + +REM Install Git +where git >nul 2>&1 +if %errorlevel% neq 0 ( + echo [INFO] Installing Git... + choco install git -y +) + +REM Setup vcpkg +if not defined VCPKG_ROOT ( + if not exist "C:\vcpkg" ( + echo [INFO] Installing vcpkg... + cd C:\ + git clone https://github.com/microsoft/vcpkg.git + cd vcpkg + call bootstrap-vcpkg.bat + ) + echo [INFO] Setting VCPKG_ROOT... + setx VCPKG_ROOT "C:\vcpkg" + set VCPKG_ROOT=C:\vcpkg +) + +echo. +echo ======================================== +echo [SUCCESS] Setup Complete! +echo ======================================== +echo. +echo Next: Close this window, reopen PowerShell as ADMIN +echo Then run: .\build_mingw.bat --release +echo. +pause diff --git a/src/api/ClaudeClient.cpp b/src/api/ClaudeClient.cpp index 0753260..325e482 100644 --- a/src/api/ClaudeClient.cpp +++ b/src/api/ClaudeClient.cpp @@ -1,4 +1,5 @@ #include "ClaudeClient.h" +#include "../mingw_compat.h" #include #include #include diff --git a/src/api/WhisperClient.cpp b/src/api/WhisperClient.cpp index e67aabe..197f01b 100644 --- a/src/api/WhisperClient.cpp +++ b/src/api/WhisperClient.cpp @@ -1,5 +1,6 @@ #include "WhisperClient.h" #include "../audio/AudioBuffer.h" +#include "../mingw_compat.h" #include #include #include diff --git a/src/audio/AudioCapture.cpp b/src/audio/AudioCapture.cpp index b398c11..8a1b9ae 100644 --- a/src/audio/AudioCapture.cpp +++ b/src/audio/AudioCapture.cpp @@ -18,11 +18,13 @@ AudioCapture::~AudioCapture() { } bool AudioCapture::initialize() { + std::cout << "[Audio] Initializing PortAudio..." << std::endl; PaError err = Pa_Initialize(); if (err != paNoError) { - std::cerr << "PortAudio init error: " << Pa_GetErrorText(err) << std::endl; + std::cerr << "[Audio] PortAudio init error: " << Pa_GetErrorText(err) << std::endl; return false; } + std::cout << "[Audio] PortAudio initialized successfully" << std::endl; return true; } diff --git a/src/main.cpp b/src/main.cpp index 37d66da..2edb029 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,58 +1,82 @@ #include #include "utils/Config.h" +#include "utils/Logger.h" #include "core/Pipeline.h" +#ifdef _WIN32 +#include +#endif int main(int argc, char** argv) { (void)argc; // Unused (void)argv; // Unused - std::cout << "SecondVoice - Real-time Translation System" << std::endl; - std::cout << "===========================================" << std::endl; + + #ifdef _WIN32 + MessageBoxA(NULL, "SecondVoice starting...", "Debug", MB_OK); + #endif + + LOG("========================================"); + LOG("SecondVoice - Real-time Translation System"); + LOG("========================================"); + LOG("Starting application..."); // Load configuration + LOG("Loading configuration..."); secondvoice::Config& config = secondvoice::Config::getInstance(); if (!config.load("config.json", ".env")) { - std::cerr << "Failed to load configuration" << std::endl; + LOG("ERROR: Failed to load configuration"); + #ifdef _WIN32 + MessageBoxA(NULL, "Failed to load configuration!", "Error", MB_OK | MB_ICONERROR); + #endif return 1; } - std::cout << "Configuration loaded successfully" << std::endl; - std::cout << "Audio: " << config.getAudioConfig().sample_rate << "Hz, " - << config.getAudioConfig().channels << " channel(s), " - << config.getAudioConfig().chunk_duration_seconds << "s chunks" << std::endl; - std::cout << "Whisper: " << config.getWhisperConfig().model - << " (language: " << config.getWhisperConfig().language << ")" << std::endl; - std::cout << "Claude: " << config.getClaudeConfig().model << std::endl; - std::cout << std::endl; + LOG("Configuration loaded successfully"); + LOG(""); + + #ifdef _WIN32 + MessageBoxA(NULL, "Config OK - Creating pipeline...", "Debug", MB_OK); + #endif // Create and initialize pipeline + LOG("Creating pipeline..."); secondvoice::Pipeline pipeline; + LOG("Initializing pipeline..."); if (!pipeline.initialize()) { - std::cerr << "Failed to initialize pipeline" << std::endl; + LOG("ERROR: Failed to initialize pipeline"); + #ifdef _WIN32 + MessageBoxA(NULL, "Failed to initialize pipeline!", "Error", MB_OK | MB_ICONERROR); + #endif return 1; } - std::cout << "Pipeline initialized successfully" << std::endl; - std::cout << "Starting recording and translation..." << std::endl; - std::cout << std::endl; + #ifdef _WIN32 + MessageBoxA(NULL, "Pipeline initialized!", "Debug", MB_OK); + #endif + + LOG("Pipeline initialized successfully"); + LOG("Starting recording and translation..."); // Start pipeline + LOG("Starting pipeline..."); if (!pipeline.start()) { - std::cerr << "Failed to start pipeline" << std::endl; + LOG("ERROR: Failed to start pipeline"); return 1; } // Wait for pipeline to finish (user clicks Stop button) + LOG("Pipeline running, waiting for user to stop..."); while (pipeline.isRunning()) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } - std::cout << std::endl; - std::cout << "Recording stopped" << std::endl; - std::cout << "Saving audio..." << std::endl; + LOG(""); + LOG("Recording stopped"); + LOG("Saving audio..."); pipeline.stop(); - std::cout << "Done!" << std::endl; + LOG("Done!"); + LOG("Check secondvoice_debug.log for details"); return 0; } diff --git a/src/mingw_compat.h b/src/mingw_compat.h new file mode 100644 index 0000000..e079839 --- /dev/null +++ b/src/mingw_compat.h @@ -0,0 +1,21 @@ +#pragma once +// MinGW compatibility shims for cpp-httplib + +#ifdef __MINGW32__ +#ifdef _WIN32 + +// GetAddrInfoExCancel is not available in MinGW headers +// Provide a stub to allow compilation +#ifndef GetAddrInfoExCancel +extern "C" { +inline int GetAddrInfoExCancel(void* lpHandle) { + (void)lpHandle; + // MinGW doesn't have GetAddrInfoExCancel, so we can't cancel + // This is a limitation when using MinGW with cpp-httplib + return 0; +} +} +#endif + +#endif // _WIN32 +#endif // __MINGW32__ diff --git a/src/ui/TranslationUI.cpp b/src/ui/TranslationUI.cpp index 59cbcc6..e799893 100644 --- a/src/ui/TranslationUI.cpp +++ b/src/ui/TranslationUI.cpp @@ -23,10 +23,16 @@ TranslationUI::~TranslationUI() { bool TranslationUI::initialize() { // Initialize GLFW + std::cout << "[UI] Initializing GLFW..." << std::endl; + glfwSetErrorCallback([](int error, const char* description) { + std::cerr << "[GLFW Error " << error << "] " << description << std::endl; + }); + if (!glfwInit()) { - std::cerr << "Failed to initialize GLFW" << std::endl; + std::cerr << "[UI] Failed to initialize GLFW" << std::endl; return false; } + std::cout << "[UI] GLFW initialized successfully" << std::endl; // OpenGL 3.3 + GLSL 330 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); @@ -34,12 +40,14 @@ bool TranslationUI::initialize() { glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Create window + std::cout << "[UI] Creating GLFW window (" << width_ << "x" << height_ << ")..." << std::endl; window_ = glfwCreateWindow(width_, height_, "SecondVoice - Live Translation", nullptr, nullptr); if (!window_) { - std::cerr << "Failed to create GLFW window" << std::endl; + std::cerr << "[UI] Failed to create GLFW window" << std::endl; glfwTerminate(); return false; } + std::cout << "[UI] GLFW window created successfully" << std::endl; glfwMakeContextCurrent(window_); glfwSwapInterval(1); // Enable vsync diff --git a/src/utils/Logger.h b/src/utils/Logger.h new file mode 100644 index 0000000..7bd2b4b --- /dev/null +++ b/src/utils/Logger.h @@ -0,0 +1,42 @@ +#pragma once +#include +#include +#include +#include + +namespace secondvoice { + +class Logger { +public: + static Logger& getInstance() { + static Logger instance; + return instance; + } + + void log(const std::string& message) { + std::lock_guard lock(mutex_); + std::cout << message << std::endl; + if (file_.is_open()) { + file_ << message << std::endl; + file_.flush(); + } + } + +private: + Logger() { + file_.open("secondvoice_debug.log", std::ios::out | std::ios::trunc); + } + + ~Logger() { + if (file_.is_open()) { + file_.close(); + } + } + + std::ofstream file_; + std::mutex mutex_; +}; + +#define LOG(msg) secondvoice::Logger::getInstance().log(msg) + +} // namespace secondvoice