feat: show generate elapsed timings

This commit is contained in:
chengma
2026-07-08 11:54:08 +08:00
parent 091e3dc553
commit 8140124954
4 changed files with 198 additions and 12 deletions
+119 -7
View File
@@ -26,7 +26,7 @@ class GenerateTab(QWidget):
"cover": "封面",
"all": "标题和封面",
}
TABLE_COLUMN_WEIGHTS = (1.0, 0.5, 1.0, 1.0, 1.25, 1.25)
TABLE_COLUMN_WEIGHTS = (1.0, 0.5, 1.8375, 1.8375, 0.4125, 0.4125)
def __init__(
self,
@@ -54,6 +54,10 @@ class GenerateTab(QWidget):
self.current_cover_template = None
self.generate_worker = None
self.generate_thread = None
self._title_elapsed_start = None
self._cover_elapsed_start = None
self._title_elapsed_seconds = 0
self._cover_elapsed_seconds = 0
self.title_prompt_edit = QPlainTextEdit()
self.title_prompt_edit.setObjectName("titlePromptEdit")
@@ -110,8 +114,23 @@ class GenerateTab(QWidget):
self.cover_progress_bar.setValue(0)
self.failed_progress_label = QLabel("失败 0")
self.failed_progress_label.setObjectName("generateFailedProgressLabel")
self.failed_progress_label.setVisible(False)
self.cmhub_balance_label = QLabel("cmhub余额:未获取")
self.cmhub_balance_label.setObjectName("generateCmhubBalanceLabel")
self.cmhub_balance_label.setVisible(False)
self.title_elapsed_label = QLabel("生标题用时 0 秒")
self.title_elapsed_label.setObjectName("generateTitleElapsedLabel")
self.cover_elapsed_label = QLabel("生图用时 0 秒")
self.cover_elapsed_label.setObjectName("generateCoverElapsedLabel")
elapsed_width = max(
self.title_elapsed_label.fontMetrics().horizontalAdvance("生标题用时 9999 秒"),
self.cover_elapsed_label.fontMetrics().horizontalAdvance("生图用时 9999 秒"),
) + 12
self.title_elapsed_label.setFixedWidth(elapsed_width)
self.cover_elapsed_label.setFixedWidth(elapsed_width)
self._generate_elapsed_timer = QTimer(self)
self._generate_elapsed_timer.setInterval(1000)
self._generate_elapsed_timer.timeout.connect(self._refresh_elapsed_labels)
left_panel = QWidget()
left_layout = QVBoxLayout(left_panel)
@@ -209,11 +228,11 @@ class GenerateTab(QWidget):
title_progress_layout = QHBoxLayout()
title_progress_layout.addWidget(self.title_progress_label)
title_progress_layout.addWidget(self.title_progress_bar, 1)
title_progress_layout.addWidget(self.title_elapsed_label)
cover_progress_layout = QHBoxLayout()
cover_progress_layout.addWidget(self.cover_progress_label)
cover_progress_layout.addWidget(self.cover_progress_bar, 1)
cover_progress_layout.addWidget(self.failed_progress_label)
cover_progress_layout.addWidget(self.cmhub_balance_label)
cover_progress_layout.addWidget(self.cover_elapsed_label)
progress_layout = QVBoxLayout()
progress_layout.addLayout(title_progress_layout)
progress_layout.addLayout(cover_progress_layout)
@@ -258,6 +277,7 @@ class GenerateTab(QWidget):
self.refresh_cover_templates()
self.refresh_tasks()
self._show_current_run_log_empty()
self._reset_generation_elapsed()
self._update_cmhub_balance_label({})
def resizeEvent(self, event):
@@ -286,6 +306,92 @@ class GenerateTab(QWidget):
f"本轮AI生成开始:任务 {len(tasks)} 条,生成封面:{cover_text}"
)
def _reset_generation_elapsed(self):
self._generate_elapsed_timer.stop()
self._title_elapsed_start = None
self._cover_elapsed_start = None
self._title_elapsed_seconds = 0
self._cover_elapsed_seconds = 0
self._refresh_elapsed_labels()
def _start_generation_elapsed(self, title_total, cover_total):
self._reset_generation_elapsed()
now = time.monotonic()
if int(title_total or 0) > 0:
self._title_elapsed_start = now
elif int(cover_total or 0) > 0:
self._cover_elapsed_start = now
self._refresh_elapsed_labels()
self._update_elapsed_timer_state()
def _elapsed_seconds(self, start, frozen_seconds):
if start is None:
return max(0, int(frozen_seconds or 0))
return max(0, int(time.monotonic() - start))
def _refresh_elapsed_labels(self):
title_seconds = self._elapsed_seconds(
self._title_elapsed_start,
self._title_elapsed_seconds,
)
cover_seconds = self._elapsed_seconds(
self._cover_elapsed_start,
self._cover_elapsed_seconds,
)
self.title_elapsed_label.setText(f"生标题用时 {title_seconds} 秒")
self.cover_elapsed_label.setText(f"生图用时 {cover_seconds} 秒")
def _update_elapsed_timer_state(self):
if self._title_elapsed_start is not None or self._cover_elapsed_start is not None:
if not self._generate_elapsed_timer.isActive():
self._generate_elapsed_timer.start()
return
self._generate_elapsed_timer.stop()
def _freeze_title_elapsed(self):
if self._title_elapsed_start is None:
return
self._title_elapsed_seconds = self._elapsed_seconds(
self._title_elapsed_start,
self._title_elapsed_seconds,
)
self._title_elapsed_start = None
def _freeze_cover_elapsed(self):
if self._cover_elapsed_start is None:
return
self._cover_elapsed_seconds = self._elapsed_seconds(
self._cover_elapsed_start,
self._cover_elapsed_seconds,
)
self._cover_elapsed_start = None
def _sync_generation_elapsed(self, payload):
title_total = max(0, int(payload.get("title_total", 0) or 0))
title_done = max(0, int(payload.get("title_done", 0) or 0))
cover_total = self._cover_total_for_progress(payload, int(payload.get("total", 0) or 0))
cover_done = max(0, int(payload.get("cover_done", 0) or 0))
if title_total > 0 and title_done >= title_total:
self._freeze_title_elapsed()
if (
cover_total > 0
and cover_done < cover_total
and self._cover_elapsed_start is None
and self._cover_elapsed_seconds == 0
and (title_total == 0 or title_done >= title_total)
):
self._cover_elapsed_start = time.monotonic()
if cover_total > 0 and cover_done >= cover_total:
self._freeze_cover_elapsed()
self._refresh_elapsed_labels()
self._update_elapsed_timer_state()
def _finish_generation_elapsed(self, payload=None):
self._freeze_title_elapsed()
self._freeze_cover_elapsed()
self._refresh_elapsed_labels()
self._update_elapsed_timer_state()
def _on_generate_cover_toggled(self, checked):
previous = bool(appconfig.ai_config(self.config).get("generate_cover", False))
if self._save_generate_cover_setting(show_status=True):
@@ -543,6 +649,10 @@ class GenerateTab(QWidget):
worker.cancelled.connect(self._on_generate_cancelled)
self._reset_generate_run_log(tasks, generate_cover)
self._reset_cmhub_balance_label()
self._start_generation_elapsed(
component_totals["title_total"],
component_totals["cover_total"] if generate_cover else 0,
)
thread = run_worker(worker, thread_name="GenerateWorker", start=False)
thread.finished.connect(lambda: self._forget_generate_thread(thread))
self.generate_worker = worker
@@ -829,6 +939,7 @@ class GenerateTab(QWidget):
def _on_generate_progress(self, payload):
self._update_generate_progress(payload)
self._sync_generation_elapsed(payload)
self._update_cmhub_balance_label(payload)
self._set_status("生成进度:" + self._generate_progress_text(payload))
@@ -842,6 +953,7 @@ class GenerateTab(QWidget):
self._set_generate_running(False)
self.refresh_tasks()
self._update_generate_progress(payload)
self._finish_generation_elapsed(payload)
self._update_cmhub_balance_label(payload)
billing_error = payload.get("billing_error")
if billing_error:
@@ -856,6 +968,7 @@ class GenerateTab(QWidget):
self._set_generate_running(False)
self.refresh_tasks()
self._update_generate_progress(payload)
self._finish_generation_elapsed(payload)
self._update_cmhub_balance_label(payload)
billing_error = payload.get("billing_error")
if billing_error:
@@ -878,17 +991,16 @@ class GenerateTab(QWidget):
self._set_progress_bar(self.cover_progress_bar, cover_done, cover_total)
def _reset_cmhub_balance_label(self):
self.cmhub_balance_label.setVisible(False)
if self._is_cmhub_backend():
self.cmhub_balance_label.setVisible(True)
self.cmhub_balance_label.setText("cmhub余额:生成后刷新")
else:
self.cmhub_balance_label.setVisible(False)
self.cmhub_balance_label.setText("")
def _update_cmhub_balance_label(self, payload):
self.cmhub_balance_label.setVisible(False)
if not self._is_cmhub_backend():
self.cmhub_balance_label.setVisible(False)
return
self.cmhub_balance_label.setVisible(True)
balance = payload.get("points_balance") if isinstance(payload, dict) else None
if balance is None:
if not self.cmhub_balance_label.text():
+1 -1
View File
@@ -9,7 +9,7 @@ import time
from concurrent.futures import ThreadPoolExecutor, as_completed
try:
from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt
from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt, QTimer
from PySide6.QtGui import QColor, QIcon, QPainter, QPixmap
from PySide6.QtWidgets import (
QAbstractItemView,