feat(ai-studio): keep workspace usable during generation
This commit is contained in:
@@ -303,6 +303,7 @@ class ImageStudioTab(QWidget):
|
||||
self._running_worker = None
|
||||
self._running_thread = None
|
||||
self._operation_running = False
|
||||
self._operation_kind = ""
|
||||
self._worker_error_handled = False
|
||||
self._download_open_after = {}
|
||||
self._thumbnail_loader = thumbnail_loader or image_studio_images.ThumbnailLoader()
|
||||
@@ -811,6 +812,9 @@ class ImageStudioTab(QWidget):
|
||||
self.project_table.resizeColumnsToContents()
|
||||
|
||||
def pull_main_images(self, checked=False):
|
||||
if self._operation_running:
|
||||
self._status("AI工场当前任务仍在进行,暂不能拉取蝦皮主图", "warning")
|
||||
return
|
||||
alias = str(self.account_combo.currentData() or "").strip()
|
||||
item_id = self.item_id_edit.text().strip()
|
||||
if not alias or not item_id:
|
||||
@@ -845,7 +849,7 @@ class ImageStudioTab(QWidget):
|
||||
worker.log.connect(self._append_log)
|
||||
worker.finished.connect(self._on_pull_finished)
|
||||
worker.failed.connect(self._on_worker_failed)
|
||||
self._start_worker(worker, "AI工场拉取蝦皮主图")
|
||||
self._start_worker(worker, "AI工场拉取蝦皮主图", operation_kind="pull_images")
|
||||
self._append_log("[AI工场] 拉取蝦皮主图开始")
|
||||
|
||||
def _local_original_count(self, project):
|
||||
@@ -1006,6 +1010,9 @@ class ImageStudioTab(QWidget):
|
||||
self._status(f"已打开项目文件夹:{opened}", "success")
|
||||
|
||||
def delete_current_project(self, checked=False):
|
||||
if self._operation_running:
|
||||
self._status("AI工场当前任务仍在进行,暂不能删除项目", "warning")
|
||||
return
|
||||
project = self.current_project
|
||||
if project is None:
|
||||
self._message("未选择商品", "请先从商品列表选择要删除的项目。")
|
||||
@@ -1518,10 +1525,13 @@ class ImageStudioTab(QWidget):
|
||||
self._refresh_project_summary()
|
||||
|
||||
def _update_project_action_buttons(self):
|
||||
enabled = self.current_project is not None and not self._operation_running
|
||||
self.open_folder_button.setEnabled(enabled)
|
||||
has_project = self.current_project is not None
|
||||
self.open_folder_button.setEnabled(
|
||||
has_project and (not self._operation_running or self._is_generation_operation())
|
||||
)
|
||||
self.delete_project_button.setEnabled(
|
||||
enabled
|
||||
has_project
|
||||
and not self._operation_running
|
||||
and not self._has_original_download_activity(
|
||||
getattr(self.current_project, "id", None)
|
||||
)
|
||||
@@ -1661,6 +1671,9 @@ class ImageStudioTab(QWidget):
|
||||
self.remove_asset(asset_id)
|
||||
|
||||
def remove_asset(self, asset_id):
|
||||
if self._operation_running:
|
||||
self._status("AI工场当前任务仍在进行,暂不能移除照片", "warning")
|
||||
return
|
||||
if not self._confirm("移除照片", "只从AI工场照片池移除记录,不删除本地图片文件。"):
|
||||
return
|
||||
try:
|
||||
@@ -1767,6 +1780,9 @@ class ImageStudioTab(QWidget):
|
||||
self._status(f"保存AI工场草稿提示词失败:{exc}", "warning")
|
||||
|
||||
def start_generation(self, checked=False):
|
||||
if self._operation_running:
|
||||
self._status("AI工场当前任务仍在进行,请等待完成或停止后再生成", "warning")
|
||||
return
|
||||
if self.current_project is None:
|
||||
self._message("未选择商品", "请先从商品列表选择商品,或拉取蝦皮主图。")
|
||||
return
|
||||
@@ -1801,7 +1817,7 @@ class ImageStudioTab(QWidget):
|
||||
worker.log.connect(self._append_log)
|
||||
worker.finished.connect(self._on_generation_finished)
|
||||
worker.failed.connect(self._on_worker_failed)
|
||||
self._start_worker(worker, "AI工场生成图片")
|
||||
self._start_worker(worker, "AI工场生成图片", operation_kind="generate")
|
||||
|
||||
def stop_generation(self, checked=False):
|
||||
if self._running_worker is not None and hasattr(self._running_worker, "cancel"):
|
||||
@@ -1810,6 +1826,9 @@ class ImageStudioTab(QWidget):
|
||||
self._status("AI工场生成已请求停止", "warning")
|
||||
|
||||
def resume_generation_jobs(self, checked=False):
|
||||
if self._operation_running:
|
||||
self._status("AI工场当前任务仍在进行,请等待完成或停止后再继续查询", "warning")
|
||||
return
|
||||
if self.current_project is None:
|
||||
self._message("未选择商品", "请先从商品列表选择商品,或拉取蝦皮主图。")
|
||||
return
|
||||
@@ -1836,9 +1855,12 @@ class ImageStudioTab(QWidget):
|
||||
worker.log.connect(self._append_log)
|
||||
worker.finished.connect(self._on_generation_finished)
|
||||
worker.failed.connect(self._on_worker_failed)
|
||||
self._start_worker(worker, "AI工场继续查询")
|
||||
self._start_worker(worker, "AI工场继续查询", operation_kind="resume")
|
||||
|
||||
def export_selections(self, checked=False):
|
||||
if self._operation_running:
|
||||
self._status("AI工场当前任务仍在进行,暂不能导出终选", "warning")
|
||||
return
|
||||
if self.current_project is None:
|
||||
self._message("未选择商品", "请先从商品列表选择商品,或拉取蝦皮主图。")
|
||||
return
|
||||
@@ -1863,7 +1885,7 @@ class ImageStudioTab(QWidget):
|
||||
worker.log.connect(self._append_log)
|
||||
worker.finished.connect(self._on_export_finished)
|
||||
worker.failed.connect(self._on_worker_failed)
|
||||
self._start_worker(worker, "AI工场导出终选")
|
||||
self._start_worker(worker, "AI工场导出终选", operation_kind="export")
|
||||
|
||||
def _export_existing_mode(self, parent_dir, main_count, detail_count):
|
||||
try:
|
||||
@@ -1963,14 +1985,18 @@ class ImageStudioTab(QWidget):
|
||||
self._on_worker_failed(-1, summary.get("error") or fallback_message)
|
||||
return True
|
||||
|
||||
def _start_worker(self, worker, thread_name):
|
||||
def _start_worker(self, worker, thread_name, *, operation_kind="exclusive"):
|
||||
if self._running_thread is not None:
|
||||
self._status("AI工场上一项任务仍在收尾,请稍候", "warning")
|
||||
return False
|
||||
thread = run_worker(worker, thread_name=thread_name, start=False)
|
||||
thread.finished.connect(lambda: self._forget_running_thread(thread))
|
||||
self._running_worker = worker
|
||||
self._running_thread = thread
|
||||
self._worker_error_handled = False
|
||||
self._set_running(True)
|
||||
self._set_running(True, operation_kind=operation_kind)
|
||||
thread.start()
|
||||
return True
|
||||
|
||||
def _finish_worker(self):
|
||||
self._set_running(False)
|
||||
@@ -1980,27 +2006,38 @@ class ImageStudioTab(QWidget):
|
||||
self._running_thread = None
|
||||
self._running_worker = None
|
||||
|
||||
def _set_running(self, running):
|
||||
def _is_generation_operation(self):
|
||||
return self._operation_running and self._operation_kind in {"generate", "resume"}
|
||||
|
||||
def _set_running(self, running, *, operation_kind="exclusive"):
|
||||
self._operation_running = bool(running)
|
||||
self._operation_kind = str(operation_kind or "exclusive") if running else ""
|
||||
generation_running = self._is_generation_operation()
|
||||
self.pull_images_button.setEnabled(not running)
|
||||
self.account_combo.setEnabled(not running)
|
||||
self.item_id_edit.setEnabled(not running)
|
||||
self.project_table.setEnabled(not running)
|
||||
self.original_grid.setEnabled(not running)
|
||||
self.pool_grid.setEnabled(not running)
|
||||
self.main_selection_list.setEnabled(not running)
|
||||
self.detail_selection_list.setEnabled(not running)
|
||||
self.template_combo.setEnabled(not running)
|
||||
self.template_new_button.setEnabled(not running)
|
||||
self.template_rename_button.setEnabled(not running)
|
||||
self.template_save_button.setEnabled(not running)
|
||||
self.template_delete_button.setEnabled(not running)
|
||||
self.prompt_edit.setEnabled(not running)
|
||||
self.job_type_combo.setEnabled(not running)
|
||||
self.count_spin.setEnabled(not running)
|
||||
self.aspect_combo.setEnabled(not running)
|
||||
self.pool_grid.setEnabled(not running or generation_running)
|
||||
self.main_selection_list.setEnabled(not running or generation_running)
|
||||
self.detail_selection_list.setEnabled(not running or generation_running)
|
||||
self.template_combo.setEnabled(not running or generation_running)
|
||||
self.template_new_button.setEnabled(not running or generation_running)
|
||||
self.template_rename_button.setEnabled(not running or generation_running)
|
||||
self.template_save_button.setEnabled(not running or generation_running)
|
||||
self.template_delete_button.setEnabled(not running or generation_running)
|
||||
self.prompt_edit.setEnabled(not running or generation_running)
|
||||
self.job_type_combo.setEnabled(not running or generation_running)
|
||||
self.count_spin.setEnabled(not running or generation_running)
|
||||
self.aspect_combo.setEnabled(not running or generation_running)
|
||||
self.start_button.setEnabled(not running)
|
||||
self.resume_button.setEnabled(not running)
|
||||
self.stop_button.setEnabled(running)
|
||||
self.export_button.setEnabled(not running)
|
||||
if generation_running:
|
||||
self.generation_guard_label.setText("本轮任务已固定;此处修改将在下一轮生成时生效。")
|
||||
else:
|
||||
self.generation_guard_label.setText("不会在失败后静默切换生成来源。")
|
||||
self._update_project_action_buttons()
|
||||
|
||||
def _set_account_combo(self, alias):
|
||||
|
||||
Reference in New Issue
Block a user