From cd4e431be2de48af15ba4bacd1382c35e51902f9 Mon Sep 17 00:00:00 2001 From: misygauziya Date: Sun, 27 Aug 2023 04:54:25 +0900 Subject: [PATCH] [Add] model test code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 既存のVRCT 1.3.2のUIをmodelのテストコードとして移動 --- test_model/config.py | 511 ++++++++++ test_model/img/app.ico | Bin 0 -> 67646 bytes test_model/img/config-icon-white.png | Bin 0 -> 5490 bytes test_model/img/info-icon-white.png | Bin 0 -> 4945 bytes test_model/img/xsoverlay.png | Bin 0 -> 1209 bytes test_model/languages.py | 6 + test_model/locales.yml | 193 ++++ test_model/main.py | 503 ++++++++++ test_model/utils.py | 106 ++ test_model/window_config.py | 1348 ++++++++++++++++++++++++++ test_model/window_information.py | 161 +++ 11 files changed, 2828 insertions(+) create mode 100644 test_model/config.py create mode 100644 test_model/img/app.ico create mode 100644 test_model/img/config-icon-white.png create mode 100644 test_model/img/info-icon-white.png create mode 100644 test_model/img/xsoverlay.png create mode 100644 test_model/languages.py create mode 100644 test_model/locales.yml create mode 100644 test_model/main.py create mode 100644 test_model/utils.py create mode 100644 test_model/window_config.py create mode 100644 test_model/window_information.py 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 0000000000000000000000000000000000000000..eca32ce73e86bb5d9cf41456997c2c74c77c7c1a GIT binary patch literal 67646 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 literal 0 HcmV?d00001 diff --git a/test_model/img/info-icon-white.png b/test_model/img/info-icon-white.png new file mode 100644 index 0000000000000000000000000000000000000000..210613e03a30370a1821eb81a53c181084186de5 GIT binary patch literal 4945 zcmeHKX;2f{7ES6`%#eBb7kXf@w1?@lw>_RQM1%R;*IXl?L7`_mCk{%ymA0^WFhe12R# zwXyVv5t++Y`S7gW{2(>D za|{!I2)6mYot+wEw6T6pg!w+SYv~^ivGtkF6bdyH4+sbs2LybK2Sib{I7b+Aa`MR9 zd9$);-}U!h>8aSoXcCD=h7Qe&*-|<5`vmwPNy6uFtVuJ0iLad~P#rk>9(8Kc_4W92<)G4wZ zn?jh%X8zIE+jpMK&5TVhey{8BO5Q;A&*7aTPtuIgrr#>b`uC?s&(3vf(Y1&(7$Kc! z6K>q&){9p3+cX?Oeo1a|*cbIQ=1@j-UHGcll_yu1&OEw4A^LVrZFJe?s3)5`mmRO! zpL<_$(ec#2Osian(c6|IY;ObX$_b&8I@z{dt<%kR4IeeLIU3x4fa_FOfDvd4*fa z91|sCYI00p2!*`YUX!4WH;1E;GqHF~1yprlSJr1+28$)(y%r`4VsVwmYz4^vOq0Zw zpUC>mHW!gvOvdKOQ4Zh7n=kJJC06T5R4vC$Pyn2P0~|IV<^Tj49YYW{ovq-> z=rWAUqH_^0hs~D3as?Od12IF3gRDg3`+8-9QkbBW2#d=BP_Tl}r?WW<9-YtgQP8<^ zmYgd`5tOTxnV}SNK@g!;q2M@i6&i~%HR@Qiz(lxUO1M}^Lm2RNwnZ&H+$H2N~N-83NOoJ;5?f9phuPe#}4d z;b&Ip(_(;K_Znzjpc68CTVW4hrl#{ZK0W8~H|_wSzi#qH{C=hDD_vj2z!xch&91L> zeGvm+r2I9z{%>^Ie!5IyYVZ$853Wi?(6(T3&9at-1_zoiT$Hx~hnIknjV2^oN1@ma zF}+kuVUY`1>`#g%qW%y1xec1=l&KrCkV3KO6bDX`&Nn{$sUcK4)9K8y$jVcrDzj|q zW6zAbJbPF^J!`%5_6d=%n3*m?qo3t!3s&!5s)=mcRoU>btt8c;~pPkW&5f57U~~cN}-A zIMlY4Qe@$gW`FLEw`SPGTZ5PDDbdgj&E53m&BAuNl~i0k`cZy~WqI*|v1QZVc|0oc zPK=7EC{c^6%HR6tszY75r|)i9nIimsPe@>~MP%ALq~;I9RL8E`h?<$MAI@!mW8XL{ zeUGp8FM3aE(x zgRnWz52Ww+bUR!9Dz$2``=Yq%?{0-naBkS($@KDVc>N~3X2kGOsYkAM&Ye`SvG}C+ zN;UI8r+>V*?+WL1&H75k4Iigk+w1p^-=m~%n9`7a@*2@zwt~}jaNN^*jU(OeI?VC2 zH{@?W;FWE;IDhj4o2yah^Nm^C@8_TQpgV8ez4@Q6q<`!hmQ_qc@^y#n=|Ndtj_~@7 zT=$`!IqVT>uMdkx*=|^Ng6&u4ywRp`eP`Ij2L>X`zc6O^!V4#t8wRCTJ=|gCwl`t1 z%^ky{tX6B+Z_Z9$lUwZ-#PFT~# z6`bZljgEBzlLywb3;z_{9Ba( literal 0 HcmV?d00001 diff --git a/test_model/img/xsoverlay.png b/test_model/img/xsoverlay.png new file mode 100644 index 0000000000000000000000000000000000000000..35c793eaed87c7b132f6b5400b732341c3e74660 GIT binary patch literal 1209 zcmV;q1V;ObP)EX>4Tx04UFukvmAkP!xv$rWPMm9PFUt5TQERMMWG-6pLV?v=v%)FuCaqnlvOS zE{=k0!NJF3)xpJCR|i)?5PX2Rx;QDiNQvhrg%+WL7Y_I1zxV$+_gp}zmzidDMFCB> z&16gxGuc(K`xOBUQ;nflW|k38EvC_Neci*y_qzzs!v9vknzI<-6N#hDFm2)u;@M5x z;Ji;9VntacJ|~_usX^jLt}7nDaW1$l@XU~zPRr|tNVF__0AVNVEC6r+!Lc30ig(RIz9sDD%KS3^qTqQ7a zET94nvg-%`gWt2Y^3zjZQcwZ{FOKsu4s`DVjhf?pA3ILt1n@rtS9;4|sRMJLq}N(n z_y`!-1}?5!nz9F6?f^qihHT2NMD1tTjqx>_{=000?uMObu0Z*6U5Zgc=ca%Ew3 zWn>_CX>@2HM@dakSAh-}0007zNklKpZw0w%6M~B1PFzS{!IeUb z+V%4@9U}oh&A@9A_IkbZXf*oE zXf%?!H7SZ>jK||Ayq2Zq9vzd-W>@@Wt!%?er9#_8FHRR= z$IMom%_jM><^!qSZcmu4bUK|eV&al7*X#9jW?#JxGnov_PznZ#^mKA(#|pO4dg z96Op!Ci?lyO90lFVo8$3YPHHW8Vzo-Sja4_3%*pV)kd_oSfT|B>!KKWbPQdKg;i~o zz&3Sw7cA?Lz}^#}g7OMHbGclTSS)r&jcy>P(チャットボックス" + 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