diff --git a/setup.py b/setup.py index 935fd55c1..41d27ecf2 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name="airunner", - version="3.0.18", + version="3.0.19", author="Capsize LLC", description="A Stable Diffusion GUI", long_description=open("README.md", "r", encoding="utf-8").read(), diff --git a/src/airunner/handlers/tts/speecht5_tts_handler.py b/src/airunner/handlers/tts/speecht5_tts_handler.py index 31718b426..6a0777c83 100644 --- a/src/airunner/handlers/tts/speecht5_tts_handler.py +++ b/src/airunner/handlers/tts/speecht5_tts_handler.py @@ -235,6 +235,7 @@ def _unload_speaker_embeddings(self): def _do_generate(self, message): self.logger.debug("Generating text-to-speech with T5") text = self._replace_unspeakable_characters(message) + text = self._roman_to_int(text) text = self._replace_numbers_with_words(text) text = text.strip() @@ -243,6 +244,8 @@ def _do_generate(self, message): self.logger.debug("Processing inputs...") + print(text) + inputs = self._processor( text=text, return_tensors="pt", @@ -302,13 +305,16 @@ def _replace_unspeakable_characters(text): # strip things like eplisis, etc text = text.replace("...", " ") text = text.replace("…", " ") - text = text.replace("’", "'") - text = text.replace("“", '"') - text = text.replace("”", '"') - text = text.replace("‘", "'") - text = text.replace("’", "'") - text = text.replace("–", "-") - text = text.replace("—", "-") + text = text.replace("’", "") + text = text.replace("“", "") + text = text.replace("”", "") + text = text.replace("‘", "") + text = text.replace("–", "") + text = text.replace("—", "") + text = text.replace("'", "") + text = text.replace('"', "") + text = text.replace("-", "") + text = text.replace("-", "") # replace windows newlines text = text.replace("\r\n", " ") @@ -323,17 +329,50 @@ def _replace_unspeakable_characters(text): text = re.sub(r"\s+", " ", text) return text + @staticmethod + def _roman_to_int(text): + roman_numerals = { + 'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000 + } + + def convert_roman_to_int(roman): + total = 0 + prev_value = 0 + for char in reversed(roman): + value = roman_numerals[char] + if value < prev_value: + total -= value + else: + total += value + prev_value = value + return str(total) + + # Replace Roman numerals with their integer values + result = re.sub(r'\b[IVXLCDM]+\b', lambda match: convert_roman_to_int(match.group(0)), text) + return result + @staticmethod def _replace_numbers_with_words(text): p = inflect.engine() - words = text.split() + + # Handle time formats separately + text = re.sub(r'(\d+):(\d+)([APap][Mm])', lambda m: f"{p.number_to_words(m.group(1))} {p.number_to_words(m.group(2)).replace('zero', '').replace('-', ' ')} {m.group(3)[0].upper()} {m.group(3)[1].upper()}", text) + text = re.sub(r'(\d+):(\d+)', lambda m: f"{p.number_to_words(m.group(1))} {p.number_to_words(m.group(2)).replace('-', ' ')}", text) + + # Split text into words and non-word characters + words = re.findall(r'\d+|\D+', text) + for i in range(len(words)): - if re.search(r'\d', words[i]): # check if the word contains a digit - parts = words[i].split(':') - parts_in_words = [p.number_to_words(part) if part.isdigit() else part for part in parts] - words[i] = ':'.join(parts_in_words) + if words[i].isdigit(): # check if the word is a digit + words[i] = p.number_to_words(words[i]).replace('-', ' ') + + # Join words with a space to ensure proper spacing + result = ' '.join(words).replace(' ', ' ') + + # Ensure "PM" and "AM" are correctly spaced + result = re.sub(r'\b([AP])M\b', r'\1 M', result) - return ' '.join(words) + return result def _unload_model(self): self._model = None diff --git a/src/airunner/tests/test_speecht5_tts_handler.py b/src/airunner/tests/test_speecht5_tts_handler.py new file mode 100644 index 000000000..1e710adc2 --- /dev/null +++ b/src/airunner/tests/test_speecht5_tts_handler.py @@ -0,0 +1,54 @@ +import unittest +from airunner.handlers.tts.speecht5_tts_handler import SpeechT5TTSHandler + +class TestSpeechT5TTSHandler(unittest.TestCase): + + def test_replace_numbers_with_words(self): + handler = SpeechT5TTSHandler() + + # Test cases + test_cases = { + "12:00PM": "twelve P M", + "3:34AM": "three thirty four A M", + "12:33pm": "twelve thirty three P M", + "34PM": "thirty four P M", + "I have 2 apples": "I have two apples", + "The time is 12:30": "The time is twelve thirty", + "He is 25 years old": "He is twenty five years old", + "Room number 404": "Room number four hundred and four", + "No numbers here": "No numbers here" + } + + for input_text, expected_output in test_cases.items(): + with self.subTest(input_text=input_text, expected_output=expected_output): + self.assertEqual(handler._replace_numbers_with_words(input_text), expected_output) + + def test_roman_to_int(self): + handler = SpeechT5TTSHandler() + + # Test cases for Roman numerals + test_cases = { + "I": "1", + "IV": "4", + "IX": "9", + "XII": "12", + "XXI": "21", + "XL": "40", + "L": "50", + "XC": "90", + "C": "100", + "CD": "400", + "D": "500", + "CM": "900", + "M": "1000", + "MMXXI": "2021", + "This is a IV test": "This is a 4 test", + "A test with no roman numerals": "A test with no roman numerals" + } + + for roman, expected in test_cases.items(): + with self.subTest(roman=roman, expected=expected): + self.assertEqual(handler._roman_to_int(roman), expected) + +if __name__ == '__main__': + unittest.main() diff --git a/src/airunner/widgets/active_grid_settings/active_grid_settings_widget.py b/src/airunner/widgets/active_grid_settings/active_grid_settings_widget.py index 7db15c864..82ca63de2 100644 --- a/src/airunner/widgets/active_grid_settings/active_grid_settings_widget.py +++ b/src/airunner/widgets/active_grid_settings/active_grid_settings_widget.py @@ -78,9 +78,6 @@ def update_size(self, message: dict): self.update_application_settings("working_width", width) self.update_application_settings("working_height", height) - def update_active_grid_settings(self, setting_key, checked): - self.update_active_grid_settings(setting_key, checked) - def action_clicked_checkbox_toggle_active_grid_border(self, checked): self.update_active_grid_settings("render_border", checked) diff --git a/src/airunner/widgets/llm/bot_preferences.py b/src/airunner/widgets/llm/bot_preferences.py index 7a4675eb5..523616332 100644 --- a/src/airunner/widgets/llm/bot_preferences.py +++ b/src/airunner/widgets/llm/bot_preferences.py @@ -18,6 +18,7 @@ def __init__(self, *args, **kwargs): def showEvent(self, event): self.load_saved_chatbots() + super().showEvent(event) def load_form_elements(self): elements = [ diff --git a/src/airunner/widgets/llm/templates/bot_preferences.ui b/src/airunner/widgets/llm/templates/bot_preferences.ui index f4f39043f..8ea998ad3 100644 --- a/src/airunner/widgets/llm/templates/bot_preferences.ui +++ b/src/airunner/widgets/llm/templates/bot_preferences.ui @@ -111,7 +111,7 @@ - + 40 @@ -593,7 +593,7 @@ - pushButton + delete_button clicked() bot_preferences delete_clicked() diff --git a/src/airunner/widgets/llm/templates/bot_preferences_ui.py b/src/airunner/widgets/llm/templates/bot_preferences_ui.py index 014d63cd4..fe87fff24 100644 --- a/src/airunner/widgets/llm/templates/bot_preferences_ui.py +++ b/src/airunner/widgets/llm/templates/bot_preferences_ui.py @@ -70,13 +70,13 @@ def setupUi(self, bot_preferences): self.gridLayout_3.addWidget(self.saved_chatbots, 0, 0, 1, 1) - self.pushButton = QPushButton(self.groupBox) - self.pushButton.setObjectName(u"pushButton") - self.pushButton.setMaximumSize(QSize(40, 16777215)) + self.delete_button = QPushButton(self.groupBox) + self.delete_button.setObjectName(u"delete_button") + self.delete_button.setMaximumSize(QSize(40, 16777215)) icon1 = QIcon(QIcon.fromTheme(u"process-stop")) - self.pushButton.setIcon(icon1) + self.delete_button.setIcon(icon1) - self.gridLayout_3.addWidget(self.pushButton, 0, 2, 1, 1) + self.gridLayout_3.addWidget(self.delete_button, 0, 2, 1, 1) self.gridLayout.addWidget(self.groupBox, 1, 0, 1, 1) @@ -242,7 +242,7 @@ def setupUi(self, bot_preferences): self.system_instructions_groupbox.toggled.connect(bot_preferences.toggle_use_system_instructions) self.saved_chatbots.currentTextChanged.connect(bot_preferences.saved_chatbots_changed) self.create_new_button.clicked.connect(bot_preferences.create_new_chatbot_clicked) - self.pushButton.clicked.connect(bot_preferences.delete_clicked) + self.delete_button.clicked.connect(bot_preferences.delete_clicked) self.comboBox.currentTextChanged.connect(bot_preferences.agent_type_changed) self.browse_documents_button.clicked.connect(bot_preferences.browse_documents) @@ -261,9 +261,9 @@ def retranslateUi(self, bot_preferences): #endif // QT_CONFIG(tooltip) self.create_new_button.setText("") #if QT_CONFIG(tooltip) - self.pushButton.setToolTip(QCoreApplication.translate("bot_preferences", u"Delete agent", None)) + self.delete_button.setToolTip(QCoreApplication.translate("bot_preferences", u"Delete agent", None)) #endif // QT_CONFIG(tooltip) - self.pushButton.setText("") + self.delete_button.setText("") self.groupBox_3.setTitle(QCoreApplication.translate("bot_preferences", u"Documents", None)) self.browse_documents_button.setText(QCoreApplication.translate("bot_preferences", u"Browse", None)) self.names_groupbox.setTitle(QCoreApplication.translate("bot_preferences", u"Use names", None)) diff --git a/src/airunner/widgets/stats/stats_widget.py b/src/airunner/widgets/stats/stats_widget.py index ad3232af6..f8d32f691 100644 --- a/src/airunner/widgets/stats/stats_widget.py +++ b/src/airunner/widgets/stats/stats_widget.py @@ -5,6 +5,7 @@ from PySide6.QtCore import Qt, QTimer from PySide6.QtWidgets import QTableWidgetItem, QApplication from airunner.enums import SignalCode, ModelStatus +from airunner.styles_mixin import StylesMixin from airunner.widgets.base_widget import BaseWidget from airunner.widgets.stats.templates.stats_ui import Ui_stats_widget from airunner.windows.main.pipeline_mixin import PipelineMixin @@ -12,7 +13,8 @@ class StatsWidget( BaseWidget, - PipelineMixin + PipelineMixin, + StylesMixin ): widget_class_ = Ui_stats_widget @@ -28,6 +30,10 @@ def __init__(self, *args, **kwargs): self.timer.timeout.connect(self.update_memory_stats) self.timer.start(500) + def showEvent(self, event): + super().showEvent(event) + self.set_stylesheet() + def update_memory_stats(self): # Clear the table headers = ["Device", "Used Memory", "Total Memory", "Free Memory"] diff --git a/src/airunner/windows/main/main_window.py b/src/airunner/windows/main/main_window.py index 9d1ab87ea..2e870f814 100644 --- a/src/airunner/windows/main/main_window.py +++ b/src/airunner/windows/main/main_window.py @@ -666,7 +666,6 @@ def closeEvent(self, event) -> None: self.logger.debug("Quitting") self.save_state() self.emit_signal(SignalCode.QUIT_APPLICATION) - # super().closeEvent(event) def show_settings_path(self, name, default_path=None): diff --git a/src/airunner/windows/main/templates/main_window.ui b/src/airunner/windows/main/templates/main_window.ui index 04ee7215b..9dc73a460 100644 --- a/src/airunner/windows/main/templates/main_window.ui +++ b/src/airunner/windows/main/templates/main_window.ui @@ -262,7 +262,6 @@ - diff --git a/src/airunner/windows/main/templates/main_window_ui.py b/src/airunner/windows/main/templates/main_window_ui.py index 0d8f5a001..f2b669a0e 100644 --- a/src/airunner/windows/main/templates/main_window_ui.py +++ b/src/airunner/windows/main/templates/main_window_ui.py @@ -535,7 +535,6 @@ def setupUi(self, MainWindow): self.menuImage.addAction(self.actionToggle_Brush) self.menuImage.addAction(self.actionToggle_Eraser) self.menuImage.addAction(self.actionToggle_Grid) - self.menuImage.addAction(self.actionRecenter) self.menuView.addAction(self.actionPrompt_Browser) self.menuView.addSeparator() self.menuView.addAction(self.actionBrowse_AI_Runner_Path) diff --git a/src/airunner/workers/llm_generate_worker.py b/src/airunner/workers/llm_generate_worker.py index 83fe79219..dcc560bed 100644 --- a/src/airunner/workers/llm_generate_worker.py +++ b/src/airunner/workers/llm_generate_worker.py @@ -1,3 +1,5 @@ +import threading + from airunner.handlers.llm.causal_lm_transformer_base_handler import CausalLMTransformerBaseHandler from airunner.enums import SignalCode from airunner.workers.worker import Worker @@ -31,6 +33,9 @@ def on_llm_on_unload_signal(self, data): callback(data) def on_llm_load_model_signal(self, data): + threading.Thread(target=self._load_llm, args=(data,)).start() + + def _load_llm(self, data): self.llm.load() callback = data.get("callback", None) if callback: