Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update version to 0.3.9 in README.md and buildspec.json; add availabl… #184

Merged
merged 4 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-project.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ jobs:
id: ccache-cache
with:
path: ${{ github.workspace }}/.ccache
key: ${{ runner.os }}-ccache-${{ needs.check-event.outputs.config }}
key: ${{ runner.os }}-ccache-${{ needs.check-event.outputs.config }}-${{ matrix.architecture }}
restore-keys: |
${{ runner.os }}-ccache-
${{ runner.os }}-ccache-${{ matrix.architecture }}-

- name: Set Up Codesigning 🔑
uses: ./.github/actions/setup-macos-codesigning
Expand Down
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
[![Discord](https://img.shields.io/discord/1200229425141252116)](https://discord.gg/KbjGU2vvUz)
<br/>
Download:</br>
<a href="https://github.com/locaal-ai/obs-localvocal/releases/download/0.3.8/obs-localvocal-0.3.8-windows-x64-cuda-Installer.exe"><img src="https://img.shields.io/badge/Windows-0078D6?style=for-the-badge&logo=windows&logoColor=white" /></a>
<a href="https://github.com/locaal-ai/obs-localvocal/releases/download/0.3.8/obs-localvocal-0.3.8-macos-x86_64.pkg"><img src="https://img.shields.io/badge/mac%20Intel-000000?style=for-the-badge" /></a>
<a href="https://github.com/locaal-ai/obs-localvocal/releases/download/0.3.8/obs-localvocal-0.3.8-macos-arm64.pkg"><img src="https://img.shields.io/badge/mac%20M1/2/3-0a0a0a?style=for-the-badge&"/></a>
<a href="https://github.com/locaal-ai/obs-localvocal/releases/download/0.3.8/obs-localvocal-0.3.8-x86_64-linux-gnu.deb"><img src="https://img.shields.io/badge/Linux-FCC624?style=for-the-badge&logo=linux&logoColor=black"/></a>
<a href="https://github.com/locaal-ai/obs-localvocal/releases/download/0.3.9/obs-localvocal-0.3.9-windows-x64-cuda-Installer.exe"><img src="https://img.shields.io/badge/Windows-0078D6?style=for-the-badge&logo=windows&logoColor=white" /></a>
<a href="https://github.com/locaal-ai/obs-localvocal/releases/download/0.3.9/obs-localvocal-0.3.9-macos-x86_64.pkg"><img src="https://img.shields.io/badge/mac%20Intel-000000?style=for-the-badge" /></a>
<a href="https://github.com/locaal-ai/obs-localvocal/releases/download/0.3.9/obs-localvocal-0.3.9-macos-arm64.pkg"><img src="https://img.shields.io/badge/mac%20M1/2/3-0a0a0a?style=for-the-badge&"/></a>
<a href="https://github.com/locaal-ai/obs-localvocal/releases/download/0.3.9/obs-localvocal-0.3.9-x86_64-linux-gnu.deb"><img src="https://img.shields.io/badge/Linux-FCC624?style=for-the-badge&logo=linux&logoColor=black"/></a>


</div>
Expand Down Expand Up @@ -85,6 +85,20 @@ Check out our other plugins:
## Download
Check out the [latest releases](https://github.com/locaal-ai/obs-localvocal/releases) for downloads and install instructions.

### Available Versions

LocalVocal is available in multiple versions to cater to different hardware configurations and operating systems. Below is a brief explanation of the different versions you can download:

- **Windows CUDA**: This version is optimized for systems with NVIDIA GPUs and utilizes CUDA for accelerated performance. Make sure you have the latest NVidia GPU drivers installed.
- **Windows CPU**: This version is designed for systems without dedicated GPUs, running solely on the CPU.
- **Windows HIPBLAS**: This version utilizes the HIP framework from AMD that accelerates computation on AMD GPUs. (⚠️ Experimental ⚠️ Please provide feedback)
- **Windows Vulkan**: This version uses Vulkan for GPU-based acceleration across many vendors like NVidia, AMD, and Intel. (⚠️ Experimental ⚠️ Please provide feedback)
- **macOS Intel (x86_64)**: This version is for Mac computers with Intel processors.
- **macOS Apple Silicon (arm64)**: This version is optimized for Mac computers with Apple Silicon (M1, M2, etc.) processors.
- **Linux x86_64**: This version is for Linux systems with x86_64 architecture.

Make sure to download the version that matches your system's hardware and operating system for the best performance.

### Models
The plugin ships with the Tiny.en model, and will autonomously download other Whisper models through a dropdown.
There's also an option to select an external GGML Whisper model file if you have it on disk.
Expand Down
2 changes: 1 addition & 1 deletion buildspec.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
},
"name": "obs-localvocal",
"displayName": "OBS Localvocal",
"version": "0.3.8",
"version": "0.3.9",
"author": "Roy Shilkrot",
"website": "https://github.com/locaal-ai/obs-localvocal",
"email": "[email protected]",
Expand Down
8 changes: 8 additions & 0 deletions cmake/BuildCTranslate2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ elseif(WIN32)
file(GLOB CT2_DLLS ${ctranslate2_fetch_SOURCE_DIR}/bin/*.dll)
install(FILES ${CT2_DLLS} DESTINATION "obs-plugins/64bit")
else()
# Enable ccache if available
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
message(STATUS "Found ccache: ${CCACHE_PROGRAM}")
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
endif()

# build cpu_features from source
set(CPU_FEATURES_VERSION "0.9.0")
set(CPU_FEATURES_URL "https://github.com/google/cpu_features.git")
Expand Down
8 changes: 8 additions & 0 deletions cmake/BuildSentencepiece.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ elseif(WIN32)

else()

# Enable ccache if available
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
message(STATUS "Found ccache: ${CCACHE_PROGRAM}")
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
endif()

set(SP_URL
"https://github.com/google/sentencepiece.git"
CACHE STRING "URL of sentencepiece repository")
Expand Down
8 changes: 8 additions & 0 deletions cmake/BuildWhispercpp.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ elseif(WIN32)
file(GLOB WHISPER_DLLS ${whispercpp_fetch_SOURCE_DIR}/bin/*.dll)
install(FILES ${WHISPER_DLLS} DESTINATION "obs-plugins/64bit")
else()
# Enable ccache if available
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
message(STATUS "Found ccache: ${CCACHE_PROGRAM}")
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
endif()

if(${CMAKE_BUILD_TYPE} STREQUAL Release OR ${CMAKE_BUILD_TYPE} STREQUAL RelWithDebInfo)
set(Whispercpp_BUILD_TYPE Release)
else()
Expand Down
4 changes: 4 additions & 0 deletions data/locale/en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,8 @@ Deepl-Translate="Deepl"
Bing-Translate="Bing Translate"
OpenAI-Translate="OpenAI"
Claude-Translate="Claude"
API-Translate="Custom API"
translate_cloud_deepl_free="Use Deepl Free API Endpoint"
translate_cloud_endpoint="API Endpoint"
translate_cloud_body="API Body"
translate_cloud_response_json_path="Response JSON Path"
13 changes: 4 additions & 9 deletions src/transcription-filter-callbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,22 +91,17 @@ void send_sentence_to_cloud_translation_async(const std::string &sentence,
gf->last_text_for_cloud_translation = sentence;
if (gf->translate_cloud && !sentence.empty()) {
obs_log(gf->log_level, "Translating text with cloud provider %s. %s -> %s",
gf->translate_cloud_provider.c_str(), source_language.c_str(),
gf->translate_cloud_config.provider.c_str(),
source_language.c_str(),
gf->translate_cloud_target_language.c_str());
std::string translated_text;
if (sentence == last_text) {
// do not translate the same sentence twice
callback(gf->last_text_cloud_translation);
return;
}
CloudTranslatorConfig config;
config.provider = gf->translate_cloud_provider;
config.access_key = gf->translate_cloud_api_key;
config.secret_key = gf->translate_cloud_secret_key;
config.free = gf->translate_cloud_deepl_free;
config.region = gf->translate_cloud_region;

translated_text = translate_cloud(config, sentence,

translated_text = translate_cloud(gf->translate_cloud_config, sentence,
gf->translate_cloud_target_language,
source_language);
if (!translated_text.empty()) {
Expand Down
7 changes: 2 additions & 5 deletions src/transcription-filter-data.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "whisper-utils/silero-vad-onnx.h"
#include "whisper-utils/whisper-processing.h"
#include "whisper-utils/token-buffer-thread.h"
#include "translation/cloud-translation/translation-cloud.h"

#define MAX_PREPROC_CHANNELS 10

Expand Down Expand Up @@ -92,16 +93,12 @@ struct transcription_filter_data {

// Cloud translation options
bool translate_cloud = false;
std::string translate_cloud_provider;
CloudTranslatorConfig translate_cloud_config;
std::string translate_cloud_target_language;
std::string translate_cloud_output;
std::string translate_cloud_api_key;
std::string translate_cloud_secret_key;
bool translate_cloud_only_full_sentences = true;
std::string last_text_for_cloud_translation;
std::string last_text_cloud_translation;
bool translate_cloud_deepl_free;
std::string translate_cloud_region;

// Transcription context sentences
int n_context_sentences;
Expand Down
38 changes: 34 additions & 4 deletions src/transcription-filter-properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ bool translation_cloud_provider_selection_callback(obs_properties_t *props, obs_
{
UNUSED_PARAMETER(p);
const char *provider = obs_data_get_string(s, "translate_cloud_provider");
// show the access key for all except the custom provider
obs_property_set_visible(obs_properties_get(props, "translate_cloud_api_key"),
strcmp(provider, "api") != 0);
obs_property_set_visible(obs_properties_get(props, "translate_cloud_deepl_free"),
strcmp(provider, "deepl") == 0);
// show the secret key input for the papago provider only
Expand All @@ -58,6 +61,14 @@ bool translation_cloud_provider_selection_callback(obs_properties_t *props, obs_
// show the region input for the azure provider only
obs_property_set_visible(obs_properties_get(props, "translate_cloud_region"),
strcmp(provider, "azure") == 0);
// show the endpoint and body input for the custom provider only
obs_property_set_visible(obs_properties_get(props, "translate_cloud_endpoint"),
strcmp(provider, "api") == 0);
obs_property_set_visible(obs_properties_get(props, "translate_cloud_body"),
strcmp(provider, "api") == 0);
// show the response json path input for the custom provider only
obs_property_set_visible(obs_properties_get(props, "translate_cloud_response_json_path"),
strcmp(provider, "api") == 0);
return true;
}

Expand All @@ -67,10 +78,12 @@ bool translation_cloud_options_callback(obs_properties_t *props, obs_property_t
UNUSED_PARAMETER(property);
// Show/Hide the cloud translation group options
const bool translate_enabled = obs_data_get_bool(settings, "translate_cloud");
for (const auto &prop : {"translate_cloud_provider", "translate_cloud_target_language",
"translate_cloud_output", "translate_cloud_api_key",
"translate_cloud_only_full_sentences",
"translate_cloud_secret_key", "translate_cloud_deepl_free"}) {
for (const auto &prop :
{"translate_cloud_provider", "translate_cloud_target_language",
"translate_cloud_output", "translate_cloud_api_key",
"translate_cloud_only_full_sentences", "translate_cloud_secret_key",
"translate_cloud_deepl_free", "translate_cloud_region", "translate_cloud_endpoint",
"translate_cloud_body", "translate_cloud_response_json_path"}) {
obs_property_set_visible(obs_properties_get(props, prop), translate_enabled);
}
if (translate_enabled) {
Expand Down Expand Up @@ -259,6 +272,7 @@ void add_translation_cloud_group_properties(obs_properties_t *ppts)
"openai");
obs_property_list_add_string(prop_translate_cloud_provider, MT_("Claude-Translate"),
"claude");
obs_property_list_add_string(prop_translate_cloud_provider, MT_("API-Translate"), "api");

// add callback to show/hide the free API option for deepl
obs_property_set_modified_callback(prop_translate_cloud_provider,
Expand Down Expand Up @@ -298,6 +312,16 @@ void add_translation_cloud_group_properties(obs_properties_t *ppts)
// add translate_cloud_region for azure
obs_properties_add_text(translation_cloud_group, "translate_cloud_region",
MT_("translate_cloud_region"), OBS_TEXT_DEFAULT);

// add input for API endpoint
obs_properties_add_text(translation_cloud_group, "translate_cloud_endpoint",
MT_("translate_cloud_endpoint"), OBS_TEXT_DEFAULT);
// add input for API body
obs_properties_add_text(translation_cloud_group, "translate_cloud_body",
MT_("translate_cloud_body"), OBS_TEXT_MULTILINE);
// add input for json response path
obs_properties_add_text(translation_cloud_group, "translate_cloud_response_json_path",
MT_("translate_cloud_response_json_path"), OBS_TEXT_DEFAULT);
}

void add_translation_group_properties(obs_properties_t *ppts)
Expand Down Expand Up @@ -667,6 +691,12 @@ void transcription_filter_defaults(obs_data_t *s)
obs_data_set_default_string(s, "translate_cloud_secret_key", "");
obs_data_set_default_bool(s, "translate_cloud_deepl_free", true);
obs_data_set_default_string(s, "translate_cloud_region", "eastus");
obs_data_set_default_string(s, "translate_cloud_endpoint",
"http://localhost:5000/translate");
obs_data_set_default_string(
s, "translate_cloud_body",
"{\n\t\"text\":\"{{sentence}}\",\n\t\"target\":\"{{target_language}}\"\n}");
obs_data_set_default_string(s, "translate_cloud_response_json_path", "translations.0.text");

// Whisper parameters
apply_whisper_params_defaults_on_settings(s);
Expand Down
15 changes: 10 additions & 5 deletions src/transcription-filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,16 +333,21 @@ void transcription_filter_update(void *data, obs_data_t *s)
}

gf->translate_cloud = obs_data_get_bool(s, "translate_cloud");
gf->translate_cloud_provider = obs_data_get_string(s, "translate_cloud_provider");
gf->translate_cloud_config.provider = obs_data_get_string(s, "translate_cloud_provider");
gf->translate_cloud_target_language =
obs_data_get_string(s, "translate_cloud_target_language");
gf->translate_cloud_output = obs_data_get_string(s, "translate_cloud_output");
gf->translate_cloud_only_full_sentences =
obs_data_get_bool(s, "translate_cloud_only_full_sentences");
gf->translate_cloud_api_key = obs_data_get_string(s, "translate_cloud_api_key");
gf->translate_cloud_secret_key = obs_data_get_string(s, "translate_cloud_secret_key");
gf->translate_cloud_deepl_free = obs_data_get_bool(s, "translate_cloud_deepl_free");
gf->translate_cloud_region = obs_data_get_string(s, "translate_cloud_region");
gf->translate_cloud_config.access_key = obs_data_get_string(s, "translate_cloud_api_key");
gf->translate_cloud_config.secret_key =
obs_data_get_string(s, "translate_cloud_secret_key");
gf->translate_cloud_config.free = obs_data_get_bool(s, "translate_cloud_deepl_free");
gf->translate_cloud_config.region = obs_data_get_string(s, "translate_cloud_region");
gf->translate_cloud_config.endpoint = obs_data_get_string(s, "translate_cloud_endpoint");
gf->translate_cloud_config.body = obs_data_get_string(s, "translate_cloud_body");
gf->translate_cloud_config.response_json_path =
obs_data_get_string(s, "translate_cloud_response_json_path");

obs_log(gf->log_level, "update text source");
// update the text source
Expand Down
1 change: 1 addition & 0 deletions src/translation/cloud-translation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ target_sources(
${CMAKE_SOURCE_DIR}/src/translation/cloud-translation/azure.cpp
${CMAKE_SOURCE_DIR}/src/translation/cloud-translation/claude.cpp
${CMAKE_SOURCE_DIR}/src/translation/cloud-translation/curl-helper.cpp
${CMAKE_SOURCE_DIR}/src/translation/cloud-translation/custom-api.cpp
${CMAKE_SOURCE_DIR}/src/translation/cloud-translation/deepl.cpp
${CMAKE_SOURCE_DIR}/src/translation/cloud-translation/google-cloud.cpp
${CMAKE_SOURCE_DIR}/src/translation/cloud-translation/openai.cpp
Expand Down
112 changes: 112 additions & 0 deletions src/translation/cloud-translation/custom-api.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#include "custom-api.h"
#include "curl-helper.h"
#include <nlohmann/json.hpp>
#include <sstream>
#include <regex>
#include <stdexcept>

using json = nlohmann::json;

CustomApiTranslator::CustomApiTranslator(const std::string &endpoint,
const std::string &body_template,
const std::string &response_json_path)
: endpoint_(endpoint),
body_template_(body_template),
response_json_path_(response_json_path),
curl_helper_(std::make_unique<CurlHelper>())
{
}

CustomApiTranslator::~CustomApiTranslator() = default;

std::string CustomApiTranslator::translate(const std::string &text, const std::string &target_lang,
const std::string &source_lang)
{
// first encode text to JSON compatible string
nlohmann::json tmp = text;
std::string textStr = tmp.dump();
// remove '"' from the beginning and end of the string
textStr = textStr.substr(1, textStr.size() - 2);
// then replace the placeholders in the body template
std::unordered_map<std::string, std::string> values = {
{"\\{\\{sentence\\}\\}", textStr},
{"\\{\\{target_lang\\}\\}", target_lang},
{"\\{\\{source_lang\\}\\}", source_lang}};

std::string body = replacePlaceholders(body_template_, values);
std::string response;

std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> curl(curl_easy_init(),
curl_easy_cleanup);

if (!curl) {
throw std::runtime_error("Failed to initialize CURL session");
}

try {
// Set up curl options
curl_easy_setopt(curl.get(), CURLOPT_URL, endpoint_.c_str());
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, CurlHelper::WriteCallback);
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, 2L);
curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, 30L);

// Set up POST request
curl_easy_setopt(curl.get(), CURLOPT_POST, 1L);
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, body.c_str());

// Set up headers
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, headers);

// Perform request
CURLcode res = curl_easy_perform(curl.get());

// Clean up headers
curl_slist_free_all(headers);

if (res != CURLE_OK) {
throw TranslationError(std::string("CURL request failed: ") +
curl_easy_strerror(res));
}

return parseResponse(response);

} catch (const std::exception &e) {
throw TranslationError(std::string("JSON parsing error: ") + e.what());
}
}

std::string CustomApiTranslator::replacePlaceholders(
const std::string &template_str,
const std::unordered_map<std::string, std::string> &values) const
{
std::string result = template_str;
for (const auto &pair : values) {
try {
std::regex placeholder(pair.first);
result = std::regex_replace(result, placeholder, pair.second);
} catch (const std::regex_error &e) {
// Handle regex error
throw TranslationError(std::string("Regex error: ") + e.what());
}
}
return result;
}

std::string CustomApiTranslator::parseResponse(const std::string &response_str)
{
try {
// parse the JSON response
json response = json::parse(response_str);

// extract the translation from the JSON response
std::string response_out = response[response_json_path_];

return response_out;
} catch (const json::exception &e) {
throw TranslationError(std::string("JSON parsing error: ") + e.what());
}
}
Loading
Loading