import sys import inspect from os import path as os_path, makedirs as os_makedirs from json import load as json_load from json import dump as json_dump import tkinter as tk from tkinter import font from models.translation.translation_languages import translation_lang from models.transcription.transcription_utils import getInputDevices, getDefaultInputDevice, getOutputDevices, getDefaultOutputDevice from models.transcription.transcription_languages import transcription_lang from utils import generatePercentageStringsList, isUniqueStrings json_serializable_vars = {} def json_serializable(var_name): def decorator(func): json_serializable_vars[var_name] = func return func return decorator def saveJson(path, key, value): with open(path, "r", encoding="utf-8") as fp: json_data = json_load(fp) json_data[key] = value with open(path, "w", encoding="utf-8") as fp: json_dump(json_data, fp, indent=4, ensure_ascii=False) class Config: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super(Config, cls).__new__(cls) cls._instance.init_config() cls._instance.load_config() return cls._instance # Read Only @property def VERSION(self): return self._VERSION @property def ENABLE_SPEAKER2CHATBOX_PASS_CONFIRMATION(self): return self._ENABLE_SPEAKER2CHATBOX_PASS_CONFIRMATION @property def PATH_LOCAL(self): return self._PATH_LOCAL @property def PATH_CONFIG(self): return self._PATH_CONFIG @property def PATH_LOGS(self): return self._PATH_LOGS @property def GITHUB_URL(self): return self._GITHUB_URL @property def BOOTH_URL(self): return self._BOOTH_URL @property def DOCUMENTS_URL(self): return self._DOCUMENTS_URL @property def DEEPL_AUTH_KEY_PAGE_URL(self): return self._DEEPL_AUTH_KEY_PAGE_URL @property def TRANSPARENCY_RANGE(self): return self._TRANSPARENCY_RANGE @property def APPEARANCE_THEME_LIST(self): return self._APPEARANCE_THEME_LIST @property def UI_SCALING_LIST(self): return self._UI_SCALING_LIST @property def TEXTBOX_UI_SCALING_RANGE(self): return self._TEXTBOX_UI_SCALING_RANGE @property def MESSAGE_BOX_RATIO_RANGE(self): return self._MESSAGE_BOX_RATIO_RANGE @property def SELECTABLE_UI_LANGUAGES_DICT(self): return self._SELECTABLE_UI_LANGUAGES_DICT @property def SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT(self): return self._SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT @property def SELECTABLE_WHISPER_WEIGHT_TYPE_DICT(self): return self._SELECTABLE_WHISPER_WEIGHT_TYPE_DICT @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 # Read Write @property def ENABLE_SPEAKER2CHATBOX(self): return self._ENABLE_SPEAKER2CHATBOX @ENABLE_SPEAKER2CHATBOX.setter def ENABLE_SPEAKER2CHATBOX(self, value): if isinstance(value, bool): self._ENABLE_SPEAKER2CHATBOX = value @property def ENABLE_TRANSLATION(self): return self._ENABLE_TRANSLATION @ENABLE_TRANSLATION.setter def ENABLE_TRANSLATION(self, value): if isinstance(value, 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 isinstance(value, 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 isinstance(value, bool): self._ENABLE_TRANSCRIPTION_RECEIVE = value @property def ENABLE_FOREGROUND(self): return self._ENABLE_FOREGROUND @ENABLE_FOREGROUND.setter def ENABLE_FOREGROUND(self, value): if isinstance(value, bool): self._ENABLE_FOREGROUND = value @property def ENABLE_CHECK_ENERGY_SEND(self): return self._ENABLE_CHECK_ENERGY_SEND @ENABLE_CHECK_ENERGY_SEND.setter def ENABLE_CHECK_ENERGY_SEND(self, value): if isinstance(value, bool): self._ENABLE_CHECK_ENERGY_SEND = value @property def ENABLE_CHECK_ENERGY_RECEIVE(self): return self._ENABLE_CHECK_ENERGY_RECEIVE @ENABLE_CHECK_ENERGY_RECEIVE.setter def ENABLE_CHECK_ENERGY_RECEIVE(self, value): if isinstance(value, bool): self._ENABLE_CHECK_ENERGY_RECEIVE = value # @property # def SENT_MESSAGES_LOG(self): # return self._SENT_MESSAGES_LOG # @SENT_MESSAGES_LOG.setter # def SENT_MESSAGES_LOG(self, value): # if isinstance(value, list): # self._SENT_MESSAGES_LOG = value # @property # def CURRENT_SENT_MESSAGES_LOG_INDEX(self): # return self._CURRENT_SENT_MESSAGES_LOG_INDEX # @CURRENT_SENT_MESSAGES_LOG_INDEX.setter # def CURRENT_SENT_MESSAGES_LOG_INDEX(self, value): # if isinstance(value, int): # self._CURRENT_SENT_MESSAGES_LOG_INDEX = value @property def IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION(self): return self._IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION @IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION.setter def IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION(self, value): if isinstance(value, bool): self._IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION = value @property def IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER(self): return self._IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER @IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER.setter def IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER(self, value): if isinstance(value, bool): self._IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER = value # @property # def IS_EASTER_EGG_ENABLED(self): # return self._IS_EASTER_EGG_ENABLED # @IS_EASTER_EGG_ENABLED.setter # def IS_EASTER_EGG_ENABLED(self, value): # if isinstance(value, bool): # self._IS_EASTER_EGG_ENABLED = value # Save Json Data ## Main Window @property @json_serializable('SELECTED_TAB_NO') def SELECTED_TAB_NO(self): return self._SELECTED_TAB_NO @SELECTED_TAB_NO.setter def SELECTED_TAB_NO(self, value): if isinstance(value, str): self._SELECTED_TAB_NO = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('SELECTED_TAB_YOUR_TRANSLATOR_ENGINES') def SELECTED_TAB_YOUR_TRANSLATOR_ENGINES(self): return self._SELECTED_TAB_YOUR_TRANSLATOR_ENGINES @SELECTED_TAB_YOUR_TRANSLATOR_ENGINES.setter def SELECTED_TAB_YOUR_TRANSLATOR_ENGINES(self, value): if isinstance(value, dict): self._SELECTED_TAB_YOUR_TRANSLATOR_ENGINES = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('SELECTED_TAB_TARGET_TRANSLATOR_ENGINES') def SELECTED_TAB_TARGET_TRANSLATOR_ENGINES(self): return self._SELECTED_TAB_TARGET_TRANSLATOR_ENGINES @SELECTED_TAB_TARGET_TRANSLATOR_ENGINES.setter def SELECTED_TAB_TARGET_TRANSLATOR_ENGINES(self, value): if isinstance(value, dict): self._SELECTED_TAB_TARGET_TRANSLATOR_ENGINES = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('SELECTED_TAB_YOUR_LANGUAGES') def SELECTED_TAB_YOUR_LANGUAGES(self): return self._SELECTED_TAB_YOUR_LANGUAGES @SELECTED_TAB_YOUR_LANGUAGES.setter def SELECTED_TAB_YOUR_LANGUAGES(self, value): try: if isinstance(value, dict): value_old = self.SELECTED_TAB_YOUR_LANGUAGES for k0, v0 in value.items(): for k1, v1 in v0.items(): language = v1["language"] country = v1["country"] if language not in list(transcription_lang.keys()) or country not in list(transcription_lang[language].keys()): value[k0][k1] = value_old[k0][k1] self._SELECTED_TAB_YOUR_LANGUAGES = value except Exception: pass saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('SELECTED_TAB_TARGET_LANGUAGES') def SELECTED_TAB_TARGET_LANGUAGES(self): return self._SELECTED_TAB_TARGET_LANGUAGES @SELECTED_TAB_TARGET_LANGUAGES.setter def SELECTED_TAB_TARGET_LANGUAGES(self, value): try: if isinstance(value, dict): value_old = self.SELECTED_TAB_TARGET_LANGUAGES for k0, v0 in value.items(): for k1, v1 in v0.items(): language = v1["language"] country = v1["country"] if language not in list(transcription_lang.keys()) or country not in list(transcription_lang[language].keys()): value[k0][k1] = value_old[k0][k1] self._SELECTED_TAB_TARGET_LANGUAGES = value except Exception: pass saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('SELECTED_TRANSCRIPTION_ENGINE') def SELECTED_TRANSCRIPTION_ENGINE(self): return self._SELECTED_TRANSCRIPTION_ENGINE @SELECTED_TRANSCRIPTION_ENGINE.setter def SELECTED_TRANSCRIPTION_ENGINE(self, value): if isinstance(value, str): self._SELECTED_TRANSCRIPTION_ENGINE = value # saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('ENABLE_MULTI_LANGUAGE_TRANSLATION') def ENABLE_MULTI_LANGUAGE_TRANSLATION(self): return self._ENABLE_MULTI_LANGUAGE_TRANSLATION @ENABLE_MULTI_LANGUAGE_TRANSLATION.setter def ENABLE_MULTI_LANGUAGE_TRANSLATION(self, value): if isinstance(value, bool): self._ENABLE_MULTI_LANGUAGE_TRANSLATION = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('ENABLE_CONVERT_MESSAGE_TO_ROMAJI') def ENABLE_CONVERT_MESSAGE_TO_ROMAJI(self): return self._ENABLE_CONVERT_MESSAGE_TO_ROMAJI @ENABLE_CONVERT_MESSAGE_TO_ROMAJI.setter def ENABLE_CONVERT_MESSAGE_TO_ROMAJI(self, value): if isinstance(value, bool): self._ENABLE_CONVERT_MESSAGE_TO_ROMAJI = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('ENABLE_CONVERT_MESSAGE_TO_HIRAGANA') def ENABLE_CONVERT_MESSAGE_TO_HIRAGANA(self): return self._ENABLE_CONVERT_MESSAGE_TO_HIRAGANA @ENABLE_CONVERT_MESSAGE_TO_HIRAGANA.setter def ENABLE_CONVERT_MESSAGE_TO_HIRAGANA(self, value): if isinstance(value, bool): self._ENABLE_CONVERT_MESSAGE_TO_HIRAGANA = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE') def IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE(self): return self._IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE @IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE.setter def IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE(self, value): if isinstance(value, bool): self._IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) ## Config Window @property @json_serializable('TRANSPARENCY') def TRANSPARENCY(self): return self._TRANSPARENCY @TRANSPARENCY.setter def TRANSPARENCY(self, value): if isinstance(value, int) and self.TRANSPARENCY_RANGE[0] <= value <= self.TRANSPARENCY_RANGE[1]: self._TRANSPARENCY = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('APPEARANCE_THEME') def APPEARANCE_THEME(self): return self._APPEARANCE_THEME @APPEARANCE_THEME.setter def APPEARANCE_THEME(self, value): if value in self.APPEARANCE_THEME_LIST: self._APPEARANCE_THEME = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('UI_SCALING') def UI_SCALING(self): return self._UI_SCALING @UI_SCALING.setter def UI_SCALING(self, value): if value in self.UI_SCALING_LIST: self._UI_SCALING = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('TEXTBOX_UI_SCALING') def TEXTBOX_UI_SCALING(self): return self._TEXTBOX_UI_SCALING @TEXTBOX_UI_SCALING.setter def TEXTBOX_UI_SCALING(self, value): if isinstance(value, int) and self.TEXTBOX_UI_SCALING_RANGE[0] <= value <= self.TEXTBOX_UI_SCALING_RANGE[1]: self._TEXTBOX_UI_SCALING = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('MESSAGE_BOX_RATIO') def MESSAGE_BOX_RATIO(self): return self._MESSAGE_BOX_RATIO @MESSAGE_BOX_RATIO.setter def MESSAGE_BOX_RATIO(self, value): if isinstance(value, int) and self.MESSAGE_BOX_RATIO_RANGE[0] <= value <= self.MESSAGE_BOX_RATIO_RANGE[1]: self._MESSAGE_BOX_RATIO = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('FONT_FAMILY') def FONT_FAMILY(self): return self._FONT_FAMILY @FONT_FAMILY.setter def FONT_FAMILY(self, value): root = tk.Tk() root.withdraw() if value in list(font.families()): self._FONT_FAMILY = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) root.destroy() @property @json_serializable('UI_LANGUAGE') def UI_LANGUAGE(self): return self._UI_LANGUAGE @UI_LANGUAGE.setter def UI_LANGUAGE(self, value): if value in list(self.SELECTABLE_UI_LANGUAGES_DICT.keys()): self._UI_LANGUAGE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY') def ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY(self): return self._ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY @ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY.setter def ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY(self, value): if isinstance(value, bool): self._ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('MAIN_WINDOW_GEOMETRY') def MAIN_WINDOW_GEOMETRY(self): return self._MAIN_WINDOW_GEOMETRY @MAIN_WINDOW_GEOMETRY.setter def MAIN_WINDOW_GEOMETRY(self, value): if isinstance(value, dict) and set(value.keys()) == set(self.MAIN_WINDOW_GEOMETRY.keys()): for key, value in value.items(): if isinstance(value, str): self._MAIN_WINDOW_GEOMETRY[key] = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, self.MAIN_WINDOW_GEOMETRY) @property @json_serializable('CHOICE_MIC_HOST') def CHOICE_MIC_HOST(self): return self._CHOICE_MIC_HOST @CHOICE_MIC_HOST.setter def CHOICE_MIC_HOST(self, value): if value in [host for host in getInputDevices().keys()]: self._CHOICE_MIC_HOST = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('CHOICE_MIC_DEVICE') def CHOICE_MIC_DEVICE(self): return self._CHOICE_MIC_DEVICE @CHOICE_MIC_DEVICE.setter def CHOICE_MIC_DEVICE(self, value): if value in [device["name"] for device in getInputDevices()[self.CHOICE_MIC_HOST]]: self._CHOICE_MIC_DEVICE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_MIC_ENERGY_THRESHOLD') def INPUT_MIC_ENERGY_THRESHOLD(self): return self._INPUT_MIC_ENERGY_THRESHOLD @INPUT_MIC_ENERGY_THRESHOLD.setter def INPUT_MIC_ENERGY_THRESHOLD(self, value): if isinstance(value, int): self._INPUT_MIC_ENERGY_THRESHOLD = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD') def INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD(self): return self._INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD @INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD.setter def INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD(self, value): if isinstance(value, bool): self._INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_MIC_RECORD_TIMEOUT') def INPUT_MIC_RECORD_TIMEOUT(self): return self._INPUT_MIC_RECORD_TIMEOUT @INPUT_MIC_RECORD_TIMEOUT.setter def INPUT_MIC_RECORD_TIMEOUT(self, value): if isinstance(value, int): self._INPUT_MIC_RECORD_TIMEOUT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_MIC_PHRASE_TIMEOUT') def INPUT_MIC_PHRASE_TIMEOUT(self): return self._INPUT_MIC_PHRASE_TIMEOUT @INPUT_MIC_PHRASE_TIMEOUT.setter def INPUT_MIC_PHRASE_TIMEOUT(self, value): if isinstance(value, int): self._INPUT_MIC_PHRASE_TIMEOUT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_MIC_MAX_PHRASES') def INPUT_MIC_MAX_PHRASES(self): return self._INPUT_MIC_MAX_PHRASES @INPUT_MIC_MAX_PHRASES.setter def INPUT_MIC_MAX_PHRASES(self, value): if isinstance(value, int): self._INPUT_MIC_MAX_PHRASES = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_MIC_WORD_FILTER') def INPUT_MIC_WORD_FILTER(self): return self._INPUT_MIC_WORD_FILTER @INPUT_MIC_WORD_FILTER.setter def INPUT_MIC_WORD_FILTER(self, value): if isinstance(value, list): self._INPUT_MIC_WORD_FILTER = sorted(set(value), key=value.index) saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_MIC_AVG_LOGPROB') def INPUT_MIC_AVG_LOGPROB(self): return self._INPUT_MIC_AVG_LOGPROB @INPUT_MIC_AVG_LOGPROB.setter def INPUT_MIC_AVG_LOGPROB(self, value): if isinstance(value, float) or isinstance(value, int): self._INPUT_MIC_AVG_LOGPROB = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_MIC_NO_SPEECH_PROB') def INPUT_MIC_NO_SPEECH_PROB(self): return self._INPUT_MIC_NO_SPEECH_PROB @INPUT_MIC_NO_SPEECH_PROB.setter def INPUT_MIC_NO_SPEECH_PROB(self, value): if isinstance(value, float) or isinstance(value, int): self._INPUT_MIC_NO_SPEECH_PROB = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('CHOICE_SPEAKER_DEVICE') def CHOICE_SPEAKER_DEVICE(self): return self._CHOICE_SPEAKER_DEVICE @CHOICE_SPEAKER_DEVICE.setter def CHOICE_SPEAKER_DEVICE(self, value): if value in [device["name"] for device in getOutputDevices()]: self._CHOICE_SPEAKER_DEVICE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_SPEAKER_ENERGY_THRESHOLD') def INPUT_SPEAKER_ENERGY_THRESHOLD(self): return self._INPUT_SPEAKER_ENERGY_THRESHOLD @INPUT_SPEAKER_ENERGY_THRESHOLD.setter def INPUT_SPEAKER_ENERGY_THRESHOLD(self, value): if isinstance(value, int): self._INPUT_SPEAKER_ENERGY_THRESHOLD = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD') def INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD(self): return self._INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD @INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD.setter def INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD(self, value): if isinstance(value, bool): self._INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_SPEAKER_RECORD_TIMEOUT') def INPUT_SPEAKER_RECORD_TIMEOUT(self): return self._INPUT_SPEAKER_RECORD_TIMEOUT @INPUT_SPEAKER_RECORD_TIMEOUT.setter def INPUT_SPEAKER_RECORD_TIMEOUT(self, value): if isinstance(value, int): self._INPUT_SPEAKER_RECORD_TIMEOUT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_SPEAKER_PHRASE_TIMEOUT') def INPUT_SPEAKER_PHRASE_TIMEOUT(self): return self._INPUT_SPEAKER_PHRASE_TIMEOUT @INPUT_SPEAKER_PHRASE_TIMEOUT.setter def INPUT_SPEAKER_PHRASE_TIMEOUT(self, value): if isinstance(value, int): self._INPUT_SPEAKER_PHRASE_TIMEOUT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_SPEAKER_MAX_PHRASES') def INPUT_SPEAKER_MAX_PHRASES(self): return self._INPUT_SPEAKER_MAX_PHRASES @INPUT_SPEAKER_MAX_PHRASES.setter def INPUT_SPEAKER_MAX_PHRASES(self, value): if isinstance(value, int): self._INPUT_SPEAKER_MAX_PHRASES = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_SPEAKER_AVG_LOGPROB') def INPUT_SPEAKER_AVG_LOGPROB(self): return self._INPUT_SPEAKER_AVG_LOGPROB @INPUT_SPEAKER_AVG_LOGPROB.setter def INPUT_SPEAKER_AVG_LOGPROB(self, value): if isinstance(value, float) or isinstance(value, int): self._INPUT_SPEAKER_AVG_LOGPROB = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('INPUT_SPEAKER_NO_SPEECH_PROB') def INPUT_SPEAKER_NO_SPEECH_PROB(self): return self._INPUT_SPEAKER_NO_SPEECH_PROB @INPUT_SPEAKER_NO_SPEECH_PROB.setter def INPUT_SPEAKER_NO_SPEECH_PROB(self, value): if isinstance(value, float) or isinstance(value, int): self._INPUT_SPEAKER_NO_SPEECH_PROB = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('OSC_IP_ADDRESS') def OSC_IP_ADDRESS(self): return self._OSC_IP_ADDRESS @OSC_IP_ADDRESS.setter def OSC_IP_ADDRESS(self, value): if isinstance(value, str): self._OSC_IP_ADDRESS = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('OSC_PORT') def OSC_PORT(self): return self._OSC_PORT @OSC_PORT.setter def OSC_PORT(self, value): if isinstance(value, int): self._OSC_PORT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('AUTH_KEYS') def AUTH_KEYS(self): return self._AUTH_KEYS @AUTH_KEYS.setter def AUTH_KEYS(self, value): if isinstance(value, dict) and set(value.keys()) == set(self.AUTH_KEYS.keys()): for key, value in value.items(): if isinstance(value, str): self._AUTH_KEYS[key] = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, self.AUTH_KEYS) @property @json_serializable('USE_EXCLUDE_WORDS') def USE_EXCLUDE_WORDS(self): return self._USE_EXCLUDE_WORDS @USE_EXCLUDE_WORDS.setter def USE_EXCLUDE_WORDS(self, value): if isinstance(value, bool): self._USE_EXCLUDE_WORDS = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('USE_TRANSLATION_FEATURE') def USE_TRANSLATION_FEATURE(self): return self._USE_TRANSLATION_FEATURE @USE_TRANSLATION_FEATURE.setter def USE_TRANSLATION_FEATURE(self, value): if isinstance(value, bool): self._USE_TRANSLATION_FEATURE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('USE_WHISPER_FEATURE') def USE_WHISPER_FEATURE(self): return self._USE_WHISPER_FEATURE @USE_WHISPER_FEATURE.setter def USE_WHISPER_FEATURE(self, value): if isinstance(value, bool): self._USE_WHISPER_FEATURE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('CTRANSLATE2_WEIGHT_TYPE') def CTRANSLATE2_WEIGHT_TYPE(self): return self._CTRANSLATE2_WEIGHT_TYPE @CTRANSLATE2_WEIGHT_TYPE.setter def CTRANSLATE2_WEIGHT_TYPE(self, value): # if isinstance(value, str) and value in self.SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT: if isinstance(value, str): self._CTRANSLATE2_WEIGHT_TYPE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('WHISPER_WEIGHT_TYPE') def WHISPER_WEIGHT_TYPE(self): return self._WHISPER_WEIGHT_TYPE @WHISPER_WEIGHT_TYPE.setter def WHISPER_WEIGHT_TYPE(self, value): if isinstance(value, str): self._WHISPER_WEIGHT_TYPE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('ENABLE_AUTO_CLEAR_MESSAGE_BOX') def ENABLE_AUTO_CLEAR_MESSAGE_BOX(self): return self._ENABLE_AUTO_CLEAR_MESSAGE_BOX @ENABLE_AUTO_CLEAR_MESSAGE_BOX.setter def ENABLE_AUTO_CLEAR_MESSAGE_BOX(self, value): if isinstance(value, bool): self._ENABLE_AUTO_CLEAR_MESSAGE_BOX = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('ENABLE_SEND_ONLY_TRANSLATED_MESSAGES') def ENABLE_SEND_ONLY_TRANSLATED_MESSAGES(self): return self._ENABLE_SEND_ONLY_TRANSLATED_MESSAGES @ENABLE_SEND_ONLY_TRANSLATED_MESSAGES.setter def ENABLE_SEND_ONLY_TRANSLATED_MESSAGES(self, value): if isinstance(value, bool): self._ENABLE_SEND_ONLY_TRANSLATED_MESSAGES = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('SEND_MESSAGE_BUTTON_TYPE') def SEND_MESSAGE_BUTTON_TYPE(self): return self._SEND_MESSAGE_BUTTON_TYPE @SEND_MESSAGE_BUTTON_TYPE.setter def SEND_MESSAGE_BUTTON_TYPE(self, value): if isinstance(value, str): self._SEND_MESSAGE_BUTTON_TYPE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('OVERLAY_SETTINGS') def OVERLAY_SETTINGS(self): return self._OVERLAY_SETTINGS @OVERLAY_SETTINGS.setter def OVERLAY_SETTINGS(self, value): if isinstance(value, dict) and set(value.keys()) == set(self.OVERLAY_SETTINGS.keys()): for key, value in value.items(): if isinstance(value, float): self._OVERLAY_SETTINGS[key] = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, self.OVERLAY_SETTINGS) @property @json_serializable('ENABLE_OVERLAY_SMALL_LOG') def ENABLE_OVERLAY_SMALL_LOG(self): return self._ENABLE_OVERLAY_SMALL_LOG @ENABLE_OVERLAY_SMALL_LOG.setter def ENABLE_OVERLAY_SMALL_LOG(self, value): if isinstance(value, bool): self._ENABLE_OVERLAY_SMALL_LOG = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('OVERLAY_SMALL_LOG_SETTINGS') def OVERLAY_SMALL_LOG_SETTINGS(self): return self._OVERLAY_SMALL_LOG_SETTINGS @OVERLAY_SMALL_LOG_SETTINGS.setter def OVERLAY_SMALL_LOG_SETTINGS(self, value): if isinstance(value, dict) and set(value.keys()) == set(self.OVERLAY_SMALL_LOG_SETTINGS.keys()): for key, value in value.items(): match (key): case "x_pos" | "y_pos" | "z_pos" | "x_rotation" | "y_rotation" | "z_rotation": if isinstance(value, float): self._OVERLAY_SMALL_LOG_SETTINGS[key] = value case "display_duration" | "fadeout_duration": if isinstance(value, int): self._OVERLAY_SMALL_LOG_SETTINGS[key] = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, self.OVERLAY_SMALL_LOG_SETTINGS) @property @json_serializable('OVERLAY_UI_TYPE') def OVERLAY_UI_TYPE(self): return self._OVERLAY_UI_TYPE @OVERLAY_UI_TYPE.setter def OVERLAY_UI_TYPE(self, value): if isinstance(value, str): self._OVERLAY_UI_TYPE = value # saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('ENABLE_SEND_MESSAGE_TO_VRC') def ENABLE_SEND_MESSAGE_TO_VRC(self): return self._ENABLE_SEND_MESSAGE_TO_VRC @ENABLE_SEND_MESSAGE_TO_VRC.setter def ENABLE_SEND_MESSAGE_TO_VRC(self, value): if isinstance(value, bool): self._ENABLE_SEND_MESSAGE_TO_VRC = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('SEND_MESSAGE_FORMAT') def SEND_MESSAGE_FORMAT(self): return self._SEND_MESSAGE_FORMAT @SEND_MESSAGE_FORMAT.setter def SEND_MESSAGE_FORMAT(self, value): if isinstance(value, str): if isUniqueStrings(["[message]"], value) is False: value = "[message]" self._SEND_MESSAGE_FORMAT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('SEND_MESSAGE_FORMAT_WITH_T') def SEND_MESSAGE_FORMAT_WITH_T(self): return self._SEND_MESSAGE_FORMAT_WITH_T @SEND_MESSAGE_FORMAT_WITH_T.setter def SEND_MESSAGE_FORMAT_WITH_T(self, value): if isinstance(value, str): if isUniqueStrings(["[message]", "[translation]"], value) is False: value = "[message]([translation])" self._SEND_MESSAGE_FORMAT_WITH_T = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('RECEIVED_MESSAGE_FORMAT') def RECEIVED_MESSAGE_FORMAT(self): return self._RECEIVED_MESSAGE_FORMAT @RECEIVED_MESSAGE_FORMAT.setter def RECEIVED_MESSAGE_FORMAT(self, value): if isinstance(value, str): if isUniqueStrings(["[message]"], value) is False: value = "[message]" self._RECEIVED_MESSAGE_FORMAT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('RECEIVED_MESSAGE_FORMAT_WITH_T') def RECEIVED_MESSAGE_FORMAT_WITH_T(self): return self._RECEIVED_MESSAGE_FORMAT_WITH_T @RECEIVED_MESSAGE_FORMAT_WITH_T.setter def RECEIVED_MESSAGE_FORMAT_WITH_T(self, value): if isinstance(value, str): if isUniqueStrings(["[message]", "[translation]"], value) is False: value = "[message]([translation])" self._RECEIVED_MESSAGE_FORMAT_WITH_T = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) # Speaker2Chatbox------------------ @property @json_serializable('ENABLE_SPEAKER2CHATBOX_PASS') def ENABLE_SPEAKER2CHATBOX_PASS(self): return self._ENABLE_SPEAKER2CHATBOX_PASS @ENABLE_SPEAKER2CHATBOX_PASS.setter def ENABLE_SPEAKER2CHATBOX_PASS(self, value): if isinstance(value, str): self._ENABLE_SPEAKER2CHATBOX_PASS = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC') def ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC(self): return self._ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC @ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC.setter def ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC(self, value): if isinstance(value, bool): if self._ENABLE_SPEAKER2CHATBOX is True: self._ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC = value else: self._ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC = False saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) # Speaker2Chatbox------------------ @property @json_serializable('ENABLE_LOGGER') def ENABLE_LOGGER(self): return self._ENABLE_LOGGER @ENABLE_LOGGER.setter def ENABLE_LOGGER(self, value): if isinstance(value, bool): self._ENABLE_LOGGER = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('ENABLE_VRC_MIC_MUTE_SYNC') def ENABLE_VRC_MIC_MUTE_SYNC(self): return self._ENABLE_VRC_MIC_MUTE_SYNC @ENABLE_VRC_MIC_MUTE_SYNC.setter def ENABLE_VRC_MIC_MUTE_SYNC(self, value): if isinstance(value, bool): self._ENABLE_VRC_MIC_MUTE_SYNC = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('IS_CONFIG_WINDOW_COMPACT_MODE') def IS_CONFIG_WINDOW_COMPACT_MODE(self): return self._IS_CONFIG_WINDOW_COMPACT_MODE @IS_CONFIG_WINDOW_COMPACT_MODE.setter def IS_CONFIG_WINDOW_COMPACT_MODE(self, value): if isinstance(value, bool): self._IS_CONFIG_WINDOW_COMPACT_MODE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) def init_config(self): # Read Only self._VERSION = "2.2.5" self._ENABLE_SPEAKER2CHATBOX = False # Speaker2Chatbox self._ENABLE_SPEAKER2CHATBOX_PASS_CONFIRMATION = "VRCT=0YEN" if getattr(sys, 'frozen', False): self._PATH_LOCAL = os_path.dirname(sys.executable) else: self._PATH_LOCAL = os_path.dirname(os_path.abspath(__file__)) self._PATH_CONFIG = os_path.join(self._PATH_LOCAL, "config.json") self._PATH_LOGS = os_path.join(self._PATH_LOCAL, "logs") os_makedirs(self._PATH_LOGS, exist_ok=True) self._GITHUB_URL = "https://api.github.com/repos/misyaguziya/VRCT/releases/latest" self._BOOTH_URL = "https://misyaguziya.booth.pm/" self._DOCUMENTS_URL = "https://mzsoftware.notion.site/VRCT-Documents-be79b7a165f64442ad8f326d86c22246" self._DEEPL_AUTH_KEY_PAGE_URL = "https://www.deepl.com/ja/account/summary" self._TRANSPARENCY_RANGE = (50, 100) self._APPEARANCE_THEME_LIST = ["Light", "Dark", "System"] self._UI_SCALING_LIST = generatePercentageStringsList(start=40, end=200, step=10) self._TEXTBOX_UI_SCALING_RANGE = (50, 200) self._MESSAGE_BOX_RATIO_RANGE = (1, 99) self._SELECTABLE_UI_LANGUAGES_DICT = { "en": "English", "ja": "日本語", "ko": "한국어", "zh-Hant": "繁體中文" # If you want to add a new language and key, please append it here. } self._SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT = { # {Save json str}: {i18n_placeholder} pairs "Small": "Small", "Large": "Large", } self._SELECTABLE_WHISPER_WEIGHT_TYPE_DICT = { # {Save json str}: {i18n_placeholder} pairs "tiny": "tiny", "base": "base", "small": "small", "medium": "medium", "large-v1": "large-v1", "large-v2": "large-v2", "large-v3": "large-v3", } self._MAX_MIC_ENERGY_THRESHOLD = 2000 self._MAX_SPEAKER_ENERGY_THRESHOLD = 4000 # Read Write self._ENABLE_TRANSLATION = False self._ENABLE_TRANSCRIPTION_SEND = False self._ENABLE_TRANSCRIPTION_RECEIVE = False self._ENABLE_FOREGROUND = False self._ENABLE_CHECK_ENERGY_SEND = False self._ENABLE_CHECK_ENERGY_RECEIVE = False # self._SENT_MESSAGES_LOG = [] # self._CURRENT_SENT_MESSAGES_LOG_INDEX = 0 self._IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION = False self._IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER = False # self._IS_EASTER_EGG_ENABLED = False # Save Json Data ## Main Window self._SELECTED_TAB_NO = "1" self._SELECTED_TAB_YOUR_TRANSLATOR_ENGINES = { "1":"CTranslate2", "2":"CTranslate2", "3":"CTranslate2", } self._SELECTED_TAB_TARGET_TRANSLATOR_ENGINES = { "1":"CTranslate2", "2":"CTranslate2", "3":"CTranslate2", } self._SELECTED_TAB_YOUR_LANGUAGES = { "1":{ "primary":{ "language":"Japanese", "country":"Japan" }, }, "2":{ "primary":{ "language":"Japanese", "country":"Japan" }, }, "3":{ "primary":{ "language":"Japanese", "country":"Japan" }, }, } self._SELECTED_TAB_TARGET_LANGUAGES = { "1":{ "primary":{ "language":"English", "country":"United States", }, "secondary":{ "language":"English", "country":"United States" }, "tertiary":{ "language":"English", "country":"United States" }, }, "2":{ "primary":{ "language":"English", "country":"United States", }, "secondary":{ "language":"English", "country":"United States" }, "tertiary":{ "language":"English", "country":"United States" }, }, "3":{ "primary":{ "language":"English", "country":"United States", }, "secondary":{ "language":"English", "country":"United States" }, "tertiary":{ "language":"English", "country":"United States" }, }, } self._SELECTED_TRANSCRIPTION_ENGINE = "Google" self._ENABLE_MULTI_LANGUAGE_TRANSLATION = False self._ENABLE_CONVERT_MESSAGE_TO_ROMAJI = False self._ENABLE_CONVERT_MESSAGE_TO_HIRAGANA = False self._IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE = False ## Config Window self._TRANSPARENCY = 100 self._APPEARANCE_THEME = "Dark" self._UI_SCALING = "100%" self._TEXTBOX_UI_SCALING = 100 self._MESSAGE_BOX_RATIO = 10 self._FONT_FAMILY = "Yu Gothic UI" self._UI_LANGUAGE = "en" self._ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY = True self._MAIN_WINDOW_GEOMETRY = { "x_pos": "0", "y_pos": "0", "width": "870", "height": "654", } self._CHOICE_MIC_HOST = getDefaultInputDevice()["host"]["name"] self._CHOICE_MIC_DEVICE = getDefaultInputDevice()["device"]["name"] self._INPUT_MIC_ENERGY_THRESHOLD = 300 self._INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD = False self._INPUT_MIC_RECORD_TIMEOUT = 3 self._INPUT_MIC_PHRASE_TIMEOUT = 3 self._INPUT_MIC_MAX_PHRASES = 10 self._INPUT_MIC_WORD_FILTER = [] self._INPUT_MIC_AVG_LOGPROB=-0.8 self._INPUT_MIC_NO_SPEECH_PROB=0.6 self._CHOICE_SPEAKER_DEVICE = getDefaultOutputDevice()["device"]["name"] self._INPUT_SPEAKER_ENERGY_THRESHOLD = 300 self._INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD = False self._INPUT_SPEAKER_RECORD_TIMEOUT = 3 self._INPUT_SPEAKER_PHRASE_TIMEOUT = 3 self._INPUT_SPEAKER_MAX_PHRASES = 10 self._INPUT_SPEAKER_AVG_LOGPROB=-0.8 self._INPUT_SPEAKER_NO_SPEECH_PROB=0.6 self._OSC_IP_ADDRESS = "127.0.0.1" self._OSC_PORT = 9000 self._AUTH_KEYS = { "DeepL_API": None, } self._USE_EXCLUDE_WORDS = True self._USE_TRANSLATION_FEATURE = True self._CTRANSLATE2_WEIGHT_TYPE = "Small" self._USE_WHISPER_FEATURE = False self._WHISPER_WEIGHT_TYPE = "base" self._SEND_MESSAGE_FORMAT = "[message]" self._SEND_MESSAGE_FORMAT_WITH_T = "[message]([translation])" self._RECEIVED_MESSAGE_FORMAT = "[message]" self._RECEIVED_MESSAGE_FORMAT_WITH_T = "[message]([translation])" self._ENABLE_AUTO_CLEAR_MESSAGE_BOX = True self._ENABLE_SEND_ONLY_TRANSLATED_MESSAGES = False self._SEND_MESSAGE_BUTTON_TYPE = "show" self._OVERLAY_SETTINGS = { "opacity": 1.0, "ui_scaling": 1.0, } self._ENABLE_OVERLAY_SMALL_LOG = False self._OVERLAY_SMALL_LOG_SETTINGS = { "x_pos": 0.0, "y_pos": 0.0, "z_pos": 0.0, "x_rotation": 0.0, "y_rotation": 0.0, "z_rotation": 0.0, "display_duration": 5, "fadeout_duration": 2, } self._OVERLAY_UI_TYPE = "default" self._ENABLE_SEND_MESSAGE_TO_VRC = True self._ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC = False # Speaker2Chatbox self._ENABLE_SPEAKER2CHATBOX_PASS = "000000000" self._ENABLE_LOGGER = False self._ENABLE_VRC_MIC_MUTE_SYNC = False def load_config(self): if os_path.isfile(self.PATH_CONFIG) is not False: with open(self.PATH_CONFIG, 'r', encoding="utf-8") as fp: config = json_load(fp) old_message_format = None for key in config.keys(): if key == "MESSAGE_FORMAT": old_message_format = config[key] setattr(self, key, config[key]) if key == "ENABLE_SPEAKER2CHATBOX_PASS": if self.ENABLE_SPEAKER2CHATBOX_PASS_CONFIRMATION == config[key]: self.ENABLE_SPEAKER2CHATBOX = True if old_message_format is not None: setattr(self, "SEND_MESSAGE_FORMAT_WITH_T", old_message_format) with open(self.PATH_CONFIG, 'w', encoding="utf-8") as fp: config = {} for var_name, var_func in json_serializable_vars.items(): config[var_name] = var_func(self) json_dump(config, fp, indent=4, ensure_ascii=False) config = Config()