Merge branch 'refactoring' into develop

This commit is contained in:
misygauziya
2023-08-20 02:33:35 +09:00
14 changed files with 1088 additions and 912 deletions

631
VRCT.py
View File

@@ -1,43 +1,25 @@
from time import sleep
from os import path as os_path
from requests import get as requests_get
from queue import Queue
import customtkinter
from customtkinter import CTk, CTkFrame, CTkCheckBox, CTkFont, CTkButton, CTkImage, CTkTabview, CTkTextbox, CTkEntry
from PIL.Image import open as Image_open
from flashtext import KeywordProcessor
from threading import Thread
from utils import print_textbox, thread_fnc, get_localized_text, widget_main_window_label_setter
from osc_tools import send_typing, send_message, send_test_action, receive_osc_parameters
from utils import print_textbox, get_localized_text, widget_main_window_label_setter
from window_config import ToplevelWindowConfig
from window_information import ToplevelWindowInformation
from languages import transcription_lang
from audio_utils import get_input_device_list, get_output_device_list
from audio_recorder import SelectedMicRecorder, SelectedSpeakerRecorder
from audio_transcriber import AudioTranscriber
from translation import Translator
from config import config
from notification import notification_xsoverlay_for_vrct
__version__ = "1.3.2"
from model import model
class App(CTk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# init instance
self.translator = Translator()
self.keyword_processor = KeywordProcessor()
## set UI theme
customtkinter.set_appearance_mode(config.APPEARANCE_THEME)
customtkinter.set_default_color_theme("blue")
## flags
self.ENABLE_OSC = False
self.UPDATE_FLAG = False
# init main window
self.iconbitmap(os_path.join(os_path.dirname(__file__), "img", "app.ico"))
self.title("VRCT")
@@ -45,82 +27,12 @@ class App(CTk):
self.minsize(400, 175)
self.grid_columnconfigure(1, weight=1)
self.grid_rowconfigure(0, weight=1)
self.wm_attributes("-alpha", config.TRANSPARENCY/100)
customtkinter.set_widget_scaling(int(config.UI_SCALING.replace("%", "")) / 100)
self.protocol("WM_DELETE_WINDOW", self.delete_window)
# add sidebar left
self.sidebar_frame = CTkFrame(self, corner_radius=0)
self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsw")
self.sidebar_frame.grid_rowconfigure(5, weight=1)
init_lang_text = "Loading..."
# add checkbox translation
self.checkbox_translation = CTkCheckBox(
self.sidebar_frame,
text=init_lang_text,
onvalue=True,
offvalue=False,
command=self.checkbox_translation_callback,
font=CTkFont(family=config.FONT_FAMILY)
)
self.checkbox_translation.grid(row=0, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we")
# add checkbox transcription send
self.checkbox_transcription_send = CTkCheckBox(
self.sidebar_frame,
text=init_lang_text,
onvalue=True,
offvalue=False,
command=self.checkbox_transcription_send_callback,
font=CTkFont(family=config.FONT_FAMILY)
)
self.checkbox_transcription_send.grid(row=1, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we")
# add checkbox transcription receive
self.checkbox_transcription_receive = CTkCheckBox(
self.sidebar_frame,
text=init_lang_text,
onvalue=True,
offvalue=False,
command=self.checkbox_transcription_receive_callback,
font=CTkFont(family=config.FONT_FAMILY)
)
self.checkbox_transcription_receive.grid(row=2, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we")
# add checkbox foreground
self.checkbox_foreground = CTkCheckBox(
self.sidebar_frame,
text=init_lang_text,
onvalue=True,
offvalue=False,
command=self.checkbox_foreground_callback,
font=CTkFont(family=config.FONT_FAMILY)
)
self.checkbox_foreground.grid(row=3, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we")
# add button information
self.button_information = CTkButton(
self.sidebar_frame,
text=None,
width=36,
command=self.button_information_callback,
image=CTkImage(Image_open(os_path.join(os_path.dirname(__file__), "img", "info-icon-white.png")))
)
self.button_information.grid(row=5, column=0, padx=(10, 5), pady=(5, 5), sticky="wse")
# add button config
self.button_config = CTkButton(
self.sidebar_frame,
text=None,
width=36,
command=self.button_config_callback,
image=CTkImage(Image_open(os_path.join(os_path.dirname(__file__), "img", "config-icon-white.png")))
)
self.button_config.grid(row=5, column=1, padx=(5, 10), pady=(5, 5), sticky="wse")
# load ui language data
language_yaml_data = get_localized_text(f"{config.UI_LANGUAGE}")
# add tabview textbox
self.add_tabview_logs(language_yaml_data)
# add sidebar
self.add_sidebar()
# add entry message box
self.entry_message_box = CTkEntry(
@@ -129,77 +41,28 @@ class App(CTk):
font=CTkFont(family=config.FONT_FAMILY),
)
self.entry_message_box.grid(row=1, column=1, columnspan=2, padx=5, pady=(5, 10), sticky="nsew")
# set default values
## set translator
if self.translator.authentication(config.CHOICE_TRANSLATOR, config.AUTH_KEYS[config.CHOICE_TRANSLATOR]) is False:
# error update Auth key
print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
# ## set checkbox enable translation
# if self.ENABLE_TRANSLATION:
# self.checkbox_translation.select()
# self.checkbox_translation_callback()
# else:
# self.checkbox_translation.deselect()
# ## set checkbox enable transcription send
# if self.ENABLE_TRANSCRIPTION_SEND:
# self.checkbox_transcription_send.select()
# self.checkbox_transcription_send_callback()
# else:
# self.checkbox_transcription_send.deselect()
# ## set checkbox enable transcription receive
# if self.ENABLE_TRANSCRIPTION_RECEIVE:
# self.checkbox_transcription_receive.select()
# self.checkbox_transcription_receive_callback()
# else:
# self.checkbox_transcription_receive.deselect()
# ## set set checkbox enable foreground
# if self.ENABLE_FOREGROUND:
# self.checkbox_foreground.select()
# self.checkbox_foreground_callback()
# else:
# self.checkbox_foreground.deselect()
## set word filter
for f in config.INPUT_MIC_WORD_FILTER:
self.keyword_processor.add_keyword(f)
## set bind entry message box
self.entry_message_box.bind("<Return>", self.entry_message_box_press_key_enter)
self.entry_message_box.bind("<Any-KeyPress>", self.entry_message_box_press_key_any)
self.entry_message_box.bind("<Leave>", self.entry_message_box_leave)
## set transparency for main window
self.wm_attributes("-alpha", config.TRANSPARENCY/100)
## set UI scale
new_scaling_float = int(config.UI_SCALING.replace("%", "")) / 100
customtkinter.set_widget_scaling(new_scaling_float)
# delete window
self.protocol("WM_DELETE_WINDOW", self.delete_window)
# add tabview textbox
self.add_tabview_logs(get_localized_text(f"{config.UI_LANGUAGE}"))
self.config_window = ToplevelWindowConfig(self)
self.information_window = ToplevelWindowInformation(self)
self.init_process()
# start receive osc
th_receive_osc_parameters = Thread(target=receive_osc_parameters, args=(self.check_osc_receive,))
th_receive_osc_parameters.daemon = True
th_receive_osc_parameters.start()
def init_process(self):
# set translator
if model.authenticationTranslator() is False:
# error update Auth key
self.printLogAuthenticationError()
# check osc started
send_test_action()
# set word filter
model.addKeywords()
# check update
response = requests_get("https://api.github.com/repos/misyaguziya/VRCT/releases/latest")
tag_name = response.json()["tag_name"]
if tag_name != __version__:
self.UPDATE_FLAG = True
# check OSC started
model.oscCheck()
def button_config_callback(self):
self.foreground_stop()
@@ -227,103 +90,36 @@ class App(CTk):
self.information_window.focus()
def checkbox_translation_callback(self):
if self.checkbox_translation.get() is True:
print_textbox(self.textbox_message_log, "Start translation", "INFO")
print_textbox(self.textbox_message_system_log, "Start translation", "INFO")
config.ENABLE_TRANSLATION = self.checkbox_translation.get()
if config.ENABLE_TRANSLATION is True:
self.printLogStartTranslation()
else:
print_textbox(self.textbox_message_log, "Stop translation", "INFO")
print_textbox(self.textbox_message_system_log, "Stop translation", "INFO")
self.printLogStopTranslation()
def transcription_send_start(self):
self.mic_audio_queue = Queue()
mic_device = [device for device in get_input_device_list()[config.CHOICE_MIC_HOST] if device["name"] == config.CHOICE_MIC_DEVICE][0]
self.mic_audio_recorder = SelectedMicRecorder(
mic_device,
config.INPUT_MIC_ENERGY_THRESHOLD,
config.INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD,
config.INPUT_MIC_RECORD_TIMEOUT,
)
self.mic_audio_recorder.record_into_queue(self.mic_audio_queue)
self.mic_transcriber = AudioTranscriber(
speaker=False,
source=self.mic_audio_recorder.source,
phrase_timeout=config.INPUT_MIC_PHRASE_TIMEOUT,
max_phrases=config.INPUT_MIC_MAX_PHRASES,
)
def mic_transcript_to_chatbox():
self.mic_transcriber.transcribe_audio_queue(self.mic_audio_queue, transcription_lang[config.INPUT_MIC_VOICE_LANGUAGE])
message = self.mic_transcriber.get_transcript()
if len(message) > 0:
# word filter
if len(self.keyword_processor.extract_keywords(message)) != 0:
print_textbox(self.textbox_message_log, f"Detect WordFilter :{message}", "INFO")
print_textbox(self.textbox_message_system_log, f"Detect WordFilter :{message}", "INFO")
return
# translate
if self.checkbox_translation.get() is False:
voice_message = f"{message}"
elif self.translator.translator_status[config.CHOICE_TRANSLATOR] is False:
print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
voice_message = f"{message}"
else:
result = self.translator.translate(
translator_name=config.CHOICE_TRANSLATOR,
source_language=config.INPUT_SOURCE_LANG,
target_language=config.INPUT_TARGET_LANG,
message=message
)
voice_message = config.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result)
if self.checkbox_transcription_send.get() is True:
if self.ENABLE_OSC is True:
# send OSC message
send_message(voice_message, config.OSC_IP_ADDRESS, config.OSC_PORT)
else:
print_textbox(self.textbox_message_log, "OSC is not enabled, please enable OSC and rejoin.", "ERROR")
print_textbox(self.textbox_message_system_log, "OSC is not enabled, please enable OSC and rejoin.", "ERROR")
# update textbox message log
print_textbox(self.textbox_message_log, f"{voice_message}", "SEND")
print_textbox(self.textbox_message_send_log, f"{voice_message}", "SEND")
self.mic_print_transcript = thread_fnc(mic_transcript_to_chatbox)
self.mic_print_transcript.daemon = True
self.mic_print_transcript.start()
print_textbox(self.textbox_message_log, "Start voice2chatbox", "INFO")
print_textbox(self.textbox_message_system_log, "Start voice2chatbox", "INFO")
model.startMicTranscript(self.sendMicMessage)
self.printLogStartVoice2chatbox()
self.checkbox_transcription_send.configure(state="normal")
self.checkbox_transcription_receive.configure(state="normal")
self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"])
def transcription_send_stop(self):
if isinstance(self.mic_print_transcript, thread_fnc):
self.mic_print_transcript.stop()
if self.mic_audio_recorder.stop != None:
self.mic_audio_recorder.stop()
self.mic_audio_recorder.stop = None
print_textbox(self.textbox_message_log, "Stop voice2chatbox", "INFO")
print_textbox(self.textbox_message_system_log, "Stop voice2chatbox", "INFO")
model.stopMicTranscript()
self.printLogStopVoice2chatbox()
self.checkbox_transcription_send.configure(state="normal")
self.checkbox_transcription_receive.configure(state="normal")
self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"])
def transcription_send_stop_for_config(self):
if isinstance(self.mic_print_transcript, thread_fnc):
self.mic_print_transcript.stop()
if self.mic_audio_recorder.stop != None:
self.mic_audio_recorder.stop()
self.mic_audio_recorder.stop = None
print_textbox(self.textbox_message_log, "Stop voice2chatbox", "INFO")
print_textbox(self.textbox_message_system_log, "Stop voice2chatbox", "INFO")
model.stopMicTranscript()
self.printLogStopVoice2chatbox()
def checkbox_transcription_send_callback(self):
config.ENABLE_TRANSCRIPTION_SEND = self.checkbox_transcription_send.get()
self.checkbox_transcription_send.configure(state="disabled")
self.checkbox_transcription_receive.configure(state="disabled")
self.button_config.configure(state="disabled", fg_color=["gray92", "gray14"])
if self.checkbox_transcription_send.get() is True:
if config.ENABLE_TRANSCRIPTION_SEND is True:
th_transcription_send_start = Thread(target=self.transcription_send_start)
th_transcription_send_start.daemon = True
th_transcription_send_start.start()
@@ -333,88 +129,29 @@ class App(CTk):
th_transcription_send_stop.start()
def transcription_receive_start(self):
self.spk_audio_queue = Queue()
spk_device = [device for device in get_output_device_list() if device["name"] == config.CHOICE_SPEAKER_DEVICE][0]
self.spk_audio_recorder = SelectedSpeakerRecorder(
spk_device,
config.INPUT_SPEAKER_ENERGY_THRESHOLD,
config.INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD,
config.INPUT_SPEAKER_RECORD_TIMEOUT,
)
self.spk_audio_recorder.record_into_queue(self.spk_audio_queue)
self.spk_transcriber = AudioTranscriber(
speaker=True,
source=self.spk_audio_recorder.source,
phrase_timeout=config.INPUT_SPEAKER_PHRASE_TIMEOUT,
max_phrases=config.INPUT_SPEAKER_MAX_PHRASES,
)
def spk_transcript_to_textbox():
self.spk_transcriber.transcribe_audio_queue(self.spk_audio_queue, transcription_lang[config.INPUT_SPEAKER_VOICE_LANGUAGE])
message = self.spk_transcriber.get_transcript()
if len(message) > 0:
# translate
if self.checkbox_translation.get() is False:
voice_message = f"{message}"
elif self.translator.translator_status[config.CHOICE_TRANSLATOR] is False:
print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
voice_message = f"{message}"
else:
result = self.translator.translate(
translator_name=config.CHOICE_TRANSLATOR,
source_language=config.OUTPUT_SOURCE_LANG,
target_language=config.OUTPUT_TARGET_LANG,
message=message
)
voice_message = config.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result)
# send OSC message
# send_message(voice_message, config.OSC_IP_ADDRESS, self.OSC_PORT)
if self.checkbox_transcription_receive.get() is True:
# update textbox message receive log
print_textbox(self.textbox_message_log, f"{voice_message}", "RECEIVE")
print_textbox(self.textbox_message_receive_log, f"{voice_message}", "RECEIVE")
if config.ENABLE_NOTICE_XSOVERLAY is True:
notification_xsoverlay_for_vrct(content=f"{voice_message}")
self.spk_print_transcript = thread_fnc(spk_transcript_to_textbox)
self.spk_print_transcript.daemon = True
self.spk_print_transcript.start()
print_textbox(self.textbox_message_log, "Start speaker2log", "INFO")
print_textbox(self.textbox_message_system_log, "Start speaker2log", "INFO")
model.startSpeakerTranscript(self.receiveSpeakerMessage)
self.printLogStartSpeaker2log()
self.checkbox_transcription_send.configure(state="normal")
self.checkbox_transcription_receive.configure(state="normal")
self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"])
def transcription_receive_stop(self):
if isinstance(self.spk_print_transcript, thread_fnc):
self.spk_print_transcript.stop()
if self.spk_audio_recorder.stop != None:
self.spk_audio_recorder.stop()
self.spk_audio_recorder.stop = None
print_textbox(self.textbox_message_log, "Stop speaker2log", "INFO")
print_textbox(self.textbox_message_system_log, "Stop speaker2log", "INFO")
model.stopSpeakerTranscript()
self.printLogStopSpeaker2log()
self.checkbox_transcription_send.configure(state="normal")
self.checkbox_transcription_receive.configure(state="normal")
self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"])
def transcription_receive_stop_for_config(self):
if isinstance(self.spk_print_transcript, thread_fnc):
self.spk_print_transcript.stop()
if self.spk_audio_recorder.stop != None:
self.spk_audio_recorder.stop()
self.spk_audio_recorder.stop = None
print_textbox(self.textbox_message_log, "Stop speaker2log", "INFO")
print_textbox(self.textbox_message_system_log, "Stop speaker2log", "INFO")
model.stopSpeakerTranscript()
self.printLogStopSpeaker2log()
def checkbox_transcription_receive_callback(self):
config.ENABLE_TRANSCRIPTION_RECEIVE = self.checkbox_transcription_receive.get()
self.checkbox_transcription_send.configure(state="disabled")
self.checkbox_transcription_receive.configure(state="disabled")
self.button_config.configure(state="disabled", fg_color=["gray92", "gray14"])
if self.checkbox_transcription_receive.get() is True:
if config.ENABLE_TRANSCRIPTION_RECEIVE is True:
th_transcription_receive_start = Thread(target=self.transcription_receive_start)
th_transcription_receive_start.daemon = True
th_transcription_receive_start.start()
@@ -424,113 +161,147 @@ class App(CTk):
th_transcription_receive_stop.start()
def transcription_start(self):
if self.checkbox_transcription_send.get() is True:
if config.ENABLE_TRANSCRIPTION_SEND is True:
th_transcription_send_start = Thread(target=self.transcription_send_start)
th_transcription_send_start.daemon = True
th_transcription_send_start.start()
sleep(2)
if self.checkbox_transcription_receive.get() is True:
if config.ENABLE_TRANSCRIPTION_RECEIVE is True:
th_transcription_receive_start = Thread(target=self.transcription_receive_start)
th_transcription_receive_start.daemon = True
th_transcription_receive_start.start()
def transcription_stop(self):
if self.checkbox_transcription_send.get() is True:
if config.ENABLE_TRANSCRIPTION_SEND is True:
th_transcription_send_stop = Thread(target=self.transcription_send_stop_for_config)
th_transcription_send_stop.daemon = True
th_transcription_send_stop.start()
if self.checkbox_transcription_receive.get() is True:
if config.ENABLE_TRANSCRIPTION_RECEIVE is True:
th_transcription_receive_stop = Thread(target=self.transcription_receive_stop_for_config)
th_transcription_receive_stop.daemon = True
th_transcription_receive_stop.start()
def checkbox_foreground_callback(self):
if self.checkbox_foreground.get():
config.ENABLE_FOREGROUND = self.checkbox_foreground.get()
if config.ENABLE_FOREGROUND:
self.attributes("-topmost", True)
print_textbox(self.textbox_message_log, "Start foreground", "INFO")
print_textbox(self.textbox_message_system_log, "Start foreground", "INFO")
self.printLogStartForeground()
else:
self.attributes("-topmost", False)
print_textbox(self.textbox_message_log, "Stop foreground", "INFO")
print_textbox(self.textbox_message_system_log, "Stop foreground", "INFO")
self.printLogStopForeground()
def foreground_start(self):
if self.checkbox_foreground.get():
if config.ENABLE_FOREGROUND:
self.attributes("-topmost", True)
print_textbox(self.textbox_message_log, "Start foreground", "INFO")
print_textbox(self.textbox_message_system_log, "Start foreground", "INFO")
self.printLogStartForeground()
def foreground_stop(self):
if self.checkbox_foreground.get():
if config.ENABLE_FOREGROUND:
self.attributes("-topmost", False)
print_textbox(self.textbox_message_log, "Stop foreground", "INFO")
print_textbox(self.textbox_message_system_log, "Stop foreground", "INFO")
self.printLogStopForeground()
def entry_message_box_press_key_enter(self, event):
# send OSC typing
send_typing(False, config.OSC_IP_ADDRESS, config.OSC_PORT)
# osc stop send typing
model.oscStopSendTyping()
if self.checkbox_foreground.get():
if config.ENABLE_FOREGROUND:
self.attributes("-topmost", True)
message = self.entry_message_box.get()
if len(message) > 0:
# translate
if self.checkbox_translation.get() is False:
chat_message = f"{message}"
elif self.translator.translator_status[config.CHOICE_TRANSLATOR] is False:
print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
chat_message = f"{message}"
else:
result = self.translator.translate(
translator_name=config.CHOICE_TRANSLATOR,
source_language=config.INPUT_SOURCE_LANG,
target_language=config.INPUT_TARGET_LANG,
message=message
)
chat_message = config.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result)
self.sendChatMessage(message)
# send OSC message
if self.ENABLE_OSC is True:
send_message(chat_message, config.OSC_IP_ADDRESS, config.OSC_PORT)
else:
print_textbox(self.textbox_message_log, "OSC is not enabled, please enable OSC and rejoin.", "ERROR")
print_textbox(self.textbox_message_system_log, "OSC is not enabled, please enable OSC and rejoin.", "ERROR")
# update textbox message log
print_textbox(self.textbox_message_log, f"{chat_message}", "SEND")
print_textbox(self.textbox_message_send_log, f"{chat_message}", "SEND")
# delete message in entry message box
if config.ENABLE_AUTO_CLEAR_CHATBOX is True:
self.entry_message_box.delete(0, customtkinter.END)
BREAK_KEYSYM_LIST = [
"Delete", "Select", "Up", "Down", "Next", "End", "Print",
"Prior","Insert","Home", "Left", "Clear", "Right", "Linefeed"
]
def entry_message_box_press_key_any(self, event):
# send OSC typing
send_typing(True, config.OSC_IP_ADDRESS, config.OSC_PORT)
if self.checkbox_foreground.get():
# osc start send typing
model.oscStartSendTyping()
if config.ENABLE_FOREGROUND:
self.attributes("-topmost", False)
if event.keysym != "??":
if len(event.char) != 0 and event.keysym in self.BREAK_KEYSYM_LIST:
if len(event.char) != 0 and event.keysym in config.BREAK_KEYSYM_LIST:
self.entry_message_box.insert("end", event.char)
return "break"
def entry_message_box_leave(self, event):
# send OSC typing
send_typing(False, config.OSC_IP_ADDRESS, config.OSC_PORT)
if self.checkbox_foreground.get():
# osc stop send typing
model.oscStopSendTyping()
if config.ENABLE_FOREGROUND:
self.attributes("-topmost", True)
def delete_window(self):
self.quit()
self.destroy()
def add_sidebar(self):
init_lang_text = "Loading..."
self.sidebar_frame = CTkFrame(master=self, corner_radius=0)
# add checkbox translation
self.checkbox_translation = CTkCheckBox(
self.sidebar_frame,
text=init_lang_text,
onvalue=True,
offvalue=False,
command=self.checkbox_translation_callback,
font=CTkFont(family=config.FONT_FAMILY)
)
# add checkbox transcription send
self.checkbox_transcription_send = CTkCheckBox(
self.sidebar_frame,
text=init_lang_text,
onvalue=True,
offvalue=False,
command=self.checkbox_transcription_send_callback,
font=CTkFont(family=config.FONT_FAMILY)
)
# add checkbox transcription receive
self.checkbox_transcription_receive = CTkCheckBox(
self.sidebar_frame,
text=init_lang_text,
onvalue=True,
offvalue=False,
command=self.checkbox_transcription_receive_callback,
font=CTkFont(family=config.FONT_FAMILY)
)
# add checkbox foreground
self.checkbox_foreground = CTkCheckBox(
self.sidebar_frame,
text=init_lang_text,
onvalue=True,
offvalue=False,
command=self.checkbox_foreground_callback,
font=CTkFont(family=config.FONT_FAMILY)
)
# add button information
self.button_information = CTkButton(
self.sidebar_frame,
text=None,
width=36,
command=self.button_information_callback,
image=CTkImage(Image_open(os_path.join(os_path.dirname(__file__), "img", "info-icon-white.png")))
)
# add button config
self.button_config = CTkButton(
self.sidebar_frame,
text=None,
width=36,
command=self.button_config_callback,
image=CTkImage(Image_open(os_path.join(os_path.dirname(__file__), "img", "config-icon-white.png")))
)
self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsw")
self.sidebar_frame.grid_rowconfigure(5, weight=1)
self.checkbox_translation.grid(row=0, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we")
self.checkbox_transcription_send.grid(row=1, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we")
self.checkbox_transcription_receive.grid(row=2, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we")
self.checkbox_foreground.grid(row=3, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we")
self.button_information.grid(row=5, column=0, padx=(10, 5), pady=(5, 5), sticky="wse")
self.button_config.grid(row=5, column=1, padx=(5, 10), pady=(5, 5), sticky="wse")
def delete_tabview_logs(self, pre_language_yaml_data):
self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_log"])
self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_send"])
@@ -567,39 +338,153 @@ class App(CTk):
self.tabview_logs.tab(main_tab_title_log),
font=CTkFont(family=config.FONT_FAMILY)
)
self.textbox_message_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
self.textbox_message_log.configure(state='disabled')
# add textbox message send log
self.textbox_message_send_log = CTkTextbox(
self.tabview_logs.tab(main_tab_title_send),
font=CTkFont(family=config.FONT_FAMILY)
)
self.textbox_message_send_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
self.textbox_message_send_log.configure(state='disabled')
# add textbox message receive log
self.textbox_message_receive_log = CTkTextbox(
self.tabview_logs.tab(main_tab_title_receive),
font=CTkFont(family=config.FONT_FAMILY)
)
self.textbox_message_receive_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
self.textbox_message_receive_log.configure(state='disabled')
# add textbox message system log
self.textbox_message_system_log = CTkTextbox(
self.tabview_logs.tab(main_tab_title_system),
font=CTkFont(family=config.FONT_FAMILY)
)
self.textbox_message_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
self.textbox_message_send_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
self.textbox_message_receive_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
self.textbox_message_system_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
self.textbox_message_log.configure(state='disabled')
self.textbox_message_send_log.configure(state='disabled')
self.textbox_message_receive_log.configure(state='disabled')
self.textbox_message_system_log.configure(state='disabled')
widget_main_window_label_setter(self, language_yaml_data)
def check_osc_receive(self, address, osc_arguments):
if self.ENABLE_OSC is False:
self.ENABLE_OSC = True
# print(address, osc_arguments)
def printLogAuthenticationError(self):
print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
def printLogStartTranslation(self):
print_textbox(self.textbox_message_log, "Start translation", "INFO")
print_textbox(self.textbox_message_system_log, "Start translation", "INFO")
def printLogStopTranslation(self):
print_textbox(self.textbox_message_log, "Stop translation", "INFO")
print_textbox(self.textbox_message_system_log, "Stop translation", "INFO")
def printLogStartVoice2chatbox(self):
print_textbox(self.textbox_message_log, "Start voice2chatbox", "INFO")
print_textbox(self.textbox_message_system_log, "Start voice2chatbox", "INFO")
def printLogStopVoice2chatbox(self):
print_textbox(self.textbox_message_log, "Stop voice2chatbox", "INFO")
print_textbox(self.textbox_message_system_log, "Stop voice2chatbox", "INFO")
def printLogStartSpeaker2log(self):
print_textbox(self.textbox_message_log, "Start speaker2log", "INFO")
print_textbox(self.textbox_message_system_log, "Start speaker2log", "INFO")
def printLogStopSpeaker2log(self):
print_textbox(self.textbox_message_log, "Stop speaker2log", "INFO")
print_textbox(self.textbox_message_system_log, "Stop speaker2log", "INFO")
def printLogStartForeground(self):
print_textbox(self.textbox_message_log, "Start foreground", "INFO")
print_textbox(self.textbox_message_system_log, "Start foreground", "INFO")
def printLogStopForeground(self):
print_textbox(self.textbox_message_log, "Stop foreground", "INFO")
print_textbox(self.textbox_message_system_log, "Stop foreground", "INFO")
def printLogDetectWordFilter(self, message):
print_textbox(self.textbox_message_log, f"Detect WordFilter :{message}", "INFO")
print_textbox(self.textbox_message_system_log, f"Detect WordFilter :{message}", "INFO")
def printLogOSCError(self):
print_textbox(self.textbox_message_log, "OSC is not enabled, please enable OSC and rejoin.", "ERROR")
print_textbox(self.textbox_message_system_log, "OSC is not enabled, please enable OSC and rejoin.", "ERROR")
def printLogSendMessage(self, message):
print_textbox(self.textbox_message_log, f"{message}", "SEND")
print_textbox(self.textbox_message_send_log, f"{message}", "SEND")
def printLogReceiveMessage(self, message):
print_textbox(self.textbox_message_log, f"{message}", "RECEIVE")
print_textbox(self.textbox_message_receive_log, f"{message}", "RECEIVE")
def sendChatMessage(self, message):
if len(message) > 0:
# translate
if config.ENABLE_TRANSLATION is False:
chat_message = f"{message}"
elif model.getTranslatorStatus() is False:
self.printLogAuthenticationError()
chat_message = f"{message}"
else:
chat_message = model.getInputTranslate(message)
# send OSC message
if config.ENABLE_OSC is True:
model.oscSendMessage(chat_message)
else:
self.printLogOSCError()
# update textbox message log
self.printLogSendMessage(chat_message)
# delete message in entry message box
if config.ENABLE_AUTO_CLEAR_CHATBOX is True:
self.entry_message_box.delete(0, customtkinter.END)
def sendMicMessage(self, message):
if len(message) > 0:
# word filter
if model.checkKeywords(message):
self.printLogDetectWordFilter(message)
return
# translate
if config.ENABLE_TRANSLATION is False:
voice_message = f"{message}"
elif model.getTranslatorStatus() is False:
self.printLogAuthenticationError()
voice_message = f"{message}"
else:
voice_message = model.getInputTranslate(message)
if config.ENABLE_TRANSCRIPTION_SEND is True:
if config.ENABLE_OSC is True:
# osc send message
model.oscSendMessage(voice_message)
else:
self.printLogOSCError()
# update textbox message log
self.printLogSendMessage(voice_message)
def receiveSpeakerMessage(self, message):
if len(message) > 0:
# translate
if config.ENABLE_TRANSLATION is False:
voice_message = f"{message}"
elif model.getTranslatorStatus() is False:
self.printLogAuthenticationError()
voice_message = f"{message}"
else:
voice_message = model.getOutputTranslate(message)
if config.ENABLE_TRANSCRIPTION_RECEIVE is True:
# update textbox message receive log
self.printLogReceiveMessage(voice_message)
if config.ENABLE_NOTICE_XSOVERLAY is True:
model.notificationXsoverlay(voice_message)
if __name__ == "__main__":
try:

187
config.py
View File

@@ -1,12 +1,21 @@
from json import load, dump
import inspect
from os import path as os_path
from json import load as json_load
from json import dump as json_dump
import tkinter as tk
from tkinter import font
from utils import save_json
from languages import transcription_lang, translators, translation_lang, selectable_languages
from audio_utils import get_input_device_list, get_output_device_list, get_default_input_device, get_default_output_device
from languages import selectable_languages
from models.translation.translation_languages import translatorEngine, translation_lang
from models.transcription.transcription_languages import transcription_lang
from models.transcription.transcription_utils import getInputDevices, getOutputDevices, getDefaultInputDevice, getDefaultOutputDevice
def saveJson(path, key, value):
with open(path, "r") as fp:
json_data = load(fp)
json_data[key] = value
with open(path, "w") as fp:
dump(json_data, fp, indent=4)
class Config:
_instance = None
@@ -18,10 +27,50 @@ class Config:
cls._instance.load_config()
return cls._instance
@property
def VERSION(self):
return self._VERSION
@property
def PATH_CONFIG(self):
return self._PATH_CONFIG
@property
def ENABLE_TRANSLATION(self):
return self._ENABLE_TRANSLATION
@ENABLE_TRANSLATION.setter
def ENABLE_TRANSLATION(self, value):
if type(value) is bool:
self._ENABLE_TRANSLATION = value
@property
def ENABLE_TRANSCRIPTION_SEND(self):
return self._ENABLE_TRANSCRIPTION_SEND
@ENABLE_TRANSCRIPTION_SEND.setter
def ENABLE_TRANSCRIPTION_SEND(self, value):
if type(value) is bool:
self._ENABLE_TRANSCRIPTION_SEND = value
@property
def ENABLE_TRANSCRIPTION_RECEIVE(self):
return self._ENABLE_TRANSCRIPTION_RECEIVE
@ENABLE_TRANSCRIPTION_RECEIVE.setter
def ENABLE_TRANSCRIPTION_RECEIVE(self, value):
if type(value) is bool:
self._ENABLE_TRANSCRIPTION_RECEIVE = value
@property
def ENABLE_FOREGROUND(self):
return self._ENABLE_FOREGROUND
@ENABLE_FOREGROUND.setter
def ENABLE_FOREGROUND(self, value):
if type(value) is bool:
self._ENABLE_FOREGROUND = value
@property
def TRANSPARENCY(self):
return self._TRANSPARENCY
@@ -30,7 +79,7 @@ class Config:
def TRANSPARENCY(self, value):
if type(value) is int and 0 <= value <= 100:
self._TRANSPARENCY = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def APPEARANCE_THEME(self):
@@ -40,7 +89,7 @@ class Config:
def APPEARANCE_THEME(self, value):
if value in ["Light", "Dark", "System"]:
self._APPEARANCE_THEME = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def UI_SCALING(self):
@@ -50,7 +99,7 @@ class Config:
def UI_SCALING(self, value):
if value in ["80%", "90%", "100%", "110%", "120%"]:
self._UI_SCALING = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def FONT_FAMILY(self):
@@ -62,7 +111,7 @@ class Config:
root.withdraw()
if value in list(font.families()):
self._FONT_FAMILY = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
root.destroy()
@property
@@ -73,7 +122,7 @@ class Config:
def UI_LANGUAGE(self, value):
if value in list(selectable_languages.keys()):
self._UI_LANGUAGE = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def CHOICE_TRANSLATOR(self):
@@ -81,9 +130,9 @@ class Config:
@CHOICE_TRANSLATOR.setter
def CHOICE_TRANSLATOR(self, value):
if value in translators:
if value in translatorEngine:
self._CHOICE_TRANSLATOR = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_SOURCE_LANG(self):
@@ -93,7 +142,7 @@ class Config:
def INPUT_SOURCE_LANG(self, value):
if value in list(translation_lang[self.CHOICE_TRANSLATOR]["source"].keys()):
self._INPUT_SOURCE_LANG = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_TARGET_LANG(self):
@@ -103,7 +152,7 @@ class Config:
def INPUT_TARGET_LANG(self, value):
if value in list(translation_lang[self.CHOICE_TRANSLATOR]["target"].keys()):
self._INPUT_TARGET_LANG = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def OUTPUT_SOURCE_LANG(self):
@@ -113,7 +162,7 @@ class Config:
def OUTPUT_SOURCE_LANG(self, value):
if value in list(translation_lang[self.CHOICE_TRANSLATOR]["source"].keys()):
self._OUTPUT_SOURCE_LANG = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def OUTPUT_TARGET_LANG(self):
@@ -123,7 +172,7 @@ class Config:
def OUTPUT_TARGET_LANG(self, value):
if value in list(translation_lang[self.CHOICE_TRANSLATOR]["target"].keys()):
self._OUTPUT_TARGET_LANG = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def CHOICE_MIC_HOST(self):
@@ -131,9 +180,9 @@ class Config:
@CHOICE_MIC_HOST.setter
def CHOICE_MIC_HOST(self, value):
if value in [host for host in get_input_device_list().keys()]:
if value in [host for host in getInputDevices().keys()]:
self._CHOICE_MIC_HOST = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def CHOICE_MIC_DEVICE(self):
@@ -141,9 +190,9 @@ class Config:
@CHOICE_MIC_DEVICE.setter
def CHOICE_MIC_DEVICE(self, value):
if value in [device["name"] for device in get_input_device_list()[self.CHOICE_MIC_HOST]]:
if value in [device["name"] for device in getInputDevices()[self.CHOICE_MIC_HOST]]:
self._CHOICE_MIC_DEVICE = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_MIC_VOICE_LANGUAGE(self):
@@ -153,7 +202,7 @@ class Config:
def INPUT_MIC_VOICE_LANGUAGE(self, value):
if value in list(transcription_lang.keys()):
self._INPUT_MIC_VOICE_LANGUAGE = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_MIC_ENERGY_THRESHOLD(self):
@@ -163,7 +212,7 @@ class Config:
def INPUT_MIC_ENERGY_THRESHOLD(self, value):
if type(value) is int:
self._INPUT_MIC_ENERGY_THRESHOLD = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD(self):
@@ -173,7 +222,7 @@ class Config:
def INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD(self, value):
if type(value) is bool:
self._INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_MIC_RECORD_TIMEOUT(self):
@@ -183,7 +232,7 @@ class Config:
def INPUT_MIC_RECORD_TIMEOUT(self, value):
if type(value) is int:
self._INPUT_MIC_RECORD_TIMEOUT = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_MIC_PHRASE_TIMEOUT(self):
@@ -193,7 +242,7 @@ class Config:
def INPUT_MIC_PHRASE_TIMEOUT(self, value):
if type(value) is int:
self._INPUT_MIC_PHRASE_TIMEOUT = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_MIC_MAX_PHRASES(self):
@@ -203,7 +252,7 @@ class Config:
def INPUT_MIC_MAX_PHRASES(self, value):
if type(value) is int:
self._INPUT_MIC_MAX_PHRASES = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_MIC_WORD_FILTER(self):
@@ -213,7 +262,7 @@ class Config:
def INPUT_MIC_WORD_FILTER(self, value):
if type(value) is list:
self._INPUT_MIC_WORD_FILTER = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def CHOICE_SPEAKER_DEVICE(self):
@@ -221,11 +270,11 @@ class Config:
@CHOICE_SPEAKER_DEVICE.setter
def CHOICE_SPEAKER_DEVICE(self, value):
if value in [device["name"] for device in get_output_device_list()]:
speaker_device = [device for device in get_output_device_list() if device["name"] == value][0]
if get_default_output_device()["index"] == speaker_device["index"]:
if value in [device["name"] for device in getOutputDevices()]:
speaker_device = [device for device in getOutputDevices() if device["name"] == value][0]
if getDefaultOutputDevice()["index"] == speaker_device["index"]:
self._CHOICE_SPEAKER_DEVICE = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_SPEAKER_VOICE_LANGUAGE(self):
@@ -235,7 +284,7 @@ class Config:
def INPUT_SPEAKER_VOICE_LANGUAGE(self, value):
if value in list(transcription_lang.keys()):
self._INPUT_SPEAKER_VOICE_LANGUAGE = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_SPEAKER_ENERGY_THRESHOLD(self):
@@ -245,7 +294,7 @@ class Config:
def INPUT_SPEAKER_ENERGY_THRESHOLD(self, value):
if type(value) is int:
self._INPUT_SPEAKER_ENERGY_THRESHOLD = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD(self):
@@ -255,7 +304,7 @@ class Config:
def INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD(self, value):
if type(value) is bool:
self._INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_SPEAKER_RECORD_TIMEOUT(self):
@@ -265,7 +314,7 @@ class Config:
def INPUT_SPEAKER_RECORD_TIMEOUT(self, value):
if type(value) is int:
self._INPUT_SPEAKER_RECORD_TIMEOUT = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_SPEAKER_PHRASE_TIMEOUT(self):
@@ -275,7 +324,7 @@ class Config:
def INPUT_SPEAKER_PHRASE_TIMEOUT(self, value):
if type(value) is int:
self._INPUT_SPEAKER_PHRASE_TIMEOUT = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def INPUT_SPEAKER_MAX_PHRASES(self):
@@ -285,7 +334,7 @@ class Config:
def INPUT_SPEAKER_MAX_PHRASES(self, value):
if type(value) is int:
self._INPUT_SPEAKER_MAX_PHRASES = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def OSC_IP_ADDRESS(self):
@@ -295,7 +344,7 @@ class Config:
def OSC_IP_ADDRESS(self, value):
if type(value) is str:
self._OSC_IP_ADDRESS = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def OSC_PORT(self):
@@ -305,7 +354,7 @@ class Config:
def OSC_PORT(self, value):
if type(value) is int:
self._OSC_PORT = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def AUTH_KEYS(self):
@@ -317,7 +366,7 @@ class Config:
for key, value in value.items():
if type(value) is str:
self._AUTH_KEYS[key] = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, self.AUTH_KEYS)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, self.AUTH_KEYS)
@property
def MESSAGE_FORMAT(self):
@@ -327,7 +376,7 @@ class Config:
def MESSAGE_FORMAT(self, value):
if type(value) is str:
self._MESSAGE_FORMAT = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def ENABLE_AUTO_CLEAR_CHATBOX(self):
@@ -337,7 +386,7 @@ class Config:
def ENABLE_AUTO_CLEAR_CHATBOX(self, value):
if type(value) is bool:
self._ENABLE_AUTO_CLEAR_CHATBOX = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def ENABLE_NOTICE_XSOVERLAY(self):
@@ -347,22 +396,61 @@ class Config:
def ENABLE_NOTICE_XSOVERLAY(self, value):
if type(value) is bool:
self._ENABLE_NOTICE_XSOVERLAY = value
save_json(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
def ENABLE_OSC(self):
return self._ENABLE_OSC
@ENABLE_OSC.setter
def ENABLE_OSC(self, value):
if type(value) is bool:
self._ENABLE_OSC = value
@property
def UPDATE_FLAG(self):
return self._UPDATE_FLAG
@UPDATE_FLAG.setter
def UPDATE_FLAG(self, value):
if type(value) is bool:
self._UPDATE_FLAG = value
@property
def GITHUB_URL(self):
return self._GITHUB_URL
@property
def BREAK_KEYSYM_LIST(self):
return self._BREAK_KEYSYM_LIST
@property
def MAX_MIC_ENERGY_THRESHOLD(self):
return self._MAX_MIC_ENERGY_THRESHOLD
@property
def MAX_SPEAKER_ENERGY_THRESHOLD(self):
return self._MAX_SPEAKER_ENERGY_THRESHOLD
def init_config(self):
self._VERSION = "1.3.2"
self._PATH_CONFIG = "./config.json"
self._ENABLE_TRANSLATION = False
self._ENABLE_TRANSCRIPTION_SEND = False
self._ENABLE_TRANSCRIPTION_RECEIVE = False
self._ENABLE_FOREGROUND = False
self._TRANSPARENCY = 100
self._APPEARANCE_THEME = "System"
self._UI_SCALING = "100%"
self._FONT_FAMILY = "Yu Gothic UI"
self._UI_LANGUAGE = "en"
self._CHOICE_TRANSLATOR = translators[0]
self._CHOICE_TRANSLATOR = translatorEngine[0]
self._INPUT_SOURCE_LANG = list(translation_lang[self.CHOICE_TRANSLATOR]["source"].keys())[0]
self._INPUT_TARGET_LANG = list(translation_lang[self.CHOICE_TRANSLATOR]["target"].keys())[1]
self._OUTPUT_SOURCE_LANG = list(translation_lang[self.CHOICE_TRANSLATOR]["source"].keys())[1]
self._OUTPUT_TARGET_LANG = list(translation_lang[self.CHOICE_TRANSLATOR]["target"].keys())[0]
self._CHOICE_MIC_HOST = get_default_input_device()["host"]["name"]
self._CHOICE_MIC_DEVICE = get_default_input_device()["device"]["name"]
self._CHOICE_MIC_HOST = getDefaultInputDevice()["host"]["name"]
self._CHOICE_MIC_DEVICE = getDefaultInputDevice()["device"]["name"]
self._INPUT_MIC_VOICE_LANGUAGE = list(transcription_lang.keys())[0]
self._INPUT_MIC_ENERGY_THRESHOLD = 300
self._INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD = True
@@ -370,7 +458,7 @@ class Config:
self._INPUT_MIC_PHRASE_TIMEOUT = 3
self._INPUT_MIC_MAX_PHRASES = 10
self._INPUT_MIC_WORD_FILTER = []
self._CHOICE_SPEAKER_DEVICE = get_default_output_device()["name"]
self._CHOICE_SPEAKER_DEVICE = getDefaultOutputDevice()["name"]
self._INPUT_SPEAKER_VOICE_LANGUAGE = list(transcription_lang.keys())[1]
self._INPUT_SPEAKER_ENERGY_THRESHOLD = 300
self._INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD = True
@@ -388,6 +476,15 @@ class Config:
self._MESSAGE_FORMAT = "[message]([translation])"
self._ENABLE_AUTO_CLEAR_CHATBOX = False
self._ENABLE_NOTICE_XSOVERLAY = False
self._ENABLE_OSC = False
self._UPDATE_FLAG = False
self._GITHUB_URL = "https://api.github.com/repos/misyaguziya/VRCT/releases/latest"
self._BREAK_KEYSYM_LIST = [
"Delete", "Select", "Up", "Down", "Next", "End", "Print",
"Prior","Insert","Home", "Left", "Clear", "Right", "Linefeed"
]
self._MAX_MIC_ENERGY_THRESHOLD = 2000
self._MAX_SPEAKER_ENERGY_THRESHOLD = 4000
def load_config(self):
if os_path.isfile(self.PATH_CONFIG) is not False:

View File

@@ -1,339 +1,3 @@
transcription_lang = {
"Japanese (Japan)":"ja-JP",
"English (United States)":"en-US",
"English (United Kingdom)":"en-GB",
"Afrikaans (South Africa)":"af-ZA",
"Arabic (Algeria)":"ar-DZ",
"Arabic (Bahrain)":"ar-BH",
"Arabic (Egypt)":"ar-EG",
"Arabic (Israel)":"ar-IL",
"Arabic (Iraq)":"ar-IQ",
"Arabic (Jordan)":"ar-JO",
"Arabic (Kuwait)":"ar-KW",
"Arabic (Lebanon)":"ar-LB",
"Arabic (Morocco)":"ar-MA",
"Arabic (Oman)":"ar-OM",
"Arabic (State of Palestine)":"ar-PS",
"Arabic (Qatar)":"ar-QA",
"Arabic (Saudi Arabia)":"ar-SA",
"Arabic (Tunisia)":"ar-TN",
"Arabic (United Arab Emirates)":"ar-AE",
"Basque (Spain)":"eu-ES",
"Bulgarian (Bulgaria)":"bg-BG",
"Catalan (Spain)":"ca-ES",
"Chinese, Mandarin (Simplified, China)":"cmn-Hans-CN",
"Chinese, Mandarin (Simplified, Hong Kong)":"cmn-Hans-HK",
"Chinese, Mandarin (Traditional, Taiwan)":"cmn-Hant-TW",
"Chinese, Cantonese (Traditional Hong Kong)":"yue-Hant-HK",
"Croatian (Croatia)":"hr-HR",
"Czech (Czech Republic)":"cs-CZ",
"Danish (Denmark)":"da-DK",
"English (Australia)":"en-AU",
"English (Canada)":"en-CA",
"English (India)":"en-IN",
"English (Ireland)":"en-IE",
"English (New Zealand)":"en-NZ",
"English (Philippines)":"en-PH",
"English (South Africa)":"en-ZA",
"Persian (Iran)":"fa-IR",
"French (France)":"fr-FR",
"Filipino (Philippines)":"fil-PH",
"Galician (Spain)":"gl-ES",
"German (Germany)":"de-DE",
"Greek (Greece)":"el-GR",
"Finnish (Finland)":"fi-FI",
"Hebrew (Israel)":"he-IL",
"Hindi (India)":"hi-IN",
"Hungarian (Hungary)":"hu-HU",
"Indonesian (Indonesia)":"id-ID",
"Icelandic (Iceland)":"is-IS",
"Italian (Italy)":"it-IT",
"Italian (Switzerland)":"it-CH",
"Korean (South Korea)":"ko-KR",
"Lithuanian (Lithuania)":"lt-LT",
"Malay (Malaysia)":"ms-MY",
"Dutch (Netherlands)":"nl-NL",
"Norwegian Bokmål (Norway)":"nb-NO",
"Polish (Poland)":"pl-PL",
"Portuguese (Brazil)":"pt-BR",
"Portuguese (Portugal)":"pt-PT",
"Romanian (Romania)":"ro-RO",
"Russian (Russia)":"ru-RU",
"Serbian (Serbia)":"sr-RS",
"Slovak (Slovakia)":"sk-SK",
"Slovenian (Slovenia)":"sl-SI",
"Spanish (Argentina)":"es-AR",
"Spanish (Bolivia)":"es-BO",
"Spanish (Chile)":"es-CL",
"Spanish (Colombia)":"es-CO",
"Spanish (Costa Rica)":"es-CR",
"Spanish (Dominican Republic)":"es-DO",
"Spanish (Ecuador)":"es-EC",
"Spanish (El Salvador)":"es-SV",
"Spanish (Guatemala)":"es-GT",
"Spanish (Honduras)":"es-HN",
"Spanish (Mexico)":"es-MX",
"Spanish (Nicaragua)":"es-NI",
"Spanish (Panama)":"es-PA",
"Spanish (Paraguay)":"es-PY",
"Spanish (Peru)":"es-PE",
"Spanish (Puerto Rico)":"es-PR",
"Spanish (Spain)":"es-ES",
"Spanish (Uruguay)":"es-UY",
"Spanish (United States)":"es-US",
"Spanish (Venezuela)":"es-VE",
"Swedish (Sweden)":"sv-SE",
"Thai (Thailand)":"th-TH",
"Turkish (Turkey)":"tr-TR",
"Ukrainian (Ukraine)":"uk-UA",
"Vietnamese (Vietnam)":"vi-VN",
"Zulu (South Africa)":"zu-ZA"
}
translators = ["DeepL(web)", "DeepL(auth)", "Google(web)", "Bing(web)"]
translation_lang = {}
dict_deepl_web_languages = {
"Japanese":"JA",
"English":"EN",
"Korean":"KO",
"Bulgarian":"BG",
"Chinese":"ZH",
"Czech":"CS",
"Danish":"DA",
"Dutch":"NL",
"Estonian":"ET",
"Finnish":"FI",
"French":"FR",
"German":"DE",
"Greek":"EL",
"Hungarian":"HU",
"Italian":"IT",
"Latvian":"LV",
"Lithuanian":"LT",
"Polish":"PL",
"Portuguese":"PT",
"Romanian":"RO",
"Russian":"RU",
"Slovak":"SK",
"Slovenian":"SL",
"Spanish":"ES",
"Swedish":"SV",
"Indonesian":"ID",
"Ukrainian":"UK",
"Turkish":"TR",
"Norwegian":"NB",
}
translation_lang["DeepL(web)"] = {
"source":dict_deepl_web_languages,
"target":dict_deepl_web_languages,
}
dict_deepl_auth_source_languages = {
"Japanese":"ja",
"English":"en",
"Bulgarian":"bg",
"Czech":"cs",
"Danish":"da",
"German":"de",
"Greek":"el",
"Spanish":"es",
"Estonian":"et",
"Finnish":"fi",
"French":"fr",
"Hungarian":"hu",
"Indonesian":"id",
"Italian":"it",
"Korean":"ko",
"Lithuanian":"lt",
"Latvian":"lv",
"Norwegian":"nb",
"Dutch":"nl",
"Polish":"pl",
"Portuguese":"pt",
"Romanian":"ro",
"Russian":"ru",
"Slovak":"sk",
"Slovenian":"sl",
"Swedish":"sv",
"Turkish":"tr",
"Ukrainian":"uk",
"Chinese":"zh"
}
dict_deepl_auth_target_languages = {
"Japanese":"ja",
"English American":"en-US",
"English British":"en-GB",
"Bulgarian":"bg",
"Czech":"cs",
"Danish":"da",
"German":"de",
"Greek":"el",
"English":"en",
"Spanish":"es",
"Estonian":"et",
"Finnish":"fi",
"French":"fr",
"Hungarian":"hu",
"Indonesian":"id",
"Italian":"it",
"Korean":"ko",
"Lithuanian":"lt",
"Latvian":"lv",
"Norwegian":"nb",
"Dutch":"nl",
"Polish":"pl",
"Portuguese Brazilian":"pt-BR",
"Portuguese European":"pt-PT",
"Romanian":"ro",
"Russian":"ru",
"Slovak":"sk",
"Slovenian":"sl",
"Swedish":"sv",
"Turkish":"tr",
"Ukrainian":"uk",
"Chinese":"zh"
}
translation_lang["DeepL(auth)"] = {
"source": dict_deepl_auth_source_languages,
"target": dict_deepl_auth_target_languages,
}
dict_google_web_languages = {
"Japanese":"ja",
"English":"en",
"Chinese":"zh",
"Arabic":"ar",
"Russian":"ru",
"French":"fr",
"German":"de",
"Spanish":"es",
"Portuguese":"pt",
"Italian":"it",
"Korean":"ko",
"Greek":"el",
"Dutch":"nl",
"Hindi":"hi",
"Turkish":"tr",
"Malay":"ms",
"Thai":"th",
"Vietnamese":"vi",
"Indonesian":"id",
"Hebrew":"he",
"Polish":"pl",
"Mongolian":"mn",
"Czech":"cs",
"Hungarian":"hu",
"Estonian":"et",
"Bulgarian":"bg",
"Danish":"da",
"Finnish":"fi",
"Romanian":"ro",
"Swedish":"sv",
"Slovenian":"sl",
"Persian/Farsi":"fa",
"Bosnian":"bs",
"Serbian":"sr",
"Filipino":"tl",
"Haitiancreole":"ht",
"Catalan":"ca",
"Croatian":"hr",
"Latvian":"lv",
"Lithuanian":"lt",
"Urdu":"ur",
"Ukrainian":"uk",
"Welsh":"cy",
"Swahili":"sw",
"Samoan":"sm",
"Slovak":"sk",
"Afrikaans":"af",
"Norwegian":"no",
"Bengali":"bn",
"Malagasy":"mg",
"Maltese":"mt",
"Gujarati":"gu",
"Tamil":"ta",
"Telugu":"te",
"Punjabi":"pa",
"Amharic":"am",
"Azerbaijani":"az",
"Belarusian":"be",
"Cebuano":"ceb",
"Esperanto":"eo",
"Basque":"eu",
"Irish":"ga"
}
translation_lang["Google(web)"] = {
"source":dict_google_web_languages,
"target":dict_google_web_languages,
}
dict_bing_web_languages = {
"Japanese":"ja",
"English":"en",
"Chinese":"zh",
"Arabic":"ar",
"Russian":"ru",
"French":"fr",
"German":"de",
"Spanish":"es",
"Portuguese":"pt",
"Italian":"it",
"Korean":"ko",
"Greek":"el",
"Dutch":"nl",
"Hindi":"hi",
"Turkish":"tr",
"Malay":"ms",
"Thai":"th",
"Vietnamese":"vi",
"Indonesian":"id",
"Hebrew":"he",
"Polish":"pl",
"Czech":"cs",
"Hungarian":"hu",
"Estonian":"et",
"Bulgarian":"bg",
"Danish":"da",
"Finnish":"fi",
"Romanian":"ro",
"Swedish":"sv",
"Slovenian":"sl",
"Persian/Farsi":"fa",
"Bosnian":"bs",
"Serbian":"sr",
"Fijian":"fj",
"Filipino":"tl",
"Haitiancreole":"ht",
"Catalan":"ca",
"Croatian":"hr",
"Latvian":"lv",
"Lithuanian":"lt",
"Urdu":"ur",
"Ukrainian":"uk",
"Welsh":"cy",
"Tahiti":"ty",
"Tongan":"to",
"Swahili":"sw",
"Samoan":"sm",
"Slovak":"sk",
"Afrikaans":"af",
"Norwegian":"no",
"Bengali":"bn",
"Malagasy":"mg",
"Maltese":"mt",
"Queretaro otomi":"otq",
"Klingon/tlhingan Hol":"tlh",
"Gujarati":"gu",
"Tamil":"ta",
"Telugu":"te",
"Punjabi":"pa",
"Irish":"ga"
}
translation_lang["Bing(web)"] = {
"source":dict_bing_web_languages,
"target":dict_bing_web_languages,
}
selectable_languages = {
"en": "English",
"ja": "日本語",

271
model.py Normal file
View File

@@ -0,0 +1,271 @@
from time import sleep
from queue import Queue
from threading import Thread, Event
from requests import get as requests_get
from flashtext import KeywordProcessor
from models.translation.translation_translator import Translator
from models.transcription.transcription_utils import getInputDevices, getOutputDevices, getDefaultInputDevice, getDefaultOutputDevice
from models.osc.osc_tools import sendTyping, sendMessage, sendTestAction, receiveOscParameters
from models.transcription.transcription_recorder import SelectedMicRecorder, SelectedSpeakerRecorder
from models.transcription.transcription_recorder import SelectedMicEnergyRecorder, SelectedSpeakeEnergyRecorder
from models.transcription.transcription_transcriber import AudioTranscriber
from models.xsoverlay.notification import xsoverlayForVRCT
from config import config
class threadFnc(Thread):
def __init__(self, fnc, daemon=True, *args, **kwargs):
super(threadFnc, self).__init__(daemon=daemon, *args, **kwargs)
self.fnc = fnc
self._stop = Event()
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.isSet()
def run(self):
while True:
if self.stopped():
return
self.fnc(*self._args, **self._kwargs)
class Model:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(Model, cls).__new__(cls)
cls._instance.init()
return cls._instance
def init(self):
self.mic_energy_recorder = None
self.mic_energy_plot_progressbar = None
self.speaker_energy_get_progressbar = None
self.speaker_energy_plot_progressbar = None
self.translator = Translator()
self.keyword_processor = KeywordProcessor()
def resetTranslator(self):
del self.translator
self.translator = Translator()
def resetKeywordProcessor(self):
del self.translator
self.keyword_processor = KeywordProcessor()
def authenticationTranslator(self, choice_translator=None, auth_key=None):
if choice_translator == None:
choice_translator = config.CHOICE_TRANSLATOR
if auth_key == None:
auth_key = config.AUTH_KEYS[choice_translator]
result = self.translator.authentication(choice_translator, auth_key)
if result:
auth_keys = config.AUTH_KEYS
auth_keys[choice_translator] = auth_key
config.AUTH_KEYS = auth_keys
return result
def getTranslatorStatus(self):
return self.translator.translator_status[config.CHOICE_TRANSLATOR]
def getListTranslatorName(self):
return list(self.translator.translator_status.keys())
def getInputTranslate(self, message):
translation = self.translator.translate(
translator_name=config.CHOICE_TRANSLATOR,
source_language=config.INPUT_SOURCE_LANG,
target_language=config.INPUT_TARGET_LANG,
message=message
)
message = config.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", translation)
return message
def getOutputTranslate(self, message):
translation = self.translator.translate(
translator_name=config.CHOICE_TRANSLATOR,
source_language=config.OUTPUT_SOURCE_LANG,
target_language=config.OUTPUT_TARGET_LANG,
message=message
)
message = config.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", translation)
return message
def addKeywords(self):
for f in config.INPUT_MIC_WORD_FILTER:
self.keyword_processor.add_keyword(f)
def checkKeywords(self, message):
return len(self.keyword_processor.extract_keywords(message)) != 0
@staticmethod
def oscStartSendTyping():
sendTyping(True, config.OSC_IP_ADDRESS, config.OSC_PORT)
@staticmethod
def oscStopSendTyping():
sendTyping(False, config.OSC_IP_ADDRESS, config.OSC_PORT)
@staticmethod
def oscSendMessage(message):
sendMessage(message, config.OSC_IP_ADDRESS, config.OSC_PORT)
@staticmethod
def oscCheck():
def check_osc_receive(address, osc_arguments):
if config.ENABLE_OSC is False:
config.ENABLE_OSC = True
# start receive osc
th_receive_osc_parameters = Thread(target=receiveOscParameters, args=(check_osc_receive,))
th_receive_osc_parameters.daemon = True
th_receive_osc_parameters.start()
# check osc started
sendTestAction()
# check update
response = requests_get(config.GITHUB_URL)
tag_name = response.json()["tag_name"]
if tag_name != config.VERSION:
config.UPDATE_FLAG = True
@staticmethod
def getListInputHost():
return [host for host in getInputDevices().keys()]
@staticmethod
def getListInputDevice():
return [device["name"] for device in getInputDevices()[config.CHOICE_MIC_HOST]]
@staticmethod
def getInputDefaultDevice():
return [device["name"] for device in getInputDevices()[config.CHOICE_MIC_HOST]][0]
@staticmethod
def getListOutputDevice():
return [device["name"] for device in getOutputDevices()]
@staticmethod
def checkSpeakerStatus(choice=config.CHOICE_SPEAKER_DEVICE):
speaker_device = [device for device in getOutputDevices() if device["name"] == choice][0]
if getDefaultOutputDevice()["index"] == speaker_device["index"]:
return True
return False
def startMicTranscript(self, fnc):
mic_audio_queue = Queue()
self.mic_audio_recorder = SelectedMicRecorder(
[device for device in getInputDevices()[config.CHOICE_MIC_HOST] if device["name"] == config.CHOICE_MIC_DEVICE][0],
config.INPUT_MIC_ENERGY_THRESHOLD,
config.INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD,
config.INPUT_MIC_RECORD_TIMEOUT,
)
self.mic_audio_recorder.recordIntoQueue(mic_audio_queue)
mic_transcriber = AudioTranscriber(
speaker=False,
source=self.mic_audio_recorder.source,
phrase_timeout=config.INPUT_MIC_PHRASE_TIMEOUT,
max_phrases=config.INPUT_MIC_MAX_PHRASES,
)
def sendMicTranscript():
mic_transcriber.transcribeAudioQueue(mic_audio_queue, config.INPUT_MIC_VOICE_LANGUAGE)
message = mic_transcriber.getTranscript()
fnc(message)
self.mic_print_transcript = threadFnc(sendMicTranscript)
self.mic_print_transcript.daemon = True
self.mic_print_transcript.start()
def stopMicTranscript(self):
if isinstance(self.mic_print_transcript, threadFnc):
self.mic_print_transcript.stop()
if self.mic_audio_recorder.stop != None:
self.mic_audio_recorder.stop()
self.mic_audio_recorder.stop = None
def startCheckMicEnergy(self, fnc):
def sendMicEnergy():
if mic_energy_queue.empty() is False:
energy = mic_energy_queue.get()
fnc(energy)
sleep(0.01)
mic_energy_queue = Queue()
mic_device = [device for device in getInputDevices()[config.CHOICE_MIC_HOST] if device["name"] == config.CHOICE_MIC_DEVICE][0]
self.mic_energy_recorder = SelectedMicEnergyRecorder(mic_device)
self.mic_energy_recorder.recordIntoQueue(mic_energy_queue)
self.mic_energy_plot_progressbar = threadFnc(sendMicEnergy)
self.mic_energy_plot_progressbar.daemon = True
self.mic_energy_plot_progressbar.start()
def stopCheckMicEnergy(self):
if self.mic_energy_recorder != None:
self.mic_energy_recorder.stop()
if self.mic_energy_plot_progressbar != None:
self.mic_energy_plot_progressbar.stop()
def startSpeakerTranscript(self, fnc):
spk_audio_queue = Queue()
spk_device = [device for device in getOutputDevices() if device["name"] == config.CHOICE_SPEAKER_DEVICE][0]
self.spk_audio_recorder = SelectedSpeakerRecorder(
spk_device,
config.INPUT_SPEAKER_ENERGY_THRESHOLD,
config.INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD,
config.INPUT_SPEAKER_RECORD_TIMEOUT,
)
self.spk_audio_recorder.recordIntoQueue(spk_audio_queue)
spk_transcriber = AudioTranscriber(
speaker=True,
source=self.spk_audio_recorder.source,
phrase_timeout=config.INPUT_SPEAKER_PHRASE_TIMEOUT,
max_phrases=config.INPUT_SPEAKER_MAX_PHRASES,
)
def sendSpkTranscript():
spk_transcriber.transcribeAudioQueue(spk_audio_queue, config.INPUT_SPEAKER_VOICE_LANGUAGE)
message = spk_transcriber.getTranscript()
fnc(message)
self.spk_print_transcript = threadFnc(sendSpkTranscript)
self.spk_print_transcript.daemon = True
self.spk_print_transcript.start()
def stopSpeakerTranscript(self):
if isinstance(self.spk_print_transcript, threadFnc):
self.spk_print_transcript.stop()
if self.spk_audio_recorder.stop != None:
self.spk_audio_recorder.stop()
self.spk_audio_recorder.stop = None
def startCheckSpeakerEnergy(self, fnc):
def sendSpeakerEnergy():
if speaker_energy_queue.empty() is False:
energy = speaker_energy_queue.get()
fnc(energy)
sleep(0.01)
def getSpeakerEnergy():
with self.speaker_energy_recorder.source as source:
energy = self.speaker_energy_recorder.recorder.listen_energy(source)
speaker_energy_queue.put(energy)
speaker_device = [device for device in getOutputDevices() if device["name"] == config.CHOICE_SPEAKER_DEVICE][0]
speaker_energy_queue = Queue()
self.speaker_energy_recorder = SelectedSpeakeEnergyRecorder(speaker_device)
self.speaker_energy_get_progressbar = threadFnc(getSpeakerEnergy)
self.speaker_energy_get_progressbar.daemon = True
self.speaker_energy_get_progressbar.start()
self.speaker_energy_plot_progressbar = threadFnc(sendSpeakerEnergy)
self.speaker_energy_plot_progressbar.daemon = True
self.speaker_energy_plot_progressbar.start()
def stopCheckSpeakerEnergy(self):
if self.speaker_energy_get_progressbar != None:
self.speaker_energy_get_progressbar.stop()
if self.speaker_energy_plot_progressbar != None:
self.speaker_energy_plot_progressbar.stop()
def notificationXSOverlay(self, message):
xsoverlayForVRCT(content=f"{message}")
model = Model()

View File

@@ -6,7 +6,7 @@ from pythonosc import dispatcher
from pythonosc import osc_server
# send OSC message typing
def send_typing(flag=False, ip_address="127.0.0.1", port=9000):
def sendTyping(flag=False, ip_address="127.0.0.1", port=9000):
typing = osc_message_builder.OscMessageBuilder(address="/chatbox/typing")
typing.add_arg(flag)
b_typing = typing.build()
@@ -14,7 +14,7 @@ def send_typing(flag=False, ip_address="127.0.0.1", port=9000):
client.send(b_typing)
# send OSC message
def send_message(message=None, ip_address="127.0.0.1", port=9000):
def sendMessage(message=None, ip_address="127.0.0.1", port=9000):
if message != None:
msg = osc_message_builder.OscMessageBuilder(address="/chatbox/input")
msg.add_arg(f"{message}")
@@ -24,13 +24,13 @@ def send_message(message=None, ip_address="127.0.0.1", port=9000):
client = udp_client.SimpleUDPClient(ip_address, port)
client.send(b_msg)
def send_test_action(ip_address="127.0.0.1", port=9000):
def sendTestAction(ip_address="127.0.0.1", port=9000):
client = udp_client.SimpleUDPClient(ip_address, port)
client.send_message("/input/Vertical", 1)
sleep(0.01)
client.send_message("/input/Vertical", False)
def receive_osc_parameters(target, filter="/*", ip_address="127.0.0.1", port=9001):
def receiveOscParameters(target, filter="/*", ip_address="127.0.0.1", port=9001):
_dispatcher = dispatcher.Dispatcher()
_dispatcher.map(filter, target)
server = osc_server.ThreadingOSCUDPServer((ip_address, port), _dispatcher)

View File

@@ -0,0 +1,91 @@
transcription_lang = {
"Japanese (Japan)":"ja-JP",
"English (United States)":"en-US",
"English (United Kingdom)":"en-GB",
"Afrikaans (South Africa)":"af-ZA",
"Arabic (Algeria)":"ar-DZ",
"Arabic (Bahrain)":"ar-BH",
"Arabic (Egypt)":"ar-EG",
"Arabic (Israel)":"ar-IL",
"Arabic (Iraq)":"ar-IQ",
"Arabic (Jordan)":"ar-JO",
"Arabic (Kuwait)":"ar-KW",
"Arabic (Lebanon)":"ar-LB",
"Arabic (Morocco)":"ar-MA",
"Arabic (Oman)":"ar-OM",
"Arabic (State of Palestine)":"ar-PS",
"Arabic (Qatar)":"ar-QA",
"Arabic (Saudi Arabia)":"ar-SA",
"Arabic (Tunisia)":"ar-TN",
"Arabic (United Arab Emirates)":"ar-AE",
"Basque (Spain)":"eu-ES",
"Bulgarian (Bulgaria)":"bg-BG",
"Catalan (Spain)":"ca-ES",
"Chinese, Mandarin (Simplified, China)":"cmn-Hans-CN",
"Chinese, Mandarin (Simplified, Hong Kong)":"cmn-Hans-HK",
"Chinese, Mandarin (Traditional, Taiwan)":"cmn-Hant-TW",
"Chinese, Cantonese (Traditional Hong Kong)":"yue-Hant-HK",
"Croatian (Croatia)":"hr-HR",
"Czech (Czech Republic)":"cs-CZ",
"Danish (Denmark)":"da-DK",
"English (Australia)":"en-AU",
"English (Canada)":"en-CA",
"English (India)":"en-IN",
"English (Ireland)":"en-IE",
"English (New Zealand)":"en-NZ",
"English (Philippines)":"en-PH",
"English (South Africa)":"en-ZA",
"Persian (Iran)":"fa-IR",
"French (France)":"fr-FR",
"Filipino (Philippines)":"fil-PH",
"Galician (Spain)":"gl-ES",
"German (Germany)":"de-DE",
"Greek (Greece)":"el-GR",
"Finnish (Finland)":"fi-FI",
"Hebrew (Israel)":"he-IL",
"Hindi (India)":"hi-IN",
"Hungarian (Hungary)":"hu-HU",
"Indonesian (Indonesia)":"id-ID",
"Icelandic (Iceland)":"is-IS",
"Italian (Italy)":"it-IT",
"Italian (Switzerland)":"it-CH",
"Korean (South Korea)":"ko-KR",
"Lithuanian (Lithuania)":"lt-LT",
"Malay (Malaysia)":"ms-MY",
"Dutch (Netherlands)":"nl-NL",
"Norwegian Bokmål (Norway)":"nb-NO",
"Polish (Poland)":"pl-PL",
"Portuguese (Brazil)":"pt-BR",
"Portuguese (Portugal)":"pt-PT",
"Romanian (Romania)":"ro-RO",
"Russian (Russia)":"ru-RU",
"Serbian (Serbia)":"sr-RS",
"Slovak (Slovakia)":"sk-SK",
"Slovenian (Slovenia)":"sl-SI",
"Spanish (Argentina)":"es-AR",
"Spanish (Bolivia)":"es-BO",
"Spanish (Chile)":"es-CL",
"Spanish (Colombia)":"es-CO",
"Spanish (Costa Rica)":"es-CR",
"Spanish (Dominican Republic)":"es-DO",
"Spanish (Ecuador)":"es-EC",
"Spanish (El Salvador)":"es-SV",
"Spanish (Guatemala)":"es-GT",
"Spanish (Honduras)":"es-HN",
"Spanish (Mexico)":"es-MX",
"Spanish (Nicaragua)":"es-NI",
"Spanish (Panama)":"es-PA",
"Spanish (Paraguay)":"es-PY",
"Spanish (Peru)":"es-PE",
"Spanish (Puerto Rico)":"es-PR",
"Spanish (Spain)":"es-ES",
"Spanish (Uruguay)":"es-UY",
"Spanish (United States)":"es-US",
"Spanish (Venezuela)":"es-VE",
"Swedish (Sweden)":"sv-SE",
"Thai (Thailand)":"th-TH",
"Turkish (Turkey)":"tr-TR",
"Ukrainian (Ukraine)":"uk-UA",
"Vietnamese (Vietnam)":"vi-VN",
"Zulu (South Africa)":"zu-ZA"
}

View File

@@ -15,11 +15,11 @@ class BaseRecorder:
self.source = source
def adjust_for_noise(self):
def adjustForNoise(self):
with self.source:
self.recorder.adjust_for_ambient_noise(self.source)
def record_into_queue(self, audio_queue):
def recordIntoQueue(self, audio_queue):
def record_callback(_, audio):
audio_queue.put((audio.get_raw_data(), datetime.now()))
@@ -32,7 +32,7 @@ class SelectedMicRecorder(BaseRecorder):
sample_rate=int(device["defaultSampleRate"]),
)
super().__init__(source=source, energy_threshold=energy_threshold, dynamic_energy_threshold=dynamic_energy_threshold, record_timeout=record_timeout)
# self.adjust_for_noise()
# self.adjustForNoise()
class SelectedSpeakerRecorder(BaseRecorder):
def __init__(self, device, energy_threshold, dynamic_energy_threshold, record_timeout):
@@ -44,7 +44,7 @@ class SelectedSpeakerRecorder(BaseRecorder):
channels=device["maxInputChannels"]
)
super().__init__(source=source, energy_threshold=energy_threshold, dynamic_energy_threshold=dynamic_energy_threshold, record_timeout=record_timeout)
# self.adjust_for_noise()
# self.adjustForNoise()
class BaseEnergyRecorder:
def __init__(self, source):
@@ -59,15 +59,15 @@ class BaseEnergyRecorder:
self.source = source
def adjust_for_noise(self):
def adjustForNoise(self):
with self.source:
self.recorder.adjust_for_ambient_noise(self.source)
def record_into_queue(self, energy_queue):
def record_callback(_, energy):
def recordIntoQueue(self, energy_queue):
def recordCallback(_, energy):
energy_queue.put(energy)
self.stop = self.recorder.listen_energy_in_background(self.source, record_callback)
self.stop = self.recorder.listen_energy_in_background(self.source, recordCallback)
class SelectedMicEnergyRecorder(BaseEnergyRecorder):
def __init__(self, device):
@@ -76,7 +76,7 @@ class SelectedMicEnergyRecorder(BaseEnergyRecorder):
sample_rate=int(device["defaultSampleRate"]),
)
super().__init__(source=source)
# self.adjust_for_noise()
# self.adjustForNoise()
class SelectedSpeakeEnergyRecorder(BaseEnergyRecorder):
def __init__(self, device):
@@ -88,4 +88,4 @@ class SelectedSpeakeEnergyRecorder(BaseEnergyRecorder):
channels=device["maxInputChannels"]
)
super().__init__(source=source)
# self.adjust_for_noise()
# self.adjustForNoise()

View File

@@ -4,6 +4,7 @@ import wave
from speech_recognition import Recognizer, AudioData, AudioFile
from datetime import timedelta
from pyaudiowpatch import get_sample_size, paInt16
from .transcription_languages import transcription_lang
PHRASE_TIMEOUT = 3
MAX_PHRASES = 10
@@ -23,20 +24,20 @@ class AudioTranscriber:
"last_sample": bytes(),
"last_spoken": None,
"new_phrase": True,
"process_data_func": self.process_speaker_data if speaker else self.process_speaker_data
"process_data_func": self.processSpeakerData if speaker else self.processSpeakerData
}
def transcribe_audio_queue(self, audio_queue, language):
def transcribeAudioQueue(self, audio_queue, language):
# while True:
audio, time_spoken = audio_queue.get()
self.update_last_sample_and_phrase_status(audio, time_spoken)
self.updateLastSampleAndPhraseStatus(audio, time_spoken)
text = ''
try:
# fd, path = tempfile.mkstemp(suffix=".wav")
# os.close(fd)
audio_data = self.audio_sources["process_data_func"]()
text = self.audio_recognizer.recognize_google(audio_data, language=language)
text = self.audio_recognizer.recognize_google(audio_data, language=transcription_lang[language])
except Exception as e:
pass
finally:
@@ -44,9 +45,9 @@ class AudioTranscriber:
# os.unlink(path)
if text != '':
self.update_transcript(text)
self.updateTranscript(text)
def update_last_sample_and_phrase_status(self, data, time_spoken):
def updateLastSampleAndPhraseStatus(self, data, time_spoken):
source_info = self.audio_sources
if source_info["last_spoken"] and time_spoken - source_info["last_spoken"] > timedelta(seconds=self.phrase_timeout):
source_info["last_sample"] = bytes()
@@ -57,11 +58,11 @@ class AudioTranscriber:
source_info["last_sample"] += data
source_info["last_spoken"] = time_spoken
def process_mic_data(self):
def processMicData(self):
audio_data = AudioData(self.audio_sources["last_sample"], self.audio_sources["sample_rate"], self.audio_sources["sample_width"])
return audio_data
def process_speaker_data(self):
def processSpeakerData(self):
temp_file = BytesIO()
with wave.open(temp_file, 'wb') as wf:
wf.setnchannels(self.audio_sources["channels"])
@@ -73,7 +74,7 @@ class AudioTranscriber:
audio = self.audio_recognizer.record(source)
return audio
def update_transcript(self, text):
def updateTranscript(self, text):
source_info = self.audio_sources
transcript = self.transcript_data
@@ -84,14 +85,14 @@ class AudioTranscriber:
else:
transcript[0] = text
def get_transcript(self):
def getTranscript(self):
if len(self.transcript_data) > 0:
text = self.transcript_data.pop(-1)
else:
text = ""
return text
def clear_transcript_data(self):
def clearTranscriptData(self):
self.transcript_data.clear()
self.audio_sources["last_sample"] = bytes()
self.audio_sources["new_phrase"] = True

View File

@@ -1,6 +1,6 @@
from pyaudiowpatch import PyAudio, paWASAPI
def get_input_device_list():
def getInputDevices():
devices = {}
with PyAudio() as p:
for host_index in range(0, p.get_host_api_count()):
@@ -14,7 +14,7 @@ def get_input_device_list():
devices[host["name"]] = [device]
return devices
def get_output_device_list():
def getOutputDevices():
devices =[]
with PyAudio() as p:
wasapi_info = p.get_host_api_info_by_type(paWASAPI)
@@ -23,7 +23,7 @@ def get_output_device_list():
devices.append(device)
return devices
def get_default_input_device():
def getDefaultInputDevice():
with PyAudio() as p:
api_info = p.get_default_host_api_info()
defaultInputDevice = api_info["defaultInputDevice"]
@@ -35,7 +35,7 @@ def get_default_input_device():
if device["index"] == defaultInputDevice:
return {"host":host, "device": device}
def get_default_output_device():
def getDefaultOutputDevice():
with PyAudio() as p:
wasapi_info = p.get_host_api_info_by_type(paWASAPI)
defaultOutputDevice = wasapi_info["defaultOutputDevice"]

View File

@@ -0,0 +1,243 @@
translatorEngine = ["DeepL(web)", "DeepL(auth)", "Google(web)", "Bing(web)"]
translation_lang = {}
dict_deepl_web_languages = {
"Japanese":"JA",
"English":"EN",
"Korean":"KO",
"Bulgarian":"BG",
"Chinese":"ZH",
"Czech":"CS",
"Danish":"DA",
"Dutch":"NL",
"Estonian":"ET",
"Finnish":"FI",
"French":"FR",
"German":"DE",
"Greek":"EL",
"Hungarian":"HU",
"Italian":"IT",
"Latvian":"LV",
"Lithuanian":"LT",
"Polish":"PL",
"Portuguese":"PT",
"Romanian":"RO",
"Russian":"RU",
"Slovak":"SK",
"Slovenian":"SL",
"Spanish":"ES",
"Swedish":"SV",
"Indonesian":"ID",
"Ukrainian":"UK",
"Turkish":"TR",
"Norwegian":"NB",
}
translation_lang["DeepL(web)"] = {
"source":dict_deepl_web_languages,
"target":dict_deepl_web_languages,
}
dict_deepl_auth_source_languages = {
"Japanese":"ja",
"English":"en",
"Bulgarian":"bg",
"Czech":"cs",
"Danish":"da",
"German":"de",
"Greek":"el",
"Spanish":"es",
"Estonian":"et",
"Finnish":"fi",
"French":"fr",
"Hungarian":"hu",
"Indonesian":"id",
"Italian":"it",
"Korean":"ko",
"Lithuanian":"lt",
"Latvian":"lv",
"Norwegian":"nb",
"Dutch":"nl",
"Polish":"pl",
"Portuguese":"pt",
"Romanian":"ro",
"Russian":"ru",
"Slovak":"sk",
"Slovenian":"sl",
"Swedish":"sv",
"Turkish":"tr",
"Ukrainian":"uk",
"Chinese":"zh"
}
dict_deepl_auth_target_languages = {
"Japanese":"ja",
"English American":"en-US",
"English British":"en-GB",
"Bulgarian":"bg",
"Czech":"cs",
"Danish":"da",
"German":"de",
"Greek":"el",
"English":"en",
"Spanish":"es",
"Estonian":"et",
"Finnish":"fi",
"French":"fr",
"Hungarian":"hu",
"Indonesian":"id",
"Italian":"it",
"Korean":"ko",
"Lithuanian":"lt",
"Latvian":"lv",
"Norwegian":"nb",
"Dutch":"nl",
"Polish":"pl",
"Portuguese Brazilian":"pt-BR",
"Portuguese European":"pt-PT",
"Romanian":"ro",
"Russian":"ru",
"Slovak":"sk",
"Slovenian":"sl",
"Swedish":"sv",
"Turkish":"tr",
"Ukrainian":"uk",
"Chinese":"zh"
}
translation_lang["DeepL(auth)"] = {
"source": dict_deepl_auth_source_languages,
"target": dict_deepl_auth_target_languages,
}
dict_google_web_languages = {
"Japanese":"ja",
"English":"en",
"Chinese":"zh",
"Arabic":"ar",
"Russian":"ru",
"French":"fr",
"German":"de",
"Spanish":"es",
"Portuguese":"pt",
"Italian":"it",
"Korean":"ko",
"Greek":"el",
"Dutch":"nl",
"Hindi":"hi",
"Turkish":"tr",
"Malay":"ms",
"Thai":"th",
"Vietnamese":"vi",
"Indonesian":"id",
"Hebrew":"he",
"Polish":"pl",
"Mongolian":"mn",
"Czech":"cs",
"Hungarian":"hu",
"Estonian":"et",
"Bulgarian":"bg",
"Danish":"da",
"Finnish":"fi",
"Romanian":"ro",
"Swedish":"sv",
"Slovenian":"sl",
"Persian/Farsi":"fa",
"Bosnian":"bs",
"Serbian":"sr",
"Filipino":"tl",
"Haitiancreole":"ht",
"Catalan":"ca",
"Croatian":"hr",
"Latvian":"lv",
"Lithuanian":"lt",
"Urdu":"ur",
"Ukrainian":"uk",
"Welsh":"cy",
"Swahili":"sw",
"Samoan":"sm",
"Slovak":"sk",
"Afrikaans":"af",
"Norwegian":"no",
"Bengali":"bn",
"Malagasy":"mg",
"Maltese":"mt",
"Gujarati":"gu",
"Tamil":"ta",
"Telugu":"te",
"Punjabi":"pa",
"Amharic":"am",
"Azerbaijani":"az",
"Belarusian":"be",
"Cebuano":"ceb",
"Esperanto":"eo",
"Basque":"eu",
"Irish":"ga"
}
translation_lang["Google(web)"] = {
"source":dict_google_web_languages,
"target":dict_google_web_languages,
}
dict_bing_web_languages = {
"Japanese":"ja",
"English":"en",
"Chinese":"zh",
"Arabic":"ar",
"Russian":"ru",
"French":"fr",
"German":"de",
"Spanish":"es",
"Portuguese":"pt",
"Italian":"it",
"Korean":"ko",
"Greek":"el",
"Dutch":"nl",
"Hindi":"hi",
"Turkish":"tr",
"Malay":"ms",
"Thai":"th",
"Vietnamese":"vi",
"Indonesian":"id",
"Hebrew":"he",
"Polish":"pl",
"Czech":"cs",
"Hungarian":"hu",
"Estonian":"et",
"Bulgarian":"bg",
"Danish":"da",
"Finnish":"fi",
"Romanian":"ro",
"Swedish":"sv",
"Slovenian":"sl",
"Persian/Farsi":"fa",
"Bosnian":"bs",
"Serbian":"sr",
"Fijian":"fj",
"Filipino":"tl",
"Haitiancreole":"ht",
"Catalan":"ca",
"Croatian":"hr",
"Latvian":"lv",
"Lithuanian":"lt",
"Urdu":"ur",
"Ukrainian":"uk",
"Welsh":"cy",
"Tahiti":"ty",
"Tongan":"to",
"Swahili":"sw",
"Samoan":"sm",
"Slovak":"sk",
"Afrikaans":"af",
"Norwegian":"no",
"Bengali":"bn",
"Malagasy":"mg",
"Maltese":"mt",
"Queretaro otomi":"otq",
"Klingon/tlhingan Hol":"tlh",
"Gujarati":"gu",
"Tamil":"ta",
"Telugu":"te",
"Punjabi":"pa",
"Irish":"ga"
}
translation_lang["Bing(web)"] = {
"source":dict_bing_web_languages,
"target":dict_bing_web_languages,
}

View File

@@ -1,13 +1,13 @@
from deepl import Translator as deepl_Translator
from deepl_translate import translate as deepl_web_Translator
from translators import translate_text as other_web_Translator
from languages import translators, translation_lang
from .translation_languages import translatorEngine, translation_lang
# Translator
class Translator():
def __init__(self):
self.translator_status = {}
for translator in translators:
for translator in translatorEngine:
self.translator_status[translator] = False
self.deepl_client = None

View File

@@ -19,7 +19,7 @@ import socket
import json
import base64
def notification_xsoverlay(
def XSOverlay(
endpoint:tuple=("127.0.0.1", 42069), messageType:int=1, index:int=0, timeout:float=2,
height:float=120.0, opacity:float=1.0, volume:float=0.0, audioPath:str="",
title:str="", content:str="", useBase64Icon:bool=False, icon:str="default", sourceApp:str=""
@@ -58,8 +58,8 @@ def notification_xsoverlay(
sock.close()
return response
def notification_xsoverlay_for_vrct(content:str="") -> int:
response = notification_xsoverlay(
def xsoverlayForVRCT(content:str="") -> int:
response = XSOverlay(
title="VRCT",
content=content,
useBase64Icon=True,
@@ -69,4 +69,4 @@ def notification_xsoverlay_for_vrct(content:str="") -> int:
return response
if __name__ == "__main__":
notification_xsoverlay_for_vrct(content="notification test")
xsoverlayForVRCT(content="notification test")

View File

@@ -1,15 +1,6 @@
from json import load, dump
from os import path as os_path
import yaml
from datetime import datetime
from threading import Thread, Event
def save_json(path, key, value):
with open(path, "r") as fp:
json_data = load(fp)
json_data[key] = value
with open(path, "w") as fp:
dump(json_data, fp, indent=4)
def print_textbox(textbox, message, tags=None):
now = datetime.now()
@@ -27,21 +18,6 @@ def print_textbox(textbox, message, tags=None):
textbox.configure(state='disabled')
textbox.see("end")
class thread_fnc(Thread):
def __init__(self, fnc, daemon=True, *args, **kwargs):
super(thread_fnc, self).__init__(daemon=daemon, *args, **kwargs)
self.fnc = fnc
self._stop = Event()
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.isSet()
def run(self):
while True:
if self.stopped():
return
self.fnc(*self._args, **self._kwargs)
def get_localized_text(language):
file_path = os_path.join(os_path.dirname(__file__), "locales.yml")

View File

@@ -1,19 +1,16 @@
from time import sleep
from queue import Queue
from os import path as os_path
from tkinter import DoubleVar, IntVar
from tkinter import font as tk_font
import customtkinter
from customtkinter import CTkToplevel, CTkTabview, CTkFont, CTkLabel, CTkSlider, CTkOptionMenu, StringVar, CTkEntry, CTkCheckBox, CTkProgressBar
from flashtext import KeywordProcessor
from threading import Thread
from config import config
from utils import print_textbox, thread_fnc, get_localized_text, get_key_by_value, widget_config_window_label_setter
from audio_utils import get_input_device_list, get_output_device_list, get_default_output_device
from audio_recorder import SelectedMicEnergyRecorder, SelectedSpeakeEnergyRecorder
from languages import translation_lang, transcription_lang, selectable_languages
from model import model
from utils import print_textbox, get_localized_text, get_key_by_value, widget_config_window_label_setter
from languages import selectable_languages
from models.translation.translation_languages import translation_lang
from models.transcription.transcription_languages import transcription_lang
from ctk_scrollable_dropdown import CTkScrollableDropdown
SCROLLABLE_DROPDOWN = False
@@ -33,15 +30,6 @@ class ToplevelWindowConfig(CTkToplevel):
self.after(200, lambda: self.iconbitmap(os_path.join(os_path.dirname(__file__), "img", "app.ico")))
self.title("Config")
# init parameter
self.MAX_MIC_ENERGY_THRESHOLD = 2000
self.MAX_SPEAKER_ENERGY_THRESHOLD = 4000
self.mic_energy_recorder = None
self.mic_energy_plot_progressbar = None
self.speaker_energy_recorder = None
self.speaker_energy_get_progressbar = None
self.speaker_energy_plot_progressbar = None
# load ui language data
language_yaml_data = get_localized_text(f"{config.UI_LANGUAGE}")
# add tabview config
@@ -202,7 +190,7 @@ class ToplevelWindowConfig(CTkToplevel):
def optionmenu_translation_translator_callback(self, choice):
self.optionmenu_translation_translator.set(choice)
if self.parent.translator.authentication(choice, config.AUTH_KEYS[choice]) is False:
if model.authenticationTranslator(choice_translator=choice) is False:
print_textbox(self.parent.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
print_textbox(self.parent.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
else:
@@ -253,15 +241,15 @@ class ToplevelWindowConfig(CTkToplevel):
def optionmenu_input_mic_host_callback(self, choice):
self.optionmenu_input_mic_host.set(choice)
config.CHOICE_MIC_HOST = choice
config.CHOICE_MIC_DEVICE = model.getInputDefaultDevice()
self.optionmenu_input_mic_device.configure(
values=[device["name"] for device in get_input_device_list()[choice]],
variable=StringVar(value=[device["name"] for device in get_input_device_list()[choice]][0]))
values=model.getListInputDevice(),
variable=StringVar(value=model.getInputDefaultDevice()))
if SCROLLABLE_DROPDOWN:
self.scrollableDropdown_input_mic_device.configure(values=[device["name"] for device in get_input_device_list()[choice]])
config.CHOICE_MIC_HOST = choice
config.CHOICE_MIC_DEVICE = [device["name"] for device in get_input_device_list()[choice]][0]
self.scrollableDropdown_input_mic_device.configure(values=model.getListInputDevice())
def optionmenu_input_mic_device_callback(self, choice):
self.optionmenu_input_mic_device.set(choice)
@@ -273,31 +261,18 @@ class ToplevelWindowConfig(CTkToplevel):
self.optionmenu_input_mic_voice_language.set(choice)
config.INPUT_MIC_VOICE_LANGUAGE = choice
def progressBar_input_mic_energy_plot(self):
if self.mic_energy_queue.empty() is False:
energy = self.mic_energy_queue.get()
def mic_threshold_check_start(self):
def plotProgressBar(energy):
try:
self.progressBar_input_mic_energy_threshold.set(energy/self.MAX_MIC_ENERGY_THRESHOLD)
self.progressBar_input_mic_energy_threshold.set(energy/config.MAX_MIC_ENERGY_THRESHOLD)
except:
pass
sleep(0.01)
def mic_threshold_check_start(self):
self.mic_energy_queue = Queue()
mic_device = [device for device in get_input_device_list()[config.CHOICE_MIC_HOST] if device["name"] == config.CHOICE_MIC_DEVICE][0]
self.mic_energy_recorder = SelectedMicEnergyRecorder(mic_device)
self.mic_energy_recorder.record_into_queue(self.mic_energy_queue)
self.mic_energy_plot_progressbar = thread_fnc(self.progressBar_input_mic_energy_plot)
self.mic_energy_plot_progressbar.daemon = True
self.mic_energy_plot_progressbar.start()
model.startCheckMicEnergy(plotProgressBar)
self.checkbox_input_mic_threshold_check.configure(state="normal")
self.checkbox_input_speaker_threshold_check.configure(state="normal")
def mic_threshold_check_stop(self):
if self.mic_energy_recorder != None:
self.mic_energy_recorder.stop()
if self.mic_energy_plot_progressbar != None:
self.mic_energy_plot_progressbar.stop()
model.stopCheckMicEnergy()
self.progressBar_input_mic_energy_threshold.set(0)
self.checkbox_input_mic_threshold_check.configure(state="normal")
self.checkbox_input_speaker_threshold_check.configure(state="normal")
@@ -338,13 +313,11 @@ class ToplevelWindowConfig(CTkToplevel):
config.INPUT_MIC_WORD_FILTER = word_filter.split(",")
else:
config.INPUT_MIC_WORD_FILTER = []
self.parent.keyword_processor = KeywordProcessor()
for f in self.parent.INPUT_MIC_WORD_FILTER:
self.parent.keyword_processor.add_keyword(f)
model.resetKeywordProcessor()
model.addKeywords()
def optionmenu_input_speaker_device_callback(self, choice):
speaker_device = [device for device in get_output_device_list() if device["name"] == choice][0]
if get_default_output_device()["index"] == speaker_device["index"]:
if model.checkSpeakerStatus(choice):
self.optionmenu_input_speaker_device.set(choice)
config.CHOICE_SPEAKER_DEVICE = choice
else:
@@ -356,45 +329,18 @@ class ToplevelWindowConfig(CTkToplevel):
self.optionmenu_input_speaker_voice_language.set(choice)
config.INPUT_SPEAKER_VOICE_LANGUAGE = choice
def progressBar_input_speaker_energy_plot(self):
if self.speaker_energy_queue.empty() is False:
energy = self.speaker_energy_queue.get()
def speaker_threshold_check_start(self):
def plotProgressBar(energy):
try:
self.progressBar_input_speaker_energy_threshold.set(energy/self.MAX_SPEAKER_ENERGY_THRESHOLD)
self.progressBar_input_speaker_energy_threshold.set(energy/config.MAX_MIC_ENERGY_THRESHOLD)
except:
pass
sleep(0.01)
def progressBar_input_speaker_energy_get(self):
with self.speaker_energy_recorder.source as source:
energy = self.speaker_energy_recorder.recorder.listen_energy(source)
self.speaker_energy_queue.put(energy)
def speaker_threshold_check_start(self):
speaker_device = [device for device in get_output_device_list() if device["name"] == config.CHOICE_SPEAKER_DEVICE][0]
if get_default_output_device()["index"] == speaker_device["index"]:
self.speaker_energy_queue = Queue()
self.speaker_energy_recorder = SelectedSpeakeEnergyRecorder(speaker_device)
self.speaker_energy_get_progressbar = thread_fnc(self.progressBar_input_speaker_energy_get)
self.speaker_energy_get_progressbar.daemon = True
self.speaker_energy_get_progressbar.start()
self.speaker_energy_plot_progressbar = thread_fnc(self.progressBar_input_speaker_energy_plot)
self.speaker_energy_plot_progressbar.daemon = True
self.speaker_energy_plot_progressbar.start()
else:
print_textbox(self.parent.textbox_message_log, "Windows playback device and selected device do not match. Change the Windows playback device.", "ERROR")
print_textbox(self.parent.textbox_message_system_log, "Windows playback device and selected device do not match. Change the Windows playback device.", "ERROR")
self.checkbox_input_speaker_threshold_check.deselect()
model.startCheckSpeakerEnergy(plotProgressBar)
self.checkbox_input_mic_threshold_check.configure(state="normal")
self.checkbox_input_speaker_threshold_check.configure(state="normal")
def speaker_threshold_check_stop(self):
if self.speaker_energy_get_progressbar != None:
self.speaker_energy_get_progressbar.stop()
if self.speaker_energy_plot_progressbar != None:
self.speaker_energy_plot_progressbar.stop()
model.stopCheckSpeakerEnergy()
self.progressBar_input_speaker_energy_threshold.set(0)
self.checkbox_input_mic_threshold_check.configure(state="normal")
self.checkbox_input_speaker_threshold_check.configure(state="normal")
@@ -404,9 +350,14 @@ class ToplevelWindowConfig(CTkToplevel):
self.checkbox_input_speaker_threshold_check.configure(state="disabled")
self.update()
if self.checkbox_input_speaker_threshold_check.get():
th_speaker_threshold_check_start = Thread(target=self.speaker_threshold_check_start)
th_speaker_threshold_check_start.daemon = True
th_speaker_threshold_check_start.start()
if model.checkSpeakerStatus():
th_speaker_threshold_check_start = Thread(target=self.speaker_threshold_check_start)
th_speaker_threshold_check_start.daemon = True
th_speaker_threshold_check_start.start()
else:
print_textbox(self.parent.textbox_message_log, "Windows playback device and selected device do not match. Change the Windows playback device.", "ERROR")
print_textbox(self.parent.textbox_message_system_log, "Windows playback device and selected device do not match. Change the Windows playback device.", "ERROR")
self.checkbox_input_speaker_threshold_check.deselect()
else:
th_speaker_threshold_check_stop = Thread(target=self.speaker_threshold_check_stop)
th_speaker_threshold_check_stop.daemon = True
@@ -436,10 +387,7 @@ class ToplevelWindowConfig(CTkToplevel):
def entry_authkey_callback(self, event):
value = self.entry_authkey.get()
if len(value) > 0:
if self.parent.translator.authentication("DeepL(auth)", value) is True:
auth_keys = config.AUTH_KEYS
auth_keys["DeepL(auth)"] = value
config.AUTH_KEYS = auth_keys
if model.authenticationTranslator(choice_translator="DeepL(auth)", auth_key=value) is True:
print_textbox(self.parent.textbox_message_log, "Auth key update completed", "INFO")
print_textbox(self.parent.textbox_message_system_log, "Auth key update completed", "INFO")
else:
@@ -683,7 +631,7 @@ class ToplevelWindowConfig(CTkToplevel):
self.label_translation_translator.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw")
self.optionmenu_translation_translator = CTkOptionMenu(
self.tabview_config.tab(config_tab_title_translation),
values=list(self.parent.translator.translator_status.keys()),
values=model.getListTranslatorName(),
command=self.optionmenu_translation_translator_callback,
variable=StringVar(value=config.CHOICE_TRANSLATOR),
font=CTkFont(family=config.FONT_FAMILY),
@@ -695,7 +643,7 @@ class ToplevelWindowConfig(CTkToplevel):
if SCROLLABLE_DROPDOWN:
self.scrollableDropdown_translation_translator = CTkScrollableDropdown(
self.optionmenu_translation_translator,
values=list(self.parent.translator.translator_status.keys()),
values=model.getListTranslatorName(),
justify="left",
button_color="transparent",
command=self.optionmenu_translation_translator_callback,
@@ -862,7 +810,7 @@ class ToplevelWindowConfig(CTkToplevel):
self.label_input_mic_host.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw")
self.optionmenu_input_mic_host = CTkOptionMenu(
self.tabview_config.tab(config_tab_title_transcription),
values=[host for host in get_input_device_list().keys()],
values=model.getListInputHost(),
command=self.optionmenu_input_mic_host_callback,
variable=StringVar(value=config.CHOICE_MIC_HOST),
font=CTkFont(family=config.FONT_FAMILY),
@@ -874,7 +822,7 @@ class ToplevelWindowConfig(CTkToplevel):
if SCROLLABLE_DROPDOWN:
self.scrollableDropdown_input_mic_host = CTkScrollableDropdown(
self.optionmenu_input_mic_host,
values=[host for host in get_input_device_list().keys()],
values=model.getListInputHost(),
justify="left",
button_color="transparent",
command=self.optionmenu_input_mic_host_callback,
@@ -896,7 +844,7 @@ class ToplevelWindowConfig(CTkToplevel):
self.label_input_mic_device.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw")
self.optionmenu_input_mic_device = CTkOptionMenu(
self.tabview_config.tab(config_tab_title_transcription),
values=[device["name"] for device in get_input_device_list()[config.CHOICE_MIC_HOST]],
values=model.getListInputDevice(),
command=self.optionmenu_input_mic_device_callback,
variable=StringVar(value=config.CHOICE_MIC_DEVICE),
font=CTkFont(family=config.FONT_FAMILY),
@@ -908,7 +856,7 @@ class ToplevelWindowConfig(CTkToplevel):
if SCROLLABLE_DROPDOWN:
self.scrollableDropdown_input_mic_device = CTkScrollableDropdown(
self.optionmenu_input_mic_device,
values=[device["name"] for device in get_input_device_list()[config.CHOICE_MIC_HOST]],
values=model.getListInputDevice(),
justify="left",
button_color="transparent",
command=self.optionmenu_input_mic_device_callback,
@@ -966,11 +914,11 @@ class ToplevelWindowConfig(CTkToplevel):
self.slider_input_mic_energy_threshold = CTkSlider(
self.tabview_config.tab(config_tab_title_transcription),
from_=0,
to=self.MAX_MIC_ENERGY_THRESHOLD,
to=config.MAX_MIC_ENERGY_THRESHOLD,
border_width=7,
button_length=0,
button_corner_radius=3,
number_of_steps=self.MAX_MIC_ENERGY_THRESHOLD,
number_of_steps=config.MAX_MIC_ENERGY_THRESHOLD,
command=self.slider_input_mic_energy_threshold_callback,
variable=IntVar(value=config.INPUT_MIC_ENERGY_THRESHOLD),
)
@@ -1102,7 +1050,7 @@ class ToplevelWindowConfig(CTkToplevel):
self.label_input_speaker_device.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw")
self.optionmenu_input_speaker_device = CTkOptionMenu(
self.tabview_config.tab(config_tab_title_transcription),
values=[device["name"] for device in get_output_device_list()],
values=model.getListOutputDevice(),
command=self.optionmenu_input_speaker_device_callback,
variable=StringVar(value=config.CHOICE_SPEAKER_DEVICE),
font=CTkFont(family=config.FONT_FAMILY),
@@ -1114,7 +1062,7 @@ class ToplevelWindowConfig(CTkToplevel):
if SCROLLABLE_DROPDOWN:
self.scrollableDropdown_input_speaker_device = CTkScrollableDropdown(
self.optionmenu_input_speaker_device,
values=[device["name"] for device in get_output_device_list()],
values=model.getListOutputDevice(),
justify="left",
button_color="transparent",
command=self.optionmenu_input_speaker_device_callback,
@@ -1173,11 +1121,11 @@ class ToplevelWindowConfig(CTkToplevel):
self.slider_input_speaker_energy_threshold = CTkSlider(
self.tabview_config.tab(config_tab_title_transcription),
from_=0,
to=self.MAX_SPEAKER_ENERGY_THRESHOLD,
to=config.MAX_SPEAKER_ENERGY_THRESHOLD,
border_width=7,
button_length=0,
button_corner_radius=3,
number_of_steps=self.MAX_SPEAKER_ENERGY_THRESHOLD,
number_of_steps=config.MAX_SPEAKER_ENERGY_THRESHOLD,
command=self.slider_input_speaker_energy_threshold_callback,
variable=IntVar(value=config.INPUT_SPEAKER_ENERGY_THRESHOLD),
)