[Update] Refactor message formatting and add validation for message structure
This commit is contained in:
@@ -11,7 +11,7 @@ from models.translation.translation_languages import translation_lang
|
|||||||
from models.translation.translation_utils import ctranslate2_weights
|
from models.translation.translation_utils import ctranslate2_weights
|
||||||
from models.transcription.transcription_languages import transcription_lang
|
from models.transcription.transcription_languages import transcription_lang
|
||||||
from models.transcription.transcription_whisper import _MODELS as whisper_models
|
from models.transcription.transcription_whisper import _MODELS as whisper_models
|
||||||
from utils import errorLogging
|
from utils import errorLogging, validateDictStructure
|
||||||
|
|
||||||
json_serializable_vars = {}
|
json_serializable_vars = {}
|
||||||
def json_serializable(var_name):
|
def json_serializable(var_name):
|
||||||
@@ -139,21 +139,42 @@ class Config:
|
|||||||
def SEND_MESSAGE_BUTTON_TYPE_LIST(self):
|
def SEND_MESSAGE_BUTTON_TYPE_LIST(self):
|
||||||
return self._SEND_MESSAGE_BUTTON_TYPE_LIST
|
return self._SEND_MESSAGE_BUTTON_TYPE_LIST
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def SEND_MESSAGE_FORMAT(self):
|
@json_serializable('SEND_MESSAGE_FORMAT_PARTS')
|
||||||
return self._SEND_MESSAGE_FORMAT
|
def SEND_MESSAGE_FORMAT_PARTS(self):
|
||||||
|
return self._SEND_MESSAGE_FORMAT_PARTS
|
||||||
|
|
||||||
|
@SEND_MESSAGE_FORMAT_PARTS.setter
|
||||||
|
def SEND_MESSAGE_FORMAT_PARTS(self, value):
|
||||||
|
if isinstance(value, dict):
|
||||||
|
valid_parts = {
|
||||||
|
"message": {"prefix": str, "suffix": str},
|
||||||
|
"separator": str,
|
||||||
|
"translation": {"prefix": str, "separator": str, "suffix": str},
|
||||||
|
"translation_first": bool
|
||||||
|
}
|
||||||
|
|
||||||
|
if validateDictStructure(value, valid_parts):
|
||||||
|
self._SEND_MESSAGE_FORMAT_PARTS = value
|
||||||
|
self.saveConfig(inspect.currentframe().f_code.co_name, value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def SEND_MESSAGE_FORMAT_WITH_T(self):
|
@json_serializable('RECEIVED_MESSAGE_FORMAT_PARTS')
|
||||||
return self._SEND_MESSAGE_FORMAT_WITH_T
|
def RECEIVED_MESSAGE_FORMAT_PARTS(self):
|
||||||
|
return self._RECEIVED_MESSAGE_FORMAT_PARTS
|
||||||
|
|
||||||
@property
|
@RECEIVED_MESSAGE_FORMAT_PARTS.setter
|
||||||
def RECEIVED_MESSAGE_FORMAT(self):
|
def RECEIVED_MESSAGE_FORMAT_PARTS(self, value):
|
||||||
return self._RECEIVED_MESSAGE_FORMAT
|
if isinstance(value, dict):
|
||||||
|
valid_parts = {
|
||||||
@property
|
"message": {"prefix": str, "suffix": str},
|
||||||
def RECEIVED_MESSAGE_FORMAT_WITH_T(self):
|
"separator": str,
|
||||||
return self._RECEIVED_MESSAGE_FORMAT_WITH_T
|
"translation": {"prefix": str, "separator": str, "suffix": str},
|
||||||
|
"translation_first": bool
|
||||||
|
}
|
||||||
|
if validateDictStructure(value, valid_parts):
|
||||||
|
self._RECEIVED_MESSAGE_FORMAT_PARTS = value
|
||||||
|
self.saveConfig(inspect.currentframe().f_code.co_name, value)
|
||||||
|
|
||||||
# Read Write
|
# Read Write
|
||||||
@property
|
@property
|
||||||
@@ -997,7 +1018,6 @@ class Config:
|
|||||||
self._WEBSOCKET_PORT = value
|
self._WEBSOCKET_PORT = value
|
||||||
self.saveConfig(inspect.currentframe().f_code.co_name, value)
|
self.saveConfig(inspect.currentframe().f_code.co_name, value)
|
||||||
|
|
||||||
|
|
||||||
def init_config(self):
|
def init_config(self):
|
||||||
# Read Only
|
# Read Only
|
||||||
self._VERSION = "3.2.1"
|
self._VERSION = "3.2.1"
|
||||||
@@ -1032,10 +1052,32 @@ class Config:
|
|||||||
self._SELECTABLE_COMPUTE_DEVICE_LIST.append({"device":"cuda", "device_index": i, "device_name": torch.cuda.get_device_name(i)})
|
self._SELECTABLE_COMPUTE_DEVICE_LIST.append({"device":"cuda", "device_index": i, "device_name": torch.cuda.get_device_name(i)})
|
||||||
self._SELECTABLE_COMPUTE_DEVICE_LIST.append({"device":"cpu", "device_index": 0, "device_name": "cpu"})
|
self._SELECTABLE_COMPUTE_DEVICE_LIST.append({"device":"cpu", "device_index": 0, "device_name": "cpu"})
|
||||||
self._SEND_MESSAGE_BUTTON_TYPE_LIST = ["show", "hide", "show_and_disable_enter_key"]
|
self._SEND_MESSAGE_BUTTON_TYPE_LIST = ["show", "hide", "show_and_disable_enter_key"]
|
||||||
self._SEND_MESSAGE_FORMAT = "[message]"
|
self._SEND_MESSAGE_FORMAT_PARTS = {
|
||||||
self._SEND_MESSAGE_FORMAT_WITH_T = "[message]\n[translation]"
|
"message": {
|
||||||
self._RECEIVED_MESSAGE_FORMAT = "[message]"
|
"prefix": "",
|
||||||
self._RECEIVED_MESSAGE_FORMAT_WITH_T = "[message]\n[translation]"
|
"suffix": ""
|
||||||
|
},
|
||||||
|
"separator": "\n",
|
||||||
|
"translation": {
|
||||||
|
"prefix": "",
|
||||||
|
"separator": "\n",
|
||||||
|
"suffix": ""
|
||||||
|
},
|
||||||
|
"translation_first": False,
|
||||||
|
}
|
||||||
|
self._RECEIVED_MESSAGE_FORMAT_PARTS = {
|
||||||
|
"message": {
|
||||||
|
"prefix": "",
|
||||||
|
"suffix": ""
|
||||||
|
},
|
||||||
|
"separator": "\n",
|
||||||
|
"translation": {
|
||||||
|
"prefix": "",
|
||||||
|
"separator": "\n",
|
||||||
|
"suffix": ""
|
||||||
|
},
|
||||||
|
"translation_first": False,
|
||||||
|
}
|
||||||
|
|
||||||
# Read Write
|
# Read Write
|
||||||
self._ENABLE_TRANSLATION = False
|
self._ENABLE_TRANSLATION = False
|
||||||
|
|||||||
@@ -306,11 +306,11 @@ class Controller:
|
|||||||
if config.SEND_MESSAGE_TO_VRC is True:
|
if config.SEND_MESSAGE_TO_VRC is True:
|
||||||
if config.SEND_ONLY_TRANSLATED_MESSAGES is True:
|
if config.SEND_ONLY_TRANSLATED_MESSAGES is True:
|
||||||
if config.ENABLE_TRANSLATION is False:
|
if config.ENABLE_TRANSLATION is False:
|
||||||
osc_message = self.messageFormatter("SEND", "", [message])
|
osc_message = self.messageFormatter("SEND", [], message)
|
||||||
else:
|
else:
|
||||||
osc_message = self.messageFormatter("SEND", "", translation)
|
osc_message = self.messageFormatter("SEND", translation, "")
|
||||||
else:
|
else:
|
||||||
osc_message = self.messageFormatter("SEND", translation, [message])
|
osc_message = self.messageFormatter("SEND", translation, message)
|
||||||
model.oscSendMessage(osc_message)
|
model.oscSendMessage(osc_message)
|
||||||
|
|
||||||
self.run(
|
self.run(
|
||||||
@@ -470,7 +470,13 @@ class Controller:
|
|||||||
model.updateOverlayLargeLog(overlay_image)
|
model.updateOverlayLargeLog(overlay_image)
|
||||||
|
|
||||||
if config.SEND_RECEIVED_MESSAGE_TO_VRC is True:
|
if config.SEND_RECEIVED_MESSAGE_TO_VRC is True:
|
||||||
osc_message = self.messageFormatter("RECEIVED", translation, [message])
|
if config.SEND_ONLY_TRANSLATED_MESSAGES is True:
|
||||||
|
if config.ENABLE_TRANSLATION is False:
|
||||||
|
osc_message = self.messageFormatter("RECEIVED", [], message)
|
||||||
|
else:
|
||||||
|
osc_message = self.messageFormatter("RECEIVED", translation, "")
|
||||||
|
else:
|
||||||
|
osc_message = self.messageFormatter("RECEIVED", translation, message)
|
||||||
model.oscSendMessage(osc_message)
|
model.oscSendMessage(osc_message)
|
||||||
|
|
||||||
# update textbox message log (Received)
|
# update textbox message log (Received)
|
||||||
@@ -573,11 +579,11 @@ class Controller:
|
|||||||
if config.SEND_MESSAGE_TO_VRC is True:
|
if config.SEND_MESSAGE_TO_VRC is True:
|
||||||
if config.SEND_ONLY_TRANSLATED_MESSAGES is True:
|
if config.SEND_ONLY_TRANSLATED_MESSAGES is True:
|
||||||
if config.ENABLE_TRANSLATION is False:
|
if config.ENABLE_TRANSLATION is False:
|
||||||
osc_message = self.messageFormatter("SEND", "", [message])
|
osc_message = self.messageFormatter("SEND", [], message)
|
||||||
else:
|
else:
|
||||||
osc_message = self.messageFormatter("SEND", "", translation)
|
osc_message = self.messageFormatter("SEND", translation, "")
|
||||||
else:
|
else:
|
||||||
osc_message = self.messageFormatter("SEND", translation, [message])
|
osc_message = self.messageFormatter("SEND", translation, message)
|
||||||
model.oscSendMessage(osc_message)
|
model.oscSendMessage(osc_message)
|
||||||
|
|
||||||
if config.OVERLAY_LARGE_LOG is True:
|
if config.OVERLAY_LARGE_LOG is True:
|
||||||
@@ -1450,6 +1456,24 @@ class Controller:
|
|||||||
config.WHISPER_WEIGHT_TYPE = str(data)
|
config.WHISPER_WEIGHT_TYPE = str(data)
|
||||||
return {"status":200, "result": config.WHISPER_WEIGHT_TYPE}
|
return {"status":200, "result": config.WHISPER_WEIGHT_TYPE}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getSendMessageFormatParts(*args, **kwargs) -> dict:
|
||||||
|
return {"status":200, "result":config.SEND_MESSAGE_FORMAT_PARTS}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def setSendMessageFormatParts(data, *args, **kwargs) -> dict:
|
||||||
|
config.SEND_MESSAGE_FORMAT_PARTS = str(data)
|
||||||
|
return {"status":200, "result":config.SEND_MESSAGE_FORMAT_PARTS}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getReceivedMessageFormatParts(*args, **kwargs) -> dict:
|
||||||
|
return {"status":200, "result":config.RECEIVED_MESSAGE_FORMAT_PARTS}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def setReceivedMessageFormatParts(data, *args, **kwargs) -> dict:
|
||||||
|
config.RECEIVED_MESSAGE_FORMAT_PARTS = str(data)
|
||||||
|
return {"status":200, "result":config.RECEIVED_MESSAGE_FORMAT_PARTS}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getAutoClearMessageBox(*args, **kwargs) -> dict:
|
def getAutoClearMessageBox(*args, **kwargs) -> dict:
|
||||||
return {"status":200, "result":config.AUTO_CLEAR_MESSAGE_BOX}
|
return {"status":200, "result":config.AUTO_CLEAR_MESSAGE_BOX}
|
||||||
@@ -1769,21 +1793,27 @@ class Controller:
|
|||||||
return {"status":200, "result":True}
|
return {"status":200, "result":True}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def messageFormatter(format_type:str, translation:list, message:list) -> str:
|
def messageFormatter(format_type:str, translation:list, message:str) -> str:
|
||||||
if format_type == "RECEIVED":
|
if format_type == "RECEIVED":
|
||||||
FORMAT_WITH_T = config.RECEIVED_MESSAGE_FORMAT_WITH_T
|
format_parts = config.RECEIVED_MESSAGE_FORMAT_PARTS
|
||||||
FORMAT = config.RECEIVED_MESSAGE_FORMAT
|
|
||||||
elif format_type == "SEND":
|
elif format_type == "SEND":
|
||||||
FORMAT_WITH_T = config.SEND_MESSAGE_FORMAT_WITH_T
|
format_parts = config.SEND_MESSAGE_FORMAT_PARTS
|
||||||
FORMAT = config.SEND_MESSAGE_FORMAT
|
|
||||||
else:
|
else:
|
||||||
raise ValueError("format_type is not found", format_type)
|
raise ValueError("format_type is not found", format_type)
|
||||||
|
|
||||||
if len(translation) > 0:
|
message_part = format_parts["message"]["prefix"] + message + format_parts["message"]["suffix"]
|
||||||
osc_message = FORMAT_WITH_T.replace("[message]", "\n".join(message))
|
translation_part = format_parts["translation"]["prefix"] + format_parts["translation"]["separator"].join(translation) + format_parts["translation"]["suffix"]
|
||||||
osc_message = osc_message.replace("[translation]", "\n".join(translation))
|
|
||||||
|
if len(translation) > 0 and message != "":
|
||||||
|
# 翻訳とメッセージの順序を決定
|
||||||
|
if format_parts["translation_first"]:
|
||||||
|
osc_message = translation_part + format_parts["separator"] + message_part
|
||||||
|
else:
|
||||||
|
osc_message = message_part + format_parts["separator"] + translation_part
|
||||||
|
elif len(translation) > 0 and message == "":
|
||||||
|
osc_message = translation_part
|
||||||
else:
|
else:
|
||||||
osc_message = FORMAT.replace("[message]", "\n".join(message))
|
osc_message = message_part
|
||||||
return osc_message
|
return osc_message
|
||||||
|
|
||||||
def changeToCTranslate2Process(self) -> None:
|
def changeToCTranslate2Process(self) -> None:
|
||||||
|
|||||||
@@ -285,6 +285,11 @@ mapping = {
|
|||||||
"/set/disable/overlay_show_only_translated_messages": {"status": True, "variable":controller.setDisableOverlayShowOnlyTranslatedMessages},
|
"/set/disable/overlay_show_only_translated_messages": {"status": True, "variable":controller.setDisableOverlayShowOnlyTranslatedMessages},
|
||||||
|
|
||||||
# Others
|
# Others
|
||||||
|
"/get/data/send_message_format_parts": {"status": True, "variable":controller.getSendMessageFormatParts},
|
||||||
|
"/set/data/send_message_format_parts": {"status": True, "variable":controller.setSendMessageFormatParts},
|
||||||
|
"/get/data/received_message_format_parts": {"status": True, "variable":controller.getReceivedMessageFormatParts},
|
||||||
|
"/set/data/received_message_format_parts": {"status": True, "variable":controller.setReceivedMessageFormatParts},
|
||||||
|
|
||||||
"/get/data/auto_clear_message_box": {"status": True, "variable":controller.getAutoClearMessageBox},
|
"/get/data/auto_clear_message_box": {"status": True, "variable":controller.getAutoClearMessageBox},
|
||||||
"/set/enable/auto_clear_message_box": {"status": True, "variable":controller.setEnableAutoClearMessageBox},
|
"/set/enable/auto_clear_message_box": {"status": True, "variable":controller.setEnableAutoClearMessageBox},
|
||||||
"/set/disable/auto_clear_message_box": {"status": True, "variable":controller.setDisableAutoClearMessageBox},
|
"/set/disable/auto_clear_message_box": {"status": True, "variable":controller.setDisableAutoClearMessageBox},
|
||||||
@@ -591,14 +596,34 @@ if __name__ == "__main__":
|
|||||||
"display_duration": 5,
|
"display_duration": 5,
|
||||||
"fadeout_duration": 0.5,
|
"fadeout_duration": 0.5,
|
||||||
}
|
}
|
||||||
case "/set/data/send_message_format":
|
case "/set/data/send_message_format_parts":
|
||||||
data = "[message]"
|
data = {
|
||||||
case "/set/data/send_message_format_with_t":
|
"message": {
|
||||||
data = "[message]([translation])"
|
"prefix": "",
|
||||||
case "/set/data/received_message_format":
|
"suffix": ""
|
||||||
data = "[message]"
|
},
|
||||||
case "/set/data/received_message_format_with_t":
|
"between_separator": "\n",
|
||||||
data = "[message]([translation])"
|
"translation": {
|
||||||
|
"prefix": "(",
|
||||||
|
"separator": "\\",
|
||||||
|
"suffix": ")"
|
||||||
|
},
|
||||||
|
"translation_first": False,
|
||||||
|
}
|
||||||
|
case "/set/data/received_message_format_parts":
|
||||||
|
data = {
|
||||||
|
"message": {
|
||||||
|
"prefix": "",
|
||||||
|
"suffix": ""
|
||||||
|
},
|
||||||
|
"between_separator": "\n",
|
||||||
|
"translation": {
|
||||||
|
"prefix": "(",
|
||||||
|
"separator": "\\",
|
||||||
|
"suffix": ")"
|
||||||
|
},
|
||||||
|
"translation_first": True,
|
||||||
|
}
|
||||||
case "/set/data/osc_ip_address":
|
case "/set/data/osc_ip_address":
|
||||||
data = "127.0.0.1"
|
data = "127.0.0.1"
|
||||||
case "/set/data/osc_port":
|
case "/set/data/osc_port":
|
||||||
|
|||||||
@@ -10,6 +10,41 @@ import requests
|
|||||||
import ipaddress
|
import ipaddress
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
|
def validateDictStructure(data: dict, structure: dict) -> bool:
|
||||||
|
"""
|
||||||
|
辞書とその期待される構造(型)が完全に一致するかを判別する関数
|
||||||
|
Args:
|
||||||
|
data (dict): 検証対象の辞書
|
||||||
|
structure (dict): 期待される構造を定義した辞書値には型(str, int, bool等)や入れ子の辞書を指定
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 構造が完全に一致する場合True、そうでなければFalse
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not isinstance(data, dict) or not isinstance(structure, dict):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# キーの数と名前が完全に一致するかチェック
|
||||||
|
if set(data.keys()) != set(structure.keys()):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 各キーの値の型または構造をチェック
|
||||||
|
for key, expected_type_or_structure in structure.items():
|
||||||
|
if key not in data:
|
||||||
|
return False
|
||||||
|
|
||||||
|
value = data[key]
|
||||||
|
# 期待される型が辞書の場合(入れ子構造)
|
||||||
|
if isinstance(expected_type_or_structure, dict):
|
||||||
|
# 再帰的に検証(多重入れ子に対応)
|
||||||
|
if not validateDictStructure(value, expected_type_or_structure):
|
||||||
|
return False
|
||||||
|
# 期待される型が型オブジェクトの場合
|
||||||
|
else:
|
||||||
|
if not isinstance(value, expected_type_or_structure):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def isConnectedNetwork(url="http://www.google.com", timeout=3) -> bool:
|
def isConnectedNetwork(url="http://www.google.com", timeout=3) -> bool:
|
||||||
try:
|
try:
|
||||||
response = requests.get(url, timeout=timeout)
|
response = requests.get(url, timeout=timeout)
|
||||||
|
|||||||
Reference in New Issue
Block a user