diff --git a/main.py b/main.py index 9a89921..67c98cf 100644 --- a/main.py +++ b/main.py @@ -18,6 +18,7 @@ from modules.model_manager import ModelManager from modules.sampler_manager import SamplerManager from modules.prompt_window import PromptWindow from modules.negative_prompt_window import NegativePromptWindow +from modules.size_preset_manager import SizePresetManager class GenerationThread(QThread): progress_updated = pyqtSignal(float, str) @@ -202,6 +203,11 @@ class MainWindow(QMainWindow): self.sampler_manager = SamplerManager(self.api_url) settings_layout.addWidget(self.sampler_manager) + # Добавляем менеджер пресетов размеров + self.size_preset_manager = SizePresetManager() + self.size_preset_manager.size_changed.connect(self.on_size_preset_changed) + settings_layout.addWidget(self.size_preset_manager) + # Параметры генерации params_layout = QVBoxLayout() @@ -447,11 +453,20 @@ class MainWindow(QMainWindow): save_button = QPushButton("Сохранить") save_button.clicked.connect(lambda checked, img=img: self.save_image(img)) - # Создаем контейнер для изображения и кнопки + # Создаем кнопку копирования в буфер обмена + copy_button = QPushButton("Копировать") + copy_button.clicked.connect(lambda checked, img=img: self.copy_to_clipboard(img)) + + # Создаем контейнер для изображения и кнопок container = QWidget() container_layout = QVBoxLayout(container) container_layout.addWidget(img_label) - container_layout.addWidget(save_button) + + # Создаем горизонтальный layout для кнопок + buttons_layout = QHBoxLayout() + buttons_layout.addWidget(save_button) + buttons_layout.addWidget(copy_button) + container_layout.addLayout(buttons_layout) self.results_content_layout.addWidget(container) self.log_to_console("Изображение успешно добавлено в интерфейс") @@ -471,6 +486,22 @@ class MainWindow(QMainWindow): if file_path: img.save(file_path) + def copy_to_clipboard(self, img): + """Копирование изображения в буфер обмена""" + # Конвертируем изображение в QPixmap + buffer = BytesIO() + img.save(buffer, format='PNG') + buffer.seek(0) + pixmap = QPixmap() + pixmap.loadFromData(buffer.getvalue()) + + # Копируем в буфер обмена + clipboard = QApplication.clipboard() + clipboard.setPixmap(pixmap) + + # Показываем уведомление + self.log_to_console("Изображение скопировано в буфер обмена") + def update_api_url(self): """Обновление URL API во всех компонентах""" new_url = self.api_url_input.text() @@ -478,6 +509,12 @@ class MainWindow(QMainWindow): self.sampler_manager.update_api_url(new_url) self.log_to_console(f"API URL обновлен: {new_url}") + def on_size_preset_changed(self, width, height): + """Обработчик изменения размера через пресет""" + self.width_input.setValue(width) + self.height_input.setValue(height) + self.log_to_console(f"Размер изменен на: {width}x{height}") + if __name__ == '__main__': app = QApplication(sys.argv) window = MainWindow() diff --git a/modules/__pycache__/negative_prompt_categories.cpython-310.pyc b/modules/__pycache__/negative_prompt_categories.cpython-310.pyc new file mode 100644 index 0000000..fa0e0d5 Binary files /dev/null and b/modules/__pycache__/negative_prompt_categories.cpython-310.pyc differ diff --git a/modules/__pycache__/negative_prompt_window.cpython-310.pyc b/modules/__pycache__/negative_prompt_window.cpython-310.pyc new file mode 100644 index 0000000..76153d7 Binary files /dev/null and b/modules/__pycache__/negative_prompt_window.cpython-310.pyc differ diff --git a/modules/__pycache__/prompt_categories.cpython-310.pyc b/modules/__pycache__/prompt_categories.cpython-310.pyc new file mode 100644 index 0000000..36cf75c Binary files /dev/null and b/modules/__pycache__/prompt_categories.cpython-310.pyc differ diff --git a/modules/__pycache__/prompt_translations.cpython-310.pyc b/modules/__pycache__/prompt_translations.cpython-310.pyc new file mode 100644 index 0000000..a3a02ec Binary files /dev/null and b/modules/__pycache__/prompt_translations.cpython-310.pyc differ diff --git a/modules/__pycache__/prompt_window.cpython-310.pyc b/modules/__pycache__/prompt_window.cpython-310.pyc new file mode 100644 index 0000000..9574cb8 Binary files /dev/null and b/modules/__pycache__/prompt_window.cpython-310.pyc differ diff --git a/modules/__pycache__/size_preset_manager.cpython-310.pyc b/modules/__pycache__/size_preset_manager.cpython-310.pyc new file mode 100644 index 0000000..c240cae Binary files /dev/null and b/modules/__pycache__/size_preset_manager.cpython-310.pyc differ diff --git a/modules/__pycache__/size_presets.cpython-310.pyc b/modules/__pycache__/size_presets.cpython-310.pyc new file mode 100644 index 0000000..3318816 Binary files /dev/null and b/modules/__pycache__/size_presets.cpython-310.pyc differ diff --git a/modules/negative_prompt_window.py b/modules/negative_prompt_window.py index 38f8fdc..90cbdac 100644 --- a/modules/negative_prompt_window.py +++ b/modules/negative_prompt_window.py @@ -18,8 +18,8 @@ class NegativePromptWindow(QDialog): self.setStyleSheet(""" QDialog { background-color: #2b2b2b; - min-width: 1500px; - min-height: 700px; + min-width: 1700px; + min-height: 800px; } QScrollArea { background-color: #1e1e1e; diff --git a/modules/prompt_translations.py b/modules/prompt_translations.py new file mode 100644 index 0000000..1c881e1 --- /dev/null +++ b/modules/prompt_translations.py @@ -0,0 +1,316 @@ +PROMPT_TRANSLATIONS = { + # Персонажи + "Девушка": "girl", + "Парень": "boy", + "Мужчина": "man", + "Женщина": "woman", + "Ребенок": "child", + "Малыш": "baby", + "Пожилой человек": "elderly person", + "Старик": "old man", + "Старушка": "old woman", + + # Профессии + "Художник": "artist", + "Музыкант": "musician", + "Писатель": "writer", + "Учитель": "teacher", + "Врач": "doctor", + "Инженер": "engineer", + "Программист": "programmer", + "Повар": "chef", + "Полицейский": "police officer", + "Пожарный": "firefighter", + + # Животные + "Кошка": "cat", + "Собака": "dog", + "Птица": "bird", + "Рыба": "fish", + "Лошадь": "horse", + "Корова": "cow", + "Овца": "sheep", + "Коза": "goat", + "Кролик": "rabbit", + "Хомяк": "hamster", + + # Природа + "Гора": "mountain", + "Море": "sea", + "Океан": "ocean", + "Река": "river", + "Лес": "forest", + "Поле": "field", + "Цветок": "flower", + "Дерево": "tree", + "Трава": "grass", + "Песок": "sand", + + # Погода + "Солнце": "sun", + "Дождь": "rain", + "Снег": "snow", + "Ветер": "wind", + "Туман": "fog", + "Облако": "cloud", + "Гроза": "thunderstorm", + "Радуга": "rainbow", + "Мороз": "frost", + "Иней": "hoarfrost", + + # Время суток + "Утро": "morning", + "День": "day", + "Вечер": "evening", + "Ночь": "night", + "Рассвет": "dawn", + "Закат": "sunset", + "Полдень": "noon", + "Полночь": "midnight", + + # Сезоны + "Весна": "spring", + "Лето": "summer", + "Осень": "autumn", + "Зима": "winter", + + # Эмоции + "Счастье": "happiness", + "Грусть": "sadness", + "Гнев": "anger", + "Страх": "fear", + "Удивление": "surprise", + "Отвращение": "disgust", + "Любовь": "love", + "Ненависть": "hate", + "Спокойствие": "calmness", + "Волнение": "excitement", + + # Действия + "Бег": "running", + "Ходьба": "walking", + "Прыжок": "jumping", + "Плавание": "swimming", + "Танцы": "dancing", + "Пение": "singing", + "Игра": "playing", + "Работа": "working", + "Отдых": "resting", + "Сон": "sleeping", + + # Одежда + "Платье": "dress", + "Рубашка": "shirt", + "Брюки": "pants", + "Юбка": "skirt", + "Куртка": "jacket", + "Пальто": "coat", + "Шапка": "hat", + "Обувь": "shoes", + "Перчатки": "gloves", + "Шарф": "scarf", + + # Цвета + "Красный": "red", + "Синий": "blue", + "Зеленый": "green", + "Желтый": "yellow", + "Белый": "white", + "Черный": "black", + "Серый": "gray", + "Коричневый": "brown", + "Оранжевый": "orange", + "Фиолетовый": "purple", + + # Материалы + "Дерево": "wood", + "Металл": "metal", + "Стекло": "glass", + "Пластик": "plastic", + "Ткань": "fabric", + "Бумага": "paper", + "Камень": "stone", + "Керамика": "ceramics", + "Кожа": "leather", + "Резина": "rubber", + + # Технологии + "Компьютер": "computer", + "Телефон": "phone", + "Планшет": "tablet", + "Робот": "robot", + "Дрон": "drone", + "Смартфон": "smartphone", + "Ноутбук": "laptop", + "Принтер": "printer", + "Камера": "camera", + "Наушники": "headphones", + + # Транспорт + "Машина": "car", + "Велосипед": "bicycle", + "Мотоцикл": "motorcycle", + "Поезд": "train", + "Самолет": "airplane", + "Корабль": "ship", + "Автобус": "bus", + "Трамвай": "tram", + "Метро": "subway", + "Вертолет": "helicopter", + + # Еда + "Фрукты": "fruits", + "Овощи": "vegetables", + "Мясо": "meat", + "Рыба": "fish", + "Хлеб": "bread", + "Молоко": "milk", + "Сок": "juice", + "Кофе": "coffee", + "Чай": "tea", + "Сладости": "sweets", + + # Дом + "Дом": "house", + "Квартира": "apartment", + "Комната": "room", + "Кухня": "kitchen", + "Спальня": "bedroom", + "Ванная": "bathroom", + "Гостиная": "living room", + "Балкон": "balcony", + "Подвал": "basement", + "Чердак": "attic", + + # Музыка + "Гитара": "guitar", + "Пианино": "piano", + "Скрипка": "violin", + "Барабаны": "drums", + "Флейта": "flute", + "Саксофон": "saxophone", + "Труба": "trumpet", + "Бас": "bass", + "Синтезатор": "synthesizer", + "Микрофон": "microphone", + + # Спорт + "Футбол": "football", + "Баскетбол": "basketball", + "Волейбол": "volleyball", + "Теннис": "tennis", + "Хоккей": "hockey", + "Бег": "running", + "Плавание": "swimming", + "Бокс": "boxing", + "Йога": "yoga", + "Гимнастика": "gymnastics", + + # Искусство + "Картина": "painting", + "Рисунок": "drawing", + "Скульптура": "sculpture", + "Фотография": "photography", + "Кино": "movie", + "Театр": "theater", + "Музыка": "music", + "Танец": "dance", + "Поэзия": "poetry", + "Литература": "literature", + + # Наука + "Физика": "physics", + "Химия": "chemistry", + "Биология": "biology", + "Математика": "mathematics", + "Астрономия": "astronomy", + "Геология": "geology", + "Экология": "ecology", + "Психология": "psychology", + "История": "history", + "География": "geography", + + # Время + "Секунда": "second", + "Минута": "minute", + "Час": "hour", + "День": "day", + "Неделя": "week", + "Месяц": "month", + "Год": "year", + "Век": "century", + "Эпоха": "era", + "Период": "period", + + # География + "Страна": "country", + "Город": "city", + "Деревня": "village", + "Река": "river", + "Озеро": "lake", + "Море": "sea", + "Океан": "ocean", + "Гора": "mountain", + "Пустыня": "desert", + "Джунгли": "jungle", + + # Космос + "Солнце": "sun", + "Луна": "moon", + "Звезда": "star", + "Планета": "planet", + "Галактика": "galaxy", + "Вселенная": "universe", + "Астероид": "asteroid", + "Комета": "comet", + "Спутник": "satellite", + "Космический корабль": "spaceship", + + # Фэнтези + "Дракон": "dragon", + "Единорог": "unicorn", + "Фея": "fairy", + "Волшебник": "wizard", + "Ведьма": "witch", + "Гоблин": "goblin", + "Эльф": "elf", + "Гном": "dwarf", + "Орк": "orc", + "Тролль": "troll", + + # Мифология + "Бог": "god", + "Богиня": "goddess", + "Герой": "hero", + "Миф": "myth", + "Легенда": "legend", + "Демон": "demon", + "Ангел": "angel", + "Призрак": "ghost", + "Вампир": "vampire", + "Оборотень": "werewolf", + + # Стили искусства + "Реализм": "realism", + "Импрессионизм": "impressionism", + "Экспрессионизм": "expressionism", + "Сюрреализм": "surrealism", + "Абстракционизм": "abstract art", + "Поп-арт": "pop art", + "Модернизм": "modernism", + "Постмодернизм": "postmodernism", + "Кубизм": "cubism", + "Футуризм": "futurism", + + # Эпохи + "Древний мир": "ancient world", + "Средневековье": "middle ages", + "Ренессанс": "renaissance", + "Барокко": "baroque", + "Классицизм": "classicism", + "Романтизм": "romanticism", + "Викторианская эпоха": "victorian era", + "Модерн": "art nouveau", + "Ар-деко": "art deco", + "Современность": "modern era" +} \ No newline at end of file diff --git a/modules/prompt_window.py b/modules/prompt_window.py index c2fb17d..445d896 100644 --- a/modules/prompt_window.py +++ b/modules/prompt_window.py @@ -3,6 +3,7 @@ from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QTreeWidget, QScrollArea, QWidget, QCheckBox, QFrame) from PyQt6.QtCore import Qt, pyqtSignal from .prompt_categories import PROMPT_CATEGORIES +from .prompt_translations import PROMPT_TRANSLATIONS class PromptWindow(QDialog): prompt_selected = pyqtSignal(str) @@ -217,5 +218,7 @@ class PromptWindow(QDialog): def add_selected(self): """Добавление выбранных промптов""" if self.selected_prompts: - prompts_text = ", ".join(sorted(self.selected_prompts)) + # Преобразуем русские названия в английские + translated_prompts = [PROMPT_TRANSLATIONS.get(prompt, prompt) for prompt in self.selected_prompts] + prompts_text = ", ".join(sorted(translated_prompts)) self.prompt_selected.emit(prompts_text) \ No newline at end of file diff --git a/modules/size_preset_manager.py b/modules/size_preset_manager.py new file mode 100644 index 0000000..ee83568 --- /dev/null +++ b/modules/size_preset_manager.py @@ -0,0 +1,93 @@ +from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QFrame +from PyQt6.QtCore import Qt, pyqtSignal +from .size_presets import SIZE_PRESETS + +class SizePresetManager(QWidget): + size_changed = pyqtSignal(int, int) # Сигнал для изменения размера + + def __init__(self, parent=None): + super().__init__(parent) + self.setup_ui() + + def setup_ui(self): + layout = QVBoxLayout(self) + layout.setSpacing(2) + + # Заголовок + title = QLabel("Размеры:") + title.setStyleSheet(""" + QLabel { + color: #ffffff; + font-size: 12px; + font-weight: bold; + padding: 4px; + background-color: #3b3b3b; + border-radius: 4px; + } + """) + layout.addWidget(title) + + # Создаем фрейм для кнопок + buttons_frame = QFrame() + buttons_frame.setStyleSheet(""" + QFrame { + background-color: #2b2b2b; + border: 1px solid #3b3b3b; + border-radius: 4px; + padding: 2px; + } + """) + buttons_layout = QVBoxLayout(buttons_frame) + buttons_layout.setSpacing(2) + + # Создаем две строки кнопок + row1_layout = QHBoxLayout() + row2_layout = QHBoxLayout() + + # Разделяем пресеты на две группы + presets = list(SIZE_PRESETS.items()) + half = len(presets) // 2 + + # Добавляем кнопки в первую строку + for name, (width, height) in presets[:half]: + button = self.create_preset_button(name, width, height) + row1_layout.addWidget(button) + + # Добавляем кнопки во вторую строку + for name, (width, height) in presets[half:]: + button = self.create_preset_button(name, width, height) + row2_layout.addWidget(button) + + buttons_layout.addLayout(row1_layout) + buttons_layout.addLayout(row2_layout) + layout.addWidget(buttons_frame) + + def create_preset_button(self, name, width, height): + """Создание кнопки пресета с улучшенным дизайном""" + button = QPushButton(name) + button.setStyleSheet(f""" + QPushButton {{ + background-color: #3b3b3b; + color: white; + border: 1px solid #555555; + border-radius: 4px; + padding: 4px; + font-size: 11px; + min-width: 80px; + text-align: center; + }} + QPushButton:hover {{ + background-color: #4a4a4a; + border-color: #666666; + }} + QPushButton:pressed {{ + background-color: #0d6efd; + border-color: #0b5ed7; + }} + """) + button.clicked.connect(lambda checked, w=width, h=height: self.on_preset_clicked(w, h)) + return button + + def on_preset_clicked(self, width, height): + """Обработчик нажатия на кнопку пресета""" + self.size_changed.emit(width, height) \ No newline at end of file diff --git a/modules/size_presets.py b/modules/size_presets.py new file mode 100644 index 0000000..8f49eb2 --- /dev/null +++ b/modules/size_presets.py @@ -0,0 +1,8 @@ +SIZE_PRESETS = { + "512x768": (512, 768), + "768x512": (768, 512), + "512x512": (512, 512), + "768x432": (768, 432), + "432x768": (432, 768), + "600x800": (600, 800) +} \ No newline at end of file