feat: show title generation wait timer
This commit is contained in:
@@ -7,8 +7,9 @@
|
||||
通过 Qt signal 回主线程刷新 UI(子线程不直接碰控件)。
|
||||
"""
|
||||
import logging
|
||||
import time
|
||||
|
||||
from PySide6.QtCore import QObject, QSize, Qt, QThread, QUrl, Signal
|
||||
from PySide6.QtCore import QObject, QSize, Qt, QThread, QTimer, QUrl, Signal
|
||||
from PySide6.QtGui import QDesktopServices, QIcon, QPixmap
|
||||
from PySide6.QtWidgets import (
|
||||
QAbstractItemView,
|
||||
@@ -322,6 +323,12 @@ class AiOutfitPanel(QWidget):
|
||||
self._title_worker = None
|
||||
self._title_fail = 0 # running failure count for title stats
|
||||
self._title_model_name = "" # configured 标题模型 name (§17.3 配置定名)
|
||||
self._title_wait_started_at = 0.0
|
||||
self._title_wait_limit_seconds = 0
|
||||
self._title_wait_generation = 0
|
||||
self._title_wait_timer = QTimer(self)
|
||||
self._title_wait_timer.setInterval(1000)
|
||||
self._title_wait_timer.timeout.connect(self._refresh_title_wait_label)
|
||||
self._preview_dialog = None # 最终提示词预览弹窗(§7.3,按需)
|
||||
self._row_to_table = {} # excel row_index -> table row
|
||||
self._failures = [] # list of OutfitResult (failed)
|
||||
@@ -471,7 +478,15 @@ class AiOutfitPanel(QWidget):
|
||||
"""
|
||||
box = QGroupBox()
|
||||
v = QVBoxLayout(box)
|
||||
v.addWidget(QLabel("标题生成提示词"))
|
||||
header = QHBoxLayout()
|
||||
header.addWidget(QLabel("标题生成提示词"))
|
||||
header.addStretch(1)
|
||||
self._title_wait_label = QLabel("")
|
||||
self._title_wait_label.setObjectName("titleWaitLabel")
|
||||
self._title_wait_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
self._title_wait_label.setVisible(False)
|
||||
header.addWidget(self._title_wait_label)
|
||||
v.addLayout(header)
|
||||
self._title_prompt_edit = QPlainTextEdit()
|
||||
self._title_prompt_edit.setMinimumHeight(110)
|
||||
v.addWidget(self._title_prompt_edit)
|
||||
@@ -987,6 +1002,7 @@ class AiOutfitPanel(QWidget):
|
||||
self._title_fail = 0
|
||||
self._progress.setValue(0)
|
||||
self._log.clear()
|
||||
self._start_title_wait_timer(self._title_wait_limit_for_model(model_config))
|
||||
|
||||
self._title_worker = _TitleWorker(excel, model_config, prompt)
|
||||
self._title_thread = QThread(self)
|
||||
@@ -1009,6 +1025,10 @@ class AiOutfitPanel(QWidget):
|
||||
self._append_log("标题生成:已加载 {} 行".format(len(tasks)))
|
||||
|
||||
def _on_title_progress(self, completed, total, result):
|
||||
if self._title_wait_timer.isActive():
|
||||
self._title_wait_timer.stop()
|
||||
self._set_title_wait_text("写入中 {}/{}".format(completed, total))
|
||||
|
||||
row = self._row_to_table.get(result.task.row_index)
|
||||
if row is not None:
|
||||
if result.success:
|
||||
@@ -1025,6 +1045,10 @@ class AiOutfitPanel(QWidget):
|
||||
|
||||
def _on_title_finished(self, success, fail):
|
||||
self._set_title_running(False)
|
||||
if fail:
|
||||
self._finish_title_wait("完成 {} 条,失败 {}".format(success, fail))
|
||||
else:
|
||||
self._finish_title_wait("完成 {} 条".format(success))
|
||||
msg = "标题生成结束:成功 {},失败 {}".format(success, fail)
|
||||
self._append_log(msg)
|
||||
self._reload_after_titles()
|
||||
@@ -1037,10 +1061,13 @@ class AiOutfitPanel(QWidget):
|
||||
|
||||
def _on_title_failed(self, message):
|
||||
self._set_title_running(False)
|
||||
self._finish_title_wait("生成失败")
|
||||
self._append_log("标题生成无法开始:" + message)
|
||||
QMessageBox.warning(self, "无法开始", message)
|
||||
|
||||
def _cleanup_title_thread(self):
|
||||
if self._title_wait_timer.isActive():
|
||||
self._reset_title_wait_label()
|
||||
self._title_thread = None
|
||||
self._title_worker = None
|
||||
|
||||
@@ -1064,6 +1091,51 @@ class AiOutfitPanel(QWidget):
|
||||
self._start_btn.setEnabled(not running) # mutually exclusive with 开始生成
|
||||
self._excel_edit.setEnabled(not running)
|
||||
|
||||
def _title_wait_limit_for_model(self, model_config):
|
||||
"""Return the title request wait ceiling shown in the label (§17.10)."""
|
||||
try:
|
||||
override = int(getattr(model_config, "timeout_seconds", 0) or 0)
|
||||
except (TypeError, ValueError):
|
||||
override = 0
|
||||
if override > 0:
|
||||
return override
|
||||
from services.ai_image_service import resolution_timeout
|
||||
return resolution_timeout("4K")
|
||||
|
||||
def _start_title_wait_timer(self, limit_seconds):
|
||||
self._title_wait_generation += 1
|
||||
self._title_wait_limit_seconds = max(1, int(limit_seconds or 0))
|
||||
self._title_wait_started_at = time.monotonic()
|
||||
self._refresh_title_wait_label()
|
||||
self._title_wait_timer.start()
|
||||
|
||||
def _refresh_title_wait_label(self):
|
||||
elapsed = max(0, int(time.monotonic() - self._title_wait_started_at))
|
||||
self._set_title_wait_text("等待中 {} / {}".format(
|
||||
self._format_wait_seconds(elapsed),
|
||||
self._format_wait_seconds(self._title_wait_limit_seconds)))
|
||||
|
||||
def _set_title_wait_text(self, text):
|
||||
self._title_wait_label.setText(str(text))
|
||||
self._title_wait_label.setVisible(bool(text))
|
||||
|
||||
def _finish_title_wait(self, text):
|
||||
self._title_wait_timer.stop()
|
||||
self._set_title_wait_text(text)
|
||||
token = self._title_wait_generation
|
||||
QTimer.singleShot(4000, lambda: self._reset_title_wait_label(token))
|
||||
|
||||
def _reset_title_wait_label(self, token=None):
|
||||
if token is not None and token != self._title_wait_generation:
|
||||
return
|
||||
self._title_wait_timer.stop()
|
||||
self._title_wait_label.clear()
|
||||
self._title_wait_label.setVisible(False)
|
||||
|
||||
def _format_wait_seconds(self, seconds):
|
||||
total = max(0, int(seconds or 0))
|
||||
return "{:02d}:{:02d}".format(total // 60, total % 60)
|
||||
|
||||
# -- switch info popups (user-only; §10.2) --------------------------
|
||||
|
||||
def _on_resolution_activated(self, _index):
|
||||
|
||||
Reference in New Issue
Block a user