feat: extract workflow output save phase 3
This commit is contained in:
@@ -99,6 +99,15 @@ class BBoxResolutionResult:
|
||||
return self.bbox_data is not None
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class OutputSaveResult:
|
||||
status: Literal["completed", "failed"]
|
||||
result_path: str | None
|
||||
asset_id: str | None = None
|
||||
storage_key: str | None = None
|
||||
asset_type: MediaAssetType | None = None
|
||||
|
||||
|
||||
def _emit(emit: EmitFn, order_line_id: str, message: str, level: str | None = None) -> None:
|
||||
if emit is None:
|
||||
return
|
||||
@@ -197,6 +206,100 @@ def resolve_cad_bbox(
|
||||
)
|
||||
|
||||
|
||||
def _normalize_storage_key(output_path: str) -> str:
|
||||
upload_prefix = str(app_settings.upload_dir).rstrip("/") + "/"
|
||||
return output_path[len(upload_prefix):] if output_path.startswith(upload_prefix) else output_path
|
||||
|
||||
|
||||
def _resolve_output_asset_type(output_path: str) -> MediaAssetType:
|
||||
extension = output_path.rsplit(".", 1)[-1].lower() if "." in output_path else "bin"
|
||||
return MediaAssetType.turntable if extension in ("mp4", "webm") else MediaAssetType.still
|
||||
|
||||
|
||||
def _resolve_output_mime_type(output_path: str) -> str:
|
||||
extension = output_path.rsplit(".", 1)[-1].lower() if "." in output_path else "bin"
|
||||
if extension in ("mp4", "webm"):
|
||||
return "video/mp4"
|
||||
if extension == "webp":
|
||||
return "image/webp"
|
||||
if extension in ("jpg", "jpeg"):
|
||||
return "image/jpeg"
|
||||
return "image/png"
|
||||
|
||||
|
||||
def persist_order_line_output(
|
||||
session: Session,
|
||||
line: OrderLine,
|
||||
*,
|
||||
success: bool,
|
||||
output_path: str,
|
||||
render_log: dict[str, Any] | None,
|
||||
render_completed_at: datetime | None = None,
|
||||
) -> OutputSaveResult:
|
||||
"""Persist the render result for an order line and publish the media asset if needed."""
|
||||
status: Literal["completed", "failed"] = "completed" if success else "failed"
|
||||
completed_at = render_completed_at or datetime.utcnow()
|
||||
|
||||
line.render_status = status
|
||||
line.render_completed_at = completed_at
|
||||
line.render_log = render_log
|
||||
line.result_path = output_path if success else None
|
||||
session.flush()
|
||||
|
||||
asset_id: str | None = None
|
||||
storage_key: str | None = None
|
||||
asset_type: MediaAssetType | None = None
|
||||
if success:
|
||||
storage_key = _normalize_storage_key(output_path)
|
||||
asset_type = _resolve_output_asset_type(output_path)
|
||||
existing_asset = session.execute(
|
||||
select(MediaAsset).where(MediaAsset.storage_key == storage_key).limit(1)
|
||||
).scalar_one_or_none()
|
||||
if existing_asset is None:
|
||||
output_file = Path(output_path)
|
||||
render_config = None
|
||||
if isinstance(render_log, dict):
|
||||
render_config = {
|
||||
key: render_log[key]
|
||||
for key in (
|
||||
"renderer",
|
||||
"engine_used",
|
||||
"engine",
|
||||
"samples",
|
||||
"device_used",
|
||||
"compute_type",
|
||||
"total_duration_s",
|
||||
)
|
||||
if key in render_log
|
||||
}
|
||||
asset = MediaAsset(
|
||||
tenant_id=line.product.cad_file.tenant_id if (line.product and line.product.cad_file) else None,
|
||||
order_line_id=line.id,
|
||||
product_id=line.product_id,
|
||||
asset_type=asset_type,
|
||||
storage_key=storage_key,
|
||||
mime_type=_resolve_output_mime_type(output_path),
|
||||
file_size_bytes=output_file.stat().st_size if output_file.exists() else None,
|
||||
width=None,
|
||||
height=None,
|
||||
render_config=render_config,
|
||||
)
|
||||
session.add(asset)
|
||||
session.flush()
|
||||
asset_id = str(asset.id)
|
||||
else:
|
||||
asset_id = str(existing_asset.id)
|
||||
|
||||
session.commit()
|
||||
return OutputSaveResult(
|
||||
status=status,
|
||||
result_path=line.result_path,
|
||||
asset_id=asset_id,
|
||||
storage_key=storage_key,
|
||||
asset_type=asset_type,
|
||||
)
|
||||
|
||||
|
||||
def prepare_order_line_render_context(
|
||||
session: Session,
|
||||
order_line_id: str,
|
||||
|
||||
Reference in New Issue
Block a user