diff --git a/test_model/config.py b/test_model/config.py new file mode 100644 index 00000000..cea811a5 --- /dev/null +++ b/test_model/config.py @@ -0,0 +1,511 @@ +import os +import sys +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) + +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 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 + + 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 + + @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 + + @TRANSPARENCY.setter + def TRANSPARENCY(self, value): + if type(value) is int and 0 <= value <= 100: + self._TRANSPARENCY = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def APPEARANCE_THEME(self): + return self._APPEARANCE_THEME + + @APPEARANCE_THEME.setter + def APPEARANCE_THEME(self, value): + if value in ["Light", "Dark", "System"]: + self._APPEARANCE_THEME = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def UI_SCALING(self): + return self._UI_SCALING + + @UI_SCALING.setter + def UI_SCALING(self, value): + if value in ["80%", "90%", "100%", "110%", "120%"]: + self._UI_SCALING = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 + def UI_LANGUAGE(self): + return self._UI_LANGUAGE + + @UI_LANGUAGE.setter + def UI_LANGUAGE(self, value): + if value in list(selectable_languages.keys()): + self._UI_LANGUAGE = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def CHOICE_TRANSLATOR(self): + return self._CHOICE_TRANSLATOR + + @CHOICE_TRANSLATOR.setter + def CHOICE_TRANSLATOR(self, value): + if value in translatorEngine: + self._CHOICE_TRANSLATOR = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def INPUT_SOURCE_LANG(self): + return self._INPUT_SOURCE_LANG + + @INPUT_SOURCE_LANG.setter + def INPUT_SOURCE_LANG(self, value): + if value in list(translation_lang[self.CHOICE_TRANSLATOR]["source"].keys()): + self._INPUT_SOURCE_LANG = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def INPUT_TARGET_LANG(self): + return self._INPUT_TARGET_LANG + + @INPUT_TARGET_LANG.setter + def INPUT_TARGET_LANG(self, value): + if value in list(translation_lang[self.CHOICE_TRANSLATOR]["target"].keys()): + self._INPUT_TARGET_LANG = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def OUTPUT_SOURCE_LANG(self): + return self._OUTPUT_SOURCE_LANG + + @OUTPUT_SOURCE_LANG.setter + def OUTPUT_SOURCE_LANG(self, value): + if value in list(translation_lang[self.CHOICE_TRANSLATOR]["source"].keys()): + self._OUTPUT_SOURCE_LANG = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def OUTPUT_TARGET_LANG(self): + return self._OUTPUT_TARGET_LANG + + @OUTPUT_TARGET_LANG.setter + def OUTPUT_TARGET_LANG(self, value): + if value in list(translation_lang[self.CHOICE_TRANSLATOR]["target"].keys()): + self._OUTPUT_TARGET_LANG = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 + 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 + def INPUT_MIC_VOICE_LANGUAGE(self): + return self._INPUT_MIC_VOICE_LANGUAGE + + @INPUT_MIC_VOICE_LANGUAGE.setter + def INPUT_MIC_VOICE_LANGUAGE(self, value): + if value in list(transcription_lang.keys()): + self._INPUT_MIC_VOICE_LANGUAGE = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 type(value) is int: + self._INPUT_MIC_ENERGY_THRESHOLD = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 type(value) is bool: + self._INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 type(value) is int: + self._INPUT_MIC_RECORD_TIMEOUT = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 type(value) is int: + self._INPUT_MIC_PHRASE_TIMEOUT = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 type(value) is int: + self._INPUT_MIC_MAX_PHRASES = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 type(value) is list: + self._INPUT_MIC_WORD_FILTER = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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()]: + speaker_device = [device for device in getOutputDevices() if device["name"] == value][0] + if getDefaultOutputDevice()["index"] == speaker_device["index"]: + self._CHOICE_SPEAKER_DEVICE = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def INPUT_SPEAKER_VOICE_LANGUAGE(self): + return self._INPUT_SPEAKER_VOICE_LANGUAGE + + @INPUT_SPEAKER_VOICE_LANGUAGE.setter + def INPUT_SPEAKER_VOICE_LANGUAGE(self, value): + if value in list(transcription_lang.keys()): + self._INPUT_SPEAKER_VOICE_LANGUAGE = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 type(value) is int: + self._INPUT_SPEAKER_ENERGY_THRESHOLD = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 type(value) is bool: + self._INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 type(value) is int: + self._INPUT_SPEAKER_RECORD_TIMEOUT = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 type(value) is int: + self._INPUT_SPEAKER_PHRASE_TIMEOUT = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + 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 type(value) is int: + self._INPUT_SPEAKER_MAX_PHRASES = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def OSC_IP_ADDRESS(self): + return self._OSC_IP_ADDRESS + + @OSC_IP_ADDRESS.setter + def OSC_IP_ADDRESS(self, value): + if type(value) is str: + self._OSC_IP_ADDRESS = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def OSC_PORT(self): + return self._OSC_PORT + + @OSC_PORT.setter + def OSC_PORT(self, value): + if type(value) is int: + self._OSC_PORT = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def AUTH_KEYS(self): + return self._AUTH_KEYS + + @AUTH_KEYS.setter + def AUTH_KEYS(self, value): + if type(value) is dict and set(value.keys()) == set(self.AUTH_KEYS.keys()): + for key, value in value.items(): + if type(value) is str: + self._AUTH_KEYS[key] = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, self.AUTH_KEYS) + + @property + def MESSAGE_FORMAT(self): + return self._MESSAGE_FORMAT + + @MESSAGE_FORMAT.setter + def MESSAGE_FORMAT(self, value): + if type(value) is str: + self._MESSAGE_FORMAT = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def ENABLE_AUTO_CLEAR_CHATBOX(self): + return self._ENABLE_AUTO_CLEAR_CHATBOX + + @ENABLE_AUTO_CLEAR_CHATBOX.setter + def ENABLE_AUTO_CLEAR_CHATBOX(self, value): + if type(value) is bool: + self._ENABLE_AUTO_CLEAR_CHATBOX = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + def ENABLE_NOTICE_XSOVERLAY(self): + return self._ENABLE_NOTICE_XSOVERLAY + + @ENABLE_NOTICE_XSOVERLAY.setter + def ENABLE_NOTICE_XSOVERLAY(self, value): + if type(value) is bool: + self._ENABLE_NOTICE_XSOVERLAY = 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 = os.path.join(os.path.dirname(__file__), '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 = 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 = 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 + self._INPUT_MIC_RECORD_TIMEOUT = 3 + self._INPUT_MIC_PHRASE_TIMEOUT = 3 + self._INPUT_MIC_MAX_PHRASES = 10 + self._INPUT_MIC_WORD_FILTER = [] + 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 + self._INPUT_SPEAKER_RECORD_TIMEOUT = 3 + self._INPUT_SPEAKER_PHRASE_TIMEOUT = 3 + self._INPUT_SPEAKER_MAX_PHRASES = 10 + self._OSC_IP_ADDRESS = "127.0.0.1" + self._OSC_PORT = 9000 + self._AUTH_KEYS = { + "DeepL(web)": None, + "DeepL(auth)": None, + "Bing(web)": None, + "Google(web)": None, + } + 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: + with open(self.PATH_CONFIG, 'r') as fp: + config = json_load(fp) + + for key in config.keys(): + setattr(self, key, config[key]) + + with open(self.PATH_CONFIG, 'w') as fp: + setter_methods = [ + name for name, obj in vars(type(self)).items() + if isinstance(obj, property) and obj.fset is not None + ] + config = {} + for method in setter_methods: + config[method] = getattr(self, method) + json_dump(config, fp, indent=4) + +config = Config() \ No newline at end of file diff --git a/test_model/img/app.ico b/test_model/img/app.ico new file mode 100644 index 00000000..eca32ce7 Binary files /dev/null and b/test_model/img/app.ico differ diff --git a/test_model/img/config-icon-white.png b/test_model/img/config-icon-white.png new file mode 100644 index 00000000..1222f167 Binary files /dev/null and b/test_model/img/config-icon-white.png differ diff --git a/test_model/img/info-icon-white.png b/test_model/img/info-icon-white.png new file mode 100644 index 00000000..210613e0 Binary files /dev/null and b/test_model/img/info-icon-white.png differ diff --git a/test_model/img/xsoverlay.png b/test_model/img/xsoverlay.png new file mode 100644 index 00000000..35c793ea Binary files /dev/null and b/test_model/img/xsoverlay.png differ diff --git a/test_model/languages.py b/test_model/languages.py new file mode 100644 index 00000000..bac2eb0f --- /dev/null +++ b/test_model/languages.py @@ -0,0 +1,6 @@ +selectable_languages = { + "en": "English", + "ja": "日本語", + "ko": "한국어" + # 新しい言語とキーを追加する場合はここに追記してください +} \ No newline at end of file diff --git a/test_model/locales.yml b/test_model/locales.yml new file mode 100644 index 00000000..5e94624b --- /dev/null +++ b/test_model/locales.yml @@ -0,0 +1,193 @@ +en: + # main window + checkbox_translation: "Translation" + checkbox_transcription_send: "Voice2chatbox" + checkbox_transcription_receive: "Speaker2log" + checkbox_foreground: "Foreground" + + # main tabview + main_tab_title_log: "Log" + main_tab_title_send: "Send" + main_tab_title_receive: "Receive" + main_tab_title_system: "System" + + + # configure window + # config tabview + config_tab_title_ui: "UI" + config_tab_title_translation: "Translation" + config_tab_title_transcription: "Transcription" + config_tab_title_parameter: "Parameter" + config_tab_title_others: "Others" + # tab UI + label_transparency: "Transparency" + label_appearance_theme: "Appearance Theme" + label_ui_scaling: "UI Scaling" + label_font_family: "Font Family" + label_ui_language: "UI Language" + + # tab Translation + label_translation_translator: "Select Translator" + label_translation_input_language: "Send Language" + label_translation_output_language: "Receive Language" + + # tab Transcription + label_input_mic_host: "Input Mic Host" + label_input_mic_device: "Input Mic Device" + label_input_mic_voice_language: "Input Mic Voice Language" + label_input_mic_energy_threshold: "Input Mic Energy Threshold" + checkbox_input_mic_threshold_check: "Check threshold point" + label_input_mic_dynamic_energy_threshold: "Input Mic Dynamic Energy Threshold" + label_input_mic_record_timeout: "Input Mic Record Timeout" + label_input_mic_phrase_timeout: "Input Mic Phrase Timeout" + label_input_mic_max_phrases: "Input Mic Max Phrases" + label_input_mic_word_filter: "Input Mic Word Filter" + + label_input_speaker_device: "Input Speaker Device" + label_input_speaker_voice_language: "Input Speaker Voice Language" + label_input_speaker_energy_threshold: "Input Speaker Energy Threshold" + checkbox_input_speaker_threshold_check: "Check threshold point" + label_input_speaker_dynamic_energy_threshold: "Input Speaker Dynamic Energy Threshold" + label_input_speaker_record_timeout: "Input Speaker Record Timeout" + label_input_speaker_phrase_timeout: "Input Speaker Phrase Timeout" + label_input_speaker_max_phrases: "Input Speaker Max Phrases" + + # tab Parameter + label_ip_address: "OSC IP address" + label_port: "OSC Port" + label_authkey: "DeepL Auth Key" + label_message_format: "Message Format" + + # tab Others + label_checkbox_auto_clear_chatbox: "Auto clear chat box" + label_checkbox_notice_xsoverlay: "Notification XSOverlay" + + +ja: + # main window + checkbox_translation: "翻訳" + checkbox_transcription_send: "マイク->チャットボックス" + checkbox_transcription_receive: "スピーカー->ログ" + checkbox_foreground: "最前面表示" + + # main tabview + main_tab_title_log: "ログ" + main_tab_title_send: "送信" + main_tab_title_receive: "受信" + main_tab_title_system: "システム" + + + # configure window + # config tabview + config_tab_title_ui: "UI" + config_tab_title_translation: "翻訳方法" + config_tab_title_transcription: "音声認識" + config_tab_title_parameter: "パラメーター" + config_tab_title_others: "その他" + + # tab UI + label_transparency: "透過度" + label_appearance_theme: "外観テーマを選択" + label_ui_scaling: "UIの拡大縮小" + label_font_family: "使用フォントの変更" + label_ui_language: "UI 言語" + + # tab Translation + label_translation_translator: "翻訳エンジンの選択" + label_translation_input_language: "送信言語-->翻訳言語" + label_translation_output_language: "受信言語-->翻訳言語" + + # tab Transcription + label_input_mic_host: "マイク入力ホスト" + label_input_mic_device: "マイク入力デバイス" + label_input_mic_voice_language: "マイクで話す言語" + label_input_mic_energy_threshold: "音声取得のしきい値" + checkbox_input_mic_threshold_check: "音声取得のしきい値の視覚化" + label_input_mic_dynamic_energy_threshold: "音声取得のしきい値の自動調整" + label_input_mic_record_timeout: "マイク音声の区切りの無音時間" + label_input_mic_phrase_timeout: "文字起こしする音声時間の上限" + label_input_mic_max_phrases: "保留する単語の上限(マイク)" + label_input_mic_word_filter: "ワードフィルタ" + + label_input_speaker_device: "スピーカー(聞き取りたいデバイス)" + label_input_speaker_voice_language: "聞き取る音声の言語" + label_input_speaker_energy_threshold: "音声取得のしきい値" + checkbox_input_speaker_threshold_check: "音声取得のしきい値の視覚化" + label_input_speaker_dynamic_energy_threshold: "音声取得のしきい値の自動調整" + label_input_speaker_record_timeout: "スピーカー音声の区切りの無音時間" + label_input_speaker_phrase_timeout: "文字起こしする音声時間の上限" + label_input_speaker_max_phrases: "保留する単語の上限(スピーカー)" + + # tab Parameter + # label_ip_address: "" + # label_port: "" + # label_authkey: "" + label_message_format: "送信するメッセージのフォーマット" + + # tab Others + label_checkbox_auto_clear_chatbox: "送信後はチャットボックスを空にする" + label_checkbox_notice_xsoverlay: "XSOverlayの通知機能を有効" + + +ko: + # main window + checkbox_translation: "번역" + checkbox_transcription_send: "마이크 -> 챗박스" + checkbox_transcription_receive: "스피커 -> 로그" + checkbox_foreground: "항상 위로" + + # main tabview + main_tab_title_log: "로그" + main_tab_title_send: "전송" + main_tab_title_receive: "수신" + main_tab_title_system: "시스템" + + + # configure window + # config tabview + config_tab_title_ui: "UI" + config_tab_title_translation: "번역" + config_tab_title_transcription: "음성인식" + config_tab_title_parameter: "파라미터" + config_tab_title_others: "기타" + # tab UI + label_transparency: "투명도" + label_appearance_theme: "테마" + label_ui_scaling: "UI 크기" + label_font_family: "폰트" + label_ui_language: "UI 언어" + + # tab Translation + label_translation_translator: "번역기 선택" + label_translation_input_language: "전송시 번역 언어" + label_translation_output_language: "수신시 번역 언어" + + # tab Transcription + label_input_mic_host: "마이크 호스트" + label_input_mic_device: "마이크 장치" + label_input_mic_voice_language: "입력 언어" + label_input_mic_energy_threshold: "음성 입력 최소 볼륨" + checkbox_input_mic_threshold_check: "임계점 확인" + label_input_mic_dynamic_energy_threshold: "동적 임계값" + label_input_mic_record_timeout: "최대 무음 시간" + label_input_mic_phrase_timeout: "최대 인식 시간" + label_input_mic_max_phrases: "최대 입력 절(phrases) 수" + label_input_mic_word_filter: "단어 필터" + + label_input_speaker_device: "스피커 장치" + label_input_speaker_voice_language: "입력 언어" + label_input_speaker_energy_threshold: "음성 입력 최소 볼륨" + checkbox_input_speaker_threshold_check: "임계점 확인" + label_input_speaker_dynamic_energy_threshold: "동적 임계값" + label_input_speaker_record_timeout: "최대 무음 시간" + label_input_speaker_phrase_timeout: "최대 인식 시간" + label_input_speaker_max_phrases: "최대 입력 절(phrases) 수" + + # tab Parameter + label_ip_address: "OSC IP 주소" + label_port: "OSC 포트" + label_authkey: "DeepL 인증키" + label_message_format: "전송 형식" + + # tab Others + label_checkbox_auto_clear_chatbox: "챗박스 자동 삭제" \ No newline at end of file diff --git a/test_model/main.py b/test_model/main.py new file mode 100644 index 00000000..dd4ca55b --- /dev/null +++ b/test_model/main.py @@ -0,0 +1,503 @@ +import os +import sys +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) + +from time import sleep +from os import path as os_path + +import customtkinter +from customtkinter import CTk, CTkFrame, CTkCheckBox, CTkFont, CTkButton, CTkImage, CTkTabview, CTkTextbox, CTkEntry +from PIL.Image import open as Image_open + +from threading import Thread +from utils import print_textbox, get_localized_text, widget_main_window_label_setter +from window_config import ToplevelWindowConfig +from window_information import ToplevelWindowInformation +from config import config +from model import model + +class App(CTk): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + ## set UI theme + customtkinter.set_appearance_mode(config.APPEARANCE_THEME) + customtkinter.set_default_color_theme("blue") + + # init main window + self.iconbitmap(os_path.join(os_path.dirname(__file__), "img", "app.ico")) + self.title("VRCT") + self.geometry(f"{400}x{175}") + 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 + self.add_sidebar() + + # add entry message box + self.entry_message_box = CTkEntry( + self, + placeholder_text="message", + font=CTkFont(family=config.FONT_FAMILY), + ) + self.entry_message_box.grid(row=1, column=1, columnspan=2, padx=5, pady=(5, 10), sticky="nsew") + self.entry_message_box.bind("", self.entry_message_box_press_key_enter) + self.entry_message_box.bind("", self.entry_message_box_press_key_any) + self.entry_message_box.bind("", self.entry_message_box_leave) + + # 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() + + def init_process(self): + # set translator + if model.authenticationTranslator() is False: + # error update Auth key + self.printLogAuthenticationError() + + # set word filter + model.addKeywords() + + # check OSC started + model.checkOSCStarted() + + # check Software Updated + model.checkSoftwareUpdated() + + def button_config_callback(self): + self.foreground_stop() + self.transcription_stop() + self.checkbox_translation.configure(state="disabled") + self.checkbox_transcription_send.configure(state="disabled") + self.checkbox_transcription_receive.configure(state="disabled") + self.checkbox_foreground.configure(state="disabled") + self.tabview_logs.configure(state="disabled") + 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") + self.entry_message_box.configure(state="disabled") + self.button_config.configure(state="disabled", fg_color=["gray92", "gray14"]) + self.button_information.configure(state="disabled", fg_color=["gray92", "gray14"]) + self.config_window.deiconify() + self.config_window.focus_set() + self.config_window.focus() + self.config_window.grab_set() + + def button_information_callback(self): + self.information_window.deiconify() + self.information_window.focus_set() + self.information_window.focus() + + def checkbox_translation_callback(self): + config.ENABLE_TRANSLATION = self.checkbox_translation.get() + if config.ENABLE_TRANSLATION is True: + self.printLogStartTranslation() + else: + self.printLogStopTranslation() + + def transcription_send_start(self): + 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): + 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): + 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 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() + else: + th_transcription_send_stop = Thread(target=self.transcription_send_stop) + th_transcription_send_stop.daemon = True + th_transcription_send_stop.start() + + def transcription_receive_start(self): + 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): + 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): + 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 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() + else: + th_transcription_receive_stop = Thread(target=self.transcription_receive_stop) + th_transcription_receive_stop.daemon = True + th_transcription_receive_stop.start() + + def transcription_start(self): + 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 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 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 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): + config.ENABLE_FOREGROUND = self.checkbox_foreground.get() + if config.ENABLE_FOREGROUND: + self.attributes("-topmost", True) + self.printLogStartForeground() + else: + self.attributes("-topmost", False) + self.printLogStopForeground() + + def foreground_start(self): + if config.ENABLE_FOREGROUND: + self.attributes("-topmost", True) + self.printLogStartForeground() + + def foreground_stop(self): + if config.ENABLE_FOREGROUND: + self.attributes("-topmost", False) + self.printLogStopForeground() + + def entry_message_box_press_key_enter(self, event): + # osc stop send typing + model.oscStopSendTyping() + + if config.ENABLE_FOREGROUND: + self.attributes("-topmost", True) + + message = self.entry_message_box.get() + self.sendChatMessage(message) + + def entry_message_box_press_key_any(self, event): + # 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 config.BREAK_KEYSYM_LIST: + self.entry_message_box.insert("end", event.char) + return "break" + + def entry_message_box_leave(self, event): + # 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"]) + self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_receive"]) + self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_system"]) + + def add_tabview_logs(self, language_yaml_data): + main_tab_title_log = language_yaml_data["main_tab_title_log"] + main_tab_title_send = language_yaml_data["main_tab_title_send"] + main_tab_title_receive = language_yaml_data["main_tab_title_receive"] + main_tab_title_system = language_yaml_data["main_tab_title_system"] + + # add tabview textbox + self.tabview_logs = CTkTabview(master=self) + self.tabview_logs.add(main_tab_title_log) + self.tabview_logs.add(main_tab_title_send) + self.tabview_logs.add(main_tab_title_receive) + self.tabview_logs.add(main_tab_title_system) + self.tabview_logs.grid(row=0, column=1, padx=0, pady=0, sticky="nsew") + self.tabview_logs._segmented_button.configure(font=CTkFont(family=config.FONT_FAMILY)) + self.tabview_logs._segmented_button.grid(sticky="W") + self.tabview_logs.tab(main_tab_title_log).grid_rowconfigure(0, weight=1) + self.tabview_logs.tab(main_tab_title_log).grid_columnconfigure(0, weight=1) + self.tabview_logs.tab(main_tab_title_send).grid_rowconfigure(0, weight=1) + self.tabview_logs.tab(main_tab_title_send).grid_columnconfigure(0, weight=1) + self.tabview_logs.tab(main_tab_title_receive).grid_rowconfigure(0, weight=1) + self.tabview_logs.tab(main_tab_title_receive).grid_columnconfigure(0, weight=1) + self.tabview_logs.tab(main_tab_title_system).grid_rowconfigure(0, weight=1) + self.tabview_logs.tab(main_tab_title_system).grid_columnconfigure(0, weight=1) + self.tabview_logs.configure(fg_color="transparent") + + # add textbox message log + self.textbox_message_log = CTkTextbox( + self.tabview_logs.tab(main_tab_title_log), + font=CTkFont(family=config.FONT_FAMILY) + ) + + # 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) + ) + + # 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) + ) + + # 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 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: + app = App() + app.mainloop() + except Exception as e: + import traceback + with open(os.path.join(os.path.dirname(__file__), 'error.log'), 'a') as f: + traceback.print_exc(file=f) \ No newline at end of file diff --git a/test_model/utils.py b/test_model/utils.py new file mode 100644 index 00000000..2bee5814 --- /dev/null +++ b/test_model/utils.py @@ -0,0 +1,106 @@ +from os import path as os_path +import yaml +from datetime import datetime + +def print_textbox(textbox, message, tags=None): + now = datetime.now() + now = now.strftime('%H:%M:%S') + + textbox.tag_config("ERROR", foreground="#FF0000") + textbox.tag_config("INFO", foreground="#1BFF00") + textbox.tag_config("SEND", foreground="#0378e2") + textbox.tag_config("RECEIVE", foreground="#ffa500") + + textbox.configure(state='normal') + textbox.insert("end", f"[{now}][") + textbox.insert("end", f"{tags}", tags) + textbox.insert("end", f"]{message}\n") + textbox.configure(state='disabled') + textbox.see("end") + +def get_localized_text(language): + file_path = os_path.join(os_path.dirname(__file__), "locales.yml") + + with open(file_path, encoding="utf-8") as file: + languages_yaml_data = yaml.safe_load(file) + default_language = "en" + if language in languages_yaml_data: + localized_text = languages_yaml_data[language] + if default_language in languages_yaml_data: + default_text = languages_yaml_data[default_language] + merged_text = {**default_text, **localized_text} + return merged_text + else: + return localized_text + else: + return None + +def get_key_by_value(dictionary, value): + for key, val in dictionary.items(): + if val == value: + return key + return None + +def widget_config_window_label_setter(self, language_yaml_data): + widget_names = [ + # tab UI + "label_transparency", + "label_appearance_theme", + "label_ui_scaling", + "label_font_family", + "label_ui_language", + + # tab Translation + "label_translation_translator", + "label_translation_input_language", + "label_translation_output_language", + + # tab Transcription + "label_input_mic_host", + "label_input_mic_device", + "label_input_mic_voice_language", + "label_input_mic_energy_threshold", + "checkbox_input_mic_threshold_check", + "label_input_mic_dynamic_energy_threshold", + "label_input_mic_record_timeout", + "label_input_mic_phrase_timeout", + "label_input_mic_max_phrases", + "label_input_mic_word_filter", + + "label_input_speaker_device", + "label_input_speaker_voice_language", + "label_input_speaker_energy_threshold", + "checkbox_input_speaker_threshold_check", + "label_input_speaker_dynamic_energy_threshold", + "label_input_speaker_record_timeout", + "label_input_speaker_phrase_timeout", + "label_input_speaker_max_phrases", + + # tab Parameter + "label_ip_address", + "label_port", + "label_authkey", + "label_message_format", + + # tab Others + "label_checkbox_auto_clear_chatbox", + "label_checkbox_notice_xsoverlay", + ] + for name in widget_names: + widget = getattr(self, name) + text_value = language_yaml_data.get(name) + if widget is not None and text_value is not None: + widget.configure(text=text_value + ":") + +def widget_main_window_label_setter(self, language_yaml_data): + widget_names = [ + "checkbox_translation", + "checkbox_transcription_send", + "checkbox_transcription_receive", + "checkbox_foreground", + ] + for name in widget_names: + widget = getattr(self, name) + text_value = language_yaml_data.get(name) + if widget is not None and text_value is not None: + widget.configure(text=text_value) \ No newline at end of file diff --git a/test_model/window_config.py b/test_model/window_config.py new file mode 100644 index 00000000..89dcf6ce --- /dev/null +++ b/test_model/window_config.py @@ -0,0 +1,1348 @@ +import os +import sys +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) + +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 threading import Thread +from config import config +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 + +class ToplevelWindowConfig(CTkToplevel): + + def __init__(self, parent, *args, **kwargs): + super().__init__(parent, *args, **kwargs) + + self.withdraw() + self.parent = parent + # self.geometry(f"{350}x{270}") + # self.resizable(False, False) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + self.after(200, lambda: self.iconbitmap(os_path.join(os_path.dirname(__file__), "img", "app.ico"))) + self.title("Config") + + # load ui language data + language_yaml_data = get_localized_text(f"{config.UI_LANGUAGE}") + # add tabview config + self.add_tabview_config(language_yaml_data, selectable_languages) + # set all config window labels + widget_config_window_label_setter(self, language_yaml_data) + + self.protocol("WM_DELETE_WINDOW", self.delete_window) + + def slider_transparency_callback(self, value): + self.parent.wm_attributes("-alpha", value/100) + config.TRANSPARENCY = value + + def optionmenu_appearance_theme_callback(self, choice): + self.optionmenu_appearance_theme.set(choice) + + customtkinter.set_appearance_mode(choice) + config.APPEARANCE_THEME = choice + + def optionmenu_ui_scaling_callback(self, choice): + self.optionmenu_ui_scaling.set(choice) + + new_scaling_float = int(choice.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + config.UI_SCALING = choice + + def optionmenu_font_family_callback(self, choice): + self.optionmenu_font_family.set(choice) + + # tab menu + self.tabview_config._segmented_button.configure(font=CTkFont(family=choice)) + + # tab UI + self.label_transparency.configure(font=CTkFont(family=choice)) + self.label_appearance_theme.configure(font=CTkFont(family=choice)) + self.optionmenu_appearance_theme.configure(font=CTkFont(family=choice)) + self.optionmenu_appearance_theme._dropdown_menu.configure(font=CTkFont(family=choice)) + self.label_ui_scaling.configure(font=CTkFont(family=choice)) + self.optionmenu_ui_scaling.configure(font=CTkFont(family=choice)) + self.optionmenu_ui_scaling._dropdown_menu.configure(font=CTkFont(family=choice)) + self.label_font_family.configure(font=CTkFont(family=choice)) + self.optionmenu_font_family.configure(font=CTkFont(family=choice)) + self.optionmenu_font_family._dropdown_menu.configure(font=CTkFont(family=choice)) + self.label_ui_language.configure(font=CTkFont(family=choice)) + self.optionmenu_ui_language.configure(font=CTkFont(family=choice)) + self.optionmenu_ui_language._dropdown_menu.configure(font=CTkFont(family=choice)) + + # tab Translation + self.label_translation_translator.configure(font=CTkFont(family=choice)) + self.optionmenu_translation_translator.configure(font=CTkFont(family=choice)) + self.optionmenu_translation_translator._dropdown_menu.configure(font=CTkFont(family=choice)) + self.label_translation_input_language.configure(font=CTkFont(family=choice)) + self.optionmenu_translation_input_source_language.configure(font=CTkFont(family=choice)) + self.optionmenu_translation_input_source_language._dropdown_menu.configure(font=CTkFont(family=choice)) + self.label_translation_input_arrow.configure(font=CTkFont(family=choice)) + self.optionmenu_translation_input_target_language.configure(font=CTkFont(family=choice)) + self.optionmenu_translation_input_target_language._dropdown_menu.configure(font=CTkFont(family=choice)) + self.label_translation_output_language.configure(font=CTkFont(family=choice)) + self.optionmenu_translation_output_source_language.configure(font=CTkFont(family=choice)) + self.optionmenu_translation_output_source_language._dropdown_menu.configure(font=CTkFont(family=choice)) + self.label_translation_output_arrow.configure(font=CTkFont(family=choice)) + self.optionmenu_translation_output_target_language.configure(font=CTkFont(family=choice)) + self.optionmenu_translation_output_target_language._dropdown_menu.configure(font=CTkFont(family=choice)) + + # tab Transcription + self.label_input_mic_host.configure(font=CTkFont(family=choice)) + self.optionmenu_input_mic_host.configure(font=CTkFont(family=choice)) + self.optionmenu_input_mic_host._dropdown_menu.configure(font=CTkFont(family=choice)) + self.label_input_mic_device.configure(font=CTkFont(family=choice)) + self.optionmenu_input_mic_device.configure(font=CTkFont(family=choice)) + self.optionmenu_input_mic_device._dropdown_menu.configure(font=CTkFont(family=choice)) + self.label_input_mic_voice_language.configure(font=CTkFont(family=choice)) + self.optionmenu_input_mic_voice_language.configure(font=CTkFont(family=choice)) + self.optionmenu_input_mic_voice_language._dropdown_menu.configure(font=CTkFont(family=choice)) + self.checkbox_input_mic_threshold_check.configure(font=CTkFont(family=choice)) + self.label_input_mic_energy_threshold.configure(font=CTkFont(family=choice)) + self.label_input_mic_dynamic_energy_threshold.configure(font=CTkFont(family=choice)) + self.label_input_mic_record_timeout.configure(font=CTkFont(family=choice)) + self.entry_input_mic_record_timeout.configure(font=CTkFont(family=choice)) + self.label_input_mic_phrase_timeout.configure(font=CTkFont(family=choice)) + self.entry_input_mic_phrase_timeout.configure(font=CTkFont(family=choice)) + self.label_input_mic_max_phrases.configure(font=CTkFont(family=choice)) + self.entry_input_mic_max_phrases.configure(font=CTkFont(family=choice)) + self.label_input_mic_word_filter.configure(font=CTkFont(family=choice)) + self.entry_input_mic_word_filter.configure(font=CTkFont(family=choice)) + self.label_input_speaker_device.configure(font=CTkFont(family=choice)) + self.optionmenu_input_speaker_device.configure(font=CTkFont(family=choice)) + self.optionmenu_input_speaker_device._dropdown_menu.configure(font=CTkFont(family=choice)) + self.label_input_speaker_voice_language.configure(font=CTkFont(family=choice)) + self.optionmenu_input_speaker_voice_language.configure(font=CTkFont(family=choice)) + self.optionmenu_input_speaker_voice_language._dropdown_menu.configure(font=CTkFont(family=choice)) + self.checkbox_input_speaker_threshold_check.configure(font=CTkFont(family=choice)) + self.label_input_speaker_energy_threshold.configure(font=CTkFont(family=choice)) + self.label_input_speaker_dynamic_energy_threshold.configure(font=CTkFont(family=choice)) + self.label_input_speaker_record_timeout.configure(font=CTkFont(family=choice)) + self.entry_input_speaker_record_timeout.configure(font=CTkFont(family=choice)) + self.label_input_speaker_phrase_timeout.configure(font=CTkFont(family=choice)) + self.entry_input_speaker_phrase_timeout.configure(font=CTkFont(family=choice)) + self.label_input_speaker_max_phrases.configure(font=CTkFont(family=choice)) + self.entry_input_speaker_max_phrases.configure(font=CTkFont(family=choice)) + + # tab Parameter + self.label_ip_address.configure(font=CTkFont(family=choice)) + self.entry_ip_address.configure(font=CTkFont(family=choice)) + self.label_port.configure(font=CTkFont(family=choice)) + self.entry_port.configure(font=CTkFont(family=choice)) + self.label_authkey.configure(font=CTkFont(family=choice)) + self.entry_authkey.configure(font=CTkFont(family=choice)) + self.label_message_format.configure(font=CTkFont(family=choice)) + self.entry_message_format.configure(font=CTkFont(family=choice)) + + # tab Others + self.label_checkbox_auto_clear_chatbox.configure(font=CTkFont(family=choice)) + + # main window + self.parent.checkbox_translation.configure(font=CTkFont(family=choice)) + self.parent.checkbox_transcription_send.configure(font=CTkFont(family=choice)) + self.parent.checkbox_transcription_receive.configure(font=CTkFont(family=choice)) + self.parent.checkbox_foreground.configure(font=CTkFont(family=choice)) + self.parent.textbox_message_log.configure(font=CTkFont(family=choice)) + self.parent.textbox_message_send_log.configure(font=CTkFont(family=choice)) + self.parent.textbox_message_receive_log.configure(font=CTkFont(family=choice)) + self.parent.textbox_message_system_log.configure(font=CTkFont(family=choice)) + self.parent.entry_message_box.configure(font=CTkFont(family=choice)) + self.parent.tabview_logs._segmented_button.configure(font=CTkFont(family=choice)) + + # window information + try: + self.parent.information_window.textbox_information.configure(font=CTkFont(family=choice)) + except: + pass + + config.FONT_FAMILY = choice + + def optionmenu_ui_language_callback(self, choice): + self.optionmenu_ui_language.set(choice) + + self.withdraw() + pre_language_yaml_data = get_localized_text(f"{config.UI_LANGUAGE}") + config.UI_LANGUAGE = get_key_by_value(selectable_languages, choice) + language_yaml_data = get_localized_text(f"{config.UI_LANGUAGE}") + + # delete + self.parent.delete_tabview_logs(pre_language_yaml_data) + self.delete_tabview_config(pre_language_yaml_data) + # add tabview textbox + self.parent.add_tabview_logs(language_yaml_data) + self.add_tabview_config(language_yaml_data, selectable_languages) + + # 翻訳予定 + # window information + # try: + # self.parent.information_window.textbox_information.configure(font=customtkinter.CTkFont(family=choice)) + # except: + # pass + self.deiconify() + + def optionmenu_translation_translator_callback(self, choice): + self.optionmenu_translation_translator.set(choice) + + 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: + self.optionmenu_translation_input_source_language.configure( + values=list(translation_lang[choice]["source"].keys()), + variable=StringVar(value=list(translation_lang[choice]["source"].keys())[0])) + self.optionmenu_translation_input_target_language.configure( + values=list(translation_lang[choice]["target"].keys()), + variable=StringVar(value=list(translation_lang[choice]["target"].keys())[1])) + self.optionmenu_translation_output_source_language.configure( + values=list(translation_lang[choice]["source"].keys()), + variable=StringVar(value=list(translation_lang[choice]["source"].keys())[1])) + self.optionmenu_translation_output_target_language.configure( + values=list(translation_lang[choice]["target"].keys()), + variable=StringVar(value=list(translation_lang[choice]["target"].keys())[0])) + + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_translation_input_source_language.configure( + values=list(translation_lang[choice]["source"].keys())) + self.scrollableDropdown_translation_input_target_language.configure( + values=list(translation_lang[choice]["target"].keys())) + self.scrollableDropdown_translation_output_source_language.configure( + values=list(translation_lang[choice]["source"].keys())) + self.scrollableDropdown_translation_output_target_language.configure( + values=list(translation_lang[choice]["target"].keys())) + + config.CHOICE_TRANSLATOR = choice + config.INPUT_SOURCE_LANG = list(translation_lang[choice]["source"].keys())[0] + config.INPUT_TARGET_LANG = list(translation_lang[choice]["target"].keys())[1] + config.OUTPUT_SOURCE_LANG = list(translation_lang[choice]["source"].keys())[1] + config.OUTPUT_TARGET_LANG = list(translation_lang[choice]["target"].keys())[0] + + def optionmenu_translation_input_source_language_callback(self, choice): + self.optionmenu_translation_input_source_language.set(choice) + config.INPUT_SOURCE_LANG = choice + + def optionmenu_translation_input_target_language_callback(self, choice): + self.optionmenu_translation_input_target_language.set(choice) + config.INPUT_TARGET_LANG = choice + + def optionmenu_translation_output_source_language_callback(self, choice): + self.optionmenu_translation_output_source_language.set(choice) + config.OUTPUT_SOURCE_LANG = choice + + def optionmenu_translation_output_target_language_callback(self, choice): + self.optionmenu_translation_output_target_language.set(choice) + config.OUTPUT_TARGET_LANG = choice + + 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=model.getListInputDevice(), + variable=StringVar(value=model.getInputDefaultDevice())) + + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_input_mic_device.configure(values=model.getListInputDevice()) + + def optionmenu_input_mic_device_callback(self, choice): + self.optionmenu_input_mic_device.set(choice) + config.CHOICE_MIC_DEVICE = choice + self.checkbox_input_mic_threshold_check.deselect() + self.checkbox_input_mic_threshold_check_callback() + + def optionmenu_input_mic_voice_language_callback(self, choice): + self.optionmenu_input_mic_voice_language.set(choice) + config.INPUT_MIC_VOICE_LANGUAGE = choice + + def mic_threshold_check_start(self): + def plotProgressBar(energy): + try: + self.progressBar_input_mic_energy_threshold.set(energy/config.MAX_MIC_ENERGY_THRESHOLD) + except: + pass + 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): + 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") + + def checkbox_input_mic_threshold_check_callback(self): + self.checkbox_input_mic_threshold_check.configure(state="disabled") + self.checkbox_input_speaker_threshold_check.configure(state="disabled") + self.update() + if self.checkbox_input_mic_threshold_check.get(): + th_mic_threshold_check_start = Thread(target=self.mic_threshold_check_start) + th_mic_threshold_check_start.daemon = True + th_mic_threshold_check_start.start() + else: + th_mic_threshold_check_stop = Thread(target=self.mic_threshold_check_stop) + th_mic_threshold_check_stop.daemon = True + th_mic_threshold_check_stop.start() + + def slider_input_mic_energy_threshold_callback(self, value): + config.INPUT_MIC_ENERGY_THRESHOLD = int(value) + + def checkbox_input_mic_dynamic_energy_threshold_callback(self): + config.INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD = self.checkbox_input_mic_dynamic_energy_threshold.get() + + def entry_input_mic_record_timeout_callback(self, event): + config.INPUT_MIC_RECORD_TIMEOUT = int(self.entry_input_mic_record_timeout.get()) + + def entry_input_mic_phrase_timeout_callback(self, event): + config.INPUT_MIC_PHRASE_TIMEOUT = int(self.entry_input_mic_phrase_timeout.get()) + + def entry_input_mic_max_phrases_callback(self, event): + config.INPUT_MIC_MAX_PHRASES = int(self.entry_input_mic_max_phrases.get()) + + def entry_input_mic_word_filters_callback(self, event): + word_filter = self.entry_input_mic_word_filter.get() + word_filter = [w.strip() for w in word_filter.split(",") if len(w.strip()) > 0] + word_filter = ",".join(word_filter) + if len(word_filter) > 0: + config.INPUT_MIC_WORD_FILTER = word_filter.split(",") + else: + config.INPUT_MIC_WORD_FILTER = [] + model.resetKeywordProcessor() + model.addKeywords() + + def optionmenu_input_speaker_device_callback(self, choice): + if model.checkSpeakerStatus(choice): + self.optionmenu_input_speaker_device.set(choice) + config.CHOICE_SPEAKER_DEVICE = choice + 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.optionmenu_input_speaker_device.configure(variable=StringVar(value=config.CHOICE_SPEAKER_DEVICE)) + + def optionmenu_input_speaker_voice_language_callback(self, choice): + self.optionmenu_input_speaker_voice_language.set(choice) + config.INPUT_SPEAKER_VOICE_LANGUAGE = choice + + def speaker_threshold_check_start(self): + def plotProgressBar(energy): + try: + self.progressBar_input_speaker_energy_threshold.set(energy/config.MAX_MIC_ENERGY_THRESHOLD) + except: + pass + 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): + 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") + + def checkbox_input_speaker_threshold_check_callback(self): + self.checkbox_input_mic_threshold_check.configure(state="disabled") + self.checkbox_input_speaker_threshold_check.configure(state="disabled") + self.update() + if self.checkbox_input_speaker_threshold_check.get(): + 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 + th_speaker_threshold_check_stop.start() + + def slider_input_speaker_energy_threshold_callback(self, value): + config.INPUT_SPEAKER_ENERGY_THRESHOLD = int(value) + + def checkbox_input_speaker_dynamic_energy_threshold_callback(self): + config.INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD = self.checkbox_input_speaker_dynamic_energy_threshold.get() + + def entry_input_speaker_record_timeout_callback(self, event): + config.INPUT_SPEAKER_RECORD_TIMEOUT = int(self.entry_input_speaker_record_timeout.get()) + + def entry_input_speaker_phrase_timeout_callback(self, event): + config.INPUT_SPEAKER_PHRASE_TIMEOUT = int(self.entry_input_speaker_phrase_timeout.get()) + + def entry_input_speaker_max_phrases_callback(self, event): + config.INPUT_SPEAKER_MAX_PHRASES = int(self.entry_input_speaker_max_phrases.get()) + + def entry_ip_address_callback(self, event): + config.OSC_IP_ADDRESS = self.entry_ip_address.get() + + def entry_port_callback(self, event): + config.OSC_PORT = self.entry_port.get() + + def entry_authkey_callback(self, event): + value = self.entry_authkey.get() + if len(value) > 0: + 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: + pass + + def checkbox_auto_clear_chatbox_callback(self): + config.ENABLE_AUTO_CLEAR_CHATBOX = self.checkbox_auto_clear_chatbox.get() + + def checkbox_notice_xsoverlay_callback(self): + config.ENABLE_NOTICE_XSOVERLAY = self.checkbox_notice_xsoverlay.get() + + def delete_window(self): + self.checkbox_input_mic_threshold_check.deselect() + self.checkbox_input_speaker_threshold_check.deselect() + self.checkbox_input_mic_threshold_check_callback() + self.checkbox_input_speaker_threshold_check_callback() + self.parent.transcription_start() + self.parent.foreground_start() + self.parent.checkbox_translation.configure(state="normal") + self.parent.checkbox_transcription_send.configure(state="normal") + self.parent.checkbox_transcription_receive.configure(state="normal") + self.parent.checkbox_foreground.configure(state="normal") + self.parent.tabview_logs.configure(state="normal") + self.parent.textbox_message_log.configure(state="normal") + self.parent.textbox_message_send_log.configure(state="normal") + self.parent.textbox_message_receive_log.configure(state="normal") + self.parent.textbox_message_system_log.configure(state="normal") + self.parent.entry_message_box.configure(state="normal") + self.parent.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"]) + self.parent.button_information.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"]) + self.withdraw() + self.grab_release() + + def entry_message_format_callback(self, event): + value = self.entry_message_format.get() + if len(value) > 0: + config.MESSAGE_FORMAT = value + + def delete_tabview_config(self, pre_language_yaml_data): + self.tabview_config.delete(pre_language_yaml_data["config_tab_title_ui"]) + self.tabview_config.delete(pre_language_yaml_data["config_tab_title_translation"]) + self.tabview_config.delete(pre_language_yaml_data["config_tab_title_transcription"]) + self.tabview_config.delete(pre_language_yaml_data["config_tab_title_parameter"]) + self.tabview_config.delete(pre_language_yaml_data["config_tab_title_others"]) + + def add_tabview_config(self, language_yaml_data, selectable_languages): + config_tab_title_ui = language_yaml_data["config_tab_title_ui"] + config_tab_title_translation = language_yaml_data["config_tab_title_translation"] + config_tab_title_transcription = language_yaml_data["config_tab_title_transcription"] + config_tab_title_parameter = language_yaml_data["config_tab_title_parameter"] + config_tab_title_others = language_yaml_data["config_tab_title_others"] + + init_lang_text = "Loading..." + + # tabwiew config + self.tabview_config = CTkTabview(self) + self.tabview_config.grid(row=0, column=0, padx=5, pady=5, sticky="nsew") + self.tabview_config.add(config_tab_title_ui) + self.tabview_config.add(config_tab_title_translation) + self.tabview_config.add(config_tab_title_transcription) + self.tabview_config.add(config_tab_title_parameter) + self.tabview_config.add(config_tab_title_others) + self.tabview_config.tab(config_tab_title_ui).grid_columnconfigure(1, weight=1) + self.tabview_config.tab(config_tab_title_translation).grid_columnconfigure([1,2,3], weight=1) + self.tabview_config.tab(config_tab_title_transcription).grid_columnconfigure(1, weight=1) + self.tabview_config.tab(config_tab_title_parameter).grid_columnconfigure(1, weight=1) + self.tabview_config.tab(config_tab_title_others).grid_columnconfigure(1, weight=1) + self.tabview_config._segmented_button.configure(font=CTkFont(family=config.FONT_FAMILY)) + self.tabview_config._segmented_button.grid(sticky="W") + + # tab UI + ## slider transparency + row = 0 + padx = 5 + pady = 1 + self.label_transparency = CTkLabel( + self.tabview_config.tab(config_tab_title_ui), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_transparency.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.slider_transparency = CTkSlider( + self.tabview_config.tab(config_tab_title_ui), + from_=50, + to=100, + command=self.slider_transparency_callback, + variable=DoubleVar(value=config.TRANSPARENCY), + ) + self.slider_transparency.grid(row=row, column=1, columnspan=1, padx=padx, pady=10, sticky="nsew") + + ## optionmenu theme + row += 1 + self.label_appearance_theme = CTkLabel( + self.tabview_config.tab(config_tab_title_ui), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_appearance_theme.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.optionmenu_appearance_theme = CTkOptionMenu( + self.tabview_config.tab(config_tab_title_ui), + values=["Light", "Dark", "System"], + command=self.optionmenu_appearance_theme_callback, + variable=StringVar(value=config.APPEARANCE_THEME), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_appearance_theme.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown appearance theme + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_appearance_theme = CTkScrollableDropdown( + self.optionmenu_appearance_theme, + values=["Light", "Dark", "System"], + justify="left", + button_color="transparent", + command=self.optionmenu_appearance_theme_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_appearance_theme.bind( + "", + lambda e: self.scrollableDropdown_appearance_theme._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_appearance_theme.frame._parent_frame)) else None, + ) + + ## optionmenu UI scaling + row += 1 + self.label_ui_scaling = CTkLabel( + self.tabview_config.tab(config_tab_title_ui), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_ui_scaling.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.optionmenu_ui_scaling = CTkOptionMenu( + self.tabview_config.tab(config_tab_title_ui), + values=["80%", "90%", "100%", "110%", "120%"], + command=self.optionmenu_ui_scaling_callback, + variable=StringVar(value=config.UI_SCALING), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_ui_scaling.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown ui scaling + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_ui_scaling = CTkScrollableDropdown( + self.optionmenu_ui_scaling, + values=["80%", "90%", "100%", "110%", "120%"], + justify="left", + button_color="transparent", + command=self.optionmenu_ui_scaling_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_ui_scaling.bind( + "", + lambda e: self.scrollableDropdown_ui_scaling._iconify() if not str(e.widget).startswith(str(self.scrollableDropdown_ui_scaling.frame._parent_frame)) else None, + ) + + ## optionmenu font family + row += 1 + self.label_font_family = CTkLabel( + self.tabview_config.tab(config_tab_title_ui), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_font_family.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + font_families = list(tk_font.families()) + self.optionmenu_font_family = CTkOptionMenu( + self.tabview_config.tab(config_tab_title_ui), + values=font_families, + command=self.optionmenu_font_family_callback, + variable=StringVar(value=config.FONT_FAMILY), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_font_family.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown font family + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_font_family = CTkScrollableDropdown( + self.optionmenu_font_family, + values=font_families, + justify="left", + button_color="transparent", + command=self.optionmenu_font_family_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_font_family.bind( + "", + lambda e: self.scrollableDropdown_font_family._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_font_family.frame._parent_frame)) else None, + ) + + ## optionmenu ui language + row += 1 + self.label_ui_language = CTkLabel( + self.tabview_config.tab(config_tab_title_ui), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_ui_language.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + selectable_languages_values = list(selectable_languages.values()) + self.optionmenu_ui_language = CTkOptionMenu( + self.tabview_config.tab(config_tab_title_ui), + values=selectable_languages_values, + command=self.optionmenu_ui_language_callback, + variable=StringVar(value=selectable_languages[config.UI_LANGUAGE]), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_ui_language.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown ui language + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_ui_language = CTkScrollableDropdown( + self.optionmenu_ui_language, + values=selectable_languages_values, + justify="left", + button_color="transparent", + command=self.optionmenu_ui_language_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_ui_language.bind( + "", + lambda e: self.scrollableDropdown_ui_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_ui_language.frame._parent_frame)) else None, + ) + + # tab Translation + ## optionmenu translation translator + row = 0 + padx = 5 + pady = 1 + self.label_translation_translator = CTkLabel( + self.tabview_config.tab(config_tab_title_translation), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY), + ) + 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=model.getListTranslatorName(), + command=self.optionmenu_translation_translator_callback, + variable=StringVar(value=config.CHOICE_TRANSLATOR), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_translation_translator.grid(row=row, column=1, columnspan=3, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown translation translator + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_translation_translator = CTkScrollableDropdown( + self.optionmenu_translation_translator, + values=model.getListTranslatorName(), + justify="left", + button_color="transparent", + command=self.optionmenu_translation_translator_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_translation_translator.bind( + "", + lambda e: self.scrollableDropdown_translation_translator._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_translation_translator.frame._parent_frame)) else None, + ) + + ## optionmenu translation input language + row +=1 + self.label_translation_input_language = CTkLabel( + self.tabview_config.tab(config_tab_title_translation), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_translation_input_language.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + + ## select translation input source language + self.optionmenu_translation_input_source_language = CTkOptionMenu( + self.tabview_config.tab(config_tab_title_translation), + command=self.optionmenu_translation_input_source_language_callback, + values=list(translation_lang[config.CHOICE_TRANSLATOR]["source"].keys()), + variable=StringVar(value=config.INPUT_SOURCE_LANG), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_translation_input_source_language.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown translation input source language + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_translation_input_source_language = CTkScrollableDropdown( + self.optionmenu_translation_input_source_language, + values=list(translation_lang[config.CHOICE_TRANSLATOR]["source"].keys()), + justify="left", + button_color="transparent", + command=self.optionmenu_translation_input_source_language_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_translation_input_source_language.bind( + "", + lambda e: self.scrollableDropdown_translation_input_source_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_translation_input_source_language.frame._parent_frame)) else None, + ) + + ## label translation input arrow + self.label_translation_input_arrow = CTkLabel( + self.tabview_config.tab(config_tab_title_translation), + text="-->", + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_translation_input_arrow.grid(row=row, column=2, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## select translation input target language + self.optionmenu_translation_input_target_language = CTkOptionMenu( + self.tabview_config.tab(config_tab_title_translation), + command=self.optionmenu_translation_input_target_language_callback, + values=list(translation_lang[config.CHOICE_TRANSLATOR]["target"].keys()), + variable=StringVar(value=config.INPUT_TARGET_LANG), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_translation_input_target_language.grid(row=row, column=3, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown translation input target language + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_translation_input_target_language = CTkScrollableDropdown( + self.optionmenu_translation_input_target_language, + values=list(translation_lang[config.CHOICE_TRANSLATOR]["target"].keys()), + justify="left", + button_color="transparent", + command=self.optionmenu_translation_input_target_language_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_translation_input_target_language.bind( + "", + lambda e: self.scrollableDropdown_translation_input_target_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_translation_input_target_language.frame._parent_frame)) else None, + ) + + ## optionmenu translation output language + row +=1 + self.label_translation_output_language = CTkLabel( + self.tabview_config.tab(config_tab_title_translation), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_translation_output_language.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + + ## select translation output source language + self.optionmenu_translation_output_source_language = CTkOptionMenu( + self.tabview_config.tab(config_tab_title_translation), + command=self.optionmenu_translation_output_source_language_callback, + values=list(translation_lang[config.CHOICE_TRANSLATOR]["source"].keys()), + variable=StringVar(value=config.OUTPUT_SOURCE_LANG), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_translation_output_source_language.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown translation output source language + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_translation_output_source_language = CTkScrollableDropdown( + self.optionmenu_translation_output_source_language, + values=list(translation_lang[config.CHOICE_TRANSLATOR]["source"].keys()), + justify="left", + button_color="transparent", + command=self.optionmenu_translation_output_source_language_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_translation_output_source_language.bind( + "", + lambda e: self.scrollableDropdown_translation_output_source_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_translation_output_source_language.frame._parent_frame)) else None, + ) + + ## label translation output arrow + self.label_translation_output_arrow = CTkLabel( + self.tabview_config.tab(config_tab_title_translation), + text="-->", + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_translation_output_arrow.grid(row=row, column=2, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## select translation output target language + self.optionmenu_translation_output_target_language = CTkOptionMenu( + self.tabview_config.tab(config_tab_title_translation), + command=self.optionmenu_translation_output_target_language_callback, + values=list(translation_lang[config.CHOICE_TRANSLATOR]["target"].keys()), + variable=StringVar(value=config.OUTPUT_TARGET_LANG), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_translation_output_target_language.grid(row=row, column=3, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown translation output target language + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_translation_output_target_language = CTkScrollableDropdown( + self.optionmenu_translation_output_target_language, + values=list(translation_lang[config.CHOICE_TRANSLATOR]["target"].keys()), + justify="left", + button_color="transparent", + command=self.optionmenu_translation_output_target_language_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_translation_output_target_language.bind( + "", + lambda e: self.scrollableDropdown_translation_output_target_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_translation_output_target_language.frame._parent_frame)) else None, + ) + + # tab Transcription + ## optionmenu input mic device's host + row = 0 + padx = 5 + pady = 1 + self.label_input_mic_host = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + 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=model.getListInputHost(), + command=self.optionmenu_input_mic_host_callback, + variable=StringVar(value=config.CHOICE_MIC_HOST), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_input_mic_host.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown input mic device's host + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_input_mic_host = CTkScrollableDropdown( + self.optionmenu_input_mic_host, + values=model.getListInputHost(), + justify="left", + button_color="transparent", + command=self.optionmenu_input_mic_host_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_input_mic_host.bind( + "", + lambda e: self.scrollableDropdown_input_mic_host._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_input_mic_host.frame._parent_frame)) else None, + ) + + ## optionmenu input mic device + row += 1 + self.label_input_mic_device = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + 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=model.getListInputDevice(), + command=self.optionmenu_input_mic_device_callback, + variable=StringVar(value=config.CHOICE_MIC_DEVICE), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_input_mic_device.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown input mic device + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_input_mic_device = CTkScrollableDropdown( + self.optionmenu_input_mic_device, + values=model.getListInputDevice(), + justify="left", + button_color="transparent", + command=self.optionmenu_input_mic_device_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_input_mic_device.bind( + "", + lambda e: self.scrollableDropdown_input_mic_device._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_input_mic_device.frame._parent_frame)) else None, + ) + + ## optionmenu input mic voice language + row +=1 + self.label_input_mic_voice_language = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_mic_voice_language.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.optionmenu_input_mic_voice_language = CTkOptionMenu( + self.tabview_config.tab(config_tab_title_transcription), + values=list(transcription_lang.keys()), + command=self.optionmenu_input_mic_voice_language_callback, + variable=StringVar(value=config.INPUT_MIC_VOICE_LANGUAGE), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_input_mic_voice_language.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown input mic voice language + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_input_voice_language = CTkScrollableDropdown( + self.optionmenu_input_mic_voice_language, + values=list(transcription_lang.keys()), + justify="left", + button_color="transparent", + command=self.optionmenu_input_mic_voice_language_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_input_voice_language.bind( + "", + lambda e: self.scrollableDropdown_input_voice_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_input_voice_language.frame._parent_frame)) else None, + ) + + ## slider input mic energy threshold + row +=1 + self.label_input_mic_energy_threshold = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_mic_energy_threshold.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + + self.slider_input_mic_energy_threshold = CTkSlider( + self.tabview_config.tab(config_tab_title_transcription), + from_=0, + to=config.MAX_MIC_ENERGY_THRESHOLD, + border_width=7, + button_length=0, + button_corner_radius=3, + number_of_steps=config.MAX_MIC_ENERGY_THRESHOLD, + command=self.slider_input_mic_energy_threshold_callback, + variable=IntVar(value=config.INPUT_MIC_ENERGY_THRESHOLD), + ) + self.slider_input_mic_energy_threshold.grid(row=row, column=1, columnspan=1, padx=0, pady=5, sticky="nsew") + + ## progressBar input mic energy threshold + row +=1 + self.checkbox_input_mic_threshold_check = CTkCheckBox( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + onvalue=True, + offvalue=False, + command=self.checkbox_input_mic_threshold_check_callback, + font=CTkFont(family=config.FONT_FAMILY) + ) + self.checkbox_input_mic_threshold_check.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + + self.progressBar_input_mic_energy_threshold = CTkProgressBar( + self.tabview_config.tab(config_tab_title_transcription), + corner_radius=0 + ) + self.progressBar_input_mic_energy_threshold.grid(row=row, column=1, columnspan=1, padx=padx, pady=5, sticky="nsew") + self.progressBar_input_mic_energy_threshold.set(0) + + ## checkbox input mic dynamic energy threshold + row +=1 + self.label_input_mic_dynamic_energy_threshold = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_mic_dynamic_energy_threshold.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.checkbox_input_mic_dynamic_energy_threshold = CTkCheckBox( + self.tabview_config.tab(config_tab_title_transcription), + text="", + onvalue=True, + offvalue=False, + command=self.checkbox_input_mic_dynamic_energy_threshold_callback, + font=CTkFont(family=config.FONT_FAMILY) + ) + self.checkbox_input_mic_dynamic_energy_threshold.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + if config.INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD is True: + self.checkbox_input_mic_dynamic_energy_threshold.select() + else: + self.checkbox_input_mic_dynamic_energy_threshold.deselect() + + ## entry input mic record timeout + row +=1 + self.label_input_mic_record_timeout = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_mic_record_timeout.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.entry_input_mic_record_timeout = CTkEntry( + self.tabview_config.tab(config_tab_title_transcription), + textvariable=StringVar(value=config.INPUT_MIC_RECORD_TIMEOUT), + font=CTkFont(family=config.FONT_FAMILY) + ) + self.entry_input_mic_record_timeout.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + self.entry_input_mic_record_timeout.bind("", self.entry_input_mic_record_timeout_callback) + + ## entry input mic phrase timeout + row +=1 + self.label_input_mic_phrase_timeout = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_mic_phrase_timeout.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.entry_input_mic_phrase_timeout = CTkEntry( + self.tabview_config.tab(config_tab_title_transcription), + textvariable=StringVar(value=config.INPUT_MIC_PHRASE_TIMEOUT), + font=CTkFont(family=config.FONT_FAMILY) + ) + self.entry_input_mic_phrase_timeout.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + self.entry_input_mic_phrase_timeout.bind("", self.entry_input_mic_phrase_timeout_callback) + + ## entry input mic max phrases + row +=1 + self.label_input_mic_max_phrases = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_mic_max_phrases.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.entry_input_mic_max_phrases = CTkEntry( + self.tabview_config.tab(config_tab_title_transcription), + textvariable=StringVar(value=config.INPUT_MIC_MAX_PHRASES), + font=CTkFont(family=config.FONT_FAMILY) + ) + self.entry_input_mic_max_phrases.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + self.entry_input_mic_max_phrases.bind("", self.entry_input_mic_max_phrases_callback) + + ## entry input mic word filter + row +=1 + self.label_input_mic_word_filter = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_mic_word_filter.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + if len(config.INPUT_MIC_WORD_FILTER) > 0: + textvariable=StringVar(value=",".join(config.INPUT_MIC_WORD_FILTER)) + else: + textvariable=None + self.entry_input_mic_word_filter = CTkEntry( + self.tabview_config.tab(config_tab_title_transcription), + textvariable=textvariable, + placeholder_text="AAA,BBB,CCC", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.entry_input_mic_word_filter.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + self.entry_input_mic_word_filter.bind("", self.entry_input_mic_word_filters_callback) + + ## optionmenu input speaker device + row +=1 + self.label_input_speaker_device = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + 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=model.getListOutputDevice(), + command=self.optionmenu_input_speaker_device_callback, + variable=StringVar(value=config.CHOICE_SPEAKER_DEVICE), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_input_speaker_device.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown input speaker device + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_input_speaker_device = CTkScrollableDropdown( + self.optionmenu_input_speaker_device, + values=model.getListOutputDevice(), + justify="left", + button_color="transparent", + command=self.optionmenu_input_speaker_device_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_input_speaker_device.bind( + "", + lambda e: self.scrollableDropdown_input_speaker_device._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_input_speaker_device.frame._parent_frame)) else None, + ) + + ## optionmenu input speaker voice language + row +=1 + self.label_input_speaker_voice_language = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_speaker_voice_language.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.optionmenu_input_speaker_voice_language = CTkOptionMenu( + self.tabview_config.tab(config_tab_title_transcription), + values=list(transcription_lang.keys()), + command=self.optionmenu_input_speaker_voice_language_callback, + variable=StringVar(value=config.INPUT_SPEAKER_VOICE_LANGUAGE), + font=CTkFont(family=config.FONT_FAMILY), + dropdown_font=CTkFont(family=config.FONT_FAMILY), + ) + self.optionmenu_input_speaker_voice_language.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + + ## scrollableDropdown input speaker voice language + if SCROLLABLE_DROPDOWN: + self.scrollableDropdown_input_speaker_voice_language = CTkScrollableDropdown( + self.optionmenu_input_speaker_voice_language, + values=list(transcription_lang.keys()), + justify="left", + button_color="transparent", + command=self.optionmenu_input_speaker_voice_language_callback, + font=CTkFont(family=config.FONT_FAMILY), + ) + self.scrollableDropdown_input_speaker_voice_language.bind( + "", + lambda e: self.scrollableDropdown_input_speaker_voice_language._withdraw() if not str(e.widget).startswith(str(self.scrollableDropdown_input_speaker_voice_language.frame._parent_frame)) else None, + ) + + ## entry input speaker energy threshold + row +=1 + self.label_input_speaker_energy_threshold = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_speaker_energy_threshold.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + + ## progressBar input speaker energy threshold + self.slider_input_speaker_energy_threshold = CTkSlider( + self.tabview_config.tab(config_tab_title_transcription), + from_=0, + to=config.MAX_SPEAKER_ENERGY_THRESHOLD, + border_width=7, + button_length=0, + button_corner_radius=3, + number_of_steps=config.MAX_SPEAKER_ENERGY_THRESHOLD, + command=self.slider_input_speaker_energy_threshold_callback, + variable=IntVar(value=config.INPUT_SPEAKER_ENERGY_THRESHOLD), + ) + self.slider_input_speaker_energy_threshold.grid(row=row, column=1, columnspan=1, padx=0, pady=5, sticky="nsew") + + ## progressBar input speaker energy threshold + row +=1 + self.checkbox_input_speaker_threshold_check = CTkCheckBox( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + onvalue=True, + offvalue=False, + command=self.checkbox_input_speaker_threshold_check_callback, + font=CTkFont(family=config.FONT_FAMILY) + ) + self.checkbox_input_speaker_threshold_check.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + + self.progressBar_input_speaker_energy_threshold = CTkProgressBar( + self.tabview_config.tab(config_tab_title_transcription), + corner_radius=0 + ) + self.progressBar_input_speaker_energy_threshold.grid(row=row, column=1, columnspan=1, padx=padx, pady=5, sticky="nsew") + self.progressBar_input_speaker_energy_threshold.set(0) + + ## checkbox input speaker dynamic energy threshold + row +=1 + self.label_input_speaker_dynamic_energy_threshold = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_speaker_dynamic_energy_threshold.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.checkbox_input_speaker_dynamic_energy_threshold = CTkCheckBox( + self.tabview_config.tab(config_tab_title_transcription), + text="", + onvalue=True, + offvalue=False, + command=self.checkbox_input_speaker_dynamic_energy_threshold_callback, + font=CTkFont(family=config.FONT_FAMILY) + ) + self.checkbox_input_speaker_dynamic_energy_threshold.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + if config.INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD is True: + self.checkbox_input_speaker_dynamic_energy_threshold.select() + else: + self.checkbox_input_speaker_dynamic_energy_threshold.deselect() + + ## entry input speaker record timeout + row +=1 + self.label_input_speaker_record_timeout = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_speaker_record_timeout.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.entry_input_speaker_record_timeout = CTkEntry( + self.tabview_config.tab(config_tab_title_transcription), + textvariable=StringVar(value=config.INPUT_SPEAKER_RECORD_TIMEOUT), + font=CTkFont(family=config.FONT_FAMILY) + ) + self.entry_input_speaker_record_timeout.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + self.entry_input_speaker_record_timeout.bind("", self.entry_input_speaker_record_timeout_callback) + + ## entry input speaker phrase timeout + row +=1 + self.label_input_speaker_phrase_timeout = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_speaker_phrase_timeout.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.entry_input_speaker_phrase_timeout = CTkEntry( + self.tabview_config.tab(config_tab_title_transcription), + textvariable=StringVar(value=config.INPUT_SPEAKER_PHRASE_TIMEOUT), + font=CTkFont(family=config.FONT_FAMILY) + ) + self.entry_input_speaker_phrase_timeout.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + self.entry_input_speaker_phrase_timeout.bind("", self.entry_input_speaker_phrase_timeout_callback) + + ## entry input speaker max phrases + row +=1 + self.label_input_speaker_max_phrases = CTkLabel( + self.tabview_config.tab(config_tab_title_transcription), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_input_speaker_max_phrases.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.entry_input_speaker_max_phrases = CTkEntry( + self.tabview_config.tab(config_tab_title_transcription), + textvariable=StringVar(value=config.INPUT_SPEAKER_MAX_PHRASES), + font=CTkFont(family=config.FONT_FAMILY) + ) + self.entry_input_speaker_max_phrases.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + self.entry_input_speaker_max_phrases.bind("", self.entry_input_speaker_max_phrases_callback) + + # tab Parameter + ## entry ip address + row = 0 + padx = 5 + pady = 1 + self.label_ip_address = CTkLabel( + self.tabview_config.tab(config_tab_title_parameter), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_ip_address.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.entry_ip_address = CTkEntry( + self.tabview_config.tab(config_tab_title_parameter), + textvariable=StringVar(value=config.OSC_IP_ADDRESS), + font=CTkFont(family=config.FONT_FAMILY) + ) + self.entry_ip_address.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + self.entry_ip_address.bind("", self.entry_ip_address_callback) + + ## entry port + row +=1 + self.label_port = CTkLabel( + self.tabview_config.tab(config_tab_title_parameter), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_port.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.entry_port = CTkEntry( + self.tabview_config.tab(config_tab_title_parameter), + textvariable=StringVar(value=config.OSC_PORT), + font=CTkFont(family=config.FONT_FAMILY) + ) + self.entry_port.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + self.entry_port.bind("", self.entry_port_callback) + + ## entry authkey + row +=1 + self.label_authkey = CTkLabel( + self.tabview_config.tab(config_tab_title_parameter), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_authkey.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.entry_authkey = CTkEntry( + self.tabview_config.tab(config_tab_title_parameter), + textvariable=StringVar(value=config.AUTH_KEYS["DeepL(auth)"]), + font=CTkFont(family=config.FONT_FAMILY) + ) + self.entry_authkey.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + self.entry_authkey.bind("", self.entry_authkey_callback) + + ## entry message format + row +=1 + self.label_message_format = CTkLabel( + self.tabview_config.tab(config_tab_title_parameter), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_message_format.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.entry_message_format = CTkEntry( + self.tabview_config.tab(config_tab_title_parameter), + textvariable=StringVar(value=config.MESSAGE_FORMAT), + font=CTkFont(family=config.FONT_FAMILY) + ) + self.entry_message_format.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + self.entry_message_format.bind("", self.entry_message_format_callback) + + # tab Others + ## checkbox auto clear chat box + row = 0 + self.label_checkbox_auto_clear_chatbox = CTkLabel( + self.tabview_config.tab(config_tab_title_others), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_checkbox_auto_clear_chatbox.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.checkbox_auto_clear_chatbox = CTkCheckBox( + self.tabview_config.tab(config_tab_title_others), + text="", + onvalue=True, + offvalue=False, + command=self.checkbox_auto_clear_chatbox_callback, + font=CTkFont(family=config.FONT_FAMILY) + ) + self.checkbox_auto_clear_chatbox.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + if config.ENABLE_AUTO_CLEAR_CHATBOX is True: + self.checkbox_auto_clear_chatbox.select() + else: + self.checkbox_auto_clear_chatbox.deselect() + + # checkbox notice xsoverlay + row += 1 + self.label_checkbox_notice_xsoverlay = CTkLabel( + self.tabview_config.tab(config_tab_title_others), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=config.FONT_FAMILY) + ) + self.label_checkbox_notice_xsoverlay.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.checkbox_notice_xsoverlay = CTkCheckBox( + self.tabview_config.tab(config_tab_title_others), + text="", + onvalue=True, + offvalue=False, + command=self.checkbox_notice_xsoverlay_callback, + font=CTkFont(family=config.FONT_FAMILY) + ) + self.checkbox_notice_xsoverlay.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + if config.ENABLE_NOTICE_XSOVERLAY is True: + self.checkbox_notice_xsoverlay.select() + else: + self.checkbox_notice_xsoverlay.deselect() + widget_config_window_label_setter(self, language_yaml_data) \ No newline at end of file diff --git a/test_model/window_information.py b/test_model/window_information.py new file mode 100644 index 00000000..cc8d8792 --- /dev/null +++ b/test_model/window_information.py @@ -0,0 +1,161 @@ +import os +from customtkinter import CTkToplevel, CTkTextbox, CTkFont +from config import config + +class ToplevelWindowInformation(CTkToplevel): + def __init__(self, parent, *args, **kwargs): + super().__init__(parent, *args, **kwargs) + self.withdraw() + self.parent = parent + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + # self.geometry(f"{500}x{300}") + self.minsize(500, 300) + + self.after(200, lambda: self.iconbitmap(os.path.join(os.path.dirname(__file__), "img", "app.ico"))) + self.title("Information") + # create textbox information + self.textbox_information = CTkTextbox( + self, + font=CTkFont(family=config.FONT_FAMILY) + ) + self.textbox_information.grid(row=0, column=0, padx=(10, 10), pady=(10, 10), sticky="nsew") + textbox_information_message = """VRCT(v1.3.2) + +# 概要 +VRChatで使用されるChatBoxをOSC経由でメッセージを送信するツールになります。 +翻訳エンジンを使用してメッセージとその翻訳部分を同時に送信することができます。 +(翻訳エンジンはDeepL,Google,Bingに対応) + +# 使用方法 + 初期設定時 + 0. VRChatのOSCを有効にする(重要) + + (任意) + 1. DeepLのAPIを使用するためにアカウント登録し、認証キーを取得する + 2. ギアアイコンのボタンでconfigウィンドウを開く + 3. ParameterタブのDeepL Auth Keyに認証キーを記載 + 4. configウィンドウを閉じる + + 通常使用時 + 1. メッセージボックスにメッセージを記入 + 2. Enterキーを押し、メッセージを送信する + +# その他の設定 + translation チェックボックス: 翻訳の有効無効 + voice2chatbox チェックボックス : マイクの音声を文字起こししてチャットボックスに送信する + speaker2log チェックボックス : スピーカーの音声から文字起こししてログに表示する + foreground チェックボックス: 最前面表示の有効無効 + + テキストボックス + logタブ + すべてのログを表示 + sendタブ + 送信したメッセージを表示 + receiveタブ + 受信したメッセージを表示 + systemタブ + 機能についてのメッセージを表示 + + configウィンドウ + UIタブ + Transparency: ウィンドウの透過度の調整 + Appearance Theme: ウィンドウテーマを選択 + UI Scaling: UIサイズを調整 + Font Family: 表示フォントを選択 + UI Language: UIの表示言語を選択 + Translationタブ + Select Translator: 翻訳エンジンの変更 + Send Language: 送信するメッセージに対して翻訳する言語[source, target]を選択 + Receive Language: 受信したメッセージに対して翻訳する言語[source, target]を選択 + Transcriptionタブ + Input Mic Host: マイクのホストAPIを選択 + Input Mic Device: マイクを選択 + Input Mic Voice Language: 入力する音声の言語 + Input Mic Energy Threshold: 音声取得のしきい値 + Check threshold point: Input Mic Energy Thresholdのしきい値を視覚化 + Input Mic Dynamic Energy Threshold: 音声取得のしきい値の自動調整 + Input Mic Record Timeout: 音声の区切りの無音時間 + Input Mic Phase Timeout: 文字起こしする音声時間の上限 + Input Mic Max Phrases: 保留する単語の上限 + Input Mic Word Filter: MICの文字起こし時にWord Filterで設定した文字が入っていた場合にChatboxに表示しない (ex AAA,BBB,CCC) + Input Speaker Device: スピーカーを選択 + Input Speaker Voice Language: 受信する音声の言語 + Input Speaker Energy Threshold: 音声取得のしきい値 + Check threshold point: Input Speaker Energy Thresholdのしきい値を視覚化 + Input Speaker Dynamic Energy Threshold: 音声取得のしきい値の自動調整 + Input Speaker Record Timeout: 音声の区切りの無音時間 + Input Speaker Phase Timeout: 文字起こしする音声時間の上限 + Input Speaker Max Phrases: 保留する単語の上限 + Parameterタブ + OSC IP address: 変更不要 + OSC port: 変更不要 + DeepL Auth key: DeepLの認証キーの設定 + Message Format: 送信するメッセージのデコレーションの設定 + [message]がメッセージボックスに記入したメッセージに置換される + [translation]が翻訳されたメッセージに置換される + 初期フォーマット:"[message]([translation])" + Othersタブ + Auto clear chat box: メッセージ送信後に書き込んだメッセージを空にする + (New!) Notification XSOverlay: XSOverlayの通知機能を有効(VR only) + + 設定の初期化 + config.jsonを削除 + +# お問い合わせ +要望などはTwitterまで +https://twitter.com/misya_ai + +# アップデート履歴 +[2023-05-29: v0.1b] v0.1b リリース +[2023-05-30: v0.2b] +- configボタンをギアアイコンに変更 +- 詳細情報のボタンを追加 +- 翻訳機能有効無効のチェックボックスを追加 +- 最前面表示の有効無効のチェックボックスを追加 +- いくつかのバグを修正 +[2023-06-03: v0.3b] +- 全体的にUIを刷新 +- 透過機能を追加 +- テーマのLight/Dark/Systemのモードの変更機能を追加 +- UIのスケール変更機能を追加 +- フォントの変更機能を追加 +[2023-06-06: v0.4b] +- 翻訳エンジンを追加 +- 入力と出力の翻訳言語を選択できるように変更 +[2023-06-20: v1.0] +- マイクからの音声の文字起こし機能を追加 +- スピーカーからの音声の文字起こし機能を追加 +[2023-06-28: v1.1] +- いくつかのバクを修正 +- 翻訳/文字起こし言語の表記を略称からわかりやすい文字に変更 +- 文字起こしの処理の軽量化 +[2023-07-05: v1.2] +- 文字起こし精度の向上 +[2023-07-21: v1.3] +- UIの表示言語を日本語/英語を選択できる機能を追加 +- Energy Thresholdの視覚化機能を追加 +- 文字起こしの誤認識対策のため、Word Filterを追加 +- WASAPI以外のHostAPIでもマイクとして使用できるようにHostAPIを選択できる機能を追加 +- メッセージ送信後に書き込んだメッセージを空にするか選択できる機能を追加 +- バグ対策のため、translation/voice2chatbox/speaker2log/foregroundは起動時はOFFになるように変更 +- バグ対策のため、スピーカーについて既定デバイス以外を選択した時にERRORが出るように変更 +- 半角入力時に一部の文字が書き込めないバグを修正 +[2023-07-22: v1.3.1] +- UIの表示言語選択に韓国語を追加 +[2023-07-30: v1.3.2] +- 試験的にXSOverlayへの通知機能を追加 +- checkbox ONの状態でもConfigを開けるように変更 +- 文字起こし言語の表示を修正 +- いくつかのバグを修正 + +# 注意事項 +再配布とかはやめてね +""" + + self.textbox_information.insert("end", textbox_information_message) + self.textbox_information.configure(state='disabled') + self.protocol("WM_DELETE_WINDOW", self.delete_window) + + def delete_window(self): + self.withdraw() \ No newline at end of file