feat(ai): generate covers without new titles
This commit is contained in:
@@ -349,6 +349,15 @@ def _has_generated_cover(task):
|
||||
return bool(str(getattr(task, "new_cover_path", "") or "").strip())
|
||||
|
||||
|
||||
def cover_title_context(task):
|
||||
"""Return the title used to describe a cover without changing task results."""
|
||||
|
||||
new_title = str(getattr(task, "new_title", "") or "").strip()
|
||||
if new_title:
|
||||
return new_title
|
||||
return str(getattr(task, "old_title", "") or "").strip()
|
||||
|
||||
|
||||
def generation_needs(task, generate_cover=False, generate_mode=None):
|
||||
"""Return which AI components still need generation for this task."""
|
||||
|
||||
@@ -370,7 +379,7 @@ def generation_needs(task, generate_cover=False, generate_mode=None):
|
||||
needs_cover = False
|
||||
if appconfig.generate_mode_includes_cover(mode) and not _has_generated_cover(task):
|
||||
if mode == "cover":
|
||||
needs_cover = has_title
|
||||
needs_cover = bool(cover_title_context(task))
|
||||
else:
|
||||
needs_cover = has_title or needs_title
|
||||
return {"title": needs_title, "cover": needs_cover}
|
||||
@@ -587,9 +596,29 @@ def generate_batch(tasks, prompts, ai_cfg=None, on_progress=None, should_stop=No
|
||||
|
||||
for task in eligible:
|
||||
task_id = getattr(task, "id", None)
|
||||
if task_id not in title_results and _has_generated_title(task):
|
||||
title_results[task_id] = str(getattr(task, "new_title") or "")
|
||||
_emit_generation_event(on_event, task, "title", "title_submit", "skipped", detail="已有标题")
|
||||
if task_id in title_results:
|
||||
continue
|
||||
if generate_mode == "cover":
|
||||
title_context = cover_title_context(task)
|
||||
elif _has_generated_title(task):
|
||||
title_context = str(getattr(task, "new_title") or "")
|
||||
else:
|
||||
title_context = ""
|
||||
if not title_context:
|
||||
continue
|
||||
title_results[task_id] = title_context
|
||||
if _has_generated_title(task):
|
||||
detail = "已有标题"
|
||||
else:
|
||||
detail = "没有新标题,本轮使用旧标题作为封面参考"
|
||||
_emit_generation_event(
|
||||
on_event,
|
||||
task,
|
||||
"title",
|
||||
"title_submit",
|
||||
"skipped",
|
||||
detail=detail,
|
||||
)
|
||||
|
||||
cover_tasks = [
|
||||
task for task in cover_candidates
|
||||
@@ -627,19 +656,21 @@ def generate_batch(tasks, prompts, ai_cfg=None, on_progress=None, should_stop=No
|
||||
level="warning",
|
||||
)
|
||||
|
||||
def persist_cover_success(task, new_title, new_cover_path):
|
||||
def persist_cover_success(task, title_context, new_cover_path):
|
||||
set_step(task, "db_write")
|
||||
_emit_generation_event(on_event, task, "cover", "db_write", "start")
|
||||
db.set_generated(task.id, new_title, new_cover_path, path=db_path)
|
||||
db.set_generated_cover(task.id, new_cover_path, path=db_path)
|
||||
summary["cover_done"] += 1
|
||||
summary["generated_done"] += 1
|
||||
needs_title = needs_by_task.get(getattr(task, "id", None), {}).get("title")
|
||||
persisted_title = title_context if needs_title else getattr(task, "new_title", None)
|
||||
if on_task_update is not None:
|
||||
on_task_update(
|
||||
task.id,
|
||||
{
|
||||
"stage": "generated",
|
||||
"status": "success",
|
||||
"new_title": new_title,
|
||||
"new_title": persisted_title,
|
||||
"new_cover_path": new_cover_path,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -973,6 +973,29 @@ def set_generated(task_id, new_title, new_cover_path, path=None, conn=None) -> N
|
||||
(new_title, new_cover_path, now, now, int(task_id)),
|
||||
)
|
||||
|
||||
|
||||
def set_generated_cover(task_id, new_cover_path, path=None, conn=None) -> None:
|
||||
"""Persist an AI-generated cover without changing the generated title."""
|
||||
|
||||
now = _now()
|
||||
with _connection(conn, path) as database:
|
||||
with database:
|
||||
database.execute(
|
||||
"""
|
||||
UPDATE tasks
|
||||
SET new_cover_path = ?,
|
||||
stage = 'generated',
|
||||
status = 'success',
|
||||
last_error = NULL,
|
||||
generate_attempts = generate_attempts + 1,
|
||||
generated_at = ?,
|
||||
updated_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(new_cover_path, now, now, int(task_id)),
|
||||
)
|
||||
|
||||
|
||||
def update_generated_title(task_id, new_title, path=None, conn=None) -> None:
|
||||
"""Update a generated title manually without touching Shopee or local cover files."""
|
||||
|
||||
|
||||
+11
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .. import diagnostics
|
||||
from .. import ai, appconfig, diagnostics
|
||||
from ..collect_skip import skipped_stage_text
|
||||
from .widgets import *
|
||||
|
||||
@@ -190,10 +190,15 @@ class GenerateTaskTableModel(QAbstractTableModel):
|
||||
self.db_path = db_path
|
||||
self.status_callback = status_callback
|
||||
self.last_edit_error = None
|
||||
self.generate_mode = "title"
|
||||
self.generate_cover_enabled = False
|
||||
|
||||
def set_generate_cover_enabled(self, enabled):
|
||||
self.generate_cover_enabled = bool(enabled)
|
||||
self.set_generate_mode("title_cover" if enabled else "title")
|
||||
|
||||
def set_generate_mode(self, mode):
|
||||
self.generate_mode = appconfig.normalize_generate_mode(mode)
|
||||
self.generate_cover_enabled = appconfig.generate_mode_includes_cover(self.generate_mode)
|
||||
if not self.tasks:
|
||||
return
|
||||
top_left = self.index(0, 4)
|
||||
@@ -403,7 +408,10 @@ class GenerateTaskTableModel(QAbstractTableModel):
|
||||
return "失败"
|
||||
if not self.generate_cover_enabled:
|
||||
return "未启用"
|
||||
if self._is_title_failure(task) or not self._has_new_title(task):
|
||||
if self.generate_mode == "cover":
|
||||
if not ai.cover_title_context(task):
|
||||
return "未开始"
|
||||
elif self._is_title_failure(task) or not self._has_new_title(task):
|
||||
return "未开始"
|
||||
if getattr(task, "status", None) == "running":
|
||||
return "处理中"
|
||||
|
||||
@@ -945,7 +945,7 @@ class GenerateTab(QWidget):
|
||||
self.empty_state_button.clicked.connect(self.open_accounts_callback)
|
||||
self.task_table = QTableView()
|
||||
self.model = GenerateTaskTableModel(self.task_table, db_path=self.db_path, status_callback=self._set_status)
|
||||
self.model.set_generate_cover_enabled(self._current_generate_mode_includes_cover())
|
||||
self.model.set_generate_mode(self._current_generate_mode())
|
||||
self.task_table.setModel(self.model)
|
||||
self.task_table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.task_table.setSelectionMode(QAbstractItemView.ExtendedSelection)
|
||||
@@ -1159,13 +1159,13 @@ class GenerateTab(QWidget):
|
||||
previous = appconfig.ai_generate_mode(self.config)
|
||||
current = self._current_generate_mode()
|
||||
if self._save_generate_mode_setting(show_status=True):
|
||||
self.model.set_generate_cover_enabled(appconfig.generate_mode_includes_cover(current))
|
||||
self.model.set_generate_mode(current)
|
||||
self.refresh_tasks()
|
||||
return
|
||||
self.generate_mode_combo.blockSignals(True)
|
||||
self._set_combo_by_data(self.generate_mode_combo, previous)
|
||||
self.generate_mode_combo.blockSignals(False)
|
||||
self.model.set_generate_cover_enabled(appconfig.generate_mode_includes_cover(previous))
|
||||
self.model.set_generate_mode(previous)
|
||||
|
||||
def _apply_task_table_column_widths(self):
|
||||
if self.model.columnCount() != len(self.TABLE_COLUMN_WEIGHTS):
|
||||
@@ -1524,7 +1524,7 @@ class GenerateTab(QWidget):
|
||||
]
|
||||
if not tasks:
|
||||
if generate_mode == "cover":
|
||||
self._set_status("当前筛选结果没有可生成封面的任务,请先生成标题。")
|
||||
self._set_status("当前筛选结果没有可生成的封面;请确认商品已完成采集且尚未生成新封面。")
|
||||
else:
|
||||
self._set_status("当前筛选结果没有可生成的缺失内容;请先在①导入采集完成采集,或调整生成内容")
|
||||
return
|
||||
@@ -2081,9 +2081,12 @@ class GenerateTab(QWidget):
|
||||
return None
|
||||
|
||||
def _prompt_context(self, task):
|
||||
new_title = task.new_title
|
||||
if self._current_generate_mode() == "cover":
|
||||
new_title = ai.cover_title_context(task)
|
||||
return {
|
||||
"old_title": task.old_title,
|
||||
"new_title": task.new_title,
|
||||
"new_title": new_title,
|
||||
"item_id": task.item_id,
|
||||
"account_name": self.model.account_name_for(task),
|
||||
"alias": task.alias,
|
||||
@@ -2133,7 +2136,7 @@ class GenerateTab(QWidget):
|
||||
_set_empty_state(self.empty_state_card, self.empty_state_label, self.empty_state_button)
|
||||
self._set_status(f"AI 生成任务读取失败:{exc}")
|
||||
return
|
||||
self.model.set_generate_cover_enabled(self._current_generate_mode_includes_cover())
|
||||
self.model.set_generate_mode(self._current_generate_mode())
|
||||
self.model.set_tasks(filtered_tasks, accounts_rows)
|
||||
self._apply_task_table_column_widths()
|
||||
self.summary_label.setText(
|
||||
|
||||
@@ -593,6 +593,8 @@ class GenerateWorker(BaseWorker):
|
||||
if result == "start" and step == "title_submit":
|
||||
return f"[标题] {self._task_progress_label(task)} 开始生成"
|
||||
if result == "skipped":
|
||||
if detail and "旧标题作为封面参考" in detail:
|
||||
return f"[图片] {self._task_progress_label(task)} {detail}"
|
||||
return f"[标题] {self._task_progress_label(task)} 已有标题,跳过生文"
|
||||
if result == "success" and step == "title_done":
|
||||
return f"[标题] {self._task_progress_label(task)} 成功"
|
||||
|
||||
Reference in New Issue
Block a user