From d83c0ad7534784823bda41dddf48b3ddca55c22d Mon Sep 17 00:00:00 2001 From: Khyretos Date: Wed, 3 Jan 2024 14:26:08 +0100 Subject: [PATCH] language detection fixes and installer change. --- .gitignore | 4 +- .../loquendoBot_backend.py | 26 ++--- forge.config.js | 36 ------- license => license.md | 4 +- package.json | 32 +++++- .../notifications/Tip Sound.mp3 | Bin {src/sounds => sounds}/notifications/coin.mp3 | Bin {src/sounds => sounds}/notifications/dice.mp3 | Bin .../sounds => sounds}/notifications/error.mp3 | Bin {src/sounds => sounds}/notifications/fail.wav | Bin {src/sounds => sounds}/notifications/info.mp3 | Bin .../sounds => sounds}/notifications/pling.mp3 | Bin .../notifications/spinjump.mp3 | Bin .../notifications/success.wav | Bin {src/sounds => sounds}/notifications/ting.mp3 | Bin .../Where to get STT models.txt | 4 +- src/css/home.css | 17 +--- src/images/icon.ico | Bin 35324 -> 29893 bytes src/index.html | 55 +++++++--- src/js/backend.js | 96 +++++++++++------- src/js/languages.js | 2 + src/js/renderer.js | 9 +- src/js/settings.js | 44 +++++--- src/js/sound.js | 19 +++- src/js/twitch.js | 10 +- src/main.js | 7 +- src/sounds/tts/Amazon_audio.mp3 | 0 src/sounds/tts/Google_audio.mp3 | Bin 5472 -> 0 bytes 28 files changed, 216 insertions(+), 149 deletions(-) rename {src/backend => backend}/loquendoBot_backend.py (92%) delete mode 100644 forge.config.js rename license => license.md (96%) rename {src/sounds => sounds}/notifications/Tip Sound.mp3 (100%) rename {src/sounds => sounds}/notifications/coin.mp3 (100%) rename {src/sounds => sounds}/notifications/dice.mp3 (100%) rename {src/sounds => sounds}/notifications/error.mp3 (100%) rename {src/sounds => sounds}/notifications/fail.wav (100%) rename {src/sounds => sounds}/notifications/info.mp3 (100%) rename {src/sounds => sounds}/notifications/pling.mp3 (100%) rename {src/sounds => sounds}/notifications/spinjump.mp3 (100%) rename {src/sounds => sounds}/notifications/success.wav (100%) rename {src/sounds => sounds}/notifications/ting.mp3 (100%) delete mode 100644 src/sounds/tts/Amazon_audio.mp3 delete mode 100644 src/sounds/tts/Google_audio.mp3 diff --git a/.gitignore b/.gitignore index 763e324..87c3a5b 100644 --- a/.gitignore +++ b/.gitignore @@ -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/* diff --git a/src/backend/loquendoBot_backend.py b/backend/loquendoBot_backend.py similarity index 92% rename from src/backend/loquendoBot_backend.py rename to backend/loquendoBot_backend.py index 919ff58..3bbde06 100644 --- a/src/backend/loquendoBot_backend.py +++ b/backend/loquendoBot_backend.py @@ -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) + settings_folder = os.path.dirname(settingsPath) if environment == "dev": - settings_folder = os.path.dirname(settingsPath) 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 diff --git a/forge.config.js b/forge.config.js deleted file mode 100644 index 78ea629..0000000 --- a/forge.config.js +++ /dev/null @@ -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: {}, - }, - ], -}; diff --git a/license b/license.md similarity index 96% rename from license rename to license.md index 7522c81..02cfa3d 100644 --- a/license +++ b/license.md @@ -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 @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/package.json b/package.json index 22e6cbc..4b8f5c2 100644 --- a/package.json +++ b/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", diff --git a/src/sounds/notifications/Tip Sound.mp3 b/sounds/notifications/Tip Sound.mp3 similarity index 100% rename from src/sounds/notifications/Tip Sound.mp3 rename to sounds/notifications/Tip Sound.mp3 diff --git a/src/sounds/notifications/coin.mp3 b/sounds/notifications/coin.mp3 similarity index 100% rename from src/sounds/notifications/coin.mp3 rename to sounds/notifications/coin.mp3 diff --git a/src/sounds/notifications/dice.mp3 b/sounds/notifications/dice.mp3 similarity index 100% rename from src/sounds/notifications/dice.mp3 rename to sounds/notifications/dice.mp3 diff --git a/src/sounds/notifications/error.mp3 b/sounds/notifications/error.mp3 similarity index 100% rename from src/sounds/notifications/error.mp3 rename to sounds/notifications/error.mp3 diff --git a/src/sounds/notifications/fail.wav b/sounds/notifications/fail.wav similarity index 100% rename from src/sounds/notifications/fail.wav rename to sounds/notifications/fail.wav diff --git a/src/sounds/notifications/info.mp3 b/sounds/notifications/info.mp3 similarity index 100% rename from src/sounds/notifications/info.mp3 rename to sounds/notifications/info.mp3 diff --git a/src/sounds/notifications/pling.mp3 b/sounds/notifications/pling.mp3 similarity index 100% rename from src/sounds/notifications/pling.mp3 rename to sounds/notifications/pling.mp3 diff --git a/src/sounds/notifications/spinjump.mp3 b/sounds/notifications/spinjump.mp3 similarity index 100% rename from src/sounds/notifications/spinjump.mp3 rename to sounds/notifications/spinjump.mp3 diff --git a/src/sounds/notifications/success.wav b/sounds/notifications/success.wav similarity index 100% rename from src/sounds/notifications/success.wav rename to sounds/notifications/success.wav diff --git a/src/sounds/notifications/ting.mp3 b/sounds/notifications/ting.mp3 similarity index 100% rename from src/sounds/notifications/ting.mp3 rename to sounds/notifications/ting.mp3 diff --git a/speech_to_text_models/Where to get STT models.txt b/speech_to_text_models/Where to get STT models.txt index d41ac68..21a635e 100644 --- a/speech_to_text_models/Where to get STT models.txt +++ b/speech_to_text_models/Where to get STT models.txt @@ -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. diff --git a/src/css/home.css b/src/css/home.css index 5dcccf6..07cf50a 100644 --- a/src/css/home.css +++ b/src/css/home.css @@ -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 { diff --git a/src/images/icon.ico b/src/images/icon.ico index 84862b24327fd45372e8435dd5ebca049972254d..5c324395e680abf93d8115b85f0966788a248299 100644 GIT binary patch literal 29893 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 T^^^8C0DhF@)Mcxs%|iYU``-^T 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
2nd Internal Voice
+
Test 2nd Internal Voice
@@ -235,8 +240,13 @@
-
Voice Language
+
Voice Language model
+
@@ -247,27 +257,42 @@
Enable Language detection
-
-
Translate chat messages to
- -
-
-
Broadcast translation to chat
- - -
-
-
Output translation to TTS
- - -
Default TTS service language
+
2nd TTS service language
+ +
+
+
Translate chat messages to
+ +
+
+
Broadcast translation to chat
+ + +
+
+
Output translation to TTS
+ + +
diff --git a/src/js/backend.js b/src/js/backend.js index 63e692e..751deb5 100644 --- a/src/js/backend.js +++ b/src/js/backend.js @@ -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,35 +45,39 @@ async function getInstalledVoices() { } function setTranslatedMessage(message) { - const messageBox = document.getElementById(message.messageId).getElementsByClassName('msg-box')[0]; + if (message.language.selectedLanguage.ISO639 !== message.language.detectedLanguage.ISO639) { + const messageBox = document.getElementById(message.messageId).getElementsByClassName('msg-box')[0]; - const translationHeader = document.createElement('div'); - translationHeader.className = 'translation-header'; - translationHeader.innerText = 'Translation'; - messageBox.appendChild(translationHeader); + const translationHeader = document.createElement('div'); + translationHeader.className = 'translation-header'; + translationHeader.innerText = 'Translation'; + messageBox.appendChild(translationHeader); - const translationIcon = document.createElement('div'); - 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); - addSingleTooltip(languageElement); - translationIcon.appendChild(languageElement); - messageBox.appendChild(translationIcon); + const translationIcon = document.createElement('div'); + translationIcon.className = 'translation-icon'; + const languageElement = document.createElement('span'); + const language = getLanguageProperties(settings.LANGUAGE.TRANSLATE_TO); + languageElement.classList = `fi fi-${message.language.selectedLanguage.ISO3166} fis`; + languageElement.setAttribute('tip', message.language.selectedLanguage.name); + addSingleTooltip(languageElement); + translationIcon.appendChild(languageElement); + messageBox.appendChild(translationIcon); + + const translationMessage = document.createElement('div'); + translationMessage.className = 'translation-message'; + translationMessage.innerText = message.translation; + messageBox.appendChild(translationMessage); + showChatMessage(); + } - const translationMessage = document.createElement('div'); - translationMessage.className = 'translation-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(); } }); diff --git a/src/js/languages.js b/src/js/languages.js index 2290568..9507f38 100644 --- a/src/js/languages.js +++ b/src/js/languages.js @@ -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' }, diff --git a/src/js/renderer.js b/src/js/renderer.js index c1264cd..db95f3a 100644 --- a/src/js/renderer.js +++ b/src/js/renderer.js @@ -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() { diff --git a/src/js/settings.js b/src/js/settings.js index 4f3afb6..40ffea2 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -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'); }); diff --git a/src/js/sound.js b/src/js/sound.js index ebbd573..6a570b7 100644 --- a/src/js/sound.js +++ b/src/js/sound.js @@ -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; } } diff --git a/src/js/twitch.js b/src/js/twitch.js index f293d2d..6fe09d0 100644 --- a/src/js/twitch.js +++ b/src/js/twitch.js @@ -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(); } diff --git a/src/main.js b/src/main.js index 499d2b6..fc584ac 100644 --- a/src/main.js +++ b/src/main.js @@ -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, diff --git a/src/sounds/tts/Amazon_audio.mp3 b/src/sounds/tts/Amazon_audio.mp3 deleted file mode 100644 index e69de29..0000000 diff --git a/src/sounds/tts/Google_audio.mp3 b/src/sounds/tts/Google_audio.mp3 deleted file mode 100644 index d7f31c8206c596304eb691dce9a72755ef52f276..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5472 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