diff --git a/config.py b/config.py index be98a68f..669c2e64 100644 --- a/config.py +++ b/config.py @@ -94,6 +94,10 @@ class Config: def SELECTABLE_UI_LANGUAGES_DICT(self): return self._SELECTABLE_UI_LANGUAGES_DICT + @property + def SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT(self): + return self._SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT + @property def MAX_MIC_ENERGY_THRESHOLD(self): return self._MAX_MIC_ENERGY_THRESHOLD @@ -544,6 +548,17 @@ class Config: self._AUTH_KEYS[key] = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, self.AUTH_KEYS) + @property + @json_serializable('USE_TRANSLATION_FEATURE') + def USE_TRANSLATION_FEATURE(self): + return self._USE_TRANSLATION_FEATURE + + @USE_TRANSLATION_FEATURE.setter + def USE_TRANSLATION_FEATURE(self, value): + if isinstance(value, bool): + self._USE_TRANSLATION_FEATURE = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + @property @json_serializable('WEIGHT_TYPE') def WEIGHT_TYPE(self): @@ -551,6 +566,7 @@ class Config: @WEIGHT_TYPE.setter def WEIGHT_TYPE(self, value): + # if isinstance(value, str) and value in self.SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT: if isinstance(value, str): self._WEIGHT_TYPE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -726,6 +742,11 @@ class Config: "ko": "한국어" # If you want to add a new language and key, please append it here. } + self._SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT = { + # {Save json str}: {i18n_placeholder} pairs + "Small": "Small", + "Large": "Large", + } self._MAX_MIC_ENERGY_THRESHOLD = 2000 self._MAX_SPEAKER_ENERGY_THRESHOLD = 4000 @@ -799,6 +820,7 @@ class Config: self._AUTH_KEYS = { "DeepL_API": None, } + self._USE_TRANSLATION_FEATURE = True self._WEIGHT_TYPE = "m2m100_418m" self._SEND_MESSAGE_FORMAT = "[message]" self._SEND_MESSAGE_FORMAT_WITH_T = "[message]([translation])" diff --git a/controller.py b/controller.py index 22d9eb2d..0c6d368f 100644 --- a/controller.py +++ b/controller.py @@ -55,6 +55,12 @@ def messageFormatter(format_type:str, translation, message): osc_message = FORMAT.replace("[message]", message) return osc_message +def changeToCTranslate2Process(): + config.CHOICE_INPUT_TRANSLATOR = "CTranslate2" + config.CHOICE_OUTPUT_TRANSLATOR = "CTranslate2" + updateTranslationEngineAndEngineList() + view.printToTextbox_TranslationEngineLimitError() + # func transcription send message def sendMicMessage(message): if len(message) > 0: @@ -67,9 +73,7 @@ def sendMicMessage(message): else: translation, success = model.getInputTranslate(message) if success is False: - config.CHOICE_INPUT_TRANSLATOR = "CTranslate2" - config.CHOICE_OUTPUT_TRANSLATOR = "CTranslate2" - updateTranslationEngineAndEngineList() + changeToCTranslate2Process() if config.ENABLE_TRANSCRIPTION_SEND is True: if config.ENABLE_SEND_MESSAGE_TO_VRC is True: @@ -134,9 +138,7 @@ def receiveSpeakerMessage(message): else: translation, success = model.getOutputTranslate(message) if success is False: - config.CHOICE_INPUT_TRANSLATOR = "CTranslate2" - config.CHOICE_OUTPUT_TRANSLATOR = "CTranslate2" - updateTranslationEngineAndEngineList() + changeToCTranslate2Process() if config.ENABLE_TRANSCRIPTION_RECEIVE is True: if config.ENABLE_NOTICE_XSOVERLAY is True: @@ -204,9 +206,8 @@ def sendChatMessage(message): else: translation, success = model.getInputTranslate(message) if success is False: - config.CHOICE_INPUT_TRANSLATOR = "CTranslate2" - config.CHOICE_OUTPUT_TRANSLATOR = "CTranslate2" - updateTranslationEngineAndEngineList() + changeToCTranslate2Process() + # send OSC message if config.ENABLE_SEND_MESSAGE_TO_VRC is True: if config.ENABLE_SEND_ONLY_TRANSLATED_MESSAGES is True: @@ -482,6 +483,20 @@ def callbackSetEnableRestoreMainWindowGeometry(value): config.ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY = value # Translation Tab +def callbackSetUseTranslationFeature(value): + print("callbackSetUseTranslationFeature", value) + config.USE_TRANSLATION_FEATURE = value + if config.USE_TRANSLATION_FEATURE is True: + view.setLatestCTranslate2WeightType() + view.openCtranslate2WeightTypeWidget() + else: + view.closeCtranslate2WeightTypeWidget() + +def callbackSetCtranslate2WeightType(value): + print("callbackSetCtranslate2WeightType", value) + config.WEIGHT_TYPE = str(value) + view.updateSelectedCtranslate2WeightType(config.WEIGHT_TYPE) + def callbackSetDeeplAuthkey(value): print("callbackSetDeeplAuthkey", str(value)) if len(value) == 39: @@ -922,6 +937,8 @@ def createMainWindow(): "callback_set_enable_restore_main_window_geometry": callbackSetEnableRestoreMainWindowGeometry, # Translation Tab + "callback_set_use_translation_feature": callbackSetUseTranslationFeature, + "callback_set_ctranslate2_weight_type": callbackSetCtranslate2WeightType, "callback_set_deepl_authkey": callbackSetDeeplAuthkey, # Transcription Tab (Mic) diff --git a/locales/en.yml b/locales/en.yml index d967956d..31406a23 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -32,7 +32,7 @@ main_window: no_mic_device_detected_error: No mic device detected. no_speaker_device_detected_error: No speaker device detected. - translation_engine_limit_error: It has automatically disabled the translation feature. Access has been temporarily restricted due to an excessive number of requests to the translation engine. Please wait for a while, restart VRCT, and try again. + translation_engine_limit_error: It has automatically changed the translation engine. Access has been temporarily restricted due to an excessive number of requests to the translation engine. If you want to use the same translation engine, please wait for a while, restart VRCT, and try again. detected_by_word_filter: The word %{detected_message} has not been sent due to detection by the word filter. @@ -58,9 +58,9 @@ main_window: deny_adjust_ui_size: "Keep it at this size" accept_adjust_ui_size: "Set it smaller and restart" - - translation_engine_limit_error: "It has automatically disabled the translation feature.\nAccess has been temporarily restricted\ndue to an excessive number of requests to the translation engine.\nPlease wait for a while, restart VRCT, and try again." - accept_translation_engine_limit_error: Accept and close +# [Deprecated] + # translation_engine_limit_error: "It has automatically disabled the translation feature.\nAccess has been temporarily restricted\ndue to an excessive number of requests to the translation engine.\nPlease wait for a while, restart VRCT, and try again." + # accept_translation_engine_limit_error: Accept and close selectable_language_window: @@ -119,6 +119,16 @@ config_window: label: Remember The Main Window Position desc: Restore the position and size of the previous window upon startup. + use_translation_feature: + label: Use Translation Feature + desc: You can't use the translation feature while this is turned off. Instead, the VRCT startup becomes a little faster. This is for users who don't need the translation feature and only use VRCT as a chatbox and transcription tool. + + ctranslate2_weight_type: + label: Select Internal Translation Model + desc: You can choose the translation model to use for the internal translation engine. + small: "Basic model (%{capacity})" + large: "High accuracy model (%{capacity})" + deepl_auth_key: label: DeepL Auth Key diff --git a/locales/ja.yml b/locales/ja.yml index 25748b8e..2b3eb2a8 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -32,7 +32,7 @@ main_window: no_mic_device_detected_error: マイクデバイスが検出されませんでした。 no_speaker_device_detected_error: スピーカーデバイスが検出されませんでした。 - translation_engine_limit_error: 翻訳機能を自動的に停止しました。翻訳エンジンへのリクエストが多すぎるため、一時的にアクセスが制限されています。しばらく待ってから、VRCTの再起動をしてもう一度試してみてください。 + translation_engine_limit_error: 翻訳エンジンを自動的に変更しました。対象翻訳エンジンへのリクエストが多すぎるため、一時的にアクセスが制限されています。同じ翻訳エンジンを使用したい場合はしばらく待ってから、VRCTの再起動をしてもう一度試してみてください。 detected_by_word_filter: ワードフィルターに登録されている単語 %{detected_message} が検出されたため送信しませんでした。 @@ -58,9 +58,9 @@ main_window: deny_adjust_ui_size: このサイズのままで良い accept_adjust_ui_size: 小さく設定して再起動 - - translation_engine_limit_error: "翻訳機能を自動的に停止しました。\n翻訳エンジンへのリクエストが多すぎるため\n一時的にアクセスが制限されています。\nしばらく待ってから、VRCTの再起動をしてもう一度試してみてください。" - accept_translation_engine_limit_error: 了承して閉じる +# [Deprecated] + # translation_engine_limit_error: "翻訳機能を自動的に停止しました。\n翻訳エンジンへのリクエストが多すぎるため\n一時的にアクセスが制限されています。\nしばらく待ってから、VRCTの再起動をしてもう一度試してみてください。" + # accept_translation_engine_limit_error: 了承して閉じる selectable_language_window: @@ -116,6 +116,16 @@ config_window: label: メイン画面の位置を記憶する desc: 起動時、前回の画面の位置とサイズを復元します。 + use_translation_feature: + label: 翻訳機能を使用する + desc: "オフにしている間は、翻訳機能を使わない代わり、VRCTの起動が少し速くなります。\n翻訳機能を必要とせず、VRCTをチャット送信と文字起こしツールとしてのみ使用するユーザー用です。" + + ctranslate2_weight_type: + label: オフライン翻訳のタイプ + desc: 翻訳エンジン(オフライン翻訳)で翻訳する際に、使用する翻訳モデルを選択できます。 + small: "通常モデル (%{capacity})" + large: "高精度モデル (%{capacity})" + deepl_auth_key: label: DeepL 認証キー diff --git a/locales/ko.yml b/locales/ko.yml index 692abd2c..11e23fae 100644 --- a/locales/ko.yml +++ b/locales/ko.yml @@ -30,7 +30,7 @@ main_window: no_mic_device_detected_error: 마이크 디바이스를 찾지 못했습니다. no_speaker_device_detected_error: 스피커 디바이스를 찾지 못했습니다. - translation_engine_limit_error: 번역 기능이 자동으로 중지되었습니다. 번역 엔진에 대한 요청이 너무 많아 일시적으로 사용이 제한되고 있습니다. 잠시 기다렸다가 VRCT를 재부팅하고 다시 시도해 보세요. + # translation_engine_limit_error: 번역 기능이 자동으로 중지되었습니다. 번역 엔진에 대한 요청이 너무 많아 일시적으로 사용이 제한되고 있습니다. 잠시 기다렸다가 VRCT를 재부팅하고 다시 시도해 보세요. detected_by_word_filter: 단어 필터에 등록된 단어 %{detected_message}(이)가 감지되어 전송하지 않았습니다. @@ -57,8 +57,9 @@ main_window: accept_adjust_ui_size: "작게 줄이고 재부팅" - translation_engine_limit_error: "번역 기능이 자동으로 중지되었습니다. \n번역 엔진에 대한 요청이 너무 많아 \n일시적으로 사용이 제한되었습니다. \n잠시 기다렸다가 VRCT를 재부팅한 후 다시 시도해 보십시오." - accept_translation_engine_limit_error: 확인하고 닫기 +# [Deprecated] + # translation_engine_limit_error: "번역 기능이 자동으로 중지되었습니다. \n번역 엔진에 대한 요청이 너무 많아 \n일시적으로 사용이 제한되었습니다. \n잠시 기다렸다가 VRCT를 재부팅한 후 다시 시도해 보십시오." + # accept_translation_engine_limit_error: 확인하고 닫기 selectable_language_window: diff --git a/view.py b/view.py index 76089ece..a3c7c166 100644 --- a/view.py +++ b/view.py @@ -269,6 +269,18 @@ class View(): VAR_ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY=BooleanVar(value=config.ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY), # Translation Tab + VAR_LABEL_USE_TRANSLATION_FEATURE=StringVar(value=i18n.t("config_window.use_translation_feature.label")), + VAR_DESC_USE_TRANSLATION_FEATURE=StringVar(value=i18n.t("config_window.use_translation_feature.desc")), + CALLBACK_SET_USE_TRANSLATION_FEATURE=None, + VAR_USE_TRANSLATION_FEATURE=BooleanVar(value=config.USE_TRANSLATION_FEATURE), + + VAR_LABEL_CTRANSLATE2_WEIGHT_TYPE=StringVar(value=i18n.t("config_window.ctranslate2_weight_type.label")), + VAR_DESC_CTRANSLATE2_WEIGHT_TYPE=StringVar(value=i18n.t("config_window.ctranslate2_weight_type.desc")), + DICT_CTRANSLATE2_WEIGHT_TYPE=self.getSelectableCtranslate2WeightTypeDict(), + CALLBACK_SET_CTRANSLATE2_WEIGHT_TYPE=None, + VAR_CTRANSLATE2_WEIGHT_TYPE=StringVar(value=self.getSelectableCtranslate2WeightTypeDict()["Small"]), + # VAR_CTRANSLATE2_WEIGHT_TYPE=StringVar(value=self.getSelectableCtranslate2WeightTypeDict()[config.WEIGHT_TYPE]), + VAR_LABEL_DEEPL_AUTH_KEY=StringVar(value=i18n.t("config_window.deepl_auth_key.label")), VAR_DESC_DEEPL_AUTH_KEY=None, CALLBACK_SET_DEEPL_AUTH_KEY=None, @@ -578,6 +590,8 @@ class View(): # Translation Tab + self.view_variable.CALLBACK_SET_USE_TRANSLATION_FEATURE = config_window_registers.get("callback_set_use_translation_feature", None) + self.view_variable.CALLBACK_SET_CTRANSLATE2_WEIGHT_TYPE = config_window_registers.get("callback_set_ctranslate2_weight_type", None) self.view_variable.CALLBACK_SET_DEEPL_AUTHKEY = config_window_registers.get("callback_set_deepl_authkey", None) # Transcription Tab (Mic) @@ -635,6 +649,11 @@ class View(): self.setMainWindowMessageBoxRatio(config.MESSAGE_BOX_RATIO) + if config.USE_TRANSLATION_FEATURE is True: + self.openCtranslate2WeightTypeWidget() + else: + self.closeCtranslate2WeightTypeWidget() + if config.CHOICE_MIC_HOST == "NoHost": self.view_variable.VAR_MIC_HOST.set("No Mic Host Detected") @@ -852,6 +871,13 @@ class View(): def getPreUiScaling(self): return self.restart_required_configs_pre_data.ui_scaling + @staticmethod + def getSelectableCtranslate2WeightTypeDict(): + return { + config._SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT["Small"]: i18n.t("config_window.ctranslate2_weight_type.small", capacity="418MB"), + config._SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT["Large"]: i18n.t("config_window.ctranslate2_weight_type.large", capacity="1.2GB"), + } + # Open Webpage Functions def openWebPage_Booth(self): self.openWebPage(config.BOOTH_URL) @@ -966,6 +992,22 @@ class View(): vrct_gui.config_window.setting_box_compact_mode_switch_box.configure(state="normal") + def updateSelectedCtranslate2WeightType(self, selected_weight_type:str): + self.view_variable.VAR_CTRANSLATE2_WEIGHT_TYPE.set(self.getSelectableCtranslate2WeightTypeDict()[selected_weight_type]) + + def setLatestCTranslate2WeightType(self): + selected_weight_type = self.getSelectableCtranslate2WeightTypeDict()[config.WEIGHT_TYPE] + self.view_variable.VAR_CTRANSLATE2_WEIGHT_TYPE.set(selected_weight_type) + + + def openCtranslate2WeightTypeWidget(self): + vrct_gui.config_window.sb__use_translation_feature.grid(pady=0) + vrct_gui.config_window.sb__ctranslate2_weight_type.grid() + + def closeCtranslate2WeightTypeWidget(self): + vrct_gui.config_window.sb__use_translation_feature.grid(pady=(0,1)) + vrct_gui.config_window.sb__ctranslate2_weight_type.grid_remove() + def openMicEnergyThresholdWidget(self): self.view_variable.VAR_LABEL_MIC_DYNAMIC_ENERGY_THRESHOLD.set(i18n.t("config_window.mic_dynamic_energy_threshold.label_for_manual")) @@ -1214,18 +1256,18 @@ class View(): # ※Below 40% of the UI size is not supported, and we cannot handle it at this time. +# [Deprecated] + # def translationEngineLimitErrorProcess(self): + # # turn off translation switch. + # vrct_gui.translation_switch_box.deselect() + # vrct_gui.translation_frame.markToggleManually(False) - def translationEngineLimitErrorProcess(self): - # turn off translation switch. - vrct_gui.translation_switch_box.deselect() - vrct_gui.translation_frame.markToggleManually(False) + # # disable translation feature. + # vrct_gui._changeMainWindowWidgetsStatus("disabled", ["translation_switch"], to_hold_state=True) - # disable translation feature. - vrct_gui._changeMainWindowWidgetsStatus("disabled", ["translation_switch"], to_hold_state=True) - - # print system message that mention to stopped translation feature. - view.printToTextbox_TranslationEngineLimitError() - view.showTheLimitOfTranslationEngineConfirmationModal() + # # print system message that mention to stopped translation feature. + # view.printToTextbox_TranslationEngineLimitError() + # view.showTheLimitOfTranslationEngineConfirmationModal() @@ -1267,19 +1309,19 @@ class View(): +# [Deprecated] + # def showTheLimitOfTranslationEngineConfirmationModal(self): + # self.foregroundOffIfForegroundEnabled() - def showTheLimitOfTranslationEngineConfirmationModal(self): - self.foregroundOffIfForegroundEnabled() + # self.view_variable.VAR_LABEL_MAIN_WINDOW_COVER_MESSAGE.set("") + # vrct_gui.main_window_cover.show() - self.view_variable.VAR_LABEL_MAIN_WINDOW_COVER_MESSAGE.set("") - vrct_gui.main_window_cover.show() + # self.view_variable.CALLBACK_HIDE_CONFIRMATION_MODAL=self._hideInformationModal + # self.view_variable.CALLBACK_ACCEPTED_CONFIRMATION_MODAL=self._hideInformationModal - self.view_variable.CALLBACK_HIDE_CONFIRMATION_MODAL=self._hideInformationModal - self.view_variable.CALLBACK_ACCEPTED_CONFIRMATION_MODAL=self._hideInformationModal - - self.view_variable.VAR_MESSAGE_CONFIRMATION_MODAL.set(i18n.t("main_window.confirmation_message.translation_engine_limit_error")) - self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_ACCEPT_BUTTON.set(i18n.t("main_window.confirmation_message.accept_translation_engine_limit_error")) - vrct_gui.information_modal.show(hide_title_bar=False, close_when_focusout=False) + # self.view_variable.VAR_MESSAGE_CONFIRMATION_MODAL.set(i18n.t("main_window.confirmation_message.translation_engine_limit_error")) + # self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_ACCEPT_BUTTON.set(i18n.t("main_window.confirmation_message.accept_translation_engine_limit_error")) + # vrct_gui.information_modal.show(hide_title_bar=False, close_when_focusout=False) @@ -1476,9 +1518,6 @@ class View(): self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.translation_engine_limit_error")) - # def printToTextbox_OSCError(self): [Deprecated] - # self._printToTextbox_Info("OSC is not enabled, please enable OSC and rejoin. or turn off the \"Send Message To VRChat\" setting") - def printToTextbox_DetectedByWordFilter(self, detected_message): self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.detected_by_word_filter", detected_message=detected_message)) diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_translation/createSettingBox_Translation.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_translation/createSettingBox_Translation.py index d2975d0d..574856fe 100644 --- a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_translation/createSettingBox_Translation.py +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_translation/createSettingBox_Translation.py @@ -4,14 +4,43 @@ from .._SettingBoxGenerator import _SettingBoxGenerator def createSettingBox_Translation(setting_box_wrapper, config_window, settings, view_variable): sbg = _SettingBoxGenerator(setting_box_wrapper, config_window, settings, view_variable) + createSettingBoxSwitch = sbg.createSettingBoxSwitch + createSettingBoxDropdownMenu = sbg.createSettingBoxDropdownMenu createSettingBoxEntry = sbg.createSettingBoxEntry + def switch_use_translation_feature_callback(switch_widget): + callFunctionIfCallable(view_variable.CALLBACK_SET_USE_TRANSLATION_FEATURE, switch_widget.get()) + + def optionmenu_ctranslate2_weight_type_callback(value): + callFunctionIfCallable(view_variable.CALLBACK_SET_CTRANSLATE2_WEIGHT_TYPE, value) def deepl_authkey_callback(value): callFunctionIfCallable(view_variable.CALLBACK_SET_DEEPL_AUTHKEY, value) row=0 + config_window.sb__use_translation_feature = createSettingBoxSwitch( + for_var_label_text=view_variable.VAR_LABEL_USE_TRANSLATION_FEATURE, + for_var_desc_text=view_variable.VAR_DESC_USE_TRANSLATION_FEATURE, + switch_attr_name="sb__switch_use_translation_feature", + command=lambda: switch_use_translation_feature_callback(config_window.sb__switch_use_translation_feature), + variable=view_variable.VAR_USE_TRANSLATION_FEATURE + ) + config_window.sb__use_translation_feature.grid(row=row, pady=0) + row+=1 + + config_window.sb__ctranslate2_weight_type = createSettingBoxDropdownMenu( + for_var_label_text=view_variable.VAR_LABEL_CTRANSLATE2_WEIGHT_TYPE, + for_var_desc_text=view_variable.VAR_DESC_CTRANSLATE2_WEIGHT_TYPE, + optionmenu_attr_name="sb__optionmenu_ctranslate2_weight_type", + dropdown_menu_values=view_variable.DICT_CTRANSLATE2_WEIGHT_TYPE, + command=lambda value: optionmenu_ctranslate2_weight_type_callback(value), + variable=view_variable.VAR_CTRANSLATE2_WEIGHT_TYPE, + ) + config_window.sb__ctranslate2_weight_type.grid(row=row) + row+=1 + + config_window.sb__deepl_authkey = createSettingBoxEntry( for_var_label_text=view_variable.VAR_LABEL_DEEPL_AUTH_KEY, for_var_desc_text=view_variable.VAR_DESC_DEEPL_AUTH_KEY,