diff --git a/.github/scripts/.build.zsh b/.github/scripts/.build.zsh index 4d2f08a..c6fe52a 100755 --- a/.github/scripts/.build.zsh +++ b/.github/scripts/.build.zsh @@ -230,7 +230,8 @@ ${_usage_host:-}" -DCODESIGN_IDENTITY=${CODESIGN_IDENT:--} ) - cmake_build_args+=(--preset ${_preset} --parallel --config ${config} -- ONLY_ACTIVE_ARCH=NO -arch arm64 -arch x86_64) + # TODO: enable -arch arm64 + cmake_build_args+=(--preset ${_preset} --parallel --config ${config} -- ONLY_ACTIVE_ARCH=NO -arch x86_64 -arch arm64) cmake_install_args+=(build_macos --config ${config} --prefix "${project_root}/release/${config}") local -a xcbeautify_opts=() diff --git a/.gitignore b/.gitignore index 10d3b1f..854e91d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ !CMakePresets.json !LICENSE !README.md +!patch_libobs.diff # Exclude lock files *.lock.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 271e771..afd099a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,8 +40,7 @@ if(ENABLE_QT) endif() add_subdirectory(src/ui) -target_sources(${CMAKE_PROJECT_NAME} PRIVATE src/translation-service/translation.cpp - src/plugin-main.c src/utils/config-data.cpp - src/translation-service/httpserver.cpp) +target_sources(${CMAKE_PROJECT_NAME} PRIVATE src/translation-service/translation.cpp src/plugin-main.c + src/utils/config-data.cpp src/translation-service/httpserver.cpp) set_target_properties_plugin(${CMAKE_PROJECT_NAME} PROPERTIES OUTPUT_NAME ${_name}) diff --git a/README.md b/README.md index 87881a4..07cebbd 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Current Features: - Choice of CTranslate2 model file Roadmap: -- Translation directly on OBS text sources +- Translation directly on OBS text sources, e.g. with a filter Check out our other plugins: - [Background Removal](https://github.com/royshil/obs-backgroundremoval) removes background from webcam without a green screen. @@ -34,6 +34,12 @@ Check out our other plugins: ## Download Check out the [latest releases](https://github.com/obs-ai/obs-polyglot/releases) for downloads and install instructions. +### Models +You need to download a CT2 model for the translation service to work. +Here are download links for models that are compatible with the plugin: +- https://forum.opennmt.net/t/nllb-200-with-ctranslate2/5090 NLLB-200 multilingual model (recommended) +- https://huggingface.co/models?sort=trending&search=ctranslate CTranslate2 models on HuggingFace + ## Building The plugin was built and tested on Mac OSX (Intel & Apple silicon), Windows and Linux. diff --git a/cmake/BuildCTranslate2.cmake b/cmake/BuildCTranslate2.cmake index dce5aa5..6ac33cb 100644 --- a/cmake/BuildCTranslate2.cmake +++ b/cmake/BuildCTranslate2.cmake @@ -3,68 +3,114 @@ include(ExternalProject) include(FetchContent) -# Build with OpenBLAS -set(OpenBLAS_URL "https://github.com/xianyi/OpenBLAS/releases/download/v0.3.24/OpenBLAS-0.3.24-x64.zip") -set(OpenBLAS_SHA256 "6335128ee7117ea2dd2f5f96f76dafc17256c85992637189a2d5f6da0c608163") -FetchContent_Declare( - openblas - URL ${OpenBLAS_URL} - URL_HASH SHA256=${OpenBLAS_SHA256}) -FetchContent_MakeAvailable(openblas) -set(OpenBLAS_DIR ${openblas_SOURCE_DIR}) -set(OPENBLAS_INCLUDE_DIR ${OpenBLAS_DIR}/include) +if(APPLE) -add_library(OpenBLAS STATIC IMPORTED) -set_target_properties(OpenBLAS PROPERTIES IMPORTED_LOCATION ${OpenBLAS_DIR}/lib/libopenblas.dll.a) -install(FILES ${OpenBLAS_DIR}/bin/libopenblas.dll DESTINATION "obs-plugins/64bit") + FetchContent_Declare( + ctranslate2_fetch + URL https://github.com/obs-ai/obs-ai-ctranslate2-dep/releases/download/1.0.0/libctranslate2-macos-Release-1.0.0.tar.gz + URL_HASH SHA256=8e55a6ed4fb17ac556ad0e020ddab619584e3ceb4c9497a816f819bd8fd36443) + FetchContent_MakeAvailable(ctranslate2_fetch) -set(CT2_VERSION "3.20.0") -set(CT2_URL "https://github.com/OpenNMT/CTranslate2.git") + add_library(ct2 INTERFACE) + target_link_libraries(ct2 INTERFACE "-framework Accelerate" ${ctranslate2_fetch_SOURCE_DIR}/lib/libctranslate2.a + ${ctranslate2_fetch_SOURCE_DIR}/lib/libcpu_features.a) + set_target_properties(ct2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${ctranslate2_fetch_SOURCE_DIR}/include) + target_compile_options(ct2 INTERFACE -Wno-shorten-64-to-32) -ExternalProject_Add( - ct2_build - DOWNLOAD_EXTRACT_TIMESTAMP true - GIT_REPOSITORY ${CT2_URL} - GIT_TAG v${CT2_VERSION} - GIT_PROGRESS 1 - BUILD_COMMAND ${CMAKE_COMMAND} --build --config ${CMAKE_BUILD_TYPE} - CMAKE_GENERATOR ${CMAKE_GENERATOR} - INSTALL_COMMAND ${CMAKE_COMMAND} --install --config ${CMAKE_BUILD_TYPE} - CMAKE_ARGS -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM} - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 - -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES_} - -DCMAKE_INSTALL_PREFIX= - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DBUILD_SHARED_LIBS=ON - -DWITH_CUDA=OFF - -DWITH_MKL=OFF - -DWITH_OPENBLAS=ON - -DOPENMP_RUNTIME=COMP - -DWITH_TESTS=OFF - -DWITH_EXAMPLES=OFF - -DWITH_TFLITE=OFF - -DWITH_TRT=OFF - -DWITH_PYTHON=OFF - -DWITH_SERVER=OFF - -DWITH_COVERAGE=OFF - -DWITH_PROFILING=OFF - -DBUILD_CLI=OFF - -DOPENBLAS_INCLUDE_DIR=${OPENBLAS_INCLUDE_DIR} - -DOPENBLAS_LIBRARY=${OpenBLAS_DIR}/lib/libopenblas.dll.a) -ExternalProject_Get_Property(ct2_build INSTALL_DIR) +else() + set(CT2_VERSION "3.20.0") + set(CT2_URL "https://github.com/OpenNMT/CTranslate2.git") -add_library(ct2::ct2 SHARED IMPORTED GLOBAL) -set_target_properties( - ct2::ct2 PROPERTIES IMPORTED_LOCATION - ${INSTALL_DIR}/bin/${CMAKE_SHARED_LIBRARY_PREFIX}ctranslate2${CMAKE_SHARED_LIBRARY_SUFFIX}) -set_target_properties( - ct2::ct2 PROPERTIES IMPORTED_IMPLIB - ${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}ctranslate2${CMAKE_STATIC_LIBRARY_SUFFIX}) + if(WIN32) + # Build with OpenBLAS -install(FILES ${INSTALL_DIR}/bin/${CMAKE_SHARED_LIBRARY_PREFIX}ctranslate2${CMAKE_SHARED_LIBRARY_SUFFIX} - DESTINATION "obs-plugins/64bit") + set(OpenBLAS_URL "https://github.com/xianyi/OpenBLAS/releases/download/v0.3.24/OpenBLAS-0.3.24-x64.zip") + set(OpenBLAS_SHA256 "6335128ee7117ea2dd2f5f96f76dafc17256c85992637189a2d5f6da0c608163") + FetchContent_Declare( + openblas_fetch + URL ${OpenBLAS_URL} + URL_HASH SHA256=${OpenBLAS_SHA256}) + FetchContent_MakeAvailable(openblas_fetch) + set(OpenBLAS_DIR ${openblas_fetch_SOURCE_DIR}) + set(OPENBLAS_INCLUDE_DIR ${OpenBLAS_DIR}/include) -add_library(ct2 INTERFACE) -add_dependencies(ct2 ct2_build) -target_link_libraries(ct2 INTERFACE ct2::ct2) -set_target_properties(ct2::ct2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) + add_library(openblas STATIC IMPORTED) + set_target_properties(openblas PROPERTIES IMPORTED_LOCATION ${OpenBLAS_DIR}/lib/libopenblas.dll.a) + install(FILES ${OpenBLAS_DIR}/bin/libopenblas.dll DESTINATION "obs-plugins/64bit") + + set(CT2_OPENBLAS_CMAKE_ARGS -DOPENBLAS_INCLUDE_DIR=${OPENBLAS_INCLUDE_DIR} + -DOPENBLAS_LIBRARY=${OpenBLAS_DIR}/lib/libopenblas.dll.a -DWITH_OPENBLAS=ON) + else() + set(CT2_OPENBLAS_CMAKE_ARGS -DWITH_OPENBLAS=OFF) + endif() + + if(UNIX) + if(APPLE) + set(CT2_CMAKE_PLATFORM_OPTIONS -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 -DBUILD_SHARED_LIBS=OFF -DWITH_ACCELERATE=ON + -DOPENMP_RUNTIME=NONE -DCMAKE_OSX_ARCHITECTURES=arm64) + else() + set(CT2_CMAKE_PLATFORM_OPTIONS -DBUILD_SHARED_LIBS=OFF -DOPENMP_RUNTIME=NONE -DCMAKE_POSITION_INDEPENDENT_CODE=ON) + endif() + set(CT2_LIB_INSTALL_LOCATION lib/${CMAKE_SHARED_LIBRARY_PREFIX}ctranslate2${CMAKE_STATIC_LIBRARY_SUFFIX}) + else() + set(CT2_CMAKE_PLATFORM_OPTIONS -DBUILD_SHARED_LIBS=ON -DOPENMP_RUNTIME=COMP) + set(CT2_LIB_INSTALL_LOCATION bin/${CMAKE_SHARED_LIBRARY_PREFIX}ctranslate2${CMAKE_SHARED_LIBRARY_SUFFIX}) + endif() + + ExternalProject_Add( + ct2_build + GIT_REPOSITORY ${CT2_URL} + GIT_TAG v${CT2_VERSION} + GIT_PROGRESS 1 + BUILD_COMMAND ${CMAKE_COMMAND} --build --config ${CMAKE_BUILD_TYPE} + CMAKE_GENERATOR ${CMAKE_GENERATOR} + INSTALL_COMMAND ${CMAKE_COMMAND} --install --config ${CMAKE_BUILD_TYPE} + BUILD_BYPRODUCTS /${CT2_LIB_INSTALL_LOCATION} + CMAKE_ARGS -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM} + -DCMAKE_INSTALL_PREFIX= + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DWITH_CUDA=OFF + -DWITH_MKL=OFF + -DWITH_TESTS=OFF + -DWITH_EXAMPLES=OFF + -DWITH_TFLITE=OFF + -DWITH_TRT=OFF + -DWITH_PYTHON=OFF + -DWITH_SERVER=OFF + -DWITH_COVERAGE=OFF + -DWITH_PROFILING=OFF + -DBUILD_CLI=OFF + ${CT2_OPENBLAS_CMAKE_ARGS} + ${CT2_CMAKE_PLATFORM_OPTIONS}) + ExternalProject_Get_Property(ct2_build INSTALL_DIR) + + if(UNIX) + # Get cpu_features from the CTranslate2 build - only for x86_64 builds if(APPLE) + # ExternalProject_Get_Property(ct2_build BINARY_DIR) add_library(ct2::cpu_features STATIC IMPORTED GLOBAL) + # set_target_properties( ct2::cpu_features PROPERTIES IMPORTED_LOCATION + # ${BINARY_DIR}/third_party/cpu_features/RelWithDebInfo/libcpu_features.a) endif() + + add_library(ct2::ct2 STATIC IMPORTED GLOBAL) + else() + add_library(ct2::ct2 SHARED IMPORTED GLOBAL) + set_target_properties( + ct2::ct2 PROPERTIES IMPORTED_IMPLIB + ${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}ctranslate2${CMAKE_STATIC_LIBRARY_SUFFIX}) + install(FILES ${INSTALL_DIR}/${CT2_LIB_INSTALL_LOCATION} DESTINATION "obs-plugins/64bit") + endif() + add_dependencies(ct2::ct2 ct2_build) + set_target_properties(ct2::ct2 PROPERTIES IMPORTED_LOCATION ${INSTALL_DIR}/${CT2_LIB_INSTALL_LOCATION}) + + add_library(ct2 INTERFACE) + if(APPLE) + target_link_libraries( + ct2 + INTERFACE + "-framework Accelerate /Users/roy_shilkrot/Downloads/obs-ai-ctranslate2-dep/CTranslate2-3.20.0/release/universal/RelWithDebInfo/lib/libctranslate2.a" + ) + else() + target_link_libraries(ct2 INTERFACE ct2::ct2) + endif() + set_target_properties(ct2::ct2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) + +endif() diff --git a/cmake/BuildCppHTTPLib.cmake b/cmake/BuildCppHTTPLib.cmake index 7bd3fc7..7c3cb6f 100644 --- a/cmake/BuildCppHTTPLib.cmake +++ b/cmake/BuildCppHTTPLib.cmake @@ -1,4 +1,3 @@ - set(CppHTTPLib_URL "https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.14.1.tar.gz") set(CppHTTPLib_HASH SHA256=2D4FB5544DA643E5D0A82585555D8B7502B4137EB321A4ABBB075E21D2F00E96) @@ -10,5 +9,5 @@ FetchContent_Declare( URL_HASH ${CppHTTPLib_HASH}) FetchContent_MakeAvailable(cpphttplib) -add_library(cpphttplib INTERFACE) +add_library(cpphttplib INTERFACE EXCLUDE_FROM_ALL) target_include_directories(cpphttplib INTERFACE ${cpphttplib_SOURCE_DIR}) diff --git a/cmake/BuildSentencepiece.cmake b/cmake/BuildSentencepiece.cmake index c16a700..761b809 100644 --- a/cmake/BuildSentencepiece.cmake +++ b/cmake/BuildSentencepiece.cmake @@ -1,35 +1,50 @@ # build sentencepiece from "https://github.com/google/sentencepiece.git" -include(ExternalProject) - -set(SP_URL - "https://github.com/google/sentencepiece.git" - CACHE STRING "URL of sentencepiece repository") - -ExternalProject_Add( - sentencepiece_build - DOWNLOAD_EXTRACT_TIMESTAMP true - GIT_REPOSITORY ${SP_URL} - GIT_TAG v0.1.99 - BUILD_COMMAND ${CMAKE_COMMAND} --build --config ${CMAKE_BUILD_TYPE} - CMAKE_GENERATOR ${CMAKE_GENERATOR} - INSTALL_COMMAND ${CMAKE_COMMAND} --install --config ${CMAKE_BUILD_TYPE} - CMAKE_ARGS -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM} -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 - -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES_} -DCMAKE_INSTALL_PREFIX= - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}) -ExternalProject_Get_Property(sentencepiece_build INSTALL_DIR) - -add_library(libsentencepiece SHARED IMPORTED GLOBAL) -set_target_properties( - libsentencepiece - PROPERTIES IMPORTED_LOCATION - ${INSTALL_DIR}/bin/${CMAKE_SHARED_LIBRARY_PREFIX}sentencepiece${CMAKE_SHARED_LIBRARY_SUFFIX}) -set_target_properties( - libsentencepiece - PROPERTIES IMPORTED_IMPLIB - ${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}sentencepiece${CMAKE_STATIC_LIBRARY_SUFFIX}) - -add_library(sentencepiece INTERFACE) -add_dependencies(sentencepiece sentencepiece_build) -target_link_libraries(sentencepiece INTERFACE libsentencepiece) -set_target_properties(libsentencepiece PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) +if(APPLE) + + include(FetchContent) + + FetchContent_Declare( + sentencepiece_fetch + URL https://github.com/obs-ai/obs-ai-ctranslate2-dep/releases/download/1.0.0/libsentencepiece-macos-Release-1.0.0.tar.gz + URL_HASH SHA256=67f58a8e97c14db1bc69becd507ffe69326948f371bf874fe919157d7d65aff4) + FetchContent_MakeAvailable(sentencepiece_fetch) + add_library(sentencepiece INTERFACE) + target_link_libraries(sentencepiece INTERFACE ${sentencepiece_fetch_SOURCE_DIR}/lib/libsentencepiece.a) + set_target_properties(sentencepiece PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + ${sentencepiece_fetch_SOURCE_DIR}/include) + +else() + + set(SP_URL + "https://github.com/google/sentencepiece.git" + CACHE STRING "URL of sentencepiece repository") + + set(SP_CMAKE_OPTIONS -DSPM_ENABLE_SHARED=OFF) + set(SENTENCEPIECE_INSTALL_LIB_LOCATION lib/${CMAKE_STATIC_LIBRARY_PREFIX}sentencepiece${CMAKE_STATIC_LIBRARY_SUFFIX}) + + include(ExternalProject) + + ExternalProject_Add( + sentencepiece_build + GIT_REPOSITORY ${SP_URL} + GIT_TAG v0.1.99 + BUILD_COMMAND ${CMAKE_COMMAND} --build --config ${CMAKE_BUILD_TYPE} + CMAKE_GENERATOR ${CMAKE_GENERATOR} + INSTALL_COMMAND ${CMAKE_COMMAND} --install --config ${CMAKE_BUILD_TYPE} + BUILD_BYPRODUCTS /${SENTENCEPIECE_INSTALL_LIB_LOCATION} + CMAKE_ARGS -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM} -DCMAKE_INSTALL_PREFIX= + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} ${SP_CMAKE_OPTIONS}) + ExternalProject_Get_Property(sentencepiece_build INSTALL_DIR) + + add_library(libsentencepiece STATIC IMPORTED GLOBAL) + add_dependencies(libsentencepiece sentencepiece_build) + set_target_properties(libsentencepiece PROPERTIES IMPORTED_LOCATION + ${INSTALL_DIR}/${SENTENCEPIECE_INSTALL_LIB_LOCATION}) + + add_library(sentencepiece INTERFACE) + add_dependencies(sentencepiece libsentencepiece) + target_link_libraries(sentencepiece INTERFACE libsentencepiece) + target_include_directories(sentencepiece INTERFACE ${INSTALL_DIR}/include) + +endif() diff --git a/cmake/common/buildspec_common.cmake b/cmake/common/buildspec_common.cmake index b2c2414..39cd7e9 100644 --- a/cmake/common/buildspec_common.cmake +++ b/cmake/common/buildspec_common.cmake @@ -68,11 +68,19 @@ function(_setup_obs_studio) set(_cmake_version "2.0.0") elseif(OS_MACOS) set(_cmake_generator "Xcode") - set(_cmake_arch "-DCMAKE_OSX_ARCHITECTURES:STRING='arm64;x86_64'") + # TODO: enable arm64; currently fails + set(_cmake_arch "-DCMAKE_OSX_ARCHITECTURES:STRING='x86_64;arm64'") set(_cmake_extra "-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}") set(_cmake_version "3.0.0") endif() + message(STATUS "Patch libobs") + execute_process( + COMMAND patch --forward "libobs/CMakeLists.txt" "${CMAKE_CURRENT_SOURCE_DIR}/patch_libobs.diff" + RESULT_VARIABLE _process_result + WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}") + message(STATUS "Patch - done") + message(STATUS "Configure ${label} (${arch})") execute_process( COMMAND diff --git a/cmake/macos/compilerconfig.cmake b/cmake/macos/compilerconfig.cmake index c40a532..bab27cf 100644 --- a/cmake/macos/compilerconfig.cmake +++ b/cmake/macos/compilerconfig.cmake @@ -42,7 +42,7 @@ else() # Enable color diagnostics for AppleClang set(CMAKE_COLOR_DIAGNOSTICS ON) # Set universal architectures via CMake flag for non-Xcode generators - set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") + set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64") # Enable compiler and build tracing (requires Ninja generator) if(ENABLE_COMPILER_TRACE AND CMAKE_GENERATOR STREQUAL "Ninja") diff --git a/patch_libobs.diff b/patch_libobs.diff new file mode 100644 index 0000000..efc8e93 --- /dev/null +++ b/patch_libobs.diff @@ -0,0 +1,12 @@ +diff --git a/libobs/CMakeLists.txt b/libobs/CMakeLists.txt +index d2e2671..d7797c6 100644 +--- a/libobs/CMakeLists.txt ++++ b/libobs/CMakeLists.txt +@@ -287,6 +287,7 @@ set(public_headers + util/base.h + util/bmem.h + util/c99defs.h ++ util/config-file.h + util/darray.h + util/profiler.h + util/sse-intrin.h diff --git a/src/plugin-main.c b/src/plugin-main.c index f2a94d7..50e5f21 100644 --- a/src/plugin-main.c +++ b/src/plugin-main.c @@ -27,26 +27,27 @@ OBS_MODULE_USE_DEFAULT_LOCALE(PLUGIN_NAME, "en-US") bool obs_module_load(void) { - obs_log(LOG_INFO, "plugin loaded successfully (version %s)", - PLUGIN_VERSION); + obs_log(LOG_INFO, "plugin loaded successfully (version %s)", PLUGIN_VERSION); - // load plugin settings from config + resetContext(); + + // load plugin settings from config if (loadConfig() == OBS_POLYGLOT_CONFIG_SUCCESS) { obs_log(LOG_INFO, "Loaded config from config file"); } else { obs_log(LOG_INFO, "Failed to load config from config file"); } - resetContext(); - // build the translation context - if (build_translation_context() != OBS_POLYGLOT_TRANSLATION_INIT_SUCCESS) { - obs_log(LOG_ERROR, "Failed to build translation context"); - } + // build the translation context + if (build_translation_context() != OBS_POLYGLOT_TRANSLATION_INIT_SUCCESS) { + obs_log(LOG_ERROR, "Failed to build translation context"); + } - registerDock(); + registerDock(); return true; } void obs_module_unload(void) { + freeContext(); obs_log(LOG_INFO, "plugin unloaded"); } diff --git a/src/translation-service/httpserver.cpp b/src/translation-service/httpserver.cpp index 0d984cc..34d3454 100644 --- a/src/translation-service/httpserver.cpp +++ b/src/translation-service/httpserver.cpp @@ -25,6 +25,7 @@ void start_http_server() global_context.svr->Post("/echo", [](const httplib::Request &req, httplib::Response &res, const httplib::ContentReader &content_reader) { + UNUSED_PARAMETER(req); obs_log(LOG_DEBUG, "Received request on /echo"); std::string body; content_reader([&](const char *data, size_t data_length) { @@ -37,6 +38,7 @@ void start_http_server() global_context.svr->Post( "/translate", [](const httplib::Request &req, httplib::Response &res, const httplib::ContentReader &content_reader) { + UNUSED_PARAMETER(req); obs_log(LOG_DEBUG, "Received request on /translate"); std::string body; content_reader([&](const char *data, size_t data_length) { diff --git a/src/translation-service/translation.cpp b/src/translation-service/translation.cpp index 8ac339e..d9eaffb 100644 --- a/src/translation-service/translation.cpp +++ b/src/translation-service/translation.cpp @@ -3,9 +3,8 @@ #include "utils/config-data.h" #include -#include -#include #include +#include #include int build_translation_context() @@ -17,6 +16,7 @@ int build_translation_context() const auto status = global_context.processor->Load(global_config.local_spm_path); if (!status.ok()) { obs_log(LOG_ERROR, status.ToString().c_str()); + global_context.error_callback("Failed to load SPM. " + status.ToString()); return OBS_POLYGLOT_TRANSLATION_INIT_FAIL; } @@ -45,8 +45,10 @@ int build_translation_context() global_context.options->return_scores = false; } catch (std::exception &e) { obs_log(LOG_ERROR, "Error: %s", e.what()); + global_context.error_callback("Failed to load CT2 model. " + std::string(e.what())); return OBS_POLYGLOT_TRANSLATION_INIT_FAIL; } + global_context.error_callback(""); // Clear any errors return OBS_POLYGLOT_TRANSLATION_INIT_SUCCESS; } diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index b822e1f..67e82bd 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -1,5 +1,3 @@ - -target_sources(${CMAKE_PROJECT_NAME} PRIVATE - ${CMAKE_CURRENT_LIST_DIR}/registerDock.cpp - ${CMAKE_CURRENT_LIST_DIR}/settingsdialog.cpp - ${CMAKE_CURRENT_LIST_DIR}/translatedockwidget.cpp) +target_sources( + ${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/registerDock.cpp ${CMAKE_CURRENT_LIST_DIR}/settingsdialog.cpp + ${CMAKE_CURRENT_LIST_DIR}/translatedockwidget.cpp) diff --git a/src/ui/registerDock.cpp b/src/ui/registerDock.cpp index b7430e8..f94f977 100644 --- a/src/ui/registerDock.cpp +++ b/src/ui/registerDock.cpp @@ -1,6 +1,7 @@ #include "registerDock.h" #include "translatedockwidget.h" #include "plugin-support.h" +#include "utils/config-data.h" #include #include @@ -17,6 +18,11 @@ void registerDock() QMainWindow *parent = (QMainWindow *)obs_frontend_get_main_window(); // Create the dock TranslateDockWidget *dock = new TranslateDockWidget((QWidget *)parent); + // set the error callback on the global conetxt + global_context.error_callback = [=](const std::string &error_message) { + global_context.error_message = error_message; + dock->updateErrorLabel(error_message); + }; // Register the dock obs_frontend_add_dock(dock); diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 59cde9b..fb16817 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -2,6 +2,7 @@ #include "ui_settingsdialog.h" #include "utils/config-data.h" #include "plugin-support.h" +#include "translation-service/translation.h" #include #include @@ -63,6 +64,14 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::Se // serialize to json and save to the OBS module settings if (saveConfig(false) == OBS_POLYGLOT_CONFIG_SUCCESS) { obs_log(LOG_INFO, "Saved settings"); + + // update the plugin + freeContext(); + if (build_translation_context() == OBS_POLYGLOT_TRANSLATION_INIT_SUCCESS) { + obs_log(LOG_INFO, "Translation context updated"); + } else { + obs_log(LOG_ERROR, "Failed to update translation context"); + } } else { obs_log(LOG_ERROR, "Failed to save settings"); } diff --git a/src/ui/settingsdialog.ui b/src/ui/settingsdialog.ui index 5178adf..7abd4fb 100644 --- a/src/ui/settingsdialog.ui +++ b/src/ui/settingsdialog.ui @@ -35,12 +35,18 @@ Model Files + + QFormLayout::ExpandingFieldsGrow + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + 3 + @@ -51,6 +57,21 @@ + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -80,6 +101,21 @@ + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -102,6 +138,9 @@ HTTP Server + + QFormLayout::ExpandingFieldsGrow + @@ -125,6 +164,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -138,38 +190,5 @@ - - - buttonBox - accepted() - PolyglotSettingsDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - PolyglotSettingsDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - + diff --git a/src/ui/translatedockwidget.cpp b/src/ui/translatedockwidget.cpp index 20056fc..4bc3eda 100644 --- a/src/ui/translatedockwidget.cpp +++ b/src/ui/translatedockwidget.cpp @@ -2,12 +2,16 @@ #include "ui_translatedockwidget.h" #include "settingsdialog.h" #include "translation-service/httpserver.h" +#include "utils/config-data.h" TranslateDockWidget::TranslateDockWidget(QWidget *parent) : QDockWidget(parent), ui(new Ui::TranslateDockWidget) { ui->setupUi(this); + ui->errorLabel->hide(); + this->updateErrorLabel(global_context.error_message); + // connect the settings button to the settings dialog connect(ui->settings, &QPushButton::clicked, this, &TranslateDockWidget::openSettingsDialog); @@ -34,3 +38,19 @@ void TranslateDockWidget::openSettingsDialog() // show the settings dialog settingsDialog->show(); } + +void TranslateDockWidget::updateErrorLabel(const std::string &error_message) +{ + // if there is an error message, show the error label + if (!error_message.empty()) { + // write the error text in red + ui->errorLabel->setText(QString("%1") + .arg(QString::fromStdString(error_message))); + // show the error label + ui->errorLabel->show(); + // disable the start/stop http server button + ui->startStopHTTPServer->setEnabled(false); + } else { + ui->errorLabel->hide(); + } +} diff --git a/src/ui/translatedockwidget.h b/src/ui/translatedockwidget.h index b790f15..9550b5d 100644 --- a/src/ui/translatedockwidget.h +++ b/src/ui/translatedockwidget.h @@ -13,6 +13,7 @@ class TranslateDockWidget : public QDockWidget { public: explicit TranslateDockWidget(QWidget *parent = nullptr); ~TranslateDockWidget(); + void updateErrorLabel(const std::string &error_message); private slots: void openSettingsDialog(); diff --git a/src/ui/translatedockwidget.ui b/src/ui/translatedockwidget.ui index 1a89431..f1e591f 100644 --- a/src/ui/translatedockwidget.ui +++ b/src/ui/translatedockwidget.ui @@ -32,6 +32,29 @@ + + + + Error Label + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + diff --git a/src/utils/config-data.cpp b/src/utils/config-data.cpp index 783d00b..67e6401 100644 --- a/src/utils/config-data.cpp +++ b/src/utils/config-data.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include polyglot_config_data global_config; polyglot_global_context global_context; @@ -141,4 +144,31 @@ void resetContext() global_context.translator = nullptr; global_context.processor = nullptr; global_context.svr = nullptr; + global_context.error_callback = [](const std::string &error_message) { + global_context.error_message = error_message; + obs_log(LOG_ERROR, "Error (callback): %s", error_message.c_str()); + }; + global_context.tokenizer = [](const std::string &) { return std::vector(); }; + global_context.detokenizer = [](const std::vector &) { return std::string(); }; +} + +void freeContext() +{ + if (global_context.options != nullptr) { + delete global_context.options; + global_context.options = nullptr; + } + if (global_context.translator != nullptr) { + delete global_context.translator; + global_context.translator = nullptr; + } + if (global_context.processor != nullptr) { + delete global_context.processor; + global_context.processor = nullptr; + } + if (global_context.svr != nullptr) { + delete global_context.svr; + global_context.svr = nullptr; + } + resetContext(); } diff --git a/src/utils/config-data.h b/src/utils/config-data.h index 8db37d8..5b4f90d 100644 --- a/src/utils/config-data.h +++ b/src/utils/config-data.h @@ -53,6 +53,8 @@ struct polyglot_global_context { std::function(const std::string &)> tokenizer; // detokenizer std::function &)> detokenizer; + // error callback + std::function error_callback; // http server httplib::Server *svr; }; @@ -70,6 +72,7 @@ extern "C" { #endif void resetContext(); +void freeContext(); int saveConfig(bool create_if_not_exist); int loadConfig();