diff --git a/public/scripts/extensions/translate/index.js b/public/scripts/extensions/translate/index.js index bb8b1ddb7..740cc622a 100644 --- a/public/scripts/extensions/translate/index.js +++ b/public/scripts/extensions/translate/index.js @@ -135,12 +135,15 @@ const languageCodes = { 'Zulu': 'zu', }; -const KEY_REQUIRED = ['deepl']; +const KEY_REQUIRED = ['deepl','libre']; +const LOCAL_URL = ['libre']; -function showKeyButton() { +function showKeysButton() { const providerRequiresKey = KEY_REQUIRED.includes(extension_settings.translate.provider); + const providerOptionalUrl = LOCAL_URL.includes(extension_settings.translate.provider); $("#translate_key_button").toggle(providerRequiresKey); $("#translate_key_button").toggleClass('success', Boolean(secret_state[extension_settings.translate.provider])); + $("#translate_url_button").toggle(providerOptionalUrl); } function loadSettings() { @@ -153,7 +156,7 @@ function loadSettings() { $(`#translation_provider option[value="${extension_settings.translate.provider}"]`).attr('selected', true); $(`#translation_target_language option[value="${extension_settings.translate.target_language}"]`).attr('selected', true); $(`#translation_auto_mode option[value="${extension_settings.translate.auto_mode}"]`).attr('selected', true); - showKeyButton(); + showKeysButton(); } async function translateImpersonate(text) { @@ -181,6 +184,22 @@ async function translateIncomingMessage(messageId) { updateMessageBlock(messageId, message); } +async function translateProviderLibre(text, lang) { + const response = await fetch('/libre_translate', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ text: text, lang: lang }), + }); + + if (response.ok) { + const result = await response.text(); + return result; + } + + throw new Error(response.statusText); +} + + async function translateProviderGoogle(text, lang) { const response = await fetch('/google_translate', { method: 'POST', @@ -218,6 +237,8 @@ async function translateProviderDeepl(text, lang) { async function translate(text, lang) { try { switch (extension_settings.translate.provider) { + case 'libre': + return await translateProviderLibre(text, lang); case 'google': return await translateProviderGoogle(text, lang); case 'deepl': @@ -364,10 +385,12 @@ jQuery(() => {
+
@@ -399,7 +422,7 @@ jQuery(() => { }); $('#translation_provider').on('change', (event) => { extension_settings.translate.provider = event.target.value; - showKeyButton(); + showKeysButton(); saveSettingsDebounced(); }); $('#translation_target_language').on('change', (event) => { @@ -418,6 +441,17 @@ jQuery(() => { await writeSecret(extension_settings.translate.provider, key); toastr.success('API Key saved'); }); + $('#translate_url_button').on('click', async () => { + const optionText = $('#translation_provider option:selected').text(); + const url = await callPopup(`

${optionText} API URL

`, 'input'); + + if (url == false) { + return; + } + + await writeSecret(extension_settings.translate.provider + "_url", url); + toastr.success('API URL saved'); + }); loadSettings(); diff --git a/server.js b/server.js index 63e122fe4..a99efe9e5 100644 --- a/server.js +++ b/server.js @@ -3734,6 +3734,8 @@ const SECRET_KEYS = { NOVEL: 'api_key_novel', CLAUDE: 'api_key_claude', DEEPL: 'deepl', + LIBRE: 'libre', + LIBRE_URL: 'libre_url', OPENROUTER: 'api_key_openrouter', SCALE: 'api_key_scale', } @@ -3960,6 +3962,46 @@ app.post('/horde_generateimage', jsonParser, async (request, response) => { } }); +app.post('/libre_translate', jsonParser, async (request, response) => { + const key = readSecret(SECRET_KEYS.LIBRE); + const url = readSecret(SECRET_KEYS.LIBRE_URL); + + const text = request.body.text; + const lang = request.body.lang; + + if (!text || !lang) { + return response.sendStatus(400); + } + + console.log('Input text: ' + text); + + try { + const result = await fetch(url, { + method: "POST", + body: JSON.stringify({ + q: text, + source: "auto", + target: lang, + format: "text", + api_key: key + }), + headers: { "Content-Type": "application/json" } + }); + + if (!result.ok) { + return response.sendStatus(result.status); + } + + const json = await result.json(); + console.log('Translated text: ' + json.translatedText); + + return response.send(json.translatedText); + } catch (error) { + console.log("Translation error: " + error.message); + return response.sendStatus(500); + } +}); + app.post('/google_translate', jsonParser, async (request, response) => { const { generateRequestUrl, normaliseResponse } = require('google-translate-api-browser');