[feat] Add bulk import failure info API and improve conflict detection (#4550)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Jin Yi
2025-07-29 06:13:01 +09:00
parent 21dbb86073
commit ddb9577d4c
3 changed files with 47 additions and 52 deletions

View File

@@ -68,6 +68,7 @@ import InfoTabs from '@/components/dialog/content/manager/infoPanel/InfoTabs.vue
import MetadataRow from '@/components/dialog/content/manager/infoPanel/MetadataRow.vue'
import { useConflictDetection } from '@/composables/useConflictDetection'
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import { useConflictDetectionStore } from '@/stores/conflictDetectionStore'
import { IsInstallingKey } from '@/types/comfyManagerTypes'
import { components } from '@/types/comfyRegistryTypes'
import type { ConflictDetectionResult } from '@/types/conflictDetectionTypes'
@@ -84,21 +85,27 @@ const { nodePack } = defineProps<{
const scrollContainer = ref<HTMLElement | null>(null)
const managerStore = useComfyManagerStore()
const isInstalled = computed(() => managerStore.isPackInstalled(nodePack.id))
const { isPackInstalled } = useComfyManagerStore()
const isInstalled = computed(() => isPackInstalled(nodePack.id))
const isInstalling = ref(false)
provide(IsInstallingKey, isInstalling)
whenever(isInstalled, () => {
isInstalling.value = false
})
const { isPackInstalled } = useComfyManagerStore()
const { checkVersionCompatibility } = useConflictDetection()
const { getConflictsForPackageByID } = useConflictDetectionStore()
const { t, d, n } = useI18n()
// Check compatibility once and pass to children
const conflictResult = computed((): ConflictDetectionResult | null => {
// For installed packages, use stored conflict data
if (isInstalled.value && nodePack.id) {
return getConflictsForPackageByID(nodePack.id) || null
}
// For non-installed packages, perform compatibility check
const compatibility = checkVersionCompatibility({
supported_os: nodePack.supported_os,
supported_accelerators: nodePack.supported_accelerators,

View File

@@ -422,7 +422,7 @@ export function useConflictDetection() {
/**
* Fetches Python import failure information from ComfyUI Manager.
* Gets installed packages and checks each one for import failures.
* Gets installed packages and checks each one for import failures using bulk API.
* @returns Promise that resolves to import failure data
*/
async function fetchImportFailInfo(): Promise<Record<string, any>> {
@@ -441,61 +441,32 @@ export function useConflictDetection() {
return {}
}
const importFailures: Record<string, any> = {}
const packageIds = installedPacks.value.map((pack) => pack.id || '')
// Check each installed package for import failures
// Process in smaller batches to avoid overwhelming the API
const packageIds = installedPacks.value.map((pack) => pack.id)
const batchSize = 10
// Use bulk API to get import failure info for all packages at once
const bulkResult = await comfyManagerService.getImportFailInfoBulk(
{ cnr_ids: packageIds },
abortController.value?.signal
)
for (let i = 0; i < packageIds.length; i += batchSize) {
const batch = packageIds.slice(i, i + batchSize)
if (bulkResult) {
// Filter out null values (packages without import failures)
const importFailures: Record<string, any> = {}
const batchResults = await Promise.allSettled(
batch.map(async (packageId) => {
try {
// Try to get import failure info for this package using normalized ID
const failInfo = await comfyManagerService.getImportFailInfo(
{ cnr_id: packageId },
abortController.value?.signal
)
if (failInfo) {
console.log(
`[ConflictDetection] Import failure found for ${packageId}:`,
failInfo
)
return { packageId, failInfo }
}
} catch (error) {
// If API returns 400, it means no import failure info available
// This is normal for packages that imported successfully
if (error && typeof error === 'object' && 'response' in error) {
const axiosError = error as any
if (axiosError.response?.status === 400) {
return null // No failure info available (normal case)
}
}
console.warn(
`[ConflictDetection] Failed to check import failure for ${packageId}:`,
error
)
}
return null
})
)
// Process batch results
batchResults.forEach((result) => {
if (result.status === 'fulfilled' && result.value) {
const { packageId, failInfo } = result.value
importFailures[packageId || ''] = failInfo
Object.entries(bulkResult).forEach(([packageId, failInfo]) => {
if (failInfo !== null) {
importFailures[packageId] = failInfo
console.log(
`[ConflictDetection] Import failure found for ${packageId}:`,
failInfo
)
}
})
return importFailures
}
return importFailures
return {}
} catch (error) {
console.warn(
'[ConflictDetection] Failed to fetch import failure information:',

View File

@@ -27,6 +27,7 @@ enum ManagerRoute {
LIST_INSTALLED = 'v2/customnode/installed',
GET_NODES = 'v2/customnode/getmappings',
IMPORT_FAIL_INFO = 'v2/customnode/import_fail_info',
IMPORT_FAIL_INFO_BULK = 'v2/customnode/import_fail_info_bulk',
REBOOT = 'v2/manager/reboot',
IS_LEGACY_MANAGER_UI = 'v2/manager/is_legacy_manager_ui',
TASK_HISTORY = 'v2/manager/queue/history',
@@ -150,6 +151,21 @@ export const useComfyManagerService = () => {
)
}
const getImportFailInfoBulk = async (
params: { cnr_ids?: string[]; urls?: string[] } = {},
signal?: AbortSignal
) => {
const errorContext = 'Fetching bulk import failure information'
return executeRequest<Record<string, any>>(
() =>
managerApiClient.post(ManagerRoute.IMPORT_FAIL_INFO_BULK, params, {
signal
}),
{ errorContext }
)
}
const queueTask = async (
kind: QueueTaskItem['kind'],
params: QueueTaskItem['params'],
@@ -289,6 +305,7 @@ export const useComfyManagerService = () => {
// Pack management
listInstalledPacks,
getImportFailInfo,
getImportFailInfoBulk,
installPack,
uninstallPack,
enablePack: installPack, // enable is done via install