Spaces:
Running
Running
const fetch = require('node-fetch').default; | |
const https = require('https'); | |
const express = require('express'); | |
const iconv = require('iconv-lite'); | |
const { readSecret, SECRET_KEYS } = require('./secrets'); | |
const { getConfigValue, uuidv4 } = require('../util'); | |
const { jsonParser } = require('../express-common'); | |
const DEEPLX_URL_DEFAULT = 'http://127.0.0.1:1188/translate'; | |
const ONERING_URL_DEFAULT = 'http://127.0.0.1:4990/translate'; | |
const router = express.Router(); | |
router.post('/libre', jsonParser, async (request, response) => { | |
const key = readSecret(request.user.directories, SECRET_KEYS.LIBRE); | |
const url = readSecret(request.user.directories, SECRET_KEYS.LIBRE_URL); | |
if (!url) { | |
console.log('LibreTranslate URL is not configured.'); | |
return response.sendStatus(400); | |
} | |
if (request.body.lang === 'zh-CN') { | |
request.body.lang = 'zh'; | |
} | |
if (request.body.lang === 'zh-TW') { | |
request.body.lang = 'zt'; | |
} | |
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) { | |
const error = await result.text(); | |
console.log('LibreTranslate error: ', result.statusText, error); | |
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); | |
} | |
}); | |
router.post('/google', jsonParser, async (request, response) => { | |
try { | |
const { generateRequestUrl, normaliseResponse } = require('google-translate-api-browser'); | |
const text = request.body.text; | |
const lang = request.body.lang; | |
if (!text || !lang) { | |
return response.sendStatus(400); | |
} | |
console.log('Input text: ' + text); | |
const url = generateRequestUrl(text, { to: lang }); | |
https.get(url, (resp) => { | |
const data = []; | |
resp.on('data', (chunk) => { | |
data.push(chunk); | |
}); | |
resp.on('end', () => { | |
try { | |
const decodedData = iconv.decode(Buffer.concat(data), 'utf-8'); | |
const result = normaliseResponse(JSON.parse(decodedData)); | |
console.log('Translated text: ' + result.text); | |
response.setHeader('Content-Type', 'text/plain; charset=utf-8'); | |
return response.send(result.text); | |
} catch (error) { | |
console.log('Translation error', error); | |
return response.sendStatus(500); | |
} | |
}); | |
}).on('error', (err) => { | |
console.log('Translation error: ' + err.message); | |
return response.sendStatus(500); | |
}); | |
} catch (error) { | |
console.log('Translation error', error); | |
return response.sendStatus(500); | |
} | |
}); | |
router.post('/yandex', jsonParser, async (request, response) => { | |
const chunks = request.body.chunks; | |
const lang = request.body.lang; | |
if (!chunks || !lang) { | |
return response.sendStatus(400); | |
} | |
// reconstruct original text to log | |
let inputText = ''; | |
const params = new URLSearchParams(); | |
for (const chunk of chunks) { | |
params.append('text', chunk); | |
inputText += chunk; | |
} | |
params.append('lang', lang); | |
const ucid = uuidv4().replaceAll('-', ''); | |
console.log('Input text: ' + inputText); | |
try { | |
const result = await fetch(`https://translate.yandex.net/api/v1/tr.json/translate?ucid=${ucid}&srv=android&format=text`, { | |
method: 'POST', | |
body: params, | |
headers: { | |
'Content-Type': 'application/x-www-form-urlencoded', | |
}, | |
timeout: 0, | |
}); | |
if (!result.ok) { | |
const error = await result.text(); | |
console.log('Yandex error: ', result.statusText, error); | |
return response.sendStatus(500); | |
} | |
const json = await result.json(); | |
const translated = json.text.join(); | |
console.log('Translated text: ' + translated); | |
return response.send(translated); | |
} catch (error) { | |
console.log('Translation error: ' + error.message); | |
return response.sendStatus(500); | |
} | |
}); | |
router.post('/lingva', jsonParser, async (request, response) => { | |
try { | |
const baseUrl = readSecret(request.user.directories, SECRET_KEYS.LINGVA_URL); | |
if (!baseUrl) { | |
console.log('Lingva URL is not configured.'); | |
return response.sendStatus(400); | |
} | |
const text = request.body.text; | |
const lang = request.body.lang; | |
if (!text || !lang) { | |
return response.sendStatus(400); | |
} | |
console.log('Input text: ' + text); | |
const url = `${baseUrl}/auto/${lang}/${encodeURIComponent(text)}`; | |
https.get(url, (resp) => { | |
let data = ''; | |
resp.on('data', (chunk) => { | |
data += chunk; | |
}); | |
resp.on('end', () => { | |
try { | |
const result = JSON.parse(data); | |
console.log('Translated text: ' + result.translation); | |
return response.send(result.translation); | |
} catch (error) { | |
console.log('Translation error', error); | |
return response.sendStatus(500); | |
} | |
}); | |
}).on('error', (err) => { | |
console.log('Translation error: ' + err.message); | |
return response.sendStatus(500); | |
}); | |
} catch (error) { | |
console.log('Translation error', error); | |
return response.sendStatus(500); | |
} | |
}); | |
router.post('/deepl', jsonParser, async (request, response) => { | |
const key = readSecret(request.user.directories, SECRET_KEYS.DEEPL); | |
if (!key) { | |
console.log('DeepL key is not configured.'); | |
return response.sendStatus(400); | |
} | |
if (request.body.lang === 'zh-CN' || request.body.lang === 'zh-TW') { | |
request.body.lang = 'ZH'; | |
} | |
const text = request.body.text; | |
const lang = request.body.lang; | |
const formality = getConfigValue('deepl.formality', 'default'); | |
if (!text || !lang) { | |
return response.sendStatus(400); | |
} | |
console.log('Input text: ' + text); | |
const params = new URLSearchParams(); | |
params.append('text', text); | |
params.append('target_lang', lang); | |
if (['de', 'fr', 'it', 'es', 'nl', 'ja', 'ru'].includes(lang)) { | |
// We don't specify a Portuguese variant, so ignore formality for it. | |
params.append('formality', formality); | |
} | |
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) { | |
const error = await result.text(); | |
console.log('DeepL error: ', result.statusText, error); | |
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); | |
} | |
}); | |
router.post('/onering', jsonParser, async (request, response) => { | |
const secretUrl = readSecret(request.user.directories, SECRET_KEYS.ONERING_URL); | |
const url = secretUrl || ONERING_URL_DEFAULT; | |
if (!url) { | |
console.log('OneRing URL is not configured.'); | |
return response.sendStatus(400); | |
} | |
if (!secretUrl && url === ONERING_URL_DEFAULT) { | |
console.log('OneRing URL is using default value.', ONERING_URL_DEFAULT); | |
} | |
const text = request.body.text; | |
const from_lang = request.body.from_lang; | |
const to_lang = request.body.to_lang; | |
if (!text || !from_lang || !to_lang) { | |
return response.sendStatus(400); | |
} | |
const params = new URLSearchParams(); | |
params.append('text', text); | |
params.append('from_lang', from_lang); | |
params.append('to_lang', to_lang); | |
console.log('Input text: ' + text); | |
try { | |
const fetchUrl = new URL(url); | |
fetchUrl.search = params.toString(); | |
const result = await fetch(fetchUrl, { | |
method: 'GET', | |
timeout: 0, | |
}); | |
if (!result.ok) { | |
const error = await result.text(); | |
console.log('OneRing error: ', result.statusText, error); | |
return response.sendStatus(result.status); | |
} | |
const data = await result.json(); | |
console.log('Translated text: ' + data.result); | |
return response.send(data.result); | |
} catch (error) { | |
console.log('Translation error: ' + error.message); | |
return response.sendStatus(500); | |
} | |
}); | |
router.post('/deeplx', jsonParser, async (request, response) => { | |
const secretUrl = readSecret(request.user.directories, SECRET_KEYS.DEEPLX_URL); | |
const url = secretUrl || DEEPLX_URL_DEFAULT; | |
if (!url) { | |
console.log('DeepLX URL is not configured.'); | |
return response.sendStatus(400); | |
} | |
if (!secretUrl && url === DEEPLX_URL_DEFAULT) { | |
console.log('DeepLX URL is using default value.', DEEPLX_URL_DEFAULT); | |
} | |
const text = request.body.text; | |
let lang = request.body.lang; | |
if (request.body.lang === 'zh-CN' || request.body.lang === 'zh-TW') { | |
lang = 'ZH'; | |
} | |
if (!text || !lang) { | |
return response.sendStatus(400); | |
} | |
console.log('Input text: ' + text); | |
try { | |
const result = await fetch(url, { | |
method: 'POST', | |
body: JSON.stringify({ | |
text: text, | |
source_lang: 'auto', | |
target_lang: lang, | |
}), | |
headers: { | |
'Accept': 'application/json', | |
'Content-Type': 'application/json', | |
}, | |
timeout: 0, | |
}); | |
if (!result.ok) { | |
const error = await result.text(); | |
console.log('DeepLX error: ', result.statusText, error); | |
return response.sendStatus(result.status); | |
} | |
const json = await result.json(); | |
console.log('Translated text: ' + json.data); | |
return response.send(json.data); | |
} catch (error) { | |
console.log('DeepLX translation error: ' + error.message); | |
return response.sendStatus(500); | |
} | |
}); | |
router.post('/bing', jsonParser, async (request, response) => { | |
const bingTranslateApi = require('bing-translate-api'); | |
const text = request.body.text; | |
let lang = request.body.lang; | |
if (request.body.lang === 'zh-CN') { | |
lang = 'zh-Hans'; | |
} | |
if (!text || !lang) { | |
return response.sendStatus(400); | |
} | |
console.log('Input text: ' + text); | |
bingTranslateApi.translate(text, null, lang).then(result => { | |
console.log('Translated text: ' + result.translation); | |
return response.send(result.translation); | |
}).catch(err => { | |
console.log('Translation error: ' + err.message); | |
return response.sendStatus(500); | |
}); | |
}); | |
module.exports = { router }; | |