mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-23 07:50:15 +00:00
[feat] Add async model upload with WebSocket progress tracking (#7746)
## Summary - Adds asynchronous model upload support with HTTP 202 responses - Implements WebSocket-based real-time download progress tracking via `asset_download` events - Creates `assetDownloadStore` for centralized download state management and toast notifications - Updates upload wizard UI to show "processing" state when downloads continue in background ## Changes - **Core**: New `assetDownloadStore` for managing async downloads with WebSocket events - **API**: Support for HTTP 202 async upload responses with task tracking - **UI**: Upload wizard now shows "processing" state and allows closing dialog during download - **Progress**: Periodic toast notifications (every 5s) during active downloads with completion/error toasts - **Schema**: Updated task statuses (`created`, `running`, `completed`, `failed`) and WebSocket message types ## Review Focus - WebSocket event handling and download state management in `assetDownloadStore` - Upload flow UX - users can now close the dialog and download continues in background - Toast notification frequency and timing - Schema alignment with backend async upload API Fixes #7748 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7746-feat-Add-async-model-upload-with-WebSocket-progress-tracking-2d36d73d3650811cb79ae06f470dcded) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
committed by
GitHub
parent
fbdaf5d7f3
commit
14d0ec73f6
@@ -3,12 +3,14 @@ import { fromZodError } from 'zod-validation-error'
|
||||
import { st } from '@/i18n'
|
||||
import {
|
||||
assetItemSchema,
|
||||
assetResponseSchema
|
||||
assetResponseSchema,
|
||||
asyncUploadResponseSchema
|
||||
} from '@/platform/assets/schemas/assetSchema'
|
||||
import type {
|
||||
AssetItem,
|
||||
AssetMetadata,
|
||||
AssetResponse,
|
||||
AsyncUploadResponse,
|
||||
ModelFile,
|
||||
ModelFolder
|
||||
} from '@/platform/assets/schemas/assetSchema'
|
||||
@@ -46,6 +48,7 @@ function getLocalizedErrorMessage(errorCode: string): string {
|
||||
}
|
||||
|
||||
const ASSETS_ENDPOINT = '/assets'
|
||||
const ASSETS_DOWNLOAD_ENDPOINT = '/assets/download'
|
||||
const EXPERIMENTAL_WARNING = `EXPERIMENTAL: If you are seeing this please make sure "Comfy.Assets.UseAssetAPI" is set to "false" in your ComfyUI Settings.\n`
|
||||
const DEFAULT_LIMIT = 500
|
||||
|
||||
@@ -445,6 +448,72 @@ function createAssetService() {
|
||||
return await res.json()
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads an asset asynchronously using the /api/assets/download endpoint
|
||||
* Returns immediately with either the asset (if already exists) or a task to track
|
||||
*
|
||||
* @param params - Upload parameters
|
||||
* @param params.source_url - HTTP/HTTPS URL to download from
|
||||
* @param params.tags - Optional freeform tags
|
||||
* @param params.user_metadata - Optional custom metadata object
|
||||
* @param params.preview_id - Optional UUID for preview asset
|
||||
* @returns Promise<AsyncUploadResponse> - Either sync asset or async task info
|
||||
* @throws Error if upload fails
|
||||
*/
|
||||
async function uploadAssetAsync(params: {
|
||||
source_url: string
|
||||
tags?: string[]
|
||||
user_metadata?: Record<string, unknown>
|
||||
preview_id?: string
|
||||
}): Promise<AsyncUploadResponse> {
|
||||
const res = await api.fetchApi(ASSETS_DOWNLOAD_ENDPOINT, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(params)
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(
|
||||
st(
|
||||
'assetBrowser.errorUploadFailed',
|
||||
'Failed to upload asset. Please try again.'
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
const data = await res.json()
|
||||
|
||||
if (res.status === 202) {
|
||||
const result = asyncUploadResponseSchema.safeParse({
|
||||
type: 'async',
|
||||
task: data
|
||||
})
|
||||
if (!result.success) {
|
||||
throw new Error(
|
||||
st(
|
||||
'assetBrowser.errorUploadFailed',
|
||||
'Failed to parse async upload response. Please try again.'
|
||||
)
|
||||
)
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
const result = asyncUploadResponseSchema.safeParse({
|
||||
type: 'sync',
|
||||
asset: data
|
||||
})
|
||||
if (!result.success) {
|
||||
throw new Error(
|
||||
st(
|
||||
'assetBrowser.errorUploadFailed',
|
||||
'Failed to parse sync upload response. Please try again.'
|
||||
)
|
||||
)
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
return {
|
||||
getAssetModelFolders,
|
||||
getAssetModels,
|
||||
@@ -456,7 +525,8 @@ function createAssetService() {
|
||||
updateAsset,
|
||||
getAssetMetadata,
|
||||
uploadAssetFromUrl,
|
||||
uploadAssetFromBase64
|
||||
uploadAssetFromBase64,
|
||||
uploadAssetAsync
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user