# ui/widgets/right_panel.py import json from typing import Optional # <-- Добавлен пропущенный импорт from PyQt6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QTabWidget, QTextEdit, QLineEdit, QPushButton, QFormLayout, QComboBox, QMessageBox, QApplication ) from PyQt6.QtGui import QPixmap from PyQt6.QtCore import Qt, pyqtSignal class RightPanel(QWidget): save_clicked = pyqtSignal(int, dict) send_to_comfy_clicked = pyqtSignal(str) def __init__(self, parent=None): super().__init__(parent) self.current_file_id = None self.current_filepath = None self.current_raw_prompt = None self.init_ui() def init_ui(self): layout = QVBoxLayout(self) layout.setContentsMargins(5, 5, 5, 5) self.preview_label = QLabel("Нет выделенного изображения") self.preview_label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.preview_label.setMinimumHeight(250) self.preview_label.setStyleSheet( "QLabel { background-color: #0f0f0f; border: 1px solid #2d2d2d; border-radius: 4px; }" ) layout.addWidget(self.preview_label) self.tabs = QTabWidget() self.gen_tab = QWidget() gen_layout = QVBoxLayout(self.gen_tab) gen_layout.setContentsMargins(5, 5, 5, 5) form_layout = QFormLayout() self.model_input = QLineEdit() self.model_input.setReadOnly(True) form_layout.addRow("Модель:", self.model_input) self.sampler_input = QLineEdit() self.sampler_input.setReadOnly(True) form_layout.addRow("Сэмплер:", self.sampler_input) params_row = QHBoxLayout() self.seed_input = QLineEdit() self.seed_input.setReadOnly(True) self.steps_input = QLineEdit() self.steps_input.setReadOnly(True) self.cfg_input = QLineEdit() self.cfg_input.setReadOnly(True) params_row.addWidget(QLabel("Seed:")) params_row.addWidget(self.seed_input) params_row.addWidget(QLabel("Steps:")) params_row.addWidget(self.steps_input) params_row.addWidget(QLabel("CFG:")) params_row.addWidget(self.cfg_input) form_layout.addRow(params_row) self.rating_combo = QComboBox() self.rating_combo.addItems(["Без рейтинга", "★", "★★", "★★★", "★★★★", "★★★★★"]) form_layout.addRow("Рейтинг:", self.rating_combo) gen_layout.addLayout(form_layout) gen_layout.addWidget(QLabel("Позитивный промт:")) self.positive_text = QTextEdit() gen_layout.addWidget(self.positive_text) gen_layout.addWidget(QLabel("Негативный промт:")) self.negative_text = QTextEdit() gen_layout.addWidget(self.negative_text) self.save_btn = QPushButton("Сохранить изменения") self.save_btn.clicked.connect(self._on_save_clicked) gen_layout.addWidget(self.save_btn) self.workflow_tab = QWidget() wf_layout = QVBoxLayout(self.workflow_tab) wf_layout.setContentsMargins(5, 5, 5, 5) self.workflow_text = QTextEdit() self.workflow_text.setReadOnly(True) wf_layout.addWidget(self.workflow_text) self.tabs.addTab(self.gen_tab, "Generation") self.tabs.addTab(self.workflow_tab, "Workflow") layout.addWidget(self.tabs) export_layout = QHBoxLayout() self.copy_pos_btn = QPushButton("Коп. Pos") self.copy_pos_btn.clicked.connect(self._copy_positive) self.copy_neg_btn = QPushButton("Коп. Neg") self.copy_neg_btn.clicked.connect(self._copy_negative) self.copy_wf_btn = QPushButton("Коп. Work") self.copy_wf_btn.clicked.connect(self._copy_workflow) export_layout.addWidget(self.copy_pos_btn) export_layout.addWidget(self.copy_neg_btn) export_layout.addWidget(self.copy_wf_btn) layout.addLayout(export_layout) self.send_btn = QPushButton("Отправить в ComfyUI") self.send_btn.clicked.connect(self._on_send_clicked) layout.addWidget(self.send_btn) def display_metadata(self, file_details: Optional[dict]): if not file_details: self.clear_fields() return self.current_file_id = file_details["id"] self.current_filepath = file_details["filepath"] self.current_raw_prompt = file_details.get("prompt_json") pixmap = QPixmap(self.current_filepath) if not pixmap.isNull(): scaled = pixmap.scaled( self.preview_label.width(), self.preview_label.height(), Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation ) self.preview_label.setPixmap(scaled) else: self.preview_label.setText("Ошибка рендеринга превью") self.model_input.setText(file_details.get("model_name") or "Не указано") self.sampler_input.setText(file_details.get("sampler") or "Не указано") self.seed_input.setText(str(file_details.get("seed") or "")) self.steps_input.setText(str(file_details.get("steps") or "")) self.cfg_input.setText(str(file_details.get("cfg") or "")) rating = file_details.get("rating", 0) self.rating_combo.setCurrentIndex(rating if 0 <= rating <= 5 else 0) self.positive_text.setPlainText(file_details.get("positive_prompt") or "") self.negative_text.setPlainText(file_details.get("negative_prompt") or "") wf_raw = file_details.get("workflow_json") if wf_raw: try: self.workflow_text.setPlainText(json.dumps(json.loads(wf_raw), indent=2, ensure_ascii=False)) except Exception: self.workflow_text.setPlainText(wf_raw) else: self.workflow_text.setPlainText("Workflow не найден") def clear_fields(self): self.current_file_id = None self.current_filepath = None self.current_raw_prompt = None self.preview_label.setText("Нет выделенного изображения") self.preview_label.setPixmap(QPixmap()) self.model_input.clear() self.sampler_input.clear() self.seed_input.clear() self.steps_input.clear() self.cfg_input.clear() self.rating_combo.setCurrentIndex(0) self.positive_text.clear() self.negative_text.clear() self.workflow_text.clear() def _on_save_clicked(self): if self.current_file_id is None: return payload = { "positive_prompt": self.positive_text.toPlainText(), "negative_prompt": self.negative_text.toPlainText(), "rating": self.rating_combo.currentIndex() } self.save_clicked.emit(self.current_file_id, payload) def _on_send_clicked(self): if not self.current_raw_prompt: QMessageBox.warning(self, "Ошибка", "У изображения отсутствует prompt-граф.") return self.send_to_comfy_clicked.emit(self.current_raw_prompt) def _copy_positive(self): QApplication.clipboard().setText(self.positive_text.toPlainText()) def _copy_negative(self): QApplication.clipboard().setText(self.negative_text.toPlainText()) def _copy_workflow(self): QApplication.clipboard().setText(self.workflow_text.toPlainText())