Merge branch 'develop'

This commit is contained in:
misyaguziya
2024-02-15 23:27:24 +09:00
32 changed files with 1301 additions and 273 deletions

2
.gitignore vendored
View File

@@ -6,7 +6,7 @@ VRCT.spec
*.pyc
logs/
.venv/
weight/
weights/
.vscode
error.log
*.exe

View File

@@ -1,2 +1,2 @@
pyinstaller --windowed --clean --noconfirm --icon="./img/vrct_logo_mark_black.ico" --add-data "./img;img/" --add-data "./locales;locales/" --add-data "./batch;batch/" --name VRCT --add-data ".venv\Lib\site-packages\customtkinter;customtkinter/" --exclude-module pandas --exclude-module matplotlib --exclude-module PyQt5 main.py
pyinstaller --windowed --clean --noconfirm --icon="./img/vrct_logo_mark_black.ico" --add-data "./img;img/" --add-data "./locales;locales/" --add-data "./batch;batch/" --name VRCT --add-data ".venv\Lib\site-packages\customtkinter;customtkinter/" --add-data ".venv\Lib\site-packages\zeroconf;zeroconf/" --exclude-module pandas --exclude-module matplotlib --exclude-module PyQt5 main.py
"C:\Program Files (x86)\NSIS\makensis.exe" installer/installer.nsi

142
config.py
View File

@@ -39,12 +39,8 @@ class Config:
return self._VERSION
@property
def ENABLE_SPEAKER2CHATBOX(self):
return self._ENABLE_SPEAKER2CHATBOX
@property
def ENABLE_SPEAKER2CHATBOX(self):
return self._ENABLE_SPEAKER2CHATBOX
def ENABLE_SPEAKER2CHATBOX_PASS_CONFIRMATION(self):
return self._ENABLE_SPEAKER2CHATBOX_PASS_CONFIRMATION
@property
def PATH_LOCAL(self):
@@ -70,6 +66,10 @@ class Config:
def DOCUMENTS_URL(self):
return self._DOCUMENTS_URL
@property
def DEEPL_AUTH_KEY_PAGE_URL(self):
return self._DEEPL_AUTH_KEY_PAGE_URL
@property
def TRANSPARENCY_RANGE(self):
return self._TRANSPARENCY_RANGE
@@ -98,6 +98,10 @@ class Config:
def SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT(self):
return self._SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT
@property
def SELECTABLE_WHISPER_WEIGHT_TYPE_DICT(self):
return self._SELECTABLE_WHISPER_WEIGHT_TYPE_DICT
@property
def MAX_MIC_ENERGY_THRESHOLD(self):
return self._MAX_MIC_ENERGY_THRESHOLD
@@ -107,6 +111,15 @@ class Config:
return self._MAX_SPEAKER_ENERGY_THRESHOLD
# Read Write
@property
def ENABLE_SPEAKER2CHATBOX(self):
return self._ENABLE_SPEAKER2CHATBOX
@ENABLE_SPEAKER2CHATBOX.setter
def ENABLE_SPEAKER2CHATBOX(self, value):
if isinstance(value, bool):
self._ENABLE_SPEAKER2CHATBOX = value
@property
def ENABLE_TRANSLATION(self):
return self._ENABLE_TRANSLATION
@@ -197,6 +210,24 @@ class Config:
if value in list(translation_lang.keys()):
self._CHOICE_OUTPUT_TRANSLATOR = value
@property
def SENT_MESSAGES_LOG(self):
return self._SENT_MESSAGES_LOG
@SENT_MESSAGES_LOG.setter
def SENT_MESSAGES_LOG(self, value):
if isinstance(value, list):
self._SENT_MESSAGES_LOG = value
@property
def CURRENT_SENT_MESSAGES_LOG_INDEX(self):
return self._CURRENT_SENT_MESSAGES_LOG_INDEX
@CURRENT_SENT_MESSAGES_LOG_INDEX.setter
def CURRENT_SENT_MESSAGES_LOG_INDEX(self, value):
if isinstance(value, int):
self._CURRENT_SENT_MESSAGES_LOG_INDEX = value
@property
def IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION(self):
return self._IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION
@@ -206,6 +237,15 @@ class Config:
if isinstance(value, bool):
self._IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION = value
@property
def IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER(self):
return self._IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER
@IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER.setter
def IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER(self, value):
if isinstance(value, bool):
self._IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER = value
# Save Json Data
## Main Window
@property
@@ -263,6 +303,17 @@ class Config:
self._SELECTED_TAB_TARGET_LANGUAGES = value
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
@json_serializable('SELECTED_TRANSCRIPTION_ENGINE')
def SELECTED_TRANSCRIPTION_ENGINE(self):
return self._SELECTED_TRANSCRIPTION_ENGINE
@SELECTED_TRANSCRIPTION_ENGINE.setter
def SELECTED_TRANSCRIPTION_ENGINE(self, value):
if isinstance(value, str):
self._SELECTED_TRANSCRIPTION_ENGINE = value
# saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
@json_serializable('IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE')
def IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE(self):
@@ -569,15 +620,37 @@ class Config:
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
@json_serializable('WEIGHT_TYPE')
def WEIGHT_TYPE(self):
return self._WEIGHT_TYPE
@json_serializable('USE_WHISPER_FEATURE')
def USE_WHISPER_FEATURE(self):
return self._USE_WHISPER_FEATURE
@WEIGHT_TYPE.setter
def WEIGHT_TYPE(self, value):
@USE_WHISPER_FEATURE.setter
def USE_WHISPER_FEATURE(self, value):
if isinstance(value, bool):
self._USE_WHISPER_FEATURE = value
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
@json_serializable('CTRANSLATE2_WEIGHT_TYPE')
def CTRANSLATE2_WEIGHT_TYPE(self):
return self._CTRANSLATE2_WEIGHT_TYPE
@CTRANSLATE2_WEIGHT_TYPE.setter
def CTRANSLATE2_WEIGHT_TYPE(self, value):
# if isinstance(value, str) and value in self.SELECTABLE_CTRANSLATE2_WEIGHT_TYPE_DICT:
if isinstance(value, str):
self._WEIGHT_TYPE = value
self._CTRANSLATE2_WEIGHT_TYPE = value
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
@json_serializable('WHISPER_WEIGHT_TYPE')
def WHISPER_WEIGHT_TYPE(self):
return self._WHISPER_WEIGHT_TYPE
@WHISPER_WEIGHT_TYPE.setter
def WHISPER_WEIGHT_TYPE(self, value):
if isinstance(value, str):
self._WHISPER_WEIGHT_TYPE = value
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
@@ -687,9 +760,18 @@ class Config:
self._RECEIVED_MESSAGE_FORMAT_WITH_T = value
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
# Speaker2Chatbox------------------
@property
@json_serializable('ENABLE_SPEAKER2CHATBOX_PASS')
def ENABLE_SPEAKER2CHATBOX_PASS(self):
return self._ENABLE_SPEAKER2CHATBOX_PASS
@ENABLE_SPEAKER2CHATBOX_PASS.setter
def ENABLE_SPEAKER2CHATBOX_PASS(self, value):
if isinstance(value, str):
self._ENABLE_SPEAKER2CHATBOX_PASS = value
saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value)
@property
@json_serializable('ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC')
def ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC(self):
@@ -731,8 +813,9 @@ class Config:
def init_config(self):
# Read Only
self._VERSION = "2.1.1"
self._VERSION = "2.2.0"
self._ENABLE_SPEAKER2CHATBOX = False # Speaker2Chatbox
self._ENABLE_SPEAKER2CHATBOX_PASS_CONFIRMATION = "123456789"
self._PATH_LOCAL = os_path.dirname(sys.argv[0])
self._PATH_CONFIG = os_path.join(self._PATH_LOCAL, "config.json")
self._PATH_LOGS = os_path.join(self._PATH_LOCAL, "logs")
@@ -740,6 +823,7 @@ class Config:
self._GITHUB_URL = "https://api.github.com/repos/misyaguziya/VRCT/releases/latest"
self._BOOTH_URL = "https://misyaguziya.booth.pm/"
self._DOCUMENTS_URL = "https://mzsoftware.notion.site/VRCT-Documents-be79b7a165f64442ad8f326d86c22246"
self._DEEPL_AUTH_KEY_PAGE_URL = "https://www.deepl.com/ja/account/summary"
self._TRANSPARENCY_RANGE = (50, 100)
self._APPEARANCE_THEME_LIST = ["Light", "Dark", "System"]
self._UI_SCALING_LIST = generatePercentageStringsList(start=40, end=200, step=10)
@@ -756,6 +840,18 @@ class Config:
"Small": "Small",
"Large": "Large",
}
self._SELECTABLE_WHISPER_WEIGHT_TYPE_DICT = {
# {Save json str}: {i18n_placeholder} pairs
"tiny": "tiny",
"base": "base",
"small": "small",
"medium": "medium",
"large-v1": "large-v1",
"large-v2": "large-v2",
"large-v3": "large-v3",
}
self._MAX_MIC_ENERGY_THRESHOLD = 2000
self._MAX_SPEAKER_ENERGY_THRESHOLD = 4000
@@ -770,7 +866,10 @@ class Config:
self._SOURCE_COUNTRY = "Japan"
self._TARGET_LANGUAGE = "English"
self._TARGET_COUNTRY = "United States"
self._SENT_MESSAGES_LOG = []
self._CURRENT_SENT_MESSAGES_LOG_INDEX = 0
self._IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION = False
self._IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER = False
# Save Json Data
## Main Window
@@ -795,6 +894,7 @@ class Config:
"2":"English\n(United States)",
"3":"English\n(United States)",
}
self._SELECTED_TRANSCRIPTION_ENGINE = "Google"
self._IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE = False
## Config Window
@@ -810,7 +910,7 @@ class Config:
"x_pos": "0",
"y_pos": "0",
"width": "870",
"height": "640",
"height": "654",
}
self._CHOICE_MIC_HOST = getDefaultInputDevice()["host"]["name"]
self._CHOICE_MIC_DEVICE = getDefaultInputDevice()["device"]["name"]
@@ -831,7 +931,9 @@ class Config:
"DeepL_API": None,
}
self._USE_TRANSLATION_FEATURE = True
self._WEIGHT_TYPE = "Small"
self._CTRANSLATE2_WEIGHT_TYPE = "Small"
self._USE_WHISPER_FEATURE = False
self._WHISPER_WEIGHT_TYPE = "base"
self._SEND_MESSAGE_FORMAT = "[message]"
self._SEND_MESSAGE_FORMAT_WITH_T = "[message]([translation])"
self._RECEIVED_MESSAGE_FORMAT = "[message]"
@@ -842,6 +944,7 @@ class Config:
self._ENABLE_NOTICE_XSOVERLAY = False
self._ENABLE_SEND_MESSAGE_TO_VRC = True
self._ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC = False # Speaker2Chatbox
self._ENABLE_SPEAKER2CHATBOX_PASS = "000000000"
self._ENABLE_LOGGER = False
self._IS_CONFIG_WINDOW_COMPACT_MODE = False
@@ -855,6 +958,11 @@ class Config:
if key == "MESSAGE_FORMAT":
old_message_format = config[key]
setattr(self, key, config[key])
if key == "ENABLE_SPEAKER2CHATBOX_PASS":
if self.ENABLE_SPEAKER2CHATBOX_PASS_CONFIRMATION == config[key]:
self.ENABLE_SPEAKER2CHATBOX = True
if old_message_format is not None:
setattr(self, "SEND_MESSAGE_FORMAT_WITH_T", old_message_format)

View File

@@ -64,6 +64,7 @@ def changeToCTranslate2Process():
# func transcription send message
def sendMicMessage(message):
if len(message) > 0:
addSentMessageLog(message)
translation = ""
if model.checkKeywords(message):
view.printToTextbox_DetectedByWordFilter(detected_message=message)
@@ -200,6 +201,7 @@ def stopThreadingTranscriptionReceiveMessageOnOpenConfigWindow():
# func message box
def sendChatMessage(message):
if len(message) > 0:
addSentMessageLog(message)
translation = ""
if config.ENABLE_TRANSLATION is False:
pass
@@ -249,6 +251,29 @@ def messageBoxFocusOut(e):
if config.ENABLE_SEND_MESSAGE_TO_VRC is True:
model.oscStopSendTyping()
def addSentMessageLog(sent_message):
config.SENT_MESSAGES_LOG.append(sent_message)
config.CURRENT_SENT_MESSAGES_LOG_INDEX = len(config.SENT_MESSAGES_LOG)
def updateMessageBox(index_offset):
if len(config.SENT_MESSAGES_LOG) == 0:
return
try:
new_index = config.CURRENT_SENT_MESSAGES_LOG_INDEX + index_offset
target_message_text = config.SENT_MESSAGES_LOG[new_index]
view.replaceMessageBox(target_message_text)
config.CURRENT_SENT_MESSAGES_LOG_INDEX = new_index
except IndexError:
pass
def messageBoxUpKeyPress():
if config.CURRENT_SENT_MESSAGES_LOG_INDEX > 0:
updateMessageBox(-1)
def messageBoxDownKeyPress():
if config.CURRENT_SENT_MESSAGES_LOG_INDEX < len(config.SENT_MESSAGES_LOG) - 1:
updateMessageBox(1)
def updateTranslationEngineAndEngineList():
engine = config.CHOICE_INPUT_TRANSLATOR
engines = model.findTranslationEngines(config.SOURCE_LANGUAGE, config.TARGET_LANGUAGE)
@@ -352,8 +377,10 @@ def callbackSelectedTranslationEngine(selected_translation_engine):
def callbackToggleTranslation(is_turned_on):
config.ENABLE_TRANSLATION = is_turned_on
if config.ENABLE_TRANSLATION is True:
model.changeTranslatorCTranslate2Model()
view.printToTextbox_enableTranslation()
else:
model.clearTranslatorCTranslate2Model()
view.printToTextbox_disableTranslation()
def callbackToggleTranscriptionSend(is_turned_on):
@@ -505,8 +532,8 @@ def callbackSetUseTranslationFeature(value):
def callbackSetCtranslate2WeightType(value):
print("callbackSetCtranslate2WeightType", value)
config.WEIGHT_TYPE = str(value)
view.updateSelectedCtranslate2WeightType(config.WEIGHT_TYPE)
config.CTRANSLATE2_WEIGHT_TYPE = str(value)
view.updateSelectedCtranslate2WeightType(config.CTRANSLATE2_WEIGHT_TYPE)
view.setWidgetsStatus_changeWeightType_Pending()
if model.checkCTranslatorCTranslate2ModelWeight():
config.IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION = False
@@ -767,6 +794,35 @@ def callbackSetSpeakerMaxPhrases(value):
except Exception:
view.showErrorMessage_SpeakerMaxPhrases()
# Transcription (Internal AI Model)
def callbackSetUserWhisperFeature(value):
print("callbackSetUserWhisperFeature", value)
config.USE_WHISPER_FEATURE = value
if config.USE_WHISPER_FEATURE is True:
view.openWhisperWeightTypeWidget()
if model.checkTranscriptionWhisperModelWeight() is True:
config.IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER = False
config.SELECTED_TRANSCRIPTION_ENGINE = "Whisper"
else:
config.IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER = True
config.SELECTED_TRANSCRIPTION_ENGINE = "Google"
else:
view.closeWhisperWeightTypeWidget()
config.IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER = False
config.SELECTED_TRANSCRIPTION_ENGINE = "Google"
view.showRestartButtonIfRequired()
def callbackSetWhisperWeightType(value):
print("callbackSetWhisperWeightType", value)
config.WHISPER_WEIGHT_TYPE = str(value)
view.updateSelectedWhisperWeightType(config.WHISPER_WEIGHT_TYPE)
if model.checkTranscriptionWhisperModelWeight() is True:
config.IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER = False
config.SELECTED_TRANSCRIPTION_ENGINE = "Whisper"
else:
config.IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER = True
config.SELECTED_TRANSCRIPTION_ENGINE = "Google"
view.showRestartButtonIfRequired()
# Others Tab
def callbackSetEnableAutoClearMessageBox(value):
@@ -898,13 +954,18 @@ def createMainWindow(splash):
# set Translation Engine
updateTranslationEngineAndEngineList()
# set Transcription Engine
if config.USE_WHISPER_FEATURE is True:
config.SELECTED_TRANSCRIPTION_ENGINE = "Whisper"
else:
config.SELECTED_TRANSCRIPTION_ENGINE = "Google"
# set word filter
model.addKeywords()
# check Software Updated
if config.ENABLE_SPEAKER2CHATBOX is False:
if model.checkSoftwareUpdated() is True:
view.showUpdateAvailableButton()
if model.checkSoftwareUpdated() is True:
view.showUpdateAvailableButton()
# init logger
if config.ENABLE_LOGGER is True:
@@ -949,6 +1010,8 @@ def createMainWindow(splash):
"message_box_bind_Any_KeyPress": messageBoxPressKeyAny,
"message_box_bind_FocusIn": messageBoxFocusIn,
"message_box_bind_FocusOut": messageBoxFocusOut,
"message_box_bind_Up_KeyPress": messageBoxUpKeyPress,
"message_box_bind_Down_KeyPress": messageBoxDownKeyPress,
},
config_window_registers={
@@ -993,6 +1056,10 @@ def createMainWindow(splash):
"callback_set_speaker_phrase_timeout": callbackSetSpeakerPhraseTimeout,
"callback_set_speaker_max_phrases": callbackSetSpeakerMaxPhrases,
# Transcription Tab (Internal AI Model)
"callback_set_use_whisper_feature": callbackSetUserWhisperFeature,
"callback_set_whisper_weight_type": callbackSetWhisperWeightType,
# Others Tab
"callback_set_enable_auto_clear_chatbox": callbackSetEnableAutoClearMessageBox,
"callback_set_send_only_translated_messages": callbackSetEnableSendOnlyTranslatedMessages,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 30 KiB

BIN
img/link_icon_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

BIN
img/link_icon_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

View File

@@ -1,4 +1,2 @@
python.exe -m pip install --upgrade pip
pip install -r requirements.txt
pip install git+https://github.com/misyaguziya/translators
pip install git+https://github.com/misyaguziya/custom_speech_recognition
pip install -r requirements.txt

View File

@@ -79,9 +79,10 @@ config_window:
transcription: Transcription
transcription_mic: Mic
transcription_speaker: Speaker
transcription_internal_model: Transcription Model
others: Others
others_send_message_formats: Message Formats (Send)
others_received_message_formats: Message Formats (Received)
others_received_message_formats: Message Formats (XSOverlay & Speaker2Chatbox)
others_speaker2chatbox: Speaker2Chatbox
advanced_settings: Advanced Settings
@@ -128,6 +129,7 @@ config_window:
deepl_auth_key:
label: DeepL Auth Key
desc: Please select %{translator} on the main screen with DeepL_API when using. ※Some languages may not be supported.
open_auth_key_webpage: Open DeepL Account Webpage
mic_host:
label: Mic Host/Driver
@@ -187,6 +189,15 @@ config_window:
desc: It is the lower limit for the number of transcribed words, and only when this number is exceeded will the transcription results be displayed logs.
error_message: You can set a number equal to or greater than 0.
use_whisper_feature:
label: Use Whisper Model As Transcription
desc: In some languages, the accuracy of speech recognition may improve. During speech recognition usage, CPU usage increases, so please consider your PC specs before using this feature.
whisper_weight_type:
label: Select Whisper Model
desc: "Generally, models with larger capacity tend to have higher accuracy, but this also results in longer transcription times and increased CPU usage. Please refer to the documentation for explanations of each model.\n※Larger models, especially those exceeding medium size, can be challenging to run even depending on the CPU's performance."
model_template: "%{model_name} model (%{capacity})"
recommended_model_template: "%{model_name} model (%{capacity}) (Recommended)"
auto_clear_the_message_box:
label: Auto Clear The Message Box
@@ -217,25 +228,26 @@ config_window:
label: Message Format
desc: "You can change the decoration of the message you want to send.\n[message] will be replaced with the message."
example_text: This is an example sentence. Fonts, line breaks, etc. may differ from the actual display.
error_message: "The characters '[message]' cannot be used."
error_message: "Cannot use the term '[message]'."
send_message_format_with_t:
label: Message Format (With translation)
label: Message Format (with Translation)
desc: "You can change the decoration of the message you want to send.\n[message] will be replaced with the message, and [translation] will be replaced with the translated message."
example_text: This is an example sentence. Fonts, line breaks, etc. may differ from the actual display.
error_message: "The characters '[message]' and '[translation]' cannot be used."
error_message: "Cannot use the terms '[message]' and '[translation]'."
received_message_format:
label: Message Format
desc: "You can change the decoration of the received message you want to send.\n[message] will be replaced with the message.\nIt will be used in Notification XSOverlay too."
example_text: This is an example sentence. Fonts, line breaks, etc. may differ from the actual display.
error_message: "The characters '[message]' cannot be used."
label: Format of Received Messages
desc: "Used for XSOverlay notification receiving feature.\n[message] will be replaced with the message. \nIt will be used in Speaker2Chatbox too."
example_text: This is an example sentence. Actual display may vary, including font and line breaks.
error_message: "Cannot use the term '[message]'."
received_message_format_with_t:
label: Message Format (With translation)
desc: It will be used in Notification XSOverlay too.
example_text: This is an example sentence. Fonts, line breaks, etc. may differ from the actual display.
error_message: "The characters '[message]' and '[translation]' cannot be used."
label: Format of Received Messages (with Translation)
desc: "Used for XSOverlay notification receiving feature.\n[message] will be replaced with the message, and [translation] will be replaced with the translated message.\n※It will be used in Speaker2Chatbox too."
example_text: This is an example sentence. Actual display may vary, including font and line breaks.
error_message: "Cannot use the terms '[message]' and '[translation]'."
# Note: Speaker2Chatbox localization is fine only in English. Do not translate it into other languages.
# Speaker2Chatbox

View File

@@ -79,7 +79,10 @@ config_window:
transcription: 音声認識
transcription_mic: マイク
transcription_speaker: スピーカー
transcription_internal_model: 音声認識モデル
others: その他
others_send_message_formats: メッセージフォーマット (送信)
others_received_message_formats: メッセージフォーマット (XSOverlay & Speaker2Chatbox)
advanced_settings: 高度な設定
@@ -125,6 +128,7 @@ config_window:
deepl_auth_key:
label: DeepL 認証キー
desc: "使用の際は、メイン画面にある %{translator} をDeepL_APIに変更してください。\n※対応していない言語もあります。"
open_auth_key_webpage: DeepLアカウントページを開く
mic_host:
label: マイク(ホスト/ドライバー)
@@ -184,6 +188,16 @@ config_window:
desc: 文字起こしされた単語数の下限値で、この数値を超えた場合のみ結果をログに表示します。
error_message: 0以上の数値を設定できます。
use_whisper_feature:
label: 音声認識にWhisperモデルを使用する
desc: 一部の言語では、音声認識の精度が向上するかもしれません。音声認識使用中、CPUの使用率が上がるので、お使いのPCスペックと相談してこの機能を使用してください。
whisper_weight_type:
label: Whisperモデルのタイプ
desc: "基本的に、容量が多いモデルほど精度は高いですが、文字起こしまでの時間が伸び、CPU使用率も増加します。各モデルの説明はドキュメントをご覧ください。\n※特にmediumより容量の大きいモデルは、CPUの性能によっては使用すらも困難です。"
model_template: "%{model_name} モデル (%{capacity})"
recommended_model_template: "%{model_name} モデル (%{capacity}) (推奨)"
auto_clear_the_message_box:
label: 送信後はチャットボックスを空にする
@@ -223,14 +237,14 @@ config_window:
error_message: "[message]と[translation]という文字は使えません。"
received_message_format:
label: 信するメッセージのフォーマット
desc: "VRChatで相手に実際に見えるフォーマットを変更できます。\n[message]がメッセージに置換されます。\n※XSOverlayでの通知受け取り機能にも使われます。"
label: 信するメッセージのフォーマット
desc: "XSOverlay通知受け取り機能で使用されます。\n[message]がメッセージに置換されます。\n※Speaker2Chatboxでの送信機能にも使われます。"
example_text: これは例文です。フォントや改行箇所など、実際の表示とは異なる場合があります。
error_message: "[message]という文字は使えません。"
received_message_format_with_t:
label: 信するメッセージのフォーマット(翻訳付き)
desc: "VRChatで相手に実際に見えるフォーマットを変更できます。\n[message]がメッセージに置換され、[translation]が翻訳されたメッセージに置換されます。\n※XSOverlayでの通知受け取り機能にも使われます。"
label: 信するメッセージのフォーマット(翻訳付き)
desc: "XSOverlay通知受け取り機能で使用されます。\n[message]がメッセージに置換され、[translation]が翻訳されたメッセージに置換されます。\n※Speaker2Chatboxでの送信機能にも使われます。"
example_text: これは例文です。フォントや改行箇所など、実際の表示とは異なる場合があります。
error_message: "[message]と[translation]という文字は使えません。"

13
main.py
View File

@@ -8,11 +8,20 @@ if __name__ == "__main__":
splash.showSplash()
from config import config
from models.translation.utils import downloadCTranslate2Weight
# version 2.2.0からweightフォルダをweightsに変更する
from utils import renameWeightFolder
renameWeightFolder(config.PATH_LOCAL)
from models.translation.translation_utils import downloadCTranslate2Weight
if config.USE_TRANSLATION_FEATURE is True:
downloadCTranslate2Weight(config.PATH_LOCAL, config.WEIGHT_TYPE, splash.updateDownloadProgress)
downloadCTranslate2Weight(config.PATH_LOCAL, config.CTRANSLATE2_WEIGHT_TYPE, splash.updateDownloadProgress)
from models.transcription.transcription_whisper import downloadWhisperWeight
if config.USE_WHISPER_FEATURE is True:
downloadWhisperWeight(config.PATH_LOCAL, config.WHISPER_WEIGHT_TYPE, splash.updateDownloadProgress)
splash.toProgress(0)
import controller
controller.createMainWindow(splash)
splash.destroySplash()

108
model.py
View File

@@ -1,3 +1,4 @@
import gc
import tempfile
from zipfile import ZipFile
from subprocess import Popen
@@ -17,13 +18,14 @@ from flashtext import KeywordProcessor
from models.translation.translation_translator import Translator
from models.transcription.transcription_utils import getInputDevices, getDefaultOutputDevice
from models.osc.osc_tools import sendTyping, sendMessage, sendTestAction, receiveOscParameters
from models.transcription.transcription_recorder import SelectedMicRecorder, SelectedSpeakerRecorder
from models.transcription.transcription_recorder import SelectedMicEnergyRecorder, SelectedSpeakeEnergyRecorder
from models.transcription.transcription_recorder import SelectedMicEnergyAndAudioRecorder, SelectedSpeakerEnergyAndAudioRecorder
from models.transcription.transcription_recorder import SelectedMicEnergyRecorder, SelectedSpeakerEnergyRecorder
from models.transcription.transcription_transcriber import AudioTranscriber
from models.xsoverlay.notification import xsoverlayForVRCT
from models.translation.translation_languages import translation_lang
from models.transcription.transcription_languages import transcription_lang
from models.translation.utils import checkCTranslate2Weight
from models.translation.translation_utils import checkCTranslate2Weight
from models.transcription.transcription_whisper import checkWhisperWeight
from config import config
class threadFnc(Thread):
@@ -64,15 +66,19 @@ class Model:
self.speaker_energy_recorder = None
self.speaker_energy_plot_progressbar = None
self.translator = Translator()
if config.USE_TRANSLATION_FEATURE is True:
self.translator.changeCTranslate2Model(config.PATH_LOCAL, config.WEIGHT_TYPE)
self.keyword_processor = KeywordProcessor()
def checkCTranslatorCTranslate2ModelWeight(self):
return checkCTranslate2Weight(config.PATH_LOCAL, config.WEIGHT_TYPE)
return checkCTranslate2Weight(config.PATH_LOCAL, config.CTRANSLATE2_WEIGHT_TYPE)
def changeTranslatorCTranslate2Model(self):
self.translator.changeCTranslate2Model(config.PATH_LOCAL, config.WEIGHT_TYPE)
self.translator.changeCTranslate2Model(config.PATH_LOCAL, config.CTRANSLATE2_WEIGHT_TYPE)
def clearTranslatorCTranslate2Model(self):
self.translator.clearCTranslate2Model()
def checkTranscriptionWhisperModelWeight(self):
return checkWhisperWeight(config.PATH_LOCAL, config.WHISPER_WEIGHT_TYPE)
def resetKeywordProcessor(self):
del self.keyword_processor
@@ -317,44 +323,72 @@ class Model:
return
mic_audio_queue = Queue()
# mic_energy_queue = Queue()
device = [device for device in getInputDevices()[config.CHOICE_MIC_HOST] if device["name"] == config.CHOICE_MIC_DEVICE][0]
record_timeout = config.INPUT_MIC_RECORD_TIMEOUT
phase_timeout = config.INPUT_MIC_PHRASE_TIMEOUT
if record_timeout > phase_timeout:
record_timeout = phase_timeout
self.mic_audio_recorder = SelectedMicRecorder(
self.mic_audio_recorder = SelectedMicEnergyAndAudioRecorder(
device=device,
energy_threshold=config.INPUT_MIC_ENERGY_THRESHOLD,
dynamic_energy_threshold=config.INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD,
record_timeout=record_timeout,
)
self.mic_audio_recorder.recordIntoQueue(mic_audio_queue)
mic_transcriber = AudioTranscriber(
# self.mic_audio_recorder.recordIntoQueue(mic_audio_queue, mic_energy_queue)
self.mic_audio_recorder.recordIntoQueue(mic_audio_queue, None)
self.mic_transcriber = AudioTranscriber(
speaker=False,
source=self.mic_audio_recorder.source,
phrase_timeout=phase_timeout,
max_phrases=config.INPUT_MIC_MAX_PHRASES,
transcription_engine=config.SELECTED_TRANSCRIPTION_ENGINE,
root=config.PATH_LOCAL,
whisper_weight_type=config.WHISPER_WEIGHT_TYPE,
)
def sendMicTranscript():
mic_transcriber.transcribeAudioQueue(mic_audio_queue, config.SOURCE_LANGUAGE, config.SOURCE_COUNTRY)
message = mic_transcriber.getTranscript()
self.mic_transcriber.transcribeAudioQueue(mic_audio_queue, config.SOURCE_LANGUAGE, config.SOURCE_COUNTRY)
message = self.mic_transcriber.getTranscript()
try:
fnc(message)
except Exception:
pass
self.mic_print_transcript = threadFnc(sendMicTranscript)
def endMicTranscript():
mic_audio_queue.queue.clear()
# mic_energy_queue.queue.clear()
del self.mic_transcriber
gc.collect()
# def sendMicEnergy():
# if mic_energy_queue.empty() is False:
# energy = mic_energy_queue.get()
# # print("mic energy:", energy)
# try:
# fnc(energy)
# except Exception:
# pass
# sleep(0.01)
self.mic_print_transcript = threadFnc(sendMicTranscript, end_fnc=endMicTranscript)
self.mic_print_transcript.daemon = True
self.mic_print_transcript.start()
# self.mic_get_energy = threadFnc(sendMicEnergy)
# self.mic_get_energy.daemon = True
# self.mic_get_energy.start()
def stopMicTranscript(self):
if isinstance(self.mic_print_transcript, threadFnc):
self.mic_print_transcript.stop()
self.mic_print_transcript = None
if isinstance(self.mic_audio_recorder, SelectedMicRecorder):
if isinstance(self.mic_audio_recorder, SelectedMicEnergyAndAudioRecorder):
self.mic_audio_recorder.stop()
self.mic_audio_recorder = None
# if isinstance(self.mic_get_energy, threadFnc):
# self.mic_get_energy.stop()
# self.mic_get_energy = None
def startCheckMicEnergy(self, fnc, end_fnc, error_fnc=None):
if config.CHOICE_MIC_HOST == "NoHost" or config.CHOICE_MIC_DEVICE == "NoDevice":
@@ -399,43 +433,71 @@ class Model:
return
speaker_audio_queue = Queue()
# speaker_energy_queue = Queue()
record_timeout = config.INPUT_SPEAKER_RECORD_TIMEOUT
phase_timeout = config.INPUT_SPEAKER_PHRASE_TIMEOUT
if record_timeout > phase_timeout:
record_timeout = phase_timeout
self.speaker_audio_recorder = SelectedSpeakerRecorder(
self.speaker_audio_recorder = SelectedSpeakerEnergyAndAudioRecorder(
device=speaker_device,
energy_threshold=config.INPUT_SPEAKER_ENERGY_THRESHOLD,
dynamic_energy_threshold=config.INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD,
record_timeout=record_timeout,
)
self.speaker_audio_recorder.recordIntoQueue(speaker_audio_queue)
speaker_transcriber = AudioTranscriber(
# self.speaker_audio_recorder.recordIntoQueue(speaker_audio_queue, speaker_energy_queue)
self.speaker_audio_recorder.recordIntoQueue(speaker_audio_queue ,None)
self.speaker_transcriber = AudioTranscriber(
speaker=True,
source=self.speaker_audio_recorder.source,
phrase_timeout=phase_timeout,
max_phrases=config.INPUT_SPEAKER_MAX_PHRASES,
transcription_engine=config.SELECTED_TRANSCRIPTION_ENGINE,
root=config.PATH_LOCAL,
whisper_weight_type=config.WHISPER_WEIGHT_TYPE,
)
def sendSpeakerTranscript():
speaker_transcriber.transcribeAudioQueue(speaker_audio_queue, config.TARGET_LANGUAGE, config.TARGET_COUNTRY)
message = speaker_transcriber.getTranscript()
self.speaker_transcriber.transcribeAudioQueue(speaker_audio_queue, config.TARGET_LANGUAGE, config.TARGET_COUNTRY)
message = self.speaker_transcriber.getTranscript()
try:
fnc(message)
except Exception:
pass
self.speaker_print_transcript = threadFnc(sendSpeakerTranscript)
def endSpeakerTranscript():
speaker_audio_queue.queue.clear()
# speaker_energy_queue.queue.clear()
del self.speaker_transcriber
gc.collect()
# def sendSpeakerEnergy():
# if speaker_energy_queue.empty() is False:
# energy = speaker_energy_queue.get()
# # print("speaker energy:", energy)
# try:
# fnc(energy)
# except Exception:
# pass
# sleep(0.01)
self.speaker_print_transcript = threadFnc(sendSpeakerTranscript, end_fnc=endSpeakerTranscript)
self.speaker_print_transcript.daemon = True
self.speaker_print_transcript.start()
# self.speaker_get_energy = threadFnc(sendSpeakerEnergy)
# self.speaker_get_energy.daemon = True
# self.speaker_get_energy.start()
def stopSpeakerTranscript(self):
if isinstance(self.speaker_print_transcript, threadFnc):
self.speaker_print_transcript.stop()
self.speaker_print_transcript = None
if isinstance(self.speaker_audio_recorder, SelectedSpeakerRecorder):
if isinstance(self.speaker_audio_recorder, SelectedSpeakerEnergyAndAudioRecorder):
self.speaker_audio_recorder.stop()
self.speaker_audio_recorder = None
# if isinstance(self.speaker_get_energy, threadFnc):
# self.speaker_get_energy.stop()
# self.speaker_get_energy = None
def startCheckSpeakerEnergy(self, fnc, end_fnc, error_fnc=None):
speaker_device = getDefaultOutputDevice()
@@ -456,7 +518,7 @@ class Model:
sleep(0.01)
speaker_energy_queue = Queue()
self.speaker_energy_recorder = SelectedSpeakeEnergyRecorder(speaker_device)
self.speaker_energy_recorder = SelectedSpeakerEnergyRecorder(speaker_device)
self.speaker_energy_recorder.recordIntoQueue(speaker_energy_queue)
self.speaker_energy_plot_progressbar = threadFnc(sendSpeakerEnergy, end_fnc=end_fnc)
self.speaker_energy_plot_progressbar.daemon = True
@@ -466,7 +528,7 @@ class Model:
if isinstance(self.speaker_energy_plot_progressbar, threadFnc):
self.speaker_energy_plot_progressbar.stop()
self.speaker_energy_plot_progressbar = None
if isinstance(self.speaker_energy_recorder, SelectedSpeakeEnergyRecorder):
if isinstance(self.speaker_energy_recorder, SelectedSpeakerEnergyRecorder):
self.speaker_energy_recorder.stop()
self.speaker_energy_recorder = None

View File

@@ -1,8 +1,11 @@
from time import sleep
import threading
from pythonosc import osc_message_builder
from pythonosc import udp_client
from pythonosc import dispatcher
from pythonosc import osc_server
from tinyoscquery.queryservice import OSCQueryService
from tinyoscquery.utility import get_open_udp_port, get_open_tcp_port
# send OSC message typing
def sendTyping(flag=False, ip_address="127.0.0.1", port=9000):
@@ -45,12 +48,40 @@ def sendChangeVoice(ip_address="127.0.0.1", port=9000):
sendInputVoice(flag=0, ip_address=ip_address, port=port)
sleep(0.05)
def receiveOscParameters(target, filter="/*", ip_address="127.0.0.1", port=9001):
_dispatcher = dispatcher.Dispatcher()
_dispatcher.map(filter, target)
server = osc_server.ThreadingOSCUDPServer((ip_address, port), _dispatcher)
return server
def receiveOscParameters(dict_filter_and_target, ip_address="127.0.0.1", title="VRCT"):
osc_port = get_open_udp_port()
http_port = get_open_tcp_port()
osc_dispatcher = dispatcher.Dispatcher()
for filter, target in dict_filter_and_target.items():
osc_dispatcher.map(filter, target)
osc_udp_server = osc_server.ThreadingOSCUDPServer((ip_address, osc_port), osc_dispatcher)
threading.Thread(target=osc_udp_server.serve_forever, daemon = True).start()
osc_client = OSCQueryService(title, http_port, osc_port)
for filter, target in dict_filter_and_target.items():
osc_client.advertise_endpoint(filter)
if __name__ == "__main__":
sendChangeVoice()
sendChangeVoice()
osc_parameter_prefix = "/avatar/parameters/"
osc_avatar_change_path = "/avatar/change"
param_MuteSelf = "MuteSelf"
param_Voice = "Voice"
def print_handler_all(address, *args):
print(f"all {address}: {args}")
def print_handler_muteself(address, *args):
print(f"muteself {address}: {args}")
def print_handler_voice(address, *args):
print(f"voice {address}: {args}")
dict_filter_and_target = {
# osc_parameter_prefix + "*": print_handler_all,
osc_parameter_prefix + param_MuteSelf: print_handler_muteself,
osc_parameter_prefix + param_Voice: print_handler_voice,
}
receiveOscParameters(dict_filter_and_target)

View File

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

View File

@@ -1,6 +1,7 @@
from speech_recognition import Recognizer, Microphone
from pyaudiowpatch import get_sample_size, paInt16
from datetime import datetime
from queue import Queue
class BaseRecorder:
def __init__(self, source, energy_threshold, dynamic_energy_threshold, record_timeout):
@@ -78,7 +79,7 @@ class SelectedMicEnergyRecorder(BaseEnergyRecorder):
super().__init__(source=source)
# self.adjustForNoise()
class SelectedSpeakeEnergyRecorder(BaseEnergyRecorder):
class SelectedSpeakerEnergyRecorder(BaseEnergyRecorder):
def __init__(self, device):
source = Microphone(speaker=True,
@@ -87,4 +88,54 @@ class SelectedSpeakeEnergyRecorder(BaseEnergyRecorder):
channels=device["maxInputChannels"]
)
super().__init__(source=source)
# self.adjustForNoise()
class BaseEnergyAndAudioRecorder:
def __init__(self, source, energy_threshold, dynamic_energy_threshold, record_timeout):
self.recorder = Recognizer()
self.recorder.energy_threshold = energy_threshold
self.recorder.dynamic_energy_threshold = dynamic_energy_threshold
self.record_timeout = record_timeout
self.stop = None
if source is None:
raise ValueError("audio source can't be None")
self.source = source
def adjustForNoise(self):
with self.source:
self.recorder.adjust_for_ambient_noise(self.source)
def recordIntoQueue(self, audio_queue, energy_queue):
def audioRecordCallback(_, audio):
audio_queue.put((audio.get_raw_data(), datetime.now()))
def energyRecordCallback(energy):
energy_queue.put(energy)
if isinstance(energy_queue, Queue):
self.stop = self.recorder.listen_energy_and_audio_in_background(self.source, audioRecordCallback, phrase_time_limit=self.record_timeout, callback_energy=energyRecordCallback)
else:
self.stop = self.recorder.listen_energy_and_audio_in_background(self.source, audioRecordCallback, phrase_time_limit=self.record_timeout)
class SelectedMicEnergyAndAudioRecorder(BaseEnergyAndAudioRecorder):
def __init__(self, device, energy_threshold, dynamic_energy_threshold, record_timeout):
source=Microphone(
device_index=device['index'],
sample_rate=int(device["defaultSampleRate"]),
)
super().__init__(source=source, energy_threshold=energy_threshold, dynamic_energy_threshold=dynamic_energy_threshold, record_timeout=record_timeout)
# self.adjustForNoise()
class SelectedSpeakerEnergyAndAudioRecorder(BaseEnergyAndAudioRecorder):
def __init__(self, device, energy_threshold, dynamic_energy_threshold, record_timeout):
source = Microphone(speaker=True,
device_index= device["index"],
sample_rate=int(device["defaultSampleRate"]),
chunk_size=get_sample_size(paInt16),
channels=device["maxInputChannels"]
)
super().__init__(source=source, energy_threshold=energy_threshold, dynamic_energy_threshold=dynamic_energy_threshold, record_timeout=record_timeout)
# self.adjustForNoise()

View File

@@ -5,18 +5,24 @@ from speech_recognition import Recognizer, AudioData, AudioFile
from datetime import timedelta
from pyaudiowpatch import get_sample_size, paInt16
from .transcription_languages import transcription_lang
from .transcription_whisper import getWhisperModel, checkWhisperWeight
import torch
import numpy as np
PHRASE_TIMEOUT = 3
MAX_PHRASES = 10
class AudioTranscriber:
def __init__(self, speaker, source, phrase_timeout, max_phrases):
def __init__(self, speaker, source, phrase_timeout, max_phrases, transcription_engine, root=None, whisper_weight_type=None):
self.speaker = speaker
self.phrase_timeout = phrase_timeout
self.max_phrases = max_phrases
self.transcript_data = []
self.transcript_changed_event = Event()
self.audio_recognizer = Recognizer()
self.transcription_engine = "Google"
self.whisper_model = None
self.audio_sources = {
"sample_rate": source.SAMPLE_RATE,
"sample_width": source.SAMPLE_WIDTH,
@@ -27,22 +33,45 @@ class AudioTranscriber:
"process_data_func": self.processSpeakerData if speaker else self.processSpeakerData
}
if transcription_engine == "Whisper" and checkWhisperWeight(root, whisper_weight_type) is True:
self.whisper_model = getWhisperModel(root, whisper_weight_type)
self.transcription_engine = "Whisper"
def transcribeAudioQueue(self, audio_queue, language, country):
# while True:
audio, time_spoken = audio_queue.get()
self.updateLastSampleAndPhraseStatus(audio, time_spoken)
text = ''
try:
# fd, path = tempfile.mkstemp(suffix=".wav")
# os.close(fd)
audio_data = self.audio_sources["process_data_func"]()
text = self.audio_recognizer.recognize_google(audio_data, language=transcription_lang[language][country])
match self.transcription_engine:
case "Google":
text = self.audio_recognizer.recognize_google(audio_data, language=transcription_lang[language][country][self.transcription_engine])
case "Whisper":
audio_data = np.frombuffer(audio_data.get_raw_data(convert_rate=16000, convert_width=2), np.int16).flatten().astype(np.float32) / 32768.0
if isinstance(audio_data, torch.Tensor):
audio_data = audio_data.detach().numpy()
segments, _ = self.whisper_model.transcribe(
audio_data,
beam_size=5,
temperature=0.0,
log_prob_threshold=-0.8,
no_speech_threshold=0.6,
language=transcription_lang[language][country][self.transcription_engine],
word_timestamps=False,
without_timestamps=True,
task="transcribe",
vad_filter=False,
)
for s in segments:
if s.avg_logprob < -0.8 or s.no_speech_prob > 0.6:
continue
text += s.text
except Exception:
pass
finally:
pass
# os.unlink(path)
if text != '':
self.updateTranscript(text)

View File

@@ -0,0 +1,98 @@
from os import path as os_path, makedirs as os_makedirs
from requests import get as requests_get
from typing import Callable
import huggingface_hub
from faster_whisper import WhisperModel
import logging
logger = logging.getLogger('faster_whisper')
logger.setLevel(logging.CRITICAL)
_MODELS = {
"tiny": "Systran/faster-whisper-tiny",
"base": "Systran/faster-whisper-base",
"small": "Systran/faster-whisper-small",
"medium": "Systran/faster-whisper-medium",
"large-v1": "Systran/faster-whisper-large-v1",
"large-v2": "Systran/faster-whisper-large-v2",
"large-v3": "Systran/faster-whisper-large-v3",
}
_FILENAMES = [
"config.json",
"preprocessor_config.json",
"model.bin",
"tokenizer.json",
"vocabulary.txt",
"vocabulary.json",
]
def downloadFile(url, path, func=None):
try:
res = requests_get(url, stream=True)
res.raise_for_status()
file_size = int(res.headers.get('content-length', 0))
total_chunk = 0
with open(os_path.join(path), 'wb') as file:
for chunk in res.iter_content(chunk_size=1024*5):
file.write(chunk)
if isinstance(func, Callable):
total_chunk += len(chunk)
func(total_chunk/file_size)
except Exception as e:
print("error:downloadFile()", e)
def checkWhisperWeight(root, weight_type):
path = os_path.join(root, "weights", "whisper", weight_type)
result = False
try:
WhisperModel(
path,
device="cpu",
device_index=0,
compute_type="int8",
cpu_threads=4,
num_workers=1,
local_files_only=True,
)
result = True
except Exception:
pass
return result
def downloadWhisperWeight(root, weight_type, callbackFunc):
path = os_path.join(root, "weights", "whisper", weight_type)
os_makedirs(path, exist_ok=True)
if checkWhisperWeight(root, weight_type) is True:
return
for filename in _FILENAMES:
print("Downloading", filename, "...")
file_path = os_path.join(path, filename)
url = huggingface_hub.hf_hub_url(_MODELS[weight_type], filename)
downloadFile(url, file_path, func=callbackFunc)
def getWhisperModel(root, weight_type):
path = os_path.join(root, "weights", "whisper", weight_type)
return WhisperModel(
path,
device="cpu",
device_index=0,
compute_type="int8",
cpu_threads=4,
num_workers=1,
local_files_only=True,
)
if __name__ == "__main__":
def callback(value):
print(value)
pass
downloadWhisperWeight("./", "tiny", callback)
downloadWhisperWeight("./", "base", callback)
downloadWhisperWeight("./", "small", callback)
downloadWhisperWeight("./", "medium", callback)
downloadWhisperWeight("./", "large-v1", callback)
downloadWhisperWeight("./", "large-v2", callback)
downloadWhisperWeight("./", "large-v3", callback)

View File

@@ -1,8 +1,9 @@
import gc
import os
from deepl import Translator as deepl_Translator
from translators import translate_text as other_web_Translator
from .translation_languages import translation_lang
from .utils import ctranslate2_weights
from .translation_utils import ctranslate2_weights
import ctranslate2
import transformers
@@ -27,7 +28,8 @@ class Translator():
def changeCTranslate2Model(self, path, model_type):
directory_name = ctranslate2_weights[model_type]["directory_name"]
tokenizer = ctranslate2_weights[model_type]["tokenizer"]
weight_path = os.path.join(path, "weight", directory_name)
weight_path = os.path.join(path, "weights", "ctranslate2", directory_name)
tokenizer_path = os.path.join(path, "weights", "ctranslate2", directory_name, "tokenizer")
self.ctranslate2_translator = ctranslate2.Translator(
weight_path,
device="cpu",
@@ -36,7 +38,19 @@ class Translator():
inter_threads=1,
intra_threads=4
)
self.ctranslate2_tokenizer = transformers.AutoTokenizer.from_pretrained(tokenizer)
try:
self.ctranslate2_tokenizer = transformers.AutoTokenizer.from_pretrained(tokenizer, cache_dir=tokenizer_path)
except Exception as e:
print("Error: changeCTranslate2Model()", e)
tokenizer_path = os.path.join("./weights", "ctranslate2", directory_name, "tokenizer")
self.ctranslate2_tokenizer = transformers.AutoTokenizer.from_pretrained(tokenizer, cache_dir=tokenizer_path)
def clearCTranslate2Model(self):
del self.ctranslate2_translator
del self.ctranslate2_tokenizer
gc.collect()
self.ctranslate2_translator = None
self.ctranslate2_tokenizer = None
@staticmethod
def getLanguageCode(translator_name, target_country, source_language, target_language):

View File

@@ -39,36 +39,36 @@ def calculate_file_hash(file_path, block_size=65536):
return hash_object.hexdigest()
def checkCTranslate2Weight(path, weight_type="Small"):
directory_name = 'weight'
current_directory = path
weight_directory_name = ctranslate2_weights[weight_type]["directory_name"]
hash_data = ctranslate2_weights[weight_type]["hash"]
files = ["model.bin", "sentencepiece.model", "shared_vocabulary.txt"]
files = [
"model.bin",
"sentencepiece.model",
"shared_vocabulary.txt"
]
# check already downloaded
already_downloaded = False
if all(os_path.exists(os_path.join(current_directory, directory_name, weight_directory_name, file)) for file in files):
if all(os_path.exists(os_path.join(path, weight_directory_name, file)) for file in files):
# check hash
for file in files:
original_hash = hash_data[file]
current_hash = calculate_file_hash(os_path.join(current_directory, directory_name, weight_directory_name, file))
current_hash = calculate_file_hash(os_path.join(path, weight_directory_name, file))
if original_hash != current_hash:
break
already_downloaded = True
return already_downloaded
def downloadCTranslate2Weight(path, weight_type="Small", func=None):
def downloadCTranslate2Weight(root, weight_type="Small", func=None):
url = ctranslate2_weights[weight_type]["url"]
filename = 'weight.zip'
directory_name = 'weight'
current_directory = path
filename = "weight.zip"
path = os_path.join(root, "weights", "ctranslate2")
os_makedirs(path, exist_ok=True)
if checkCTranslate2Weight(path, weight_type):
return
try:
os_makedirs(os_path.join(current_directory, directory_name), exist_ok=True)
print(os_path.join(current_directory, directory_name))
with tempfile.TemporaryDirectory() as tmp_path:
res = requests_get(url, stream=True)
file_size = int(res.headers.get('content-length', 0))
@@ -81,6 +81,6 @@ def downloadCTranslate2Weight(path, weight_type="Small", func=None):
func(total_chunk/file_size)
with ZipFile(os_path.join(tmp_path, filename)) as zf:
zf.extractall(os_path.join(current_directory, directory_name))
zf.extractall(path)
except Exception as e:
print("error:downloadCTranslate2Weight()", e)

View File

@@ -8,6 +8,10 @@ pyyaml == 6.0.1
python-i18n == 0.3.9
CTkToolTip == 0.8
pyinstaller==6.2.0
transformers[torch]
transformers[torch]==4.37.2
sentencepiece==0.1.99
ctranslate2==3.21.0
ctranslate2==3.24.0
faster-whisper==0.10.0
translators @ git+https://github.com/misyaguziya/translators@5.8.9
SpeechRecognition @ git+https://github.com/misyaguziya/custom_speech_recognition@3.10.2
tinyoscquery @ git+https://github.com/cyberkitsune/tinyoscquery@0.1.2

View File

@@ -1,5 +1,5 @@
from typing import Union
from os import path as os_path
from os import path as os_path, rename as os_rename
from PIL.Image import open as Image_open
def getImageFile(file_name):
@@ -49,4 +49,10 @@ def isUniqueStrings(unique_strings:Union[str, list], input_string:str, require=F
return all(count == 1 for count in counts) and counts.count(1) == 2
else:
# If require is False, check if unique strings are used exactly once
return all(count == 1 for count in counts)
return all(count == 1 for count in counts)
# path先のweightフォルダがある場合にはそのフォルダ名をweightsに変更する
def renameWeightFolder(path):
weight_path = os_path.join(path, "weight")
if os_path.exists(weight_path):
os_rename(weight_path, os_path.join(path, "weights"))

214
view.py
View File

@@ -29,6 +29,7 @@ class View():
font_family=config.FONT_FAMILY,
ui_language=config.UI_LANGUAGE,
is_reset_button_displayed_for_translation=config.IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION,
is_reset_button_displayed_for_whisper=config.IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER,
)
if config.ENABLE_SPEAKER2CHATBOX is False:
@@ -36,7 +37,7 @@ class View():
else:
VERSION_TEXT=i18n.t("config_window.version", version=config.VERSION) + " (Speaker2Chatbox)"
self.TEXT_TRANSLATOR_CTRANSLATE2 = i18n.t("main_window.translator") + ": " + i18n.t("main_window.translator_ctranslate2")
self.TEXT_TRANSLATOR_CTRANSLATE2=i18n.t("main_window.translator") + ": " + i18n.t("main_window.translator_ctranslate2")
self.settings = SimpleNamespace()
theme = get_appearance_mode() if config.APPEARANCE_THEME == "System" else config.APPEARANCE_THEME
@@ -102,6 +103,7 @@ class View():
CALLBACK_UPDATE_SOFTWARE=None,
CALLBACK_OPEN_FILEPATH_LOGS=None,
CALLBACK_OPEN_FILEPATH_CONFIG_FILE=None,
CALLBACK_OPEN_WEBPAGE_DEEPL_AUTH_KEY=self.openWebPage_DeepL_Auth_Key,
CALLBACK_DELETE_MAIN_WINDOW=self.quitVRCT,
CALLBACK_QUIT_VRCT=None,
@@ -157,7 +159,7 @@ class View():
CALLBACK_SELECTED_LANGUAGE_PRESET_TAB=None,
VAR_LABEL_YOUR_LANGUAGE=StringVar(value=i18n.t("main_window.your_language")),
VAR_YOUR_LANGUAGE = StringVar(value=f"{config.SOURCE_LANGUAGE}\n({config.SOURCE_COUNTRY})"),
VAR_YOUR_LANGUAGE=StringVar(value=f"{config.SOURCE_LANGUAGE}\n({config.SOURCE_COUNTRY})"),
CALLBACK_OPEN_SELECTABLE_YOUR_LANGUAGE_WINDOW=None,
IS_OPENED_SELECTABLE_YOUR_LANGUAGE_WINDOW=False,
CALLBACK_SELECTED_YOUR_LANGUAGE=None,
@@ -168,13 +170,13 @@ class View():
CALLBACK_LEAVED_SWAP_LANGUAGES_BUTTON=self._leavedSwapLanguagesButton,
VAR_LABEL_TARGET_LANGUAGE=StringVar(value=i18n.t("main_window.target_language")),
VAR_TARGET_LANGUAGE = StringVar(value=f"{config.TARGET_LANGUAGE}\n({config.TARGET_COUNTRY})"),
VAR_TARGET_LANGUAGE=StringVar(value=f"{config.TARGET_LANGUAGE}\n({config.TARGET_COUNTRY})"),
CALLBACK_OPEN_SELECTABLE_TARGET_LANGUAGE_WINDOW=None,
IS_OPENED_SELECTABLE_TARGET_LANGUAGE_WINDOW=False,
CALLBACK_SELECTED_TARGET_LANGUAGE=None,
VAR_SELECTED_TRANSLATION_ENGINE = StringVar(value="Translator: INIT"),
CALLBACK_SELECTED_TRANSLATION_ENGINE = None,
VAR_SELECTED_TRANSLATION_ENGINE=StringVar(value="Translator: INIT"),
CALLBACK_SELECTED_TRANSLATION_ENGINE=None,
VAR_LABEL_TEXTBOX_ALL=StringVar(value=i18n.t("main_window.textbox_tab_all")),
VAR_LABEL_TEXTBOX_SENT=StringVar(value=i18n.t("main_window.textbox_tab_sent")),
@@ -184,6 +186,8 @@ class View():
VAR_UPDATE_AVAILABLE=StringVar(value=i18n.t("main_window.update_available")),
CALLBACK_MESSAGE_BOX_BIND_KEYSYM__UP=None,
CALLBACK_MESSAGE_BOX_BIND_KEYSYM__DOWN=None,
# Main Window Cover
VAR_LABEL_MAIN_WINDOW_COVER_MESSAGE=StringVar(value=""),
@@ -211,6 +215,7 @@ class View():
VAR_SIDE_MENU_LABEL_TRANSCRIPTION=StringVar(value=i18n.t("config_window.side_menu_labels.transcription")),
VAR_SECOND_TITLE_TRANSCRIPTION_MIC=StringVar(value=i18n.t("config_window.side_menu_labels.transcription_mic")),
VAR_SECOND_TITLE_TRANSCRIPTION_SPEAKER=StringVar(value=i18n.t("config_window.side_menu_labels.transcription_speaker")),
VAR_SECOND_TITLE_TRANSCRIPTION_INTERNAL_MODEL=StringVar(value=i18n.t("config_window.side_menu_labels.transcription_internal_model")),
VAR_SIDE_MENU_LABEL_OTHERS=StringVar(value=i18n.t("config_window.side_menu_labels.others")),
VAR_SIDE_MENU_LABEL_ADVANCED_SETTINGS=StringVar(value=i18n.t("config_window.side_menu_labels.advanced_settings")),
@@ -280,7 +285,7 @@ class View():
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()[config.WEIGHT_TYPE]),
VAR_CTRANSLATE2_WEIGHT_TYPE=StringVar(value=self.getSelectableCtranslate2WeightTypeDict()[config.CTRANSLATE2_WEIGHT_TYPE]),
VAR_LABEL_DEEPL_AUTH_KEY=StringVar(value=i18n.t( "config_window.deepl_auth_key.label")),
VAR_DESC_DEEPL_AUTH_KEY=StringVar(
@@ -291,6 +296,7 @@ class View():
),
CALLBACK_SET_DEEPL_AUTH_KEY=None,
VAR_DEEPL_AUTH_KEY=StringVar(value=config.AUTH_KEYS["DeepL_API"]),
VAR_OPEN_DEEPL_WEB_PAGE=StringVar(value=i18n.t( "config_window.deepl_auth_key.open_auth_key_webpage")),
# Transcription Tab (Mic)
@@ -381,6 +387,19 @@ class View():
CALLBACK_FOCUS_OUT_SPEAKER_MAX_PHRASES=self.callbackBindFocusOut_SpeakerMaxPhrases,
# Transcription Tab (Whisper Internal AI Model)
VAR_LABEL_USE_WHISPER_FEATURE=StringVar(value=i18n.t("config_window.use_whisper_feature.label")),
VAR_DESC_USE_WHISPER_FEATURE=StringVar(value=i18n.t("config_window.use_whisper_feature.desc")),
CALLBACK_SET_USE_WHISPER_FEATURE=None,
VAR_USE_WHISPER_FEATURE=BooleanVar(value=config.USE_WHISPER_FEATURE),
VAR_LABEL_WHISPER_WEIGHT_TYPE=StringVar(value=i18n.t("config_window.whisper_weight_type.label")),
VAR_DESC_WHISPER_WEIGHT_TYPE=StringVar(value=i18n.t("config_window.whisper_weight_type.desc")),
DICT_WHISPER_WEIGHT_TYPE=self.getSelectableWhisperWeightTypeDict(),
CALLBACK_SET_WHISPER_WEIGHT_TYPE=None,
VAR_WHISPER_WEIGHT_TYPE=StringVar(value=self.getSelectableWhisperWeightTypeDict()[config.WHISPER_WEIGHT_TYPE]),
# Others Tab
VAR_LABEL_ENABLE_AUTO_CLEAR_MESSAGE_BOX=StringVar(value=i18n.t("config_window.auto_clear_the_message_box.label")),
VAR_DESC_ENABLE_AUTO_CLEAR_MESSAGE_BOX=None,
@@ -527,23 +546,23 @@ class View():
if main_window_registers is not None:
self.view_variable.CALLBACK_ENABLE_MAIN_WINDOW_SIDEBAR_COMPACT_MODE = main_window_registers.get("callback_enable_main_window_sidebar_compact_mode", None)
self.view_variable.CALLBACK_DISABLE_MAIN_WINDOW_SIDEBAR_COMPACT_MODE = main_window_registers.get("callback_disable_main_window_sidebar_compact_mode", None)
self.view_variable.CALLBACK_ENABLE_MAIN_WINDOW_SIDEBAR_COMPACT_MODE=main_window_registers.get("callback_enable_main_window_sidebar_compact_mode", None)
self.view_variable.CALLBACK_DISABLE_MAIN_WINDOW_SIDEBAR_COMPACT_MODE=main_window_registers.get("callback_disable_main_window_sidebar_compact_mode", None)
self.view_variable.CALLBACK_TOGGLE_TRANSLATION = main_window_registers.get("callback_toggle_translation", None)
self.view_variable.CALLBACK_TOGGLE_TRANSCRIPTION_SEND = main_window_registers.get("callback_toggle_transcription_send", None)
self.view_variable.CALLBACK_TOGGLE_TRANSCRIPTION_RECEIVE = main_window_registers.get("callback_toggle_transcription_receive", None)
self.view_variable.CALLBACK_TOGGLE_FOREGROUND = main_window_registers.get("callback_toggle_foreground", None)
self.view_variable.CALLBACK_TOGGLE_TRANSLATION=main_window_registers.get("callback_toggle_translation", None)
self.view_variable.CALLBACK_TOGGLE_TRANSCRIPTION_SEND=main_window_registers.get("callback_toggle_transcription_send", None)
self.view_variable.CALLBACK_TOGGLE_TRANSCRIPTION_RECEIVE=main_window_registers.get("callback_toggle_transcription_receive", None)
self.view_variable.CALLBACK_TOGGLE_FOREGROUND=main_window_registers.get("callback_toggle_foreground", None)
self.view_variable.CALLBACK_SELECTED_YOUR_LANGUAGE = main_window_registers.get("callback_your_language", None)
self.view_variable.CALLBACK_SELECTED_TARGET_LANGUAGE = main_window_registers.get("callback_target_language", None)
self.view_variable.CALLBACK_SELECTED_YOUR_LANGUAGE=main_window_registers.get("callback_your_language", None)
self.view_variable.CALLBACK_SELECTED_TARGET_LANGUAGE=main_window_registers.get("callback_target_language", None)
main_window_registers.get("values", None) and self.updateList_selectableLanguages(main_window_registers["values"])
self.view_variable.CALLBACK_SWAP_LANGUAGES = main_window_registers.get("callback_swap_languages", None)
self.view_variable.CALLBACK_SWAP_LANGUAGES=main_window_registers.get("callback_swap_languages", None)
self.view_variable.CALLBACK_SELECTED_LANGUAGE_PRESET_TAB = main_window_registers.get("callback_selected_language_preset_tab", None)
self.view_variable.CALLBACK_SELECTED_LANGUAGE_PRESET_TAB=main_window_registers.get("callback_selected_language_preset_tab", None)
self.view_variable.CALLBACK_SELECTED_TRANSLATION_ENGINE = main_window_registers.get("callback_selected_translation_engine", None)
self.view_variable.CALLBACK_SELECTED_TRANSLATION_ENGINE=main_window_registers.get("callback_selected_translation_engine", None)
def adjustedMessageBoxReturnFunction(_e):
if self.view_variable.IS_ENTRY_MESSAGE_BOX_DISABLED is True:
@@ -555,11 +574,15 @@ class View():
main_window_registers.get("message_box_bind_Return")()
vrct_gui.entry_message_box.focus()
entry_message_box = getattr(vrct_gui, "entry_message_box")
entry_message_box=getattr(vrct_gui, "entry_message_box")
entry_message_box.bind("<Shift-Return>", lambda _e: None) # This is to prevent message sending on Shift + Enter key press and just add a new line.
entry_message_box.bind("<Return>", adjustedMessageBoxReturnFunction)
entry_message_box.bind("<Any-KeyPress>", main_window_registers.get("message_box_bind_Any_KeyPress"))
self.view_variable.CALLBACK_CLICKED_SEND_MESSAGE_BUTTON = pressedSendMessageButtonFunction
self.view_variable.CALLBACK_CLICKED_SEND_MESSAGE_BUTTON=pressedSendMessageButtonFunction
self.view_variable.CALLBACK_MESSAGE_BOX_BIND_KEYSYM__UP=main_window_registers.get("message_box_bind_Up_KeyPress")
self.view_variable.CALLBACK_MESSAGE_BOX_BIND_KEYSYM__DOWN=main_window_registers.get("message_box_bind_Down_KeyPress")
entry_message_box.bind("<FocusIn>", main_window_registers.get("message_box_bind_FocusIn"))
@@ -569,8 +592,8 @@ class View():
self.updateGuiVariableByPresetTabNo(config.SELECTED_TAB_NO)
vrct_gui._setDefaultActiveLanguagePresetTab(tab_no=config.SELECTED_TAB_NO)
self.view_variable.CALLBACK_OPEN_SELECTABLE_YOUR_LANGUAGE_WINDOW = self.openSelectableLanguagesWindow_YourLanguage
self.view_variable.CALLBACK_OPEN_SELECTABLE_TARGET_LANGUAGE_WINDOW = self.openSelectableLanguagesWindow_TargetLanguage
self.view_variable.CALLBACK_OPEN_SELECTABLE_YOUR_LANGUAGE_WINDOW=self.openSelectableLanguagesWindow_YourLanguage
self.view_variable.CALLBACK_OPEN_SELECTABLE_TARGET_LANGUAGE_WINDOW=self.openSelectableLanguagesWindow_TargetLanguage
# Config Window
@@ -579,74 +602,79 @@ class View():
if config_window_registers is not None:
# Compact Mode Switch
self.view_variable.CALLBACK_ENABLE_CONFIG_WINDOW_COMPACT_MODE = config_window_registers.get("callback_disable_config_window_compact_mode", None)
self.view_variable.CALLBACK_DISABLE_CONFIG_WINDOW_COMPACT_MODE = config_window_registers.get("callback_enable_config_window_compact_mode", None)
self.view_variable.CALLBACK_ENABLE_CONFIG_WINDOW_COMPACT_MODE=config_window_registers.get("callback_disable_config_window_compact_mode", None)
self.view_variable.CALLBACK_DISABLE_CONFIG_WINDOW_COMPACT_MODE=config_window_registers.get("callback_enable_config_window_compact_mode", None)
# Appearance Tab
self.view_variable.CALLBACK_SET_TRANSPARENCY = config_window_registers.get("callback_set_transparency", None)
self.view_variable.CALLBACK_SET_TRANSPARENCY=config_window_registers.get("callback_set_transparency", None)
self.view_variable.CALLBACK_SET_APPEARANCE = config_window_registers.get("callback_set_appearance", None)
self.view_variable.CALLBACK_SET_UI_SCALING = config_window_registers.get("callback_set_ui_scaling", None)
self.view_variable.CALLBACK_SET_TEXTBOX_UI_SCALING = config_window_registers.get("callback_set_textbox_ui_scaling", None)
self.view_variable.CALLBACK_SET_MESSAGE_BOX_RATIO = config_window_registers.get("callback_set_message_box_ratio", None)
self.view_variable.CALLBACK_SET_FONT_FAMILY = config_window_registers.get("callback_set_font_family", None)
self.view_variable.CALLBACK_SET_UI_LANGUAGE = config_window_registers.get("callback_set_ui_language", None)
self.view_variable.CALLBACK_SET_ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY = config_window_registers.get("callback_set_enable_restore_main_window_geometry", None)
self.view_variable.CALLBACK_SET_APPEARANCE=config_window_registers.get("callback_set_appearance", None)
self.view_variable.CALLBACK_SET_UI_SCALING=config_window_registers.get("callback_set_ui_scaling", None)
self.view_variable.CALLBACK_SET_TEXTBOX_UI_SCALING=config_window_registers.get("callback_set_textbox_ui_scaling", None)
self.view_variable.CALLBACK_SET_MESSAGE_BOX_RATIO=config_window_registers.get("callback_set_message_box_ratio", None)
self.view_variable.CALLBACK_SET_FONT_FAMILY=config_window_registers.get("callback_set_font_family", None)
self.view_variable.CALLBACK_SET_UI_LANGUAGE=config_window_registers.get("callback_set_ui_language", None)
self.view_variable.CALLBACK_SET_ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY=config_window_registers.get("callback_set_enable_restore_main_window_geometry", None)
# 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_AUTH_KEY = config_window_registers.get("callback_set_deepl_auth_key", None)
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_AUTH_KEY=config_window_registers.get("callback_set_deepl_auth_key", None)
# Transcription Tab (Mic)
self.view_variable.CALLBACK_SET_MIC_HOST = config_window_registers.get("callback_set_mic_host", None)
self.view_variable.CALLBACK_SET_MIC_HOST=config_window_registers.get("callback_set_mic_host", None)
config_window_registers.get("list_mic_host", None) and self.updateList_MicHost(config_window_registers["list_mic_host"])
self.view_variable.CALLBACK_SET_MIC_DEVICE = config_window_registers.get("callback_set_mic_device", None)
self.view_variable.CALLBACK_SET_MIC_DEVICE=config_window_registers.get("callback_set_mic_device", None)
config_window_registers.get("list_mic_device", None) and self.updateList_MicDevice(config_window_registers["list_mic_device"])
self.view_variable.CALLBACK_SET_MIC_ENERGY_THRESHOLD = config_window_registers.get("callback_set_mic_energy_threshold", None)
self.view_variable.CALLBACK_SET_MIC_DYNAMIC_ENERGY_THRESHOLD = config_window_registers.get("callback_set_mic_dynamic_energy_threshold", None)
self.view_variable.CALLBACK_CHECK_MIC_THRESHOLD = config_window_registers.get("callback_check_mic_threshold", None)
self.view_variable.CALLBACK_SET_MIC_RECORD_TIMEOUT = config_window_registers.get("callback_set_mic_record_timeout", None)
self.view_variable.CALLBACK_SET_MIC_PHRASE_TIMEOUT = config_window_registers.get("callback_set_mic_phrase_timeout", None)
self.view_variable.CALLBACK_SET_MIC_MAX_PHRASES = config_window_registers.get("callback_set_mic_max_phrases", None)
self.view_variable.CALLBACK_SET_MIC_WORD_FILTER = config_window_registers.get("callback_set_mic_word_filter", None)
self.view_variable.CALLBACK_DELETE_MIC_WORD_FILTER = config_window_registers.get("callback_delete_mic_word_filter", None)
self.view_variable.CALLBACK_SET_MIC_ENERGY_THRESHOLD=config_window_registers.get("callback_set_mic_energy_threshold", None)
self.view_variable.CALLBACK_SET_MIC_DYNAMIC_ENERGY_THRESHOLD=config_window_registers.get("callback_set_mic_dynamic_energy_threshold", None)
self.view_variable.CALLBACK_CHECK_MIC_THRESHOLD=config_window_registers.get("callback_check_mic_threshold", None)
self.view_variable.CALLBACK_SET_MIC_RECORD_TIMEOUT=config_window_registers.get("callback_set_mic_record_timeout", None)
self.view_variable.CALLBACK_SET_MIC_PHRASE_TIMEOUT=config_window_registers.get("callback_set_mic_phrase_timeout", None)
self.view_variable.CALLBACK_SET_MIC_MAX_PHRASES=config_window_registers.get("callback_set_mic_max_phrases", None)
self.view_variable.CALLBACK_SET_MIC_WORD_FILTER=config_window_registers.get("callback_set_mic_word_filter", None)
self.view_variable.CALLBACK_DELETE_MIC_WORD_FILTER=config_window_registers.get("callback_delete_mic_word_filter", None)
# Transcription Tab (Speaker)
self.view_variable.CALLBACK_SET_SPEAKER_ENERGY_THRESHOLD = config_window_registers.get("callback_set_speaker_energy_threshold", None)
self.view_variable.CALLBACK_SET_SPEAKER_DYNAMIC_ENERGY_THRESHOLD = config_window_registers.get("callback_set_speaker_dynamic_energy_threshold", None)
self.view_variable.CALLBACK_CHECK_SPEAKER_THRESHOLD = config_window_registers.get("callback_check_speaker_threshold", None)
self.view_variable.CALLBACK_SET_SPEAKER_RECORD_TIMEOUT = config_window_registers.get("callback_set_speaker_record_timeout", None)
self.view_variable.CALLBACK_SET_SPEAKER_PHRASE_TIMEOUT = config_window_registers.get("callback_set_speaker_phrase_timeout", None)
self.view_variable.CALLBACK_SET_SPEAKER_MAX_PHRASES = config_window_registers.get("callback_set_speaker_max_phrases", None)
self.view_variable.CALLBACK_SET_SPEAKER_ENERGY_THRESHOLD=config_window_registers.get("callback_set_speaker_energy_threshold", None)
self.view_variable.CALLBACK_SET_SPEAKER_DYNAMIC_ENERGY_THRESHOLD=config_window_registers.get("callback_set_speaker_dynamic_energy_threshold", None)
self.view_variable.CALLBACK_CHECK_SPEAKER_THRESHOLD=config_window_registers.get("callback_check_speaker_threshold", None)
self.view_variable.CALLBACK_SET_SPEAKER_RECORD_TIMEOUT=config_window_registers.get("callback_set_speaker_record_timeout", None)
self.view_variable.CALLBACK_SET_SPEAKER_PHRASE_TIMEOUT=config_window_registers.get("callback_set_speaker_phrase_timeout", None)
self.view_variable.CALLBACK_SET_SPEAKER_MAX_PHRASES=config_window_registers.get("callback_set_speaker_max_phrases", None)
# Transcription Tab (Internal AI Model)
self.view_variable.CALLBACK_SET_USE_WHISPER_FEATURE=config_window_registers.get("callback_set_use_whisper_feature", None)
self.view_variable.CALLBACK_SET_WHISPER_WEIGHT_TYPE=config_window_registers.get("callback_set_whisper_weight_type", None)
# Others Tab
self.view_variable.CALLBACK_SET_ENABLE_AUTO_CLEAR_MESSAGE_BOX = config_window_registers.get("callback_set_enable_auto_clear_chatbox", None)
self.view_variable.CALLBACK_SET_ENABLE_SEND_ONLY_TRANSLATED_MESSAGES = config_window_registers.get("callback_set_send_only_translated_messages", None)
self.view_variable.CALLBACK_SET_SEND_MESSAGE_BUTTON_TYPE = config_window_registers.get("callback_set_send_message_button_type", None)
self.view_variable.CALLBACK_SET_ENABLE_NOTICE_XSOVERLAY = config_window_registers.get("callback_set_enable_notice_xsoverlay", None)
self.view_variable.CALLBACK_SET_ENABLE_AUTO_EXPORT_MESSAGE_LOGS = config_window_registers.get("callback_set_enable_auto_export_message_logs", None)
self.view_variable.CALLBACK_SET_ENABLE_AUTO_CLEAR_MESSAGE_BOX=config_window_registers.get("callback_set_enable_auto_clear_chatbox", None)
self.view_variable.CALLBACK_SET_ENABLE_SEND_ONLY_TRANSLATED_MESSAGES=config_window_registers.get("callback_set_send_only_translated_messages", None)
self.view_variable.CALLBACK_SET_SEND_MESSAGE_BUTTON_TYPE=config_window_registers.get("callback_set_send_message_button_type", None)
self.view_variable.CALLBACK_SET_ENABLE_NOTICE_XSOVERLAY=config_window_registers.get("callback_set_enable_notice_xsoverlay", None)
self.view_variable.CALLBACK_SET_ENABLE_AUTO_EXPORT_MESSAGE_LOGS=config_window_registers.get("callback_set_enable_auto_export_message_logs", None)
self.view_variable.CALLBACK_SET_ENABLE_SEND_MESSAGE_TO_VRC = config_window_registers.get("callback_set_enable_send_message_to_vrc", None)
self.view_variable.CALLBACK_SET_ENABLE_SEND_MESSAGE_TO_VRC=config_window_registers.get("callback_set_enable_send_message_to_vrc", None)
self.view_variable.CALLBACK_SET_SEND_MESSAGE_FORMAT = config_window_registers.get("callback_set_send_message_format", None)
self.view_variable.CALLBACK_SET_SEND_MESSAGE_FORMAT_WITH_T = config_window_registers.get("callback_set_send_message_format_with_t", None)
self.view_variable.CALLBACK_SET_RECEIVED_MESSAGE_FORMAT = config_window_registers.get("callback_set_received_message_format", None)
self.view_variable.CALLBACK_SET_RECEIVED_MESSAGE_FORMAT_WITH_T = config_window_registers.get("callback_set_received_message_format_with_t", None)
self.view_variable.CALLBACK_SET_SEND_MESSAGE_FORMAT=config_window_registers.get("callback_set_send_message_format", None)
self.view_variable.CALLBACK_SET_SEND_MESSAGE_FORMAT_WITH_T=config_window_registers.get("callback_set_send_message_format_with_t", None)
self.view_variable.CALLBACK_SET_RECEIVED_MESSAGE_FORMAT=config_window_registers.get("callback_set_received_message_format", None)
self.view_variable.CALLBACK_SET_RECEIVED_MESSAGE_FORMAT_WITH_T=config_window_registers.get("callback_set_received_message_format_with_t", None)
# Speaker2Chatbox----------------
self.view_variable.CALLBACK_SET_ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC = config_window_registers.get("callback_set_enable_send_received_message_to_vrc", None)
self.view_variable.CALLBACK_SET_ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC=config_window_registers.get("callback_set_enable_send_received_message_to_vrc", None)
# Speaker2Chatbox----------------
# Advanced Settings Tab
self.view_variable.CALLBACK_SET_OSC_IP_ADDRESS = config_window_registers.get("callback_set_osc_ip_address", None)
self.view_variable.CALLBACK_SET_OSC_PORT = config_window_registers.get("callback_set_osc_port", None)
self.view_variable.CALLBACK_SET_OSC_IP_ADDRESS=config_window_registers.get("callback_set_osc_ip_address", None)
self.view_variable.CALLBACK_SET_OSC_PORT=config_window_registers.get("callback_set_osc_port", None)
# The initial processing after registration.
if config.IS_CONFIG_WINDOW_COMPACT_MODE is True:
@@ -678,6 +706,11 @@ class View():
)
self.replaceMicThresholdCheckButton_Disabled()
if config.USE_WHISPER_FEATURE is True:
self.openWhisperWeightTypeWidget()
else:
self.closeWhisperWeightTypeWidget()
if config.ENABLE_SPEAKER2CHATBOX is False:
vrct_gui._changeConfigWindowWidgetsStatus(
status="disabled",
@@ -882,8 +915,8 @@ class View():
@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"),
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"),
}
def useTranslationFeatureProcess(self, state:str):
@@ -919,6 +952,24 @@ class View():
vrct_gui.update()
vrct_gui.config_window.lift()
@staticmethod
def getSelectableWhisperWeightTypeDict():
def callI18n(model_name, capacity, is_recommended=False):
if is_recommended is True:
return i18n.t("config_window.whisper_weight_type.recommended_model_template", model_name=model_name, capacity=capacity)
else:
return i18n.t("config_window.whisper_weight_type.model_template", model_name=model_name, capacity=capacity)
DICT_DATA = config.SELECTABLE_WHISPER_WEIGHT_TYPE_DICT
return {
DICT_DATA["tiny"]: callI18n("tiny", "74.5MB"),
DICT_DATA["base"]: callI18n("base", "141MB", True),
DICT_DATA["small"]: callI18n("small", "463MB"),
DICT_DATA["medium"]: callI18n("medium", "1.42GB"),
DICT_DATA["large-v1"]: callI18n("large-v1", "2.87GB"),
DICT_DATA["large-v2"]: callI18n("large-v2", "2.87GB"),
DICT_DATA["large-v3"]: callI18n("large-v3", "2.87GB"),
}
# Open Webpage Functions
def openWebPage_Booth(self):
@@ -929,6 +980,10 @@ class View():
self.openWebPage(config.DOCUMENTS_URL)
self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.opened_web_page_vrct_documents"))
def openWebPage_DeepL_Auth_Key(self):
self.openWebPage(config.DEEPL_AUTH_KEY_PAGE_URL)
# Widget Control
# Common
@@ -1014,7 +1069,8 @@ class View():
self.restart_required_configs_pre_data.ui_scaling == config.UI_SCALING and
self.restart_required_configs_pre_data.font_family == config.FONT_FAMILY and
self.restart_required_configs_pre_data.ui_language == config.UI_LANGUAGE and
self.restart_required_configs_pre_data.is_reset_button_displayed_for_translation == config.IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION
self.restart_required_configs_pre_data.is_reset_button_displayed_for_translation == config.IS_RESET_BUTTON_DISPLAYED_FOR_TRANSLATION and
self.restart_required_configs_pre_data.is_reset_button_displayed_for_whisper == config.IS_RESET_BUTTON_DISPLAYED_FOR_WHISPER
)
if locale is None:
@@ -1069,7 +1125,7 @@ class View():
self.view_variable.VAR_CTRANSLATE2_WEIGHT_TYPE.set(self.getSelectableCtranslate2WeightTypeDict()[selected_weight_type])
def setLatestCTranslate2WeightType(self):
selected_weight_type = self.getSelectableCtranslate2WeightTypeDict()[config.WEIGHT_TYPE]
selected_weight_type = self.getSelectableCtranslate2WeightTypeDict()[config.CTRANSLATE2_WEIGHT_TYPE]
self.view_variable.VAR_CTRANSLATE2_WEIGHT_TYPE.set(selected_weight_type)
@@ -1082,6 +1138,23 @@ class View():
vrct_gui.config_window.sb__ctranslate2_weight_type.grid_remove()
def openWhisperWeightTypeWidget(self):
vrct_gui.config_window.sb__use_whisper_feature.grid()
vrct_gui.config_window.sb__whisper_weight_type.grid()
def closeWhisperWeightTypeWidget(self):
vrct_gui.config_window.sb__use_whisper_feature.grid()
vrct_gui.config_window.sb__whisper_weight_type.grid_remove()
def updateSelectedWhisperWeightType(self, selected_weight_type:str):
self.view_variable.VAR_WHISPER_WEIGHT_TYPE.set(self.getSelectableWhisperWeightTypeDict()[selected_weight_type])
def setLatestCTranslate2WeightType(self):
selected_weight_type = self.getSelectableWhisperWeightTypeDict()[config.WHISPER_WEIGHT_TYPE]
self.view_variable.VAR_WHISPER_WEIGHT_TYPE.set(selected_weight_type)
def openMicEnergyThresholdWidget(self):
self.view_variable.VAR_LABEL_MIC_DYNAMIC_ENERGY_THRESHOLD.set(i18n.t("config_window.mic_dynamic_energy_threshold.label_for_manual"))
self.view_variable.VAR_DESC_MIC_DYNAMIC_ENERGY_THRESHOLD.set(i18n.t("config_window.mic_dynamic_energy_threshold.desc_for_manual"))
@@ -1637,6 +1710,13 @@ class View():
def clearMessageBox(self):
self._clearTextBox(vrct_gui.entry_message_box)
@staticmethod
def insertMessageBox(text):
vrct_gui.entry_message_box.insert("end", text)
def replaceMessageBox(self, text):
self.clearMessageBox()
self.insertMessageBox(text)

View File

@@ -7,7 +7,7 @@ from ._createSettingBoxContainer import _createSettingBoxContainer
from .setting_box_containers.setting_box_appearance import createSettingBox_Appearance
from .setting_box_containers.setting_box_transcription import createSettingBox_Mic, createSettingBox_Speaker
from .setting_box_containers.setting_box_transcription import createSettingBox_Mic, createSettingBox_Speaker, createSettingBox_InternalModel
from .setting_box_containers.setting_box_others import createSettingBox_Others, createSettingBox_Others_SendMessageFormats, createSettingBox_Others_ReceivedMessageFormats, createSettingBox_Others_Additional
from .setting_box_containers.setting_box_advanced_settings import createSettingBox_AdvancedSettings
from .setting_box_containers.setting_box_translation import createSettingBox_Translation
@@ -94,6 +94,10 @@ def createSideMenuAndSettingsBoxContainers(config_window, settings, view_variabl
"var_section_title": view_variable.VAR_SECOND_TITLE_TRANSCRIPTION_SPEAKER,
"setting_box": createSettingBox_Speaker
},
{
"var_section_title": view_variable.VAR_SECOND_TITLE_TRANSCRIPTION_INTERNAL_MODEL,
"setting_box": createSettingBox_InternalModel
},
]
},
},

View File

@@ -5,7 +5,7 @@ from typing import Union
from customtkinter import CTkFont, CTkFrame, CTkLabel, CTkEntry, CTkSlider, CTkSwitch, CTkCheckBox, CTkProgressBar, CTkImage, CTkRadioButton
from CTkToolTip import *
from vrct_gui.ui_utils import createButtonWithImage, getLatestWidth, createOptionMenuBox, getLatestHeight, bindButtonFunctionAndColor, bindEnterAndLeaveFunction, bindButtonReleaseFunction, bindButtonPressFunction
from vrct_gui.ui_utils import createButtonWithImage, getLatestWidth, createOptionMenuBox, getLatestHeight, bindButtonFunctionAndColor, bindEnterAndLeaveFunction, bindButtonReleaseFunction, bindButtonPressFunction, createLabelButton
from vrct_gui import vrct_gui
from utils import isEven, callFunctionIfCallable
@@ -615,6 +615,75 @@ class _SettingBoxGenerator():
return setting_box_frame
def createSettingBoxEntry_AuthKey(self,
for_var_label_text, for_var_desc_text,
entry_attr_name,
entry_width,
entry_textvariable,
entry_bind__Any_KeyRelease,
entry_bind__FocusOut=None,
open_authkey_page_command=None,
open_authkey_text_variable=None,
image_file=None,
):
(setting_box_frame, setting_box_item_frame) = self._createSettingBoxFrame(entry_attr_name, for_var_label_text, for_var_desc_text)
all_wrapper = CTkFrame(setting_box_item_frame, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0)
all_wrapper.grid(row=1, column=0, sticky="ew")
all_wrapper.grid_columnconfigure(0, weight=1)
def adjusted_command__for_entry_bind__Any_KeyRelease(e):
entry_bind__Any_KeyRelease(e.widget.get())
entry_widget = CTkEntry(
all_wrapper,
text_color=self.settings.ctm.SB__ENTRY_TEXT_COLOR,
fg_color=self.settings.ctm.SB__ENTRY_BG_COLOR,
border_color=self.settings.ctm.SB__ENTRY_BORDER_COLOR,
width=entry_width,
height=self.settings.uism.SB__PROGRESSBAR_X_SLIDER__ENTRY_HEIGHT,
textvariable=entry_textvariable,
font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__ENTRY_FONT_SIZE, weight="normal"),
)
entry_widget.bind("<Any-KeyRelease>", adjusted_command__for_entry_bind__Any_KeyRelease)
setattr(self.config_window, entry_attr_name, entry_widget)
entry_widget.grid(row=0, column=SETTING_BOX_COLUMN, sticky="e")
if entry_bind__FocusOut is not None:
entry_widget.bind("<FocusOut>", entry_bind__FocusOut, "+")
(open_page_button, label_button_label_widget, label_button_img_widget) = createLabelButton(
parent_widget=all_wrapper,
label_button_bg_color=self.settings.ctm.SB__BUTTON_COLOR,
label_button_hovered_bg_color=self.settings.ctm.SB__BUTTON_HOVERED_COLOR,
label_button_clicked_bg_color=self.settings.ctm.SB__BUTTON_CLICKED_COLOR,
label_button_ipadx=self.settings.uism.SB__AUTHKEY_WEBPAGE_BUTTON_IPADX,
label_button_ipady=self.settings.uism.SB__AUTHKEY_WEBPAGE_BUTTON_IPADY,
variable=open_authkey_text_variable,
font_family=self.settings.FONT_FAMILY,
font_size=self.settings.uism.SB__AUTHKEY_WEBPAGE_BUTTON_LABEL_FONT_SIZE,
text_color=self.settings.ctm.LABELS_TEXT_COLOR,
label_button_clicked_command=open_authkey_page_command,
label_button_position="center",
image_file=image_file,
image_size=self.settings.uism.SB__AUTHKEY_WEBPAGE_BUTTON_IMG_SIZE,
label_button_padx_between_img=self.settings.uism.SB__AUTHKEY_WEBPAGE_PADX_BETWEEN_LABEL_AND_ICON,
)
open_page_button.grid(row=1, column=SETTING_BOX_COLUMN, pady=(self.settings.uism.SB__AUTHKEY_WEBPAGE_BUTTON_TOP_PADY,0))
return setting_box_frame

View File

@@ -1,2 +1,3 @@
from .createSettingBox_Mic import createSettingBox_Mic
from .createSettingBox_Speaker import createSettingBox_Speaker
from .createSettingBox_Speaker import createSettingBox_Speaker
from .createSettingBox_InternalModel import createSettingBox_InternalModel

View File

@@ -0,0 +1,37 @@
from utils import callFunctionIfCallable
from .._SettingBoxGenerator import _SettingBoxGenerator
def createSettingBox_InternalModel(setting_box_wrapper, config_window, settings, view_variable):
sbg = _SettingBoxGenerator(setting_box_wrapper, config_window, settings, view_variable)
createSettingBoxSwitch = sbg.createSettingBoxSwitch
createSettingBoxDropdownMenu = sbg.createSettingBoxDropdownMenu
def switchUseWhisperFeatureCallback(switch_widget):
callFunctionIfCallable(view_variable.CALLBACK_SET_USE_WHISPER_FEATURE, switch_widget.get())
def optionmenuWhisperWeightTypeCallback(value):
callFunctionIfCallable(view_variable.CALLBACK_SET_WHISPER_WEIGHT_TYPE, value)
row=0
config_window.sb__use_whisper_feature = createSettingBoxSwitch(
for_var_label_text=view_variable.VAR_LABEL_USE_WHISPER_FEATURE,
for_var_desc_text=view_variable.VAR_DESC_USE_WHISPER_FEATURE,
switch_attr_name="sb__switch_use_whisper_feature",
command=lambda: switchUseWhisperFeatureCallback(config_window.sb__switch_use_whisper_feature),
variable=view_variable.VAR_USE_WHISPER_FEATURE
)
config_window.sb__use_whisper_feature.grid(row=row, pady=0)
row+=1
config_window.sb__whisper_weight_type = createSettingBoxDropdownMenu(
for_var_label_text=view_variable.VAR_LABEL_WHISPER_WEIGHT_TYPE,
for_var_desc_text=view_variable.VAR_DESC_WHISPER_WEIGHT_TYPE,
optionmenu_attr_name="sb__optionmenu_whisper_weight_type",
dropdown_menu_values=view_variable.DICT_WHISPER_WEIGHT_TYPE,
command=lambda value: optionmenuWhisperWeightTypeCallback(value),
variable=view_variable.VAR_WHISPER_WEIGHT_TYPE,
)
config_window.sb__whisper_weight_type.grid(row=row, pady=0)
row+=1

View File

@@ -6,7 +6,7 @@ def createSettingBox_Translation(setting_box_wrapper, config_window, settings, v
sbg = _SettingBoxGenerator(setting_box_wrapper, config_window, settings, view_variable)
createSettingBoxSwitch = sbg.createSettingBoxSwitch
createSettingBoxDropdownMenu = sbg.createSettingBoxDropdownMenu
createSettingBoxEntry = sbg.createSettingBoxEntry
createSettingBoxEntry_AuthKey = sbg.createSettingBoxEntry_AuthKey
def switchUseTranslationFeatureCallback(switch_widget):
callFunctionIfCallable(view_variable.CALLBACK_SET_USE_TRANSLATION_FEATURE, switch_widget.get())
@@ -41,13 +41,16 @@ def createSettingBox_Translation(setting_box_wrapper, config_window, settings, v
row+=1
config_window.sb__deepl_auth_key = createSettingBoxEntry(
config_window.sb__deepl_auth_key = createSettingBoxEntry_AuthKey(
for_var_label_text=view_variable.VAR_LABEL_DEEPL_AUTH_KEY,
for_var_desc_text=view_variable.VAR_DESC_DEEPL_AUTH_KEY,
entry_attr_name="sb__entry_deepl_auth_key",
entry_width=settings.uism.RESPONSIVE_UI_SIZE_INT_300,
entry_bind__Any_KeyRelease=lambda value: deeplAuthKeyCallback(value),
entry_textvariable=view_variable.VAR_DEEPL_AUTH_KEY,
open_authkey_page_command=lambda _e: callFunctionIfCallable(view_variable.CALLBACK_OPEN_WEBPAGE_DEEPL_AUTH_KEY),
open_authkey_text_variable=view_variable.VAR_OPEN_DEEPL_WEB_PAGE,
image_file=settings.image_file.LINK_ICON
)
config_window.sb__deepl_auth_key.grid(row=row, pady=0)
row+=1

View File

@@ -19,6 +19,9 @@ def createEntryMessageBox(settings, main_window, view_variable):
border_width=settings.uism.TEXTBOX_ENTRY_BORDER_SIZE,
height=0,
font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.TEXTBOX_ENTRY_FONT_SIZE, weight="normal"),
undo=True,
autoseparators=True,
maxundo=64,
)
main_window.entry_message_box.grid(row=0, column=0, padx=settings.uism.TEXTBOX_ENTRY_PADX, pady=settings.uism.TEXTBOX_ENTRY_PADY, sticky="nsew")
@@ -28,6 +31,14 @@ def createEntryMessageBox(settings, main_window, view_variable):
"Delete", "Select", "Up", "Down", "Next", "End", "Print",
"Prior","Insert","Home", "Left", "Clear", "Right", "Linefeed"
]
if e.keysym == "Up":
callFunctionIfCallable(view_variable.CALLBACK_MESSAGE_BOX_BIND_KEYSYM__UP)
return "break"
if e.keysym == "Down":
callFunctionIfCallable(view_variable.CALLBACK_MESSAGE_BOX_BIND_KEYSYM__DOWN)
return "break"
if e.keysym != "??":
if len(e.char) != 0 and e.keysym in BREAK_KEYSYM_LIST:
main_window.entry_message_box.insert("end", e.char)
@@ -35,6 +46,15 @@ def createEntryMessageBox(settings, main_window, view_variable):
main_window.entry_message_box.bind("<Any-KeyPress>", messageBoxAnyKeyPress)
def messageBoxRedoFunction(_e):
try:
main_window.entry_message_box.edit_redo()
except:
pass
main_window.entry_message_box.bind("<Control-Shift-Z>", messageBoxRedoFunction, "+")
main_window.entry_message_box.bind("<Control-Y>", messageBoxRedoFunction, "+")
main_window.main_send_message_button_container = CTkFrame(main_window.main_entry_message_container, corner_radius=settings.uism.SEND_MESSAGE_BUTTON_CORNER_RADIUS, fg_color=settings.ctm.SEND_MESSAGE_BUTTON_BG_COLOR, width=0, height=0)
main_window.main_send_message_button_container.grid(row=0, column=1, padx=(0, settings.uism.TEXTBOX_ENTRY_PADX), pady=settings.uism.TEXTBOX_ENTRY_PADY, sticky="nsew")

View File

@@ -330,6 +330,7 @@ def _darkTheme(base_color):
REDO_ICON = getImageFileFromUiUtils("redo_icon_white.png"),
SWAP_ICON = getImageFileFromUiUtils("swap_icon_white.png"),
FOLDER_OPEN_ICON = getImageFileFromUiUtils("folder_open_icon_white.png"),
LINK_ICON = getImageFileFromUiUtils("link_icon_white.png"),
),
)

View File

@@ -324,6 +324,7 @@ def _lightTheme(base_color):
REDO_ICON = getImageFileFromUiUtils("redo_icon_black.png"),
SWAP_ICON = getImageFileFromUiUtils("swap_icon_black.png"),
FOLDER_OPEN_ICON = getImageFileFromUiUtils("folder_open_icon_black.png"),
LINK_ICON = getImageFileFromUiUtils("link_icon_black.png"),
),
)

View File

@@ -349,6 +349,13 @@ class UiScalingManager():
self.config_window.SB__MESSAGE_FORMAT__ENTRIES_BOTTOM_PADY = (0, self._calculateUiSize(14))
self.config_window.SB__AUTHKEY_WEBPAGE_BUTTON_IPADX = self._calculateUiSize(12)
self.config_window.SB__AUTHKEY_WEBPAGE_BUTTON_IPADY = self._calculateUiSize(6)
self.config_window.SB__AUTHKEY_WEBPAGE_BUTTON_LABEL_FONT_SIZE = self._calculateUiSize(12)
self.config_window.SB__AUTHKEY_WEBPAGE_BUTTON_IMG_SIZE = self.dupTuple(self._calculateUiSize(12))
self.config_window.SB__AUTHKEY_WEBPAGE_PADX_BETWEEN_LABEL_AND_ICON = self._calculateUiSize(10)
self.config_window.SB__AUTHKEY_WEBPAGE_BUTTON_TOP_PADY = self._calculateUiSize(10)
self.config_window.SB__BUTTON_IPADXY = self._calculateUiSize(16)
self.config_window.SB__BUTTON_ICON_SIZE = self._calculateUiSize(24)

View File

@@ -168,7 +168,27 @@ def createButtonWithImage(parent_widget, button_image_size, button_ipadxy, butto
return button_wrapper
def createLabelButton(parent_widget, label_button_bg_color, label_button_hovered_bg_color, label_button_clicked_bg_color, label_button_ipadx, label_button_ipady, variable, font_family, font_size, text_color, label_button_clicked_command, label_button_position=None, label_button_padx_between_img=0, label_button_min_height=None, label_button_min_width=None):
def createLabelButton(
parent_widget,
label_button_bg_color,
label_button_hovered_bg_color,
label_button_clicked_bg_color,
label_button_ipadx,
label_button_ipady,
variable,
font_family,
font_size,
text_color,
label_button_clicked_command,
label_button_position=None,
label_button_padx_between_img=0,
image_file=None,
image_size=None,
image_widget_attr_name=None,
label_button_min_height=None,
label_button_min_width=None,
setattr_widget=None,
):
label_button_box = CTkFrame(parent_widget, corner_radius=6, fg_color=label_button_bg_color, cursor="hand2")
@@ -181,7 +201,7 @@ def createLabelButton(parent_widget, label_button_bg_color, label_button_hovered
label_button_box.grid_columnconfigure(0, minsize=label_button_min_width)
label_button_label_wrapper = CTkFrame(label_button_box, corner_radius=0, fg_color=label_button_bg_color)
label_button_label_wrapper.grid(row=0, column=0, padx=label_button_ipadx, pady=label_button_ipady, sticky="ew")
label_button_label_wrapper.grid(row=0, column=0, padx=label_button_ipadx, pady=label_button_ipady)
LABEL_COLUMN=0
if label_button_position == "center":
@@ -198,25 +218,46 @@ def createLabelButton(parent_widget, label_button_bg_color, label_button_hovered
label_button_label_widget.grid(row=0, column=LABEL_COLUMN, padx=(0, label_button_padx_between_img))
bindEnterAndLeaveColor([label_button_label_wrapper, label_button_box, label_button_label_widget], label_button_hovered_bg_color, label_button_bg_color)
bindButtonPressColor([label_button_label_wrapper, label_button_box, label_button_label_widget], label_button_clicked_bg_color, label_button_hovered_bg_color)
register_widgets = [label_button_label_wrapper, label_button_box, label_button_label_widget]
if image_file is not None:
label_button_label_wrapper.grid_columnconfigure((0,3), weight=1)
label_button_img_widget = CTkLabel(
label_button_label_wrapper,
text=None,
corner_radius=0,
height=0,
image=CTkImage(image_file, size=image_size)
)
if image_widget_attr_name is not None:
setattr(setattr_widget, image_widget_attr_name, label_button_img_widget)
label_button_img_widget.grid(row=0, column=LABEL_COLUMN+1)
register_widgets.append(label_button_img_widget)
bindEnterAndLeaveColor(register_widgets, label_button_hovered_bg_color, label_button_bg_color)
bindButtonPressColor(register_widgets, label_button_clicked_bg_color, label_button_hovered_bg_color)
bindButtonReleaseFunction([label_button_label_wrapper, label_button_box, label_button_label_widget], label_button_clicked_command)
def bindEventFromWidgets():
bindButtonReleaseFunction([label_button_label_wrapper, label_button_box, label_button_label_widget], label_button_clicked_command)
bindEventFromWidgets()
bindButtonReleaseFunction(register_widgets, label_button_clicked_command)
def unbindEventFromWidgets():
unbindEnterLEaveButtonPressButtonReleaseFunction([label_button_label_wrapper, label_button_box, label_button_label_widget])
unbindEnterLEaveButtonPressButtonReleaseFunction(register_widgets)
bindEventFromWidgets()
label_button_box.unbindFunction = unbindEventFromWidgets
label_button_box.bindFunction = bindEventFromWidgets
if image_file is not None:
return (label_button_box, label_button_label_widget, label_button_img_widget)
else:
return (label_button_box, label_button_label_widget)
return (label_button_box, label_button_label_widget)