language detection fixes and installer change.
This commit is contained in:
parent
5cfdd498c9
commit
d83c0ad753
28 changed files with 216 additions and 149 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -104,5 +104,7 @@ src/sounds/tts/*
|
|||
loquendoBot_backend.spec
|
||||
forge.config.js
|
||||
backend/*
|
||||
src/backend/loquendoBot_backend.exe
|
||||
!backend/loquendoBot_backend.py
|
||||
backend/loquendoBot_backend.exe
|
||||
src/config/twitch-emotes.json
|
||||
dist/*
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ logger = logging.getLogger("waitress")
|
|||
logger.setLevel(logging.INFO)
|
||||
|
||||
gevent.monkey.patch_all()
|
||||
import gevent.queue
|
||||
# import gevent.queue
|
||||
|
||||
import configparser
|
||||
import pyttsx3
|
||||
|
|
@ -28,8 +28,6 @@ from deep_translator import (
|
|||
MyMemoryTranslator,
|
||||
)
|
||||
|
||||
import emoji
|
||||
|
||||
from vosk import Model, KaldiRecognizer, SetLogLevel
|
||||
|
||||
# global variables
|
||||
|
|
@ -68,7 +66,7 @@ class LanguageDetection:
|
|||
self.model = fasttext.load_model(language_detection_model)
|
||||
|
||||
def predict_lang(self, text):
|
||||
predictions = self.model.predict(text, k=5) # returns top 2 matching languages
|
||||
predictions = self.model.predict(text, k=3) # returns top 2 matching languages
|
||||
language_codes = []
|
||||
for prediction in predictions[0]:
|
||||
language_codes.append(prediction.replace("__label__", ""))
|
||||
|
|
@ -98,6 +96,7 @@ class STT:
|
|||
vosk_model = os.path.join(
|
||||
resources_folder, "speech_to_text_models", settings["STT"]["LANGUAGE"]
|
||||
)
|
||||
print(vosk_model)
|
||||
|
||||
self.model = Model(rf"{vosk_model}")
|
||||
self.dump_fn = None
|
||||
|
|
@ -137,8 +136,10 @@ class STT:
|
|||
def stop_recognition(self):
|
||||
self.is_running = False
|
||||
|
||||
|
||||
speech_recognition_service = STT()
|
||||
settings.read(settingsPath)
|
||||
print(settingsPath)
|
||||
if settings["STT"]["USE_STT"] and bool(settings["STT"]["LANGUAGE"]):
|
||||
speech_recognition_service = STT()
|
||||
|
||||
|
||||
class TTS:
|
||||
|
|
@ -156,16 +157,16 @@ class TTS:
|
|||
break
|
||||
self.engine.setProperty("voice", matching_id)
|
||||
|
||||
if environment == "dev":
|
||||
settings_folder = os.path.dirname(settingsPath)
|
||||
if environment == "dev":
|
||||
src_folder = os.path.dirname(settings_folder)
|
||||
bot_folder = os.path.dirname(src_folder)
|
||||
saveLocation = os.path.join(
|
||||
src_folder, "sounds\\tts", f"Internal_{count}.mp3"
|
||||
bot_folder, "sounds", f"Internal_{count}.mp3"
|
||||
)
|
||||
else:
|
||||
resources_folder = os.path.dirname(settingsPath)
|
||||
saveLocation = os.path.join(
|
||||
resources_folder, "sounds\\tts", f"Internal_{count}.mp3"
|
||||
settings_folder, "sounds", f"Internal_{count}.mp3"
|
||||
)
|
||||
|
||||
self.engine.save_to_file(message, saveLocation)
|
||||
|
|
@ -180,8 +181,9 @@ class TTS:
|
|||
|
||||
return [voice.name for voice in voices]
|
||||
|
||||
|
||||
text_to_speech_service = TTS()
|
||||
settings.read(settingsPath)
|
||||
if settings["TTS"]["USE_TTS"]:
|
||||
text_to_speech_service = TTS()
|
||||
|
||||
# endpoints
|
||||
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
module.exports = {
|
||||
packagerConfig: {
|
||||
icon: './src/images/icon.ico',
|
||||
asar: true,
|
||||
extraResource: ['./src/config/loquendo.db', './src/sounds', './backend', './language_detection_model', './speech_to_text_models'],
|
||||
},
|
||||
rebuildConfig: {},
|
||||
makers: [
|
||||
{
|
||||
name: '@electron-forge/maker-squirrel',
|
||||
config: {
|
||||
setupIcon: './src/images/icon.ico',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-zip',
|
||||
platforms: ['darwin'],
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-deb',
|
||||
config: {
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-rpm',
|
||||
config: {},
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
{
|
||||
name: '@electron-forge/plugin-auto-unpack-natives',
|
||||
config: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Khyretis
|
||||
Copyright (c) 2021 Khyretos
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
32
package.json
32
package.json
|
|
@ -1,14 +1,37 @@
|
|||
{
|
||||
"name": "loquendo-bot",
|
||||
"productName": "LoquendoBot",
|
||||
"version": "2.5.0",
|
||||
"description": "Bot assistant for streamers over different platforms",
|
||||
"main": "src/main.js",
|
||||
"scripts": {
|
||||
"start": "electron-forge start",
|
||||
"package": "npm run backend && electron-forge package",
|
||||
"make": "electron-forge make",
|
||||
"build": "npm run backend && electron-builder",
|
||||
"publish": "electron-forge publish",
|
||||
"backend": "pyinstaller --noconsole --onefile --collect-all vosk --distpath ./backend ./src/backend/loquendoBot_backend.py"
|
||||
"backend": "pyinstaller --noconsole --onefile --collect-all vosk --distpath ./backend ./backend/loquendoBot_backend.py"
|
||||
},
|
||||
"build": {
|
||||
"appId": "LoquendoBot",
|
||||
"win": {
|
||||
"target": [
|
||||
"nsis"
|
||||
],
|
||||
"icon": "./src/images/icon.ico"
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false,
|
||||
"installerIcon": "./src/images/icon.ico",
|
||||
"uninstallerIcon": "./src/images/icon.ico",
|
||||
"uninstallDisplayName": "LoquendoBot-uninstaller",
|
||||
"license": "license.md",
|
||||
"allowToChangeInstallationDirectory": "true"
|
||||
},
|
||||
"extraResources": [
|
||||
"speech_to_text_models/Where to get STT models.txt",
|
||||
"backend/loquendoBot_backend.exe",
|
||||
"language_detection_model",
|
||||
"sounds"
|
||||
]
|
||||
},
|
||||
"keywords": [],
|
||||
"author": {
|
||||
|
|
@ -18,7 +41,6 @@
|
|||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"axios": "^1.4.0",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"emoji-picker-element": "^1.21.0",
|
||||
"express": "^4.18.2",
|
||||
"flag-icons": "^7.1.0",
|
||||
|
|
@ -38,12 +60,12 @@
|
|||
"@electron-forge/cli": "^6.2.1",
|
||||
"@electron-forge/maker-deb": "^6.2.1",
|
||||
"@electron-forge/maker-rpm": "^6.2.1",
|
||||
"@electron-forge/maker-squirrel": "^6.2.1",
|
||||
"@electron-forge/maker-zip": "^6.2.1",
|
||||
"@electron-forge/plugin-auto-unpack-natives": "^6.2.1",
|
||||
"@electron-internal/eslint-config": "^1.0.1",
|
||||
"@electron-toolkit/eslint-config": "^1.0.2",
|
||||
"electron": "^25.9.8",
|
||||
"electron-builder": "^24.9.1",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.2",
|
||||
|
|
|
|||
|
|
@ -1 +1,3 @@
|
|||
https://alphacephei.com/vosk/models
|
||||
Download the model from here: https://alphacephei.com/vosk/models unzip it
|
||||
and drop the folder in the 'speech_to_text_models' folder. Restart the app
|
||||
to load the changes.
|
||||
|
|
|
|||
|
|
@ -36,25 +36,14 @@ html {
|
|||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
/* border-top-left-radius: 20px; */
|
||||
/* border-top-right-radius: 20px; */
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Styling of window frame and titlebar */
|
||||
|
||||
body {
|
||||
/* border: 1px solid #48545c; */
|
||||
overflow-y: hidden;
|
||||
position: relative;
|
||||
/* overflow-y: hidden;
|
||||
overflow-x: hidden; */
|
||||
}
|
||||
|
||||
#titlebar {
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 29 KiB |
|
|
@ -212,6 +212,11 @@
|
|||
<div class="AdvancedMenuRow inputTTS">
|
||||
<div class="AdvancedMenuLabel">2<sup>nd</sup> Internal Voice</div>
|
||||
<select class="menu-select" name="secondaryVoice" id="secondaryVoice"></select>
|
||||
<i
|
||||
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
|
||||
id="Info_SECONDARY_TTS"
|
||||
tip="This will only work if Language detection is enabled and a language for this voice has been selected"
|
||||
></i>
|
||||
</div>
|
||||
<div class="AdvancedMenuRow inputTTS">
|
||||
<div class="AdvancedMenuLabel">Test 2<sup>nd</sup> Internal Voice</div>
|
||||
|
|
@ -235,8 +240,13 @@
|
|||
<select class="menu-select" name="microphone" id="microphone"></select>
|
||||
</div>
|
||||
<div class="AdvancedMenuRow voiceLanguageDetection inputSTT">
|
||||
<div class="AdvancedMenuLabel">Voice Language</div>
|
||||
<div class="AdvancedMenuLabel">Voice Language model</div>
|
||||
<select class="menu-select" name="sttModel" id="sttModel" tip="Language Service to use"></select>
|
||||
<i
|
||||
class="fa-solid fa-folder-open fa-2x SmallButton option-icon-container"
|
||||
id="Info_VOICE_MODELS_FOLDER"
|
||||
tip="Open Voice models folder"
|
||||
></i>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
|
|
@ -247,27 +257,42 @@
|
|||
<label for="USE_DETECTION" class="toggle-small"></label>
|
||||
<div class="AdvancedMenuLabel3">Enable Language detection</div>
|
||||
</legend>
|
||||
<div class="AdvancedMenuRow languageDetectionInput">
|
||||
<div class="AdvancedMenuLabel">Translate chat messages to</div>
|
||||
<select class="menu-select" name="language" id="TRANSLATE_TO" tip="Language Service to use"></select>
|
||||
</div>
|
||||
<div class="AdvancedMenuRow languageDetectionInput">
|
||||
<div class="AdvancedMenuLabel">Broadcast translation to chat</div>
|
||||
<input type="checkbox" id="BROADCAST_TRANSLATION" class="checkbox" />
|
||||
<label for="BROADCAST_TRANSLATION" class="toggle-small"></label>
|
||||
</div>
|
||||
<div class="AdvancedMenuRow languageDetectionInput">
|
||||
<div class="AdvancedMenuLabel">Output translation to TTS</div>
|
||||
<input type="checkbox" id="OUTPUT_TO_TTS" class="checkbox" />
|
||||
<label for="OUTPUT_TO_TTS" class="toggle-small"></label>
|
||||
</div>
|
||||
<div class="AdvancedMenuRow outputToTtsInput">
|
||||
<div class="AdvancedMenuLabel">Default TTS service language</div>
|
||||
<select class="menu-select" name="defaultLanguage" id="defaultLanguage" tip="Language Service to use"></select>
|
||||
<i
|
||||
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
|
||||
id="Info_PRIMARY_TTS_LANGUAGE"
|
||||
tip="When the selected language is detected Your Primary TTS voice will sound"
|
||||
></i>
|
||||
</div>
|
||||
<div class="AdvancedMenuRow outputToTtsInput">
|
||||
<div class="AdvancedMenuLabel">2<sup>nd</sup> TTS service language</div>
|
||||
<select class="menu-select" name="secondaryLanguage" id="secondaryLanguage" tip="Language Service to use"></select>
|
||||
<i
|
||||
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
|
||||
id="Info_SECONDARY_TTS_LANGUAGE"
|
||||
tip="When the selected language is detected Your Secondary TTS voice will sound"
|
||||
></i>
|
||||
</div>
|
||||
<div class="AdvancedMenuRow languageDetectionInput">
|
||||
<div class="AdvancedMenuLabel">Translate chat messages to</div>
|
||||
<select class="menu-select" name="language" id="TRANSLATE_TO" tip="Language Service to use"></select>
|
||||
</div>
|
||||
<div class="AdvancedMenuRow languageDetectionInput TRANSLATE_TO">
|
||||
<div class="AdvancedMenuLabel">Broadcast translation to chat</div>
|
||||
<input type="checkbox" id="BROADCAST_TRANSLATION" class="checkbox TRANSLATE_TO" />
|
||||
<label for="BROADCAST_TRANSLATION" class="toggle-small"></label>
|
||||
</div>
|
||||
<div class="AdvancedMenuRow languageDetectionInput TRANSLATE_TO">
|
||||
<div class="AdvancedMenuLabel">Output translation to TTS</div>
|
||||
<input type="checkbox" id="OUTPUT_TO_TTS" class="checkbox TRANSLATE_TO" />
|
||||
<label for="OUTPUT_TO_TTS" class="toggle-small"></label>
|
||||
<i
|
||||
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
|
||||
id="Info_OUTPUT_TO_TTS"
|
||||
tip="All translated messages will be send to primary TTS voice but if message is detected in Secondary TTS language it will output it to the Secondary TTS voice"
|
||||
></i>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* global settings, sound, twitch, getLanguageProperties, addSingleTooltip, showChatMessage, languageObject, addVoiceService, internalVoices, ttsRequestCount, main, path, pythonPath, settingsPath, ipcRenderer */
|
||||
/* global settings, resourcesPath, sound, twitch, getLanguageProperties, addSingleTooltip, showChatMessage, languageObject, addVoiceService, internalVoices, ttsRequestCount, main, path, pythonPath, settingsPath, ipcRenderer */
|
||||
|
||||
const spawn = require('child_process').spawn;
|
||||
const kill = require('kill-process-by-name');
|
||||
|
|
@ -45,6 +45,7 @@ async function getInstalledVoices() {
|
|||
}
|
||||
|
||||
function setTranslatedMessage(message) {
|
||||
if (message.language.selectedLanguage.ISO639 !== message.language.detectedLanguage.ISO639) {
|
||||
const messageBox = document.getElementById(message.messageId).getElementsByClassName('msg-box')[0];
|
||||
|
||||
const translationHeader = document.createElement('div');
|
||||
|
|
@ -56,8 +57,8 @@ function setTranslatedMessage(message) {
|
|||
translationIcon.className = 'translation-icon';
|
||||
const languageElement = document.createElement('span');
|
||||
const language = getLanguageProperties(settings.LANGUAGE.TRANSLATE_TO);
|
||||
languageElement.classList = `fi fi-${language.ISO3166} fis`;
|
||||
languageElement.setAttribute('tip', language.name);
|
||||
languageElement.classList = `fi fi-${message.language.selectedLanguage.ISO3166} fis`;
|
||||
languageElement.setAttribute('tip', message.language.selectedLanguage.name);
|
||||
addSingleTooltip(languageElement);
|
||||
translationIcon.appendChild(languageElement);
|
||||
messageBox.appendChild(translationIcon);
|
||||
|
|
@ -67,13 +68,16 @@ function setTranslatedMessage(message) {
|
|||
translationMessage.innerText = message.translation;
|
||||
messageBox.appendChild(translationMessage);
|
||||
showChatMessage();
|
||||
}
|
||||
|
||||
if (settings.LANGUAGE.OUTPUT_TO_TTS) {
|
||||
sound.playVoice({
|
||||
originalMessage: message.originalMessage,
|
||||
filteredMessage: message.translation,
|
||||
logoUrl: message.logoUrl,
|
||||
username: message.username,
|
||||
formattedMessage: message.formattedMessage,
|
||||
language
|
||||
language: message.language
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -86,7 +90,7 @@ async function getTranslatedMessage(message) {
|
|||
},
|
||||
body: JSON.stringify({
|
||||
message: message.message,
|
||||
language: message.language
|
||||
language: message.language.detectedLanguage.IETF
|
||||
}) // Convert the data to JSON and include it in the request body
|
||||
};
|
||||
|
||||
|
|
@ -97,15 +101,18 @@ async function getTranslatedMessage(message) {
|
|||
|
||||
console.log('Translated message:', responseData);
|
||||
setTranslatedMessage({
|
||||
originalMessage: message.message,
|
||||
translation: responseData.translation,
|
||||
messageId: message.messageId,
|
||||
ISO3166: message.ISO3166,
|
||||
language: message.language,
|
||||
formattedMessage: message.formattedMessage,
|
||||
username: message.username,
|
||||
logoUrl: message.logoUrl
|
||||
});
|
||||
if (settings.LANGUAGE.BROADCAST_TRANSLATION) {
|
||||
twitch.sendMessage(`[${message.language} > ${settings.LANGUAGE.TRANSLATE_TO}] @${message.username}: ${responseData.translation}`);
|
||||
twitch.sendMessage(
|
||||
`[${message.language.detectedLanguage.name} ${message.language.detectedLanguage.ISO639} > ${message.language.selectedLanguage.name} ${message.language.selectedLanguage.ISO639}] @${message.username}: ${responseData.translation}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
console.error('Failed to send termination signal to Flask server.');
|
||||
|
|
@ -119,19 +126,40 @@ async function getTranslatedMessage(message) {
|
|||
}
|
||||
|
||||
function filterLanguage(message) {
|
||||
const language = getLanguageProperties(message.language);
|
||||
|
||||
if (settings.LANGUAGE.TRANSLATE_TO !== 'none') {
|
||||
const selectedPrimaryLanguage = getLanguageProperties(settings.LANGUAGE.TRANSLATE_TO);
|
||||
const selectedPrimaryLanguageIndex =
|
||||
message.languages.indexOf(selectedPrimaryLanguage.ISO639) === -1 ? 99 : message.languages.indexOf(selectedPrimaryLanguage.ISO639);
|
||||
const selectedSecondaryLanguage = getLanguageProperties(settings.TTS.SECONDARY_TTS_LANGUAGE);
|
||||
const selectedSecondaryLanguageIndex =
|
||||
message.languages.indexOf(selectedSecondaryLanguage.ISO639) === -1 ? 99 : message.languages.indexOf(selectedSecondaryLanguage.ISO639);
|
||||
const detectedLanguage = getLanguageProperties(message.languages[0]);
|
||||
const language = selectedPrimaryLanguageIndex < selectedSecondaryLanguageIndex ? selectedPrimaryLanguage : detectedLanguage;
|
||||
if (settings.LANGUAGE.TRANSLATE_TO !== 'none' && selectedPrimaryLanguage.ISO639 !== detectedLanguage.ISO639) {
|
||||
getTranslatedMessage({
|
||||
message: message.message,
|
||||
messageId: message.messageId,
|
||||
language: language.IETF,
|
||||
ISO3166: language.ISO3166,
|
||||
language: {
|
||||
selectedLanguage: selectedPrimaryLanguage,
|
||||
detectedLanguage
|
||||
},
|
||||
username: message.username,
|
||||
formattedMessage: message.formattedMessage
|
||||
formattedMessage: message.formattedMessage,
|
||||
logoUrl: message.logoUrl
|
||||
});
|
||||
} else {
|
||||
setTranslatedMessage({
|
||||
originalMessage: message.message,
|
||||
translation: message.message,
|
||||
messageId: message.messageId,
|
||||
language: {
|
||||
selectedLanguage: selectedPrimaryLanguage,
|
||||
detectedLanguage: selectedPrimaryLanguage
|
||||
},
|
||||
formattedMessage: message.formattedMessage,
|
||||
username: message.username,
|
||||
logoUrl: message.logoUrl
|
||||
});
|
||||
}
|
||||
|
||||
return language;
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +183,7 @@ async function getDetectedLanguage(message) {
|
|||
|
||||
console.log('Detected Languages:', responseData);
|
||||
return filterLanguage({
|
||||
language: responseData.languages[0],
|
||||
languages: responseData.languages,
|
||||
message: message.message,
|
||||
messageId: message.messageId,
|
||||
username: message.username,
|
||||
|
|
@ -232,7 +260,7 @@ const createBackendServer = () =>
|
|||
if (main.isPackaged) {
|
||||
python = spawn(path.join(pythonPath, './loquendoBot_backend.exe'), [settingsPath, 'prod']);
|
||||
} else {
|
||||
python = spawn('python', ['-u', path.join(pythonPath, './loquendoBot_backend.py'), settingsPath, 'dev']);
|
||||
python = spawn('python', ['-u', path.join(resourcesPath, '../backend/loquendoBot_backend.py'), settingsPath, 'dev']);
|
||||
}
|
||||
// Capture the stdout of the Python process
|
||||
python.stdout.on('data', data => {
|
||||
|
|
@ -266,7 +294,7 @@ async function initiateBackend() {
|
|||
createBackendServer().then(() => {
|
||||
getBackendServerStatus();
|
||||
getInstalledVoices();
|
||||
if (settings.STT.USE_STT) {
|
||||
if (settings.STT.USE_STT && !settings.STT.LANGUAGE === '') {
|
||||
startSTT();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ const languages = {
|
|||
'crimean tatar': { IETF: 'crh-RU', ISO639: 'crh', ISO3166: 'tr' },
|
||||
'crioulo upper guinea': { IETF: 'pov-GW', ISO639: 'pov', ISO3166: 'gw' },
|
||||
croatian: { IETF: 'hr-HR', ISO639: 'hr', ISO3166: 'hr' },
|
||||
'serbo-croatian': { IETF: 'sr-Cyrl-RS', ISO639: 'sh', ISO3166: 'sr' },
|
||||
czech: { IETF: 'cs-CZ', ISO639: 'cs', ISO3166: 'cz' },
|
||||
danish: { IETF: 'da-DK', ISO639: 'da', ISO3166: 'dk' },
|
||||
dari: { IETF: 'prs-AF', ISO639: 'prs', ISO3166: 'af' },
|
||||
|
|
@ -108,6 +109,7 @@ const languages = {
|
|||
garo: { IETF: 'grt-IN', ISO639: 'grt', ISO3166: 'in' },
|
||||
georgian: { IETF: 'ka-GE', ISO639: 'ka', ISO3166: 'ge' },
|
||||
german: { IETF: 'de-DE', ISO639: 'de', ISO3166: 'de' },
|
||||
'Low German': { IETF: 'nl-NL', ISO639: 'nds', ISO3166: 'nl' },
|
||||
gilbertese: { IETF: 'gil-KI', ISO639: 'gil', ISO3166: 'ki' },
|
||||
glavda: { IETF: 'glw-NG', ISO639: 'glw', ISO3166: 'ng' },
|
||||
greek: { IETF: 'el-GR', ISO639: 'el', ISO3166: 'gr' },
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable no-unused-vars */
|
||||
const fs = require('fs');
|
||||
const ini = require('ini');
|
||||
const path = require('path'); // get directory path
|
||||
|
|
@ -49,8 +50,8 @@ const config = require(path.join(__dirname, './js/settings'));
|
|||
|
||||
const mediaDevices = require(path.join(__dirname, './js/mediaDevices'));
|
||||
|
||||
const notificationSounds = path.join(__dirname, './sounds/notifications');
|
||||
const sttModels = path.join(__dirname, '../speech_to_text_models');
|
||||
const notificationSounds = path.join(resourcesPath, main.isPackaged ? './sounds/notifications' : '../sounds/notifications');
|
||||
const sttModels = path.join(resourcesPath, main.isPackaged ? './speech_to_text_models' : '../speech_to_text_models');
|
||||
|
||||
function reset() {
|
||||
ipcRenderer.send('restart');
|
||||
|
|
@ -233,10 +234,10 @@ function showChatMessage(article) {
|
|||
document.querySelector('#chatBox').appendChild(article);
|
||||
}
|
||||
|
||||
const messages = Array.from(document.body.querySelectorAll('.msg-container'));
|
||||
const messages = document.body.querySelectorAll('.msg-container');
|
||||
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
lastMessage.scrollIntoView({ behavior: 'smooth' });
|
||||
lastMessage.scrollIntoView();
|
||||
}
|
||||
|
||||
function getPostTime() {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* global settings, setZoomLevel, webFrame, theme, fs, settingsPath, ini, startVoiceRecognition,notificationSoundAudioDevices, ttsAudioDevices, notificationSound, path, resourcesPath, ipcRenderer, auth, shell, sound, twitch, server, backend */
|
||||
/* global settings,main sttModels, setZoomLevel, webFrame, theme, fs, settingsPath, ini, startVoiceRecognition,notificationSoundAudioDevices, ttsAudioDevices, notificationSound, path, resourcesPath, ipcRenderer, auth, shell, sound, twitch, server, backend */
|
||||
|
||||
function getGeneralSettings() {
|
||||
// General
|
||||
|
|
@ -130,10 +130,34 @@ document.body.querySelector('#language').addEventListener('change', () => {
|
|||
createNotification('Saved language!', 'success');
|
||||
});
|
||||
|
||||
function setTranslateToOptions() {
|
||||
const options = document.querySelectorAll('.TRANSLATE_TO');
|
||||
const index = parseInt(settings.LANGUAGE.TRANSLATE_TO_INDEX);
|
||||
|
||||
if (index === 0) {
|
||||
settings.LANGUAGE.BROADCAST_TRANSLATION = false;
|
||||
settings.LANGUAGE.OUTPUT_TO_TTS = false;
|
||||
options.forEach(item => {
|
||||
item.style.visibility = 'hidden';
|
||||
item.style.height = '0px';
|
||||
item.checked = false;
|
||||
});
|
||||
} else {
|
||||
options.forEach(item => {
|
||||
item.style.visibility = '';
|
||||
item.style.height = '';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setTranslateToOptions();
|
||||
|
||||
document.body.querySelector('#TRANSLATE_TO').addEventListener('change', () => {
|
||||
const select = document.querySelector('#TRANSLATE_TO');
|
||||
settings.LANGUAGE.TRANSLATE_TO_INDEX = select.selectedIndex;
|
||||
settings.LANGUAGE.TRANSLATE_TO = select.options[select.selectedIndex].value;
|
||||
setTranslateToOptions();
|
||||
|
||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||
createNotification('Saved primary voice!', 'success');
|
||||
});
|
||||
|
|
@ -227,7 +251,9 @@ function createNotification(message = null, type = null) {
|
|||
}
|
||||
|
||||
if (settings.AUDIO.USE_NOTIFICATION_SOUNDS) {
|
||||
const notfication = new Audio(path.join(resourcesPath, `./sounds/notifications/${alertSound}`));
|
||||
const notfication = new Audio(
|
||||
path.join(resourcesPath, main.isPackaged ? `./sounds/notifications/${alertSound}` : `../sounds/notifications/${alertSound}`)
|
||||
);
|
||||
notfication.volume = settings.AUDIO.NOTIFICATION_VOLUME / 100;
|
||||
notfication.play();
|
||||
}
|
||||
|
|
@ -268,6 +294,10 @@ document.body.querySelector('#OPEN_SETTINGS_FILE').addEventListener('click', ()
|
|||
shell.openExternal(settingsPath);
|
||||
});
|
||||
|
||||
document.body.querySelector('#Info_VOICE_MODELS_FOLDER').addEventListener('click', () => {
|
||||
shell.openExternal(sttModels);
|
||||
});
|
||||
|
||||
// #region Use Custom theme toggle logic
|
||||
document.body.querySelector('#USE_CUSTOM_THEME').addEventListener('click', () => {
|
||||
const toggle = document.getElementById('USE_CUSTOM_THEME').checked;
|
||||
|
|
@ -488,14 +518,6 @@ document.body.querySelector('#USE_STT').addEventListener('change', () => {
|
|||
createNotification(`${toggle ? 'Enabled' : 'Disabled'} speech to text!`, 'success');
|
||||
});
|
||||
|
||||
function toggleOutputToTts() {
|
||||
const toggle = settings.LANGUAGE.OUTPUT_TO_TTS;
|
||||
const inputs = document.getElementsByClassName('outputToTtsInput');
|
||||
toggleRadio(toggle, inputs);
|
||||
}
|
||||
|
||||
toggleOutputToTts();
|
||||
|
||||
document.body.querySelector('#OUTPUT_TO_TTS').addEventListener('change', () => {
|
||||
let toggle = document.getElementById('OUTPUT_TO_TTS').checked;
|
||||
if (!settings.TTS.USE_TTS) {
|
||||
|
|
@ -505,8 +527,6 @@ document.body.querySelector('#OUTPUT_TO_TTS').addEventListener('change', () => {
|
|||
}
|
||||
|
||||
settings.LANGUAGE.OUTPUT_TO_TTS = toggle;
|
||||
const inputs = document.getElementsByClassName('outputToTtsInput');
|
||||
toggleRadio(toggle, inputs);
|
||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||
createNotification(`${toggle ? 'Enabled' : 'Disabled'} Outputting translations to TTS!`, 'success');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* global ttsAudioFile, path, getLanguageProperties, resourcesPath, settings, fs, notificationSound, backend, socket, requestData */
|
||||
/* global ttsAudioFile, main, path, getLanguageProperties, resourcesPath, settings, fs, notificationSound, backend, socket, requestData */
|
||||
|
||||
const voiceSoundArray = [];
|
||||
let status = 0;
|
||||
|
|
@ -6,7 +6,10 @@ const counter = 0;
|
|||
|
||||
const playTTS = data =>
|
||||
new Promise(resolve => {
|
||||
ttsAudioFile = path.join(resourcesPath, `./sounds/tts/${data.service}_${data.count}.mp3`);
|
||||
ttsAudioFile = path.join(
|
||||
resourcesPath,
|
||||
main.isPackaged ? `./sounds/${data.service}_${data.count}.mp3` : `../sounds/${data.service}_${data.count}.mp3`
|
||||
);
|
||||
const tts = new Audio(ttsAudioFile);
|
||||
tts.setSinkId(settings.AUDIO.TTS_AUDIO_DEVICE);
|
||||
|
||||
|
|
@ -58,7 +61,12 @@ function add(data) {
|
|||
function playNotificationSound() {
|
||||
if (settings.AUDIO.USE_NOTIFICATION_SOUNDS) {
|
||||
const notfication = new Audio(
|
||||
path.join(resourcesPath, `./sounds/notifications/${notificationSound.options[settings.AUDIO.NOTIFICATION_SOUND].text}`)
|
||||
path.join(
|
||||
resourcesPath,
|
||||
main.isPackaged
|
||||
? `./sounds/notifications/${notificationSound.options[settings.AUDIO.NOTIFICATION_SOUND].text}`
|
||||
: `../sounds/notifications/${notificationSound.options[settings.AUDIO.NOTIFICATION_SOUND].text}`
|
||||
)
|
||||
);
|
||||
|
||||
notfication
|
||||
|
|
@ -93,10 +101,11 @@ async function playVoice(message) {
|
|||
let voice = settings.TTS.PRIMARY_VOICE;
|
||||
textObject.filtered = `${message.username}: ${message.filteredMessage}`;
|
||||
|
||||
if (settings.LANGUAGE.USE_DETECTION && settings.TTS.SECONDARY_VOICE && settings.LANGUAGE.OUTPUT_TO_TTS) {
|
||||
if (settings.LANGUAGE.USE_DETECTION && settings.TTS.SECONDARY_VOICE) {
|
||||
const secondaryTTSLanguage = getLanguageProperties(settings.TTS.SECONDARY_TTS_LANGUAGE);
|
||||
if (message.language.ISO639 === secondaryTTSLanguage.ISO639) {
|
||||
if (message.language.detectedLanguage === null || message.language.detectedLanguage.ISO639 === secondaryTTSLanguage.ISO639) {
|
||||
voice = settings.TTS.SECONDARY_VOICE;
|
||||
textObject.filtered = message.originalMessage ? message.originalMessage : message.filteredMessage;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ function ping(element) {
|
|||
}
|
||||
|
||||
async function displayTwitchMessage(logoUrl, username, messageObject, filteredMessage) {
|
||||
messageId++;
|
||||
const article = document.createElement('article');
|
||||
article.className = 'msg-container sender';
|
||||
article.setAttribute('id', messageId);
|
||||
|
|
@ -144,7 +145,13 @@ async function displayTwitchMessage(logoUrl, username, messageObject, filteredMe
|
|||
showChatMessage(article);
|
||||
|
||||
if (filteredMessage && !settings.LANGUAGE.OUTPUT_TO_TTS) {
|
||||
sound.playVoice({ filteredMessage, logoUrl, username, formattedMessage, language });
|
||||
sound.playVoice({
|
||||
filteredMessage,
|
||||
logoUrl,
|
||||
username,
|
||||
formattedMessage,
|
||||
language: { selectedLanguage: null, detectedLanguage: language }
|
||||
});
|
||||
}
|
||||
|
||||
window.article = article;
|
||||
|
|
@ -159,7 +166,6 @@ async function displayTwitchMessage(logoUrl, username, messageObject, filteredMe
|
|||
window.article = article;
|
||||
}
|
||||
|
||||
messageId++;
|
||||
sound.playNotificationSound();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,11 +24,6 @@ if (app.isPackaged) {
|
|||
pythonPath = path.join(resourcesPath, './backend');
|
||||
}
|
||||
|
||||
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||
if (require('electron-squirrel-startup')) {
|
||||
app.quit();
|
||||
}
|
||||
|
||||
async function createWindow() {
|
||||
if (!fs.existsSync(settingsPath)) {
|
||||
console.log(resourcesPath);
|
||||
|
|
@ -164,7 +159,7 @@ async function createIniFile() {
|
|||
MICROPHONE_ID: 'default',
|
||||
SELECTED_MICROPHONE: 'default',
|
||||
MICROPHONE: 0,
|
||||
LANGUAGE: 'vosk-model-small-es-0.42'
|
||||
LANGUAGE: ''
|
||||
},
|
||||
AUDIO: {
|
||||
USE_NOTIFICATION_SOUNDS: false,
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in a new issue