feat(ai-studio): resume hosted image jobs
This commit is contained in:
@@ -602,6 +602,53 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_image_studio_tab_shows_resume_and_job_billing_status(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"],
|
||||
)
|
||||
source = image_studio.add_asset(
|
||||
project.id,
|
||||
"original",
|
||||
local_path=self.write_test_image(os.path.join(temp_dir, "source.jpg")),
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
job = image_studio.create_job(
|
||||
project.id,
|
||||
source_asset_id=source.id,
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
image_studio.set_job_submitted(
|
||||
job.id,
|
||||
"cmhub-task-1",
|
||||
call_id="call-1",
|
||||
points_cost=2,
|
||||
points_balance=88,
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
tab = ImageStudioTab(config=cfg, db_path=cfg["db_path"])
|
||||
self.addCleanup(tab.close)
|
||||
tab._select_project(project.id)
|
||||
|
||||
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() == "任务"
|
||||
]
|
||||
self.assertEqual(1, len(statuses))
|
||||
self.assertIn("已提交", statuses[0])
|
||||
self.assertIn("扣点2", statuses[0])
|
||||
self.assertIn("余额88", statuses[0])
|
||||
self.assertIn("call_id=call-1", statuses[0])
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_startup_update_gate_forced_blocks_and_opens_download(self):
|
||||
boxes = []
|
||||
|
||||
|
||||
@@ -231,6 +231,71 @@ class ImageStudioGenerationTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_resume_failed_download_job_polls_without_new_submit(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg, project, source = self._project_source(temp_dir)
|
||||
job = image_studio.create_job(
|
||||
project.id,
|
||||
source_asset_id=source.id,
|
||||
job_type="main",
|
||||
prompt="恢复下载",
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
image_studio.set_job_submitted(
|
||||
job.id,
|
||||
"cmhub-task-download",
|
||||
call_id="call-download",
|
||||
points_cost=2,
|
||||
points_balance=88,
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
image_studio.update_job_status(
|
||||
job.id,
|
||||
"failed",
|
||||
error="下载新封面失败",
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
|
||||
resumable = image_studio.list_resumable_jobs(
|
||||
path=cfg["db_path"],
|
||||
project_id=project.id,
|
||||
include_failed_downloads=True,
|
||||
)
|
||||
self.assertEqual([job.id], [item.id for item in resumable])
|
||||
|
||||
def fake_poll(method, url, api_key, **kwargs):
|
||||
self.assertEqual("GET", method)
|
||||
return {
|
||||
"task_id": "cmhub-task-download",
|
||||
"status": "succeeded",
|
||||
"result": {"image_url": "https://cdn.example.com/recovered.png"},
|
||||
"points_balance": 88,
|
||||
}
|
||||
|
||||
with mock.patch("app.image_studio_generation._runtime", return_value=self._runtime()), \
|
||||
mock.patch("app.image_studio_generation.ai._cmhub_call_with_retry") as submit, \
|
||||
mock.patch("app.image_studio_generation.ai._cmhub_call_once", side_effect=fake_poll), \
|
||||
mock.patch(
|
||||
"app.image_studio_generation.ai._download_cmhub_image_with_retry",
|
||||
return_value=(self._png_bytes(), 0.1),
|
||||
):
|
||||
summary = image_studio_generation.resume_image_jobs(
|
||||
project_id=project.id,
|
||||
config=cfg,
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
|
||||
self.assertEqual(1, summary["success"])
|
||||
submit.assert_not_called()
|
||||
updated = image_studio.get_job(job.id, path=cfg["db_path"])
|
||||
self.assertEqual("succeeded", updated.status)
|
||||
self.assertEqual("cmhub-task-download", updated.task_id)
|
||||
self.assertEqual("call-download", updated.call_id)
|
||||
assets = image_studio.list_assets(project.id, kind="generated_main", path=cfg["db_path"])
|
||||
self.assertEqual(1, len(assets))
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_failed_cmhub_task_marks_only_that_job_failed(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg, project, source = self._project_source(temp_dir)
|
||||
|
||||
Reference in New Issue
Block a user