[WIP/Untested] DeepL translation API

This commit is contained in:
Cohee
2023-06-27 20:48:09 +03:00
parent d59174da77
commit 10e87dd5ca
3 changed files with 99 additions and 5 deletions

View File

@ -9,6 +9,7 @@ import {
updateMessageBlock, updateMessageBlock,
} from "../../../script.js"; } from "../../../script.js";
import { extension_settings, getContext } from "../../extensions.js"; import { extension_settings, getContext } from "../../extensions.js";
import { secret_state, writeSecret } from "../../secrets.js";
const autoModeOptions = { const autoModeOptions = {
NONE: 'none', NONE: 'none',
@ -134,6 +135,14 @@ const languageCodes = {
'Zulu': 'zu', 'Zulu': 'zu',
}; };
const KEY_REQUIRED = ['deepl'];
function showKeyButton() {
const providerRequiresKey = KEY_REQUIRED.includes(extension_settings.translate.provider);
$("#translate_key_button").toggle(providerRequiresKey);
$("#translate_key_button").toggleClass('success', Boolean(secret_state[extension_settings.translate.provider]));
}
function loadSettings() { function loadSettings() {
for (const key in defaultSettings) { for (const key in defaultSettings) {
if (!extension_settings.translate.hasOwnProperty(key)) { if (!extension_settings.translate.hasOwnProperty(key)) {
@ -144,6 +153,7 @@ function loadSettings() {
$(`#translation_provider option[value="${extension_settings.translate.provider}"]`).attr('selected', true); $(`#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_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); $(`#translation_auto_mode option[value="${extension_settings.translate.auto_mode}"]`).attr('selected', true);
showKeyButton();
} }
async function translateImpersonate(text) { async function translateImpersonate(text) {
@ -186,18 +196,39 @@ async function translateProviderGoogle(text, lang) {
throw new Error(response.statusText); throw new Error(response.statusText);
} }
async function translateProviderDeepl(text, lang) {
if (!secret_state.deepl) {
throw new Error('No DeepL API key');
}
const response = await fetch('/deepl_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 translate(text, lang) { async function translate(text, lang) {
try { try {
switch (extension_settings.translate.provider) { switch (extension_settings.translate.provider) {
case 'google': case 'google':
return await translateProviderGoogle(text, lang); return await translateProviderGoogle(text, lang);
case 'deepl':
return await translateProviderDeepl(text, lang);
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) {
console.log(error); console.log(error);
toastr.error('Failed to translate message'); toastr.error(String(error), 'Failed to translate message');
} }
} }
@ -331,9 +362,13 @@ jQuery(() => {
<option value="both">Translate both</option> <option value="both">Translate both</option>
</select> </select>
<label for="translation_provider">Provider</label> <label for="translation_provider">Provider</label>
<select id="translation_provider" name="provider"> <div class="flex-container gap5px flexnowrap marginBot5">
<option value="google">Google</option> <select id="translation_provider" name="provider" class="margin0">
<select> <option value="google">Google</option>
<option value="deepl">DeepL</option>
<select>
<div id="translate_key_button" class="menu_button fa-solid fa-key margin0"></div>
</div>
<label for="translation_target_language">Target Language</label> <label for="translation_target_language">Target Language</label>
<select id="translation_target_language" name="target_language"></select> <select id="translation_target_language" name="target_language"></select>
<div id="translation_clear" class="menu_button"> <div id="translation_clear" class="menu_button">
@ -364,6 +399,7 @@ jQuery(() => {
}); });
$('#translation_provider').on('change', (event) => { $('#translation_provider').on('change', (event) => {
extension_settings.translate.provider = event.target.value; extension_settings.translate.provider = event.target.value;
showKeyButton();
saveSettingsDebounced(); saveSettingsDebounced();
}); });
$('#translation_target_language').on('change', (event) => { $('#translation_target_language').on('change', (event) => {
@ -371,6 +407,17 @@ jQuery(() => {
saveSettingsDebounced(); saveSettingsDebounced();
}); });
$(document).on('click', '.mes_translate', onMessageTranslateClick); $(document).on('click', '.mes_translate', onMessageTranslateClick);
$('#translate_key_button').on('click', async () => {
const optionText = $('#translation_provider option:selected').text();
const key = await callPopup(`<h3>${optionText} API Key</h3>`, 'input');
if (key == false) {
return;
}
await writeSecret(extension_settings.translate.provider, key);
toastr.success('API Key saved');
});
loadSettings(); loadSettings();

View File

@ -2,6 +2,5 @@
width: fit-content; width: fit-content;
display: flex; display: flex;
gap: 10px; gap: 10px;
align-items: baseline;
flex-direction: row; flex-direction: row;
} }

View File

@ -3442,6 +3442,7 @@ const SECRET_KEYS = {
POE: 'api_key_poe', POE: 'api_key_poe',
NOVEL: 'api_key_novel', NOVEL: 'api_key_novel',
CLAUDE: 'api_key_claude', CLAUDE: 'api_key_claude',
DEEPL: 'deepl',
} }
function migrateSecrets() { function migrateSecrets() {
@ -3692,6 +3693,53 @@ app.post('/google_translate', jsonParser, async (request, response) => {
}); });
}); });
app.post('/deepl_translate', jsonParser, async (request, response) => {
const key = readSecret(SECRET_KEYS.DEEPL);
if (!key) {
return response.sendStatus(401);
}
const text = request.body.text;
const lang = request.body.lang;
if (!text || !lang) {
return response.sendStatus(400);
}
console.log('Input text: ' + text);
const fetch = require('node-fetch').default;
const params = new URLSearchParams();
params.append('text', text);
params.append('target_lang', lang);
try {
const result = await fetch('https://api-free.deepl.com/v2/translate', {
method: 'POST',
body: params,
headers: {
'Accept': 'application/json',
'Authorization': `DeepL-Auth-Key ${key}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
timeout: 0,
});
if (!result.ok) {
return response.sendStatus(result.status);
}
const json = await result.json();
console.log('Translated text: ' + json.translations[0].text);
return response.send(json.translations[0].text);
} catch (error) {
console.log("Translation error: " + error.message);
return response.sendStatus(500);
}
});
app.post('/novel_tts', jsonParser, async (request, response) => { app.post('/novel_tts', jsonParser, async (request, response) => {
const token = readSecret(SECRET_KEYS.NOVEL); const token = readSecret(SECRET_KEYS.NOVEL);