feat(ai-studio): add thumbnail workspace grids
This commit is contained in:
+130
-13
@@ -17,7 +17,7 @@ from app import accounts, ai, appconfig, db, image_paths, image_studio, prompts,
|
||||
if gui.QT_IMPORT_ERROR is not None:
|
||||
raise unittest.SkipTest("PySide6 未安装")
|
||||
|
||||
from PySide6.QtCore import QItemSelectionModel, QModelIndex, QRect
|
||||
from PySide6.QtCore import QItemSelectionModel, QModelIndex, QRect, QSize
|
||||
from PySide6.QtGui import QImage, QKeyEvent, QTextCursor
|
||||
from PySide6.QtWidgets import QApplication, QComboBox, QLineEdit, QPlainTextEdit, QProgressBar, QTableView
|
||||
|
||||
@@ -85,6 +85,31 @@ class FakeGenerateWorker:
|
||||
FakeGenerateWorker.instances.append(self)
|
||||
|
||||
|
||||
class FakeThumbnailLoader:
|
||||
def __init__(self):
|
||||
self.submissions = []
|
||||
self.cancelled = []
|
||||
self.closed = False
|
||||
|
||||
def submit(self, key, url, on_success=None, on_error=None):
|
||||
self.submissions.append((key, url, on_success, on_error))
|
||||
return None
|
||||
|
||||
def cancel(self, key=None):
|
||||
self.cancelled.append(key)
|
||||
|
||||
def close(self):
|
||||
self.closed = True
|
||||
|
||||
def succeed(self, index, image_bytes):
|
||||
_, _, on_success, _ = self.submissions[index]
|
||||
on_success(SimpleNamespace(image_bytes=image_bytes))
|
||||
|
||||
def fail(self, index):
|
||||
key, _, _, on_error = self.submissions[index]
|
||||
on_error(key, RuntimeError("缩略图请求失败"))
|
||||
|
||||
|
||||
class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
@@ -496,11 +521,13 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
prompts_dir = os.path.join(temp_dir, "prompts", "image_studio")
|
||||
account = accounts.create_account("主店", "alias-a", debug_port=9222, config=cfg)
|
||||
prompts.save_image_studio_template("工场模板", "完整提示词", prompts_dir)
|
||||
thumbnail_loader = FakeThumbnailLoader()
|
||||
|
||||
tab = ImageStudioTab(
|
||||
config=cfg,
|
||||
db_path=cfg["db_path"],
|
||||
prompts_dir=prompts_dir,
|
||||
thumbnail_loader=thumbnail_loader,
|
||||
)
|
||||
self.addCleanup(tab.close)
|
||||
|
||||
@@ -541,6 +568,36 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
tab.template_combo.setCurrentIndex(template_index)
|
||||
tab.load_selected_template()
|
||||
self.assertEqual("完整提示词", tab.prompt_edit.toPlainText())
|
||||
tab.resize(1280, 820)
|
||||
tab.show()
|
||||
self.app.processEvents()
|
||||
self.assertLessEqual(
|
||||
max(
|
||||
button.y()
|
||||
for button in (
|
||||
tab.template_new_button,
|
||||
tab.template_rename_button,
|
||||
tab.template_save_button,
|
||||
tab.template_delete_button,
|
||||
)
|
||||
)
|
||||
- min(
|
||||
button.y()
|
||||
for button in (
|
||||
tab.template_new_button,
|
||||
tab.template_rename_button,
|
||||
tab.template_save_button,
|
||||
tab.template_delete_button,
|
||||
)
|
||||
),
|
||||
1,
|
||||
)
|
||||
self.assertLessEqual(
|
||||
max(tab.job_type_combo.y(), tab.count_spin.y(), tab.aspect_combo.y())
|
||||
- min(tab.job_type_combo.y(), tab.count_spin.y(), tab.aspect_combo.y()),
|
||||
1,
|
||||
)
|
||||
self.assertNotIn("当前源图\n单击照片池图片设为源图,双击查看大图", label_texts)
|
||||
|
||||
project = image_studio.create_or_get_project(
|
||||
account,
|
||||
@@ -570,15 +627,75 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
)[0]
|
||||
tab.refresh_project_assets()
|
||||
|
||||
self.assertEqual(1, tab.original_table.rowCount())
|
||||
self.assertEqual("主图 #1", tab.original_table.item(0, 0).text())
|
||||
self.assertFalse(tab.original_table.item(0, 0).icon().isNull())
|
||||
self.assertEqual("远程待下载", tab.original_table.item(0, 1).text())
|
||||
self.assertEqual(1, tab.pool_table.rowCount())
|
||||
self.assertEqual(f"原图 #{original.id}", tab.pool_table.item(0, 0).text())
|
||||
self.assertFalse(tab.pool_table.item(0, 0).icon().isNull())
|
||||
self.assertEqual("远程待下载", tab.pool_table.item(0, 2).text())
|
||||
self.assertEqual(original.id, tab.pool_table.item(0, 0).data(gui.Qt.UserRole)["asset_id"])
|
||||
self.assertEqual(1, tab.original_grid.count())
|
||||
self.assertIn("主图 1", tab.original_grid.item(0).text())
|
||||
self.assertIn("加载中", tab.original_grid.item(0).text())
|
||||
self.assertFalse(tab.original_grid.item(0).icon().isNull())
|
||||
self.assertEqual(1, len(thumbnail_loader.submissions))
|
||||
self.assertEqual(0, tab.pool_grid.count())
|
||||
|
||||
thumbnail_loader.fail(0)
|
||||
self.app.processEvents()
|
||||
self.assertIn("加载失败", tab.original_grid.item(0).text())
|
||||
self.assertIn("右键重新加载", tab.original_grid.item(0).toolTip())
|
||||
tab._retry_original_thumbnail(original)
|
||||
self.assertEqual(2, len(thumbnail_loader.submissions))
|
||||
self.assertIn("加载中", tab.original_grid.item(0).text())
|
||||
|
||||
thumbnail_path = self.write_test_image(os.path.join(temp_dir, "thumbnail.png"))
|
||||
with open(thumbnail_path, "rb") as image_file:
|
||||
thumbnail_loader.succeed(1, image_file.read())
|
||||
self.app.processEvents()
|
||||
self.assertIn("可预览", tab.original_grid.item(0).text())
|
||||
self.assertIsNone(image_studio.get_asset(original.id, path=cfg["db_path"]).local_path)
|
||||
|
||||
local_original_path = self.write_test_image(os.path.join(temp_dir, "original.png"))
|
||||
image_studio.update_asset_local_path(original.id, local_original_path, path=cfg["db_path"])
|
||||
tab.refresh_project_assets()
|
||||
self.assertEqual(1, tab.pool_grid.count())
|
||||
pool_item = tab.pool_grid.item(0)
|
||||
self.assertIn("原图", pool_item.text())
|
||||
self.assertEqual(original.id, pool_item.data(gui.Qt.UserRole)["asset_id"])
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_image_studio_thumbnail_grids_keep_order_and_hide_remote_pool_duplicates(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
db.init_db(cfg["db_path"])
|
||||
project = image_studio.create_or_get_project(
|
||||
account_alias="alias-a",
|
||||
account_slug="alias_a",
|
||||
item_id="51100639510",
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
image_studio.sync_original_asset_urls(
|
||||
project.id,
|
||||
[
|
||||
{"index": index, "src": f"https://susercontent.com/main-{index}.jpg"}
|
||||
for index in range(1, 10)
|
||||
],
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
thumbnail_loader = FakeThumbnailLoader()
|
||||
tab = ImageStudioTab(
|
||||
config=cfg,
|
||||
db_path=cfg["db_path"],
|
||||
thumbnail_loader=thumbnail_loader,
|
||||
)
|
||||
self.addCleanup(tab.close)
|
||||
tab._select_project(project.id)
|
||||
|
||||
self.assertEqual(9, tab.original_grid.count())
|
||||
self.assertEqual(
|
||||
[f"主图 {index}" for index in range(1, 10)],
|
||||
[tab.original_grid.item(row).text().split("\n", 1)[0] for row in range(9)],
|
||||
)
|
||||
self.assertEqual(9, len(thumbnail_loader.submissions))
|
||||
self.assertEqual(0, tab.pool_grid.count())
|
||||
self.assertEqual(QSize(78, 92), tab.original_grid.gridSize())
|
||||
self.assertEqual(QSize(108, 124), tab.pool_grid.gridSize())
|
||||
self.assertGreaterEqual(tab.prompt_edit.minimumHeight(), 210)
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
@@ -749,9 +866,9 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
self.assertEqual("继续查询任务", tab.resume_button.text())
|
||||
statuses = [
|
||||
tab.pool_table.item(row, 2).text()
|
||||
for row in range(tab.pool_table.rowCount())
|
||||
if tab.pool_table.item(row, 0).text() == "任务"
|
||||
tab.pool_grid.item(row).text()
|
||||
for row in range(tab.pool_grid.count())
|
||||
if tab.pool_grid.item(row).data(gui.Qt.UserRole)["type"] == "job"
|
||||
]
|
||||
self.assertEqual(1, len(statuses))
|
||||
self.assertIn("已提交", statuses[0])
|
||||
|
||||
Reference in New Issue
Block a user