language detection fixes and installer change.

This commit is contained in:
Khyretos 2024-01-03 14:26:08 +01:00
parent 5cfdd498c9
commit d83c0ad753
28 changed files with 216 additions and 149 deletions

4
.gitignore vendored
View file

@ -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/*

View file

@ -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

View file

@ -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: {},
},
],
};

View file

@ -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.
SOFTWARE.

View file

@ -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",

View file

@ -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.

View file

@ -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

View file

@ -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>

View file

@ -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();
}
});

View file

@ -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' },

View file

@ -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() {

View file

@ -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');
});

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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.