add a button to translate input message
This commit is contained in:
parent
47b6562605
commit
4521dde455
|
@ -1,18 +1,9 @@
|
||||||
export { translate };
|
import {callPopup, event_types, eventSource, getRequestHeaders, reloadCurrentChat, saveSettingsDebounced, substituteParams, updateMessageBlock,} from '../../../script.js';
|
||||||
|
import {extension_settings, getContext} from '../../extensions.js';
|
||||||
|
import {findSecret, secret_state, writeSecret} from '../../secrets.js';
|
||||||
|
import {splitRecursive} from '../../utils.js';
|
||||||
|
|
||||||
import {
|
export {translate};
|
||||||
callPopup,
|
|
||||||
eventSource,
|
|
||||||
event_types,
|
|
||||||
getRequestHeaders,
|
|
||||||
reloadCurrentChat,
|
|
||||||
saveSettingsDebounced,
|
|
||||||
substituteParams,
|
|
||||||
updateMessageBlock,
|
|
||||||
} from '../../../script.js';
|
|
||||||
import { extension_settings, getContext } from '../../extensions.js';
|
|
||||||
import { findSecret, secret_state, writeSecret } from '../../secrets.js';
|
|
||||||
import { splitRecursive } from '../../utils.js';
|
|
||||||
|
|
||||||
export const autoModeOptions = {
|
export const autoModeOptions = {
|
||||||
NONE: 'none',
|
NONE: 'none',
|
||||||
|
@ -142,12 +133,21 @@ const KEY_REQUIRED = ['deepl', 'libre'];
|
||||||
const LOCAL_URL = ['libre', 'oneringtranslator', 'deeplx', 'lingva'];
|
const LOCAL_URL = ['libre', 'oneringtranslator', 'deeplx', 'lingva'];
|
||||||
|
|
||||||
function showKeysButton() {
|
function showKeysButton() {
|
||||||
const providerRequiresKey = KEY_REQUIRED.includes(extension_settings.translate.provider);
|
const providerRequiresKey =
|
||||||
const providerOptionalUrl = LOCAL_URL.includes(extension_settings.translate.provider);
|
KEY_REQUIRED.includes(extension_settings.translate.provider);
|
||||||
|
const providerOptionalUrl =
|
||||||
|
LOCAL_URL.includes(extension_settings.translate.provider);
|
||||||
$('#translate_key_button').toggle(providerRequiresKey);
|
$('#translate_key_button').toggle(providerRequiresKey);
|
||||||
$('#translate_key_button').toggleClass('success', Boolean(secret_state[extension_settings.translate.provider]));
|
$('#translate_key_button')
|
||||||
|
.toggleClass(
|
||||||
|
'success',
|
||||||
|
Boolean(secret_state[extension_settings.translate.provider]));
|
||||||
$('#translate_url_button').toggle(providerOptionalUrl);
|
$('#translate_url_button').toggle(providerOptionalUrl);
|
||||||
$('#translate_url_button').toggleClass('success', Boolean(secret_state[extension_settings.translate.provider + '_url']));
|
$('#translate_url_button')
|
||||||
|
.toggleClass(
|
||||||
|
'success',
|
||||||
|
Boolean(
|
||||||
|
secret_state[extension_settings.translate.provider + '_url']));
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
|
@ -157,14 +157,21 @@ function loadSettings() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(`#translation_provider option[value="${extension_settings.translate.provider}"]`).attr('selected', true);
|
$(`#translation_provider option[value="${
|
||||||
$(`#translation_target_language option[value="${extension_settings.translate.target_language}"]`).attr('selected', true);
|
extension_settings.translate.provider}"]`)
|
||||||
$(`#translation_auto_mode option[value="${extension_settings.translate.auto_mode}"]`).attr('selected', true);
|
.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);
|
||||||
showKeysButton();
|
showKeysButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function translateImpersonate(text) {
|
async function translateImpersonate(text) {
|
||||||
const translatedText = await translate(text, extension_settings.translate.target_language);
|
const translatedText =
|
||||||
|
await translate(text, extension_settings.translate.target_language);
|
||||||
$('#send_textarea').val(translatedText);
|
$('#send_textarea').val(translatedText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,22 +188,24 @@ async function translateIncomingMessage(messageId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const textToTranslate = substituteParams(message.mes, context.name1, message.name);
|
const textToTranslate =
|
||||||
const translation = await translate(textToTranslate, extension_settings.translate.target_language);
|
substituteParams(message.mes, context.name1, message.name);
|
||||||
|
const translation = await translate(
|
||||||
|
textToTranslate, extension_settings.translate.target_language);
|
||||||
message.extra.display_text = translation;
|
message.extra.display_text = translation;
|
||||||
|
|
||||||
updateMessageBlock(messageId, message);
|
updateMessageBlock(messageId, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function translateProviderOneRing(text, lang) {
|
async function translateProviderOneRing(text, lang) {
|
||||||
let from_lang = lang == extension_settings.translate.internal_language
|
let from_lang = lang == extension_settings.translate.internal_language ?
|
||||||
? extension_settings.translate.target_language
|
extension_settings.translate.target_language :
|
||||||
: extension_settings.translate.internal_language;
|
extension_settings.translate.internal_language;
|
||||||
|
|
||||||
const response = await fetch('/api/translate/onering', {
|
const response = await fetch('/api/translate/onering', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: getRequestHeaders(),
|
headers: getRequestHeaders(),
|
||||||
body: JSON.stringify({ text: text, from_lang: from_lang, to_lang: lang }),
|
body: JSON.stringify({text: text, from_lang: from_lang, to_lang: lang}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
@ -217,7 +226,7 @@ async function translateProviderLibre(text, lang) {
|
||||||
const response = await fetch('/api/translate/libre', {
|
const response = await fetch('/api/translate/libre', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: getRequestHeaders(),
|
headers: getRequestHeaders(),
|
||||||
body: JSON.stringify({ text: text, lang: lang }),
|
body: JSON.stringify({text: text, lang: lang}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
@ -238,7 +247,7 @@ async function translateProviderGoogle(text, lang) {
|
||||||
const response = await fetch('/api/translate/google', {
|
const response = await fetch('/api/translate/google', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: getRequestHeaders(),
|
headers: getRequestHeaders(),
|
||||||
body: JSON.stringify({ text: text, lang: lang }),
|
body: JSON.stringify({text: text, lang: lang}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
@ -259,7 +268,7 @@ async function translateProviderLingva(text, lang) {
|
||||||
const response = await fetch('/api/translate/lingva', {
|
const response = await fetch('/api/translate/lingva', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: getRequestHeaders(),
|
headers: getRequestHeaders(),
|
||||||
body: JSON.stringify({ text: text, lang: lang }),
|
body: JSON.stringify({text: text, lang: lang}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
@ -284,7 +293,7 @@ async function translateProviderDeepl(text, lang) {
|
||||||
const response = await fetch('/api/translate/deepl', {
|
const response = await fetch('/api/translate/deepl', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: getRequestHeaders(),
|
headers: getRequestHeaders(),
|
||||||
body: JSON.stringify({ text: text, lang: lang }),
|
body: JSON.stringify({text: text, lang: lang}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
@ -305,7 +314,7 @@ async function translateProviderDeepLX(text, lang) {
|
||||||
const response = await fetch('/api/translate/deeplx', {
|
const response = await fetch('/api/translate/deeplx', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: getRequestHeaders(),
|
headers: getRequestHeaders(),
|
||||||
body: JSON.stringify({ text: text, lang: lang }),
|
body: JSON.stringify({text: text, lang: lang}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
@ -326,7 +335,7 @@ async function translateProviderBing(text, lang) {
|
||||||
const response = await fetch('/api/translate/bing', {
|
const response = await fetch('/api/translate/bing', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: getRequestHeaders(),
|
headers: getRequestHeaders(),
|
||||||
body: JSON.stringify({ text: text, lang: lang }),
|
body: JSON.stringify({text: text, lang: lang}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
@ -341,7 +350,8 @@ async function translateProviderBing(text, lang) {
|
||||||
* Splits text into chunks and translates each chunk separately
|
* Splits text into chunks and translates each chunk separately
|
||||||
* @param {string} text Text to translate
|
* @param {string} text Text to translate
|
||||||
* @param {string} lang Target language code
|
* @param {string} lang Target language code
|
||||||
* @param {(text: string, lang: string) => Promise<string>} translateFn Function to translate a single chunk (must return a Promise)
|
* @param {(text: string, lang: string) => Promise<string>} translateFn Function
|
||||||
|
* to translate a single chunk (must return a Promise)
|
||||||
* @param {number} chunkSize Maximum chunk size
|
* @param {number} chunkSize Maximum chunk size
|
||||||
* @returns {Promise<string>} Translated text
|
* @returns {Promise<string>} Translated text
|
||||||
*/
|
*/
|
||||||
|
@ -375,19 +385,24 @@ async function translate(text, lang) {
|
||||||
case 'libre':
|
case 'libre':
|
||||||
return await translateProviderLibre(text, lang);
|
return await translateProviderLibre(text, lang);
|
||||||
case 'google':
|
case 'google':
|
||||||
return await chunkedTranslate(text, lang, translateProviderGoogle, 5000);
|
return await chunkedTranslate(
|
||||||
|
text, lang, translateProviderGoogle, 5000);
|
||||||
case 'lingva':
|
case 'lingva':
|
||||||
return await chunkedTranslate(text, lang, translateProviderLingva, 5000);
|
return await chunkedTranslate(
|
||||||
|
text, lang, translateProviderLingva, 5000);
|
||||||
case 'deepl':
|
case 'deepl':
|
||||||
return await translateProviderDeepl(text, lang);
|
return await translateProviderDeepl(text, lang);
|
||||||
case 'deeplx':
|
case 'deeplx':
|
||||||
return await chunkedTranslate(text, lang, translateProviderDeepLX, 1500);
|
return await chunkedTranslate(
|
||||||
|
text, lang, translateProviderDeepLX, 1500);
|
||||||
case 'oneringtranslator':
|
case 'oneringtranslator':
|
||||||
return await translateProviderOneRing(text, lang);
|
return await translateProviderOneRing(text, lang);
|
||||||
case 'bing':
|
case 'bing':
|
||||||
return await chunkedTranslate(text, lang, translateProviderBing, 1000);
|
return await chunkedTranslate(text, lang, translateProviderBing, 1000);
|
||||||
default:
|
default:
|
||||||
console.error('Unknown translation provider', extension_settings.translate.provider);
|
console.error(
|
||||||
|
'Unknown translation provider',
|
||||||
|
extension_settings.translate.provider);
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -406,7 +421,8 @@ async function translateOutgoingMessage(messageId) {
|
||||||
|
|
||||||
const originalText = message.mes;
|
const originalText = message.mes;
|
||||||
message.extra.display_text = originalText;
|
message.extra.display_text = originalText;
|
||||||
message.mes = await translate(originalText, extension_settings.translate.internal_language);
|
message.mes = await translate(
|
||||||
|
originalText, extension_settings.translate.internal_language);
|
||||||
updateMessageBlock(messageId, message);
|
updateMessageBlock(messageId, message);
|
||||||
|
|
||||||
console.log('translateOutgoingMessage', messageId);
|
console.log('translateOutgoingMessage', messageId);
|
||||||
|
@ -424,6 +440,13 @@ function createEventHandler(translateFunction, shouldTranslateFunction) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function onTranslateInputMessageClick() {
|
||||||
|
const ta = document.querySelector('#send_textarea');
|
||||||
|
toastr.info(`Input Message is translating`, 'Please wait...');
|
||||||
|
const translatedText =
|
||||||
|
await translate(ta.value, extension_settings.translate.internal_language);
|
||||||
|
$('#send_textarea').val(translatedText);
|
||||||
|
}
|
||||||
// Prevents the chat from being translated in parallel
|
// Prevents the chat from being translated in parallel
|
||||||
let translateChatExecuting = false;
|
let translateChatExecuting = false;
|
||||||
|
|
||||||
|
@ -437,7 +460,8 @@ async function onTranslateChatClick() {
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
const chat = context.chat;
|
const chat = context.chat;
|
||||||
|
|
||||||
toastr.info(`${chat.length} message(s) queued for translation.`, 'Please wait...');
|
toastr.info(
|
||||||
|
`${chat.length} message(s) queued for translation.`, 'Please wait...');
|
||||||
|
|
||||||
for (let i = 0; i < chat.length; i++) {
|
for (let i = 0; i < chat.length; i++) {
|
||||||
await translateIncomingMessage(i);
|
await translateIncomingMessage(i);
|
||||||
|
@ -453,7 +477,9 @@ async function onTranslateChatClick() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onTranslationsClearClick() {
|
async function onTranslationsClearClick() {
|
||||||
const confirm = await callPopup('<h3>Are you sure?</h3>This will remove translated text from all messages in the current chat. This action cannot be undone.', 'confirm');
|
const confirm = await callPopup(
|
||||||
|
'<h3>Are you sure?</h3>This will remove translated text from all messages in the current chat. This action cannot be undone.',
|
||||||
|
'confirm');
|
||||||
|
|
||||||
if (!confirm) {
|
if (!confirm) {
|
||||||
return;
|
return;
|
||||||
|
@ -477,11 +503,13 @@ async function translateMessageEdit(messageId) {
|
||||||
const chat = context.chat;
|
const chat = context.chat;
|
||||||
const message = chat[messageId];
|
const message = chat[messageId];
|
||||||
|
|
||||||
if (message.is_system || extension_settings.translate.auto_mode == autoModeOptions.NONE) {
|
if (message.is_system ||
|
||||||
|
extension_settings.translate.auto_mode == autoModeOptions.NONE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((message.is_user && shouldTranslate(outgoingTypes)) || (!message.is_user && shouldTranslate(incomingTypes))) {
|
if ((message.is_user && shouldTranslate(outgoingTypes)) ||
|
||||||
|
(!message.is_user && shouldTranslate(incomingTypes))) {
|
||||||
await translateIncomingMessage(messageId);
|
await translateIncomingMessage(messageId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -504,9 +532,12 @@ async function onMessageTranslateClick() {
|
||||||
await context.saveChat();
|
await context.saveChat();
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleIncomingMessage = createEventHandler(translateIncomingMessage, () => shouldTranslate(incomingTypes));
|
const handleIncomingMessage = createEventHandler(
|
||||||
const handleOutgoingMessage = createEventHandler(translateOutgoingMessage, () => shouldTranslate(outgoingTypes));
|
translateIncomingMessage, () => shouldTranslate(incomingTypes));
|
||||||
const handleImpersonateReady = createEventHandler(translateImpersonate, () => shouldTranslate(incomingTypes));
|
const handleOutgoingMessage = createEventHandler(
|
||||||
|
translateOutgoingMessage, () => shouldTranslate(outgoingTypes));
|
||||||
|
const handleImpersonateReady = createEventHandler(
|
||||||
|
translateImpersonate, () => shouldTranslate(incomingTypes));
|
||||||
const handleMessageEdit = createEventHandler(translateMessageEdit, () => true);
|
const handleMessageEdit = createEventHandler(translateMessageEdit, () => true);
|
||||||
|
|
||||||
window['translate'] = translate;
|
window['translate'] = translate;
|
||||||
|
@ -555,14 +586,21 @@ jQuery(() => {
|
||||||
<div id="translate_chat" class="list-group-item flex-container flexGap5">
|
<div id="translate_chat" class="list-group-item flex-container flexGap5">
|
||||||
<div class="fa-solid fa-language extensionsMenuExtensionButton" /></div>
|
<div class="fa-solid fa-language extensionsMenuExtensionButton" /></div>
|
||||||
Translate Chat
|
Translate Chat
|
||||||
</div>`;
|
</div>
|
||||||
|
<div id="translate_input_message" class="list-group-item flex-container flexGap5">
|
||||||
|
<div class="fa-solid fa-language extensionsMenuExtensionButton" /></div>
|
||||||
|
Translate Input Message
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
$('#extensionsMenu').append(buttonHtml);
|
$('#extensionsMenu').append(buttonHtml);
|
||||||
$('#extensions_settings2').append(html);
|
$('#extensions_settings2').append(html);
|
||||||
$('#translate_chat').on('click', onTranslateChatClick);
|
$('#translate_chat').on('click', onTranslateChatClick);
|
||||||
|
$('#translate_input_message').on('click', onTranslateInputMessageClick);
|
||||||
$('#translation_clear').on('click', onTranslationsClearClick);
|
$('#translation_clear').on('click', onTranslationsClearClick);
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(languageCodes)) {
|
for (const [key, value] of Object.entries(languageCodes)) {
|
||||||
$('#translation_target_language').append(`<option value="${value}">${key}</option>`);
|
$('#translation_target_language')
|
||||||
|
.append(`<option value="${value}">${key}</option>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#translation_auto_mode').on('change', (event) => {
|
$('#translation_auto_mode').on('change', (event) => {
|
||||||
|
@ -599,7 +637,8 @@ jQuery(() => {
|
||||||
'oneringtranslator': 'http://127.0.0.1:4990/translate',
|
'oneringtranslator': 'http://127.0.0.1:4990/translate',
|
||||||
'deeplx': 'http://127.0.0.1:1188/translate',
|
'deeplx': 'http://127.0.0.1:1188/translate',
|
||||||
};
|
};
|
||||||
const popupText = `<h3>${optionText} API URL</h3><i>Example: <tt>${String(exampleURLs[extension_settings.translate.provider])}</tt></i>`;
|
const popupText = `<h3>${optionText} API URL</h3><i>Example: <tt>${
|
||||||
|
String(exampleURLs[extension_settings.translate.provider])}</tt></i>`;
|
||||||
|
|
||||||
const secretKey = extension_settings.translate.provider + '_url';
|
const secretKey = extension_settings.translate.provider + '_url';
|
||||||
const savedUrl = secret_state[secretKey] ? await findSecret(secretKey) : '';
|
const savedUrl = secret_state[secretKey] ? await findSecret(secretKey) : '';
|
||||||
|
|
Loading…
Reference in New Issue