feat(ai-studio): make original downloads nonblocking

This commit is contained in:
chengma
2026-07-11 17:28:37 +08:00
parent 4e552ea19b
commit 879a3fe5cc
5 changed files with 726 additions and 45 deletions
+91 -9
View File
@@ -5,6 +5,7 @@ from __future__ import annotations
import datetime as _dt
import re
import threading
import time
from .. import image_studio, image_studio_export, image_studio_generation, image_studio_images
from .widgets import *
@@ -110,22 +111,103 @@ class ImageStudioPullImagesWorker(BaseWorker):
class ImageStudioDownloadOriginalWorker(BaseWorker):
"""Download one remote original image into the project pool."""
def __init__(self, asset_id, *, db_path=None, config=None, open_after=False):
def __init__(
self,
asset_id,
*,
db_path=None,
config=None,
open_after=False,
max_retries=2,
retry_delays=(1, 2),
):
super().__init__()
self.asset_id = int(asset_id)
self.db_path = db_path
self.config = config
self.open_after = bool(open_after)
self.max_retries = max(0, int(max_retries or 0))
self.retry_delays = tuple(float(delay) for delay in (retry_delays or ()))
def execute(self):
self.log.emit("[AI工场] 下载原图:开始")
asset = image_studio_images.download_original_asset(
self.asset_id,
path=self.db_path,
config=self.config,
)
self.log.emit("[AI工场] 下载原图:成功")
return {"asset": asset, "open_after": self.open_after}
attempts = self.max_retries + 1
for attempt in range(1, attempts + 1):
if self.should_cancel():
return {"asset_id": self.asset_id, "cancelled": True}
self.progress.emit(
{
"asset_id": self.asset_id,
"state": "start",
"attempt": attempt,
"attempts": attempts,
}
)
self.log.emit(f"[AI工场] 下载蝦皮原主图 #{self.asset_id}:开始")
try:
asset = image_studio_images.download_original_asset(
self.asset_id,
path=self.db_path,
config=self.config,
)
except Exception:
retry = attempt
if attempt >= attempts:
self.progress.emit(
{
"asset_id": self.asset_id,
"state": "failed",
"attempt": attempt,
"attempts": attempts,
}
)
self.log.emit(f"[AI工场] 下载蝦皮原主图 #{self.asset_id}:最终失败")
return {
"ok": False,
"asset_id": self.asset_id,
"open_after": self.open_after,
"error": "蝦皮原主图下载失败,请稍后再次点击图片重试。",
}
delay = self._retry_delay(retry)
self.progress.emit(
{
"asset_id": self.asset_id,
"state": "retry",
"retry": retry,
"max_retries": self.max_retries,
"delay_seconds": delay,
}
)
self.log.emit(
f"[AI工场] 下载蝦皮原主图 #{self.asset_id}:失败,准备重试 {retry}/{self.max_retries}"
)
if not self._wait_for_retry(delay):
return {"asset_id": self.asset_id, "cancelled": True}
continue
self.progress.emit(
{
"asset_id": self.asset_id,
"state": "success",
"attempt": attempt,
"attempts": attempts,
}
)
self.log.emit(f"[AI工场] 下载蝦皮原主图 #{self.asset_id}:成功")
return {"asset": asset, "asset_id": self.asset_id, "open_after": self.open_after}
return {"asset_id": self.asset_id, "cancelled": True}
def _retry_delay(self, retry):
if retry <= 0:
return 0.0
index = min(retry - 1, len(self.retry_delays) - 1)
return self.retry_delays[index] if index >= 0 else 0.0
def _wait_for_retry(self, delay_seconds):
deadline = time.monotonic() + max(0.0, float(delay_seconds or 0))
while time.monotonic() < deadline:
if self.should_cancel():
return False
time.sleep(min(0.1, max(0.0, deadline - time.monotonic())))
return not self.should_cancel()
class ImageStudioGenerateJobsWorker(BaseWorker):