Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
401c7cc59d |
7 changed files with 57 additions and 100 deletions
|
|
@ -13,16 +13,16 @@ logger.setLevel(logging.INFO)
|
|||
gevent.monkey.patch_all()
|
||||
# import gevent.queue
|
||||
|
||||
import configparser
|
||||
import pyttsx3
|
||||
import sys
|
||||
import os
|
||||
|
||||
import queue
|
||||
import sys
|
||||
import sounddevice as sd
|
||||
|
||||
import fasttext
|
||||
# import fasttext
|
||||
from lingua import Language, LanguageDetectorBuilder
|
||||
detector = LanguageDetectorBuilder.from_all_spoken_languages().build()
|
||||
|
||||
from deep_translator import (
|
||||
MyMemoryTranslator,
|
||||
|
|
@ -39,7 +39,6 @@ app = Flask(__name__)
|
|||
|
||||
if len(sys.argv) > 1:
|
||||
settingsPath = os.path.normpath(sys.argv[1])
|
||||
|
||||
environment = sys.argv[2]
|
||||
|
||||
q = queue.Queue()
|
||||
|
|
@ -53,31 +52,11 @@ def loadSettings():
|
|||
|
||||
# classes
|
||||
class LanguageDetection:
|
||||
def __init__(self):
|
||||
if environment == "dev":
|
||||
settings_folder = os.path.dirname(settingsPath)
|
||||
src_folder = os.path.dirname(settings_folder)
|
||||
main_folder = os.path.dirname(src_folder)
|
||||
language_detection_model = os.path.join(
|
||||
main_folder, "language_detection_model", f"lid.176.bin"
|
||||
)
|
||||
else:
|
||||
resources_folder = os.path.dirname(settingsPath)
|
||||
language_detection_model = os.path.join(
|
||||
resources_folder, "language_detection_model", f"lid.176.bin"
|
||||
)
|
||||
|
||||
language_detection_model = rf"{language_detection_model}"
|
||||
self.model = fasttext.load_model(language_detection_model)
|
||||
|
||||
def predict_lang(self, text):
|
||||
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__", ""))
|
||||
|
||||
return language_codes
|
||||
|
||||
language = detector.compute_language_confidence_values(text)
|
||||
top_languages = [confidence.language.iso_code_639_1.name.lower() for confidence in language[:5]]
|
||||
# result = ','.join(top_languages)
|
||||
return top_languages
|
||||
|
||||
class STT:
|
||||
samplerate = None
|
||||
|
|
@ -146,9 +125,6 @@ if settings["STT"]["USE_STT"] and settings["STT"]["LANGUAGE"] != '':
|
|||
|
||||
|
||||
class TTS:
|
||||
engine = None
|
||||
rate = None
|
||||
|
||||
def __init__(self):
|
||||
self.engine = pyttsx3.init()
|
||||
|
||||
|
|
@ -212,7 +188,8 @@ def terminate_processes():
|
|||
|
||||
|
||||
def shutdown_server():
|
||||
func = request.environ.get("sever shutdown")
|
||||
# func = request.environ.get("sever shutdown")
|
||||
func = request.environ.get("werkzeug.server.shutdown")
|
||||
if func is None:
|
||||
raise RuntimeError("Server is not running")
|
||||
func()
|
||||
|
|
@ -229,27 +206,28 @@ def get_language():
|
|||
request_data = request.json
|
||||
message = request_data.get("message", "")
|
||||
lang = LanguageDetection().predict_lang(message)
|
||||
|
||||
return jsonify({"languages": lang}), 200
|
||||
except Exception as e:
|
||||
return jsonify({"error": "An error occurred"}), 500
|
||||
return jsonify({"languages": lang}), 200
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route("/translate", methods=["POST"])
|
||||
def get_translation():
|
||||
loadSettings()
|
||||
request_data = request.json
|
||||
message = request_data.get("message", "")
|
||||
detectedLanguage = request_data.get("language", "")
|
||||
try:
|
||||
# try:
|
||||
translated = MyMemoryTranslator(
|
||||
source=detectedLanguage, target=settings["LANGUAGE"]["TRANSLATE_TO"]
|
||||
).translate(message)
|
||||
# except Exception as e:
|
||||
# return jsonify({"error": str(e), "code":429 }), 429
|
||||
loadSettings()
|
||||
request_data = request.json
|
||||
message = request_data.get("message", "")
|
||||
detectedLanguage = request_data.get("language", "")
|
||||
|
||||
translated = MyMemoryTranslator(
|
||||
source=detectedLanguage, target=settings["LANGUAGE"]["TRANSLATE_TO"]
|
||||
).translate(message)
|
||||
|
||||
return jsonify({"translation": translated}), 200
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e), "code":500 }), 500
|
||||
return jsonify({"translation": translated}), 200
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route("/audio", methods=["POST"])
|
||||
|
|
@ -266,7 +244,7 @@ def trigger_backend_event():
|
|||
count = request_data.get("count")
|
||||
text_to_speech_service.say(filteredMessage, voice, count)
|
||||
except Exception as e:
|
||||
return jsonify({"error": e}), 500
|
||||
return jsonify({"error": str(e)}), 500
|
||||
return jsonify({"message": "Audio triggered"}), 200
|
||||
|
||||
|
||||
|
|
@ -276,16 +254,10 @@ def get_voices():
|
|||
voices = text_to_speech_service.voices()
|
||||
return jsonify({"voices": voices}), 200
|
||||
except Exception as e:
|
||||
return jsonify({"error": e}), 500
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
loadSettings()
|
||||
port = int(settings["GENERAL"]["PORT"])
|
||||
else:
|
||||
environment = "dev"
|
||||
port = 9000
|
||||
stream_recognition()
|
||||
|
||||
loadSettings()
|
||||
port = int(settings["GENERAL"]["PORT"]) if len(sys.argv) > 1 else 9000
|
||||
serve(app, host="0.0.0.0", port=port)
|
||||
|
|
|
|||
|
|
@ -45,6 +45,5 @@ After getting your credentials you can set it in <img src="https://raw.githubuse
|
|||
* [Speech2Go](https://harposoftware.com/en/spanish-spain-/340-S2G-Jorge-Nuance-Voice.html).
|
||||
### Linux
|
||||
* WIP
|
||||
|
||||
### Mac
|
||||
* WIP
|
||||
* WIP
|
||||
BIN
sounds/Internal_17.mp3
Normal file
BIN
sounds/Internal_17.mp3
Normal file
Binary file not shown.
BIN
sounds/Internal_19.mp3
Normal file
BIN
sounds/Internal_19.mp3
Normal file
Binary file not shown.
|
|
@ -75,16 +75,14 @@ function setTranslatedUserMessage(message) {
|
|||
function setTranslatedMessage(message) {
|
||||
// this determines if it is a message that is send by a user
|
||||
const languageBox = document.getElementById(message.messageId).getElementsByClassName('language-icon flag-icon')[0];
|
||||
// if (false) {
|
||||
// if (!languageBox) {
|
||||
// twitch.sendMessage(
|
||||
// `[${message.language.detectedLanguage.name} ${message.language.detectedLanguage.ISO639} > ${message.language.selectedLanguage.name} ${message.language.selectedLanguage.ISO639}] @${settings.TWITCH.USERNAME}: ${message.translation}`
|
||||
// );
|
||||
// return setTranslatedUserMessage(message);
|
||||
// }
|
||||
|
||||
if (message.language.selectedLanguage.ISO639 !== message.language.detectedLanguage.ISO639) {
|
||||
const messageBox = document.getElementById(message.messageId).getElementsByClassName('msg-box')[0];
|
||||
|
||||
languageBox.classList = `fi fi-${message.language.detectedLanguage.ISO3166} fis language-icon flag-icon`;
|
||||
languageBox.setAttribute('tip', message.language.detectedLanguage.name);
|
||||
|
||||
|
|
@ -113,7 +111,6 @@ function setTranslatedMessage(message) {
|
|||
lastMessage.scrollIntoView({ block: 'end', behavior: 'smooth' });
|
||||
}
|
||||
|
||||
console.log(message);
|
||||
if (settings.LANGUAGE.OUTPUT_TO_TTS) {
|
||||
sound.playVoice({
|
||||
originalMessage: message.originalMessage,
|
||||
|
|
@ -129,8 +126,6 @@ function setTranslatedMessage(message) {
|
|||
|
||||
async function getTranslatedMessage(message) {
|
||||
// TODO: translate primary language to
|
||||
console.log(message);
|
||||
console.log(message.isPrimaryLanguage ? message.language.selectedLanguage.IETF : message.language.detectedLanguage.IETF);
|
||||
const requestOptions = {
|
||||
method: 'POST', // HTTP method
|
||||
headers: {
|
||||
|
|
@ -146,8 +141,6 @@ async function getTranslatedMessage(message) {
|
|||
const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/translate`, requestOptions);
|
||||
const responseData = await response.json();
|
||||
if (response.ok) {
|
||||
console.log('Translated message:', responseData);
|
||||
|
||||
if (settings.LANGUAGE.BROADCAST_TRANSLATION) {
|
||||
twitch.sendMessage(
|
||||
`[${message.language.detectedLanguage.name} ${message.language.detectedLanguage.ISO639} > ${message.language.selectedLanguage.name} ${message.language.selectedLanguage.ISO639}] @${message.username}: ${responseData.translation}`
|
||||
|
|
@ -236,8 +229,6 @@ async function filterLanguage(message) {
|
|||
const language = selectedPrimaryLanguageIndex < selectedSecondaryLanguageIndex ? selectedPrimaryLanguage : detectedLanguage;
|
||||
|
||||
if (settings.LANGUAGE.TRANSLATE_TO !== 'none' && selectedPrimaryLanguage.ISO639 !== language.ISO639) {
|
||||
// console.log('1');
|
||||
console.log('hola');
|
||||
getTranslatedMessage({
|
||||
message: message.message,
|
||||
messageId: message.messageId,
|
||||
|
|
@ -252,8 +243,6 @@ async function filterLanguage(message) {
|
|||
logoUrl: message.logoUrl
|
||||
});
|
||||
} else {
|
||||
console.log('adios');
|
||||
// console.log('2');
|
||||
setTranslatedMessage({
|
||||
originalMessage: message.message,
|
||||
translation: message.message,
|
||||
|
|
@ -266,19 +255,6 @@ async function filterLanguage(message) {
|
|||
username: message.username,
|
||||
logoUrl: message.logoUrl
|
||||
});
|
||||
// getTranslatedMessage({
|
||||
// message: message.message,
|
||||
// messageId: message.messageId,
|
||||
// remainingDetectedLanguages: [],
|
||||
// isPrimaryLanguage: true,
|
||||
// language: {
|
||||
// selectedLanguage: selectedSecondaryLanguage,
|
||||
// detectedLanguage: selectedPrimaryLanguage
|
||||
// },
|
||||
// username: message.username,
|
||||
// formattedMessage: message.formattedMessage,
|
||||
// logoUrl: message.logoUrl
|
||||
// });
|
||||
}
|
||||
|
||||
return language;
|
||||
|
|
@ -299,9 +275,8 @@ async function getDetectedLanguage(message) {
|
|||
|
||||
try {
|
||||
const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/detect`, requestOptions);
|
||||
const responseData = await response.json();
|
||||
if (response.ok) {
|
||||
const responseData = await response.json();
|
||||
|
||||
console.log('Detected Languages:', responseData);
|
||||
return await filterLanguage({
|
||||
languages: responseData.languages,
|
||||
|
|
@ -311,7 +286,7 @@ async function getDetectedLanguage(message) {
|
|||
formattedMessage: message.formattedMessage
|
||||
});
|
||||
} else {
|
||||
console.error('Failed to send termination signal to Flask server.');
|
||||
console.error('error in detect call', responseData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error sending termination signal:', error);
|
||||
|
|
@ -321,11 +296,11 @@ async function getDetectedLanguage(message) {
|
|||
async function getBackendServerStatus() {
|
||||
try {
|
||||
const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/status`, { method: 'GET' });
|
||||
const responseData = await response.json();
|
||||
if (response.ok) {
|
||||
const responseData = await response.json();
|
||||
console.log('Status:', responseData);
|
||||
} else {
|
||||
console.error('Failed to send termination signal to Flask server.');
|
||||
console.error('Error in satus call:', responseData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error sending termination signal:', error);
|
||||
|
|
@ -364,12 +339,12 @@ async function getInternalTTSAudio(requestData) {
|
|||
|
||||
try {
|
||||
const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/audio`, requestOptions);
|
||||
const responseData = await response.json();
|
||||
if (response.ok) {
|
||||
const responseData = await response.json();
|
||||
console.log('Audio:', responseData);
|
||||
return ttsRequestCount;
|
||||
} else {
|
||||
console.error('Failed to send termination signal to Flask server.');
|
||||
console.error('Error in audio call: ', responseData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error sending termination signal:', error);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@ let client = null;
|
|||
let logoUrl = null;
|
||||
const twitchChannels = [];
|
||||
|
||||
function isTranslatedMessage(inputString) {
|
||||
const regex = /\[.*>.*\]/; // Adjusted regex to ensure it matches the entire string
|
||||
return regex.test(inputString);
|
||||
}
|
||||
|
||||
function sendMessage(message) {
|
||||
client.say(settings.TWITCH.CHANNEL_NAME, message).catch(console.error);
|
||||
}
|
||||
|
|
@ -31,6 +36,10 @@ if (settings.TWITCH.USERNAME && settings.TWITCH.OAUTH_TOKEN) {
|
|||
if (self || tags['display-name'] === settings.TWITCH.USERNAME) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTranslatedMessage(message)) {
|
||||
return;
|
||||
}
|
||||
const emotes = tags.emotes || {};
|
||||
const emoteValues = Object.entries(emotes);
|
||||
let filteredMessage = message;
|
||||
|
|
@ -46,8 +55,7 @@ if (settings.TWITCH.USERNAME && settings.TWITCH.OAUTH_TOKEN) {
|
|||
});
|
||||
|
||||
const messageObject = parseString(emoteMessage);
|
||||
|
||||
getProfileImage(tags['user-id'], tags['display-name'], messageObject, filteredMessage);
|
||||
getProfileImage(tags['username'], tags['display-name'], messageObject, filteredMessage);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +146,8 @@ async function displayTwitchMessage(logoUrl, username, messageObject, filteredMe
|
|||
showChatMessage(article);
|
||||
});
|
||||
|
||||
if (settings.LANGUAGE.USE_DETECTION && filteredMessage.length > 20 && countWords(filteredMessage) > 4) {
|
||||
if (settings.LANGUAGE.USE_DETECTION) {
|
||||
// && filteredMessage.length > 20 && countWords(filteredMessage) > 2
|
||||
await backend.getDetectedLanguage({ message: filteredMessage, messageId, username, logoUrl, formattedMessage }).then(language => {
|
||||
const languageElement = document.createElement('span');
|
||||
languageElement.classList = `fi fi-${language.ISO3166} fis language-icon flag-icon`;
|
||||
|
|
@ -155,25 +164,21 @@ async function displayTwitchMessage(logoUrl, username, messageObject, filteredMe
|
|||
language: { selectedLanguage: null, detectedLanguage: language }
|
||||
});
|
||||
}
|
||||
|
||||
// window.article = article;
|
||||
});
|
||||
} else {
|
||||
if (filteredMessage) {
|
||||
sound.playVoice({ filteredMessage, logoUrl, username, formattedMessage });
|
||||
}
|
||||
|
||||
// window.article = article;
|
||||
}
|
||||
|
||||
sound.playNotificationSound();
|
||||
}
|
||||
|
||||
function getProfileImage(userid, username, message, filteredMessage) {
|
||||
function getProfileImage(username, displayname, message, filteredMessage) {
|
||||
// Get user Logo with access token
|
||||
options = {
|
||||
method: 'GET',
|
||||
url: `https://api.twitch.tv/helix/users?id=${userid}`,
|
||||
url: `https://api.twitch.tv/helix/users?username=${username}`,
|
||||
headers: { 'Client-ID': settings.TWITCH.CLIENT_ID, Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}` }
|
||||
};
|
||||
|
||||
|
|
@ -181,7 +186,7 @@ function getProfileImage(userid, username, message, filteredMessage) {
|
|||
.request(options)
|
||||
.then(responseLogoUrl => {
|
||||
logoUrl = responseLogoUrl.data.data[0].profile_image_url;
|
||||
displayTwitchMessage(logoUrl, username, message, filteredMessage);
|
||||
displayTwitchMessage(logoUrl, displayname, message, filteredMessage);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
|
|
|
|||
6
xxx.py
Normal file
6
xxx.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from lingua import Language, LanguageDetectorBuilder
|
||||
detector = LanguageDetectorBuilder.from_all_spoken_languages().build()
|
||||
language = detector.compute_language_confidence_values("hello there juan")
|
||||
top_languages = [confidence.language.iso_code_639_1.name.lower() for confidence in language]
|
||||
|
||||
print(top_languages)
|
||||
Loading…
Reference in a new issue