From ba3ccff69c75097e95da4ec0f0903ef1214b75a7 Mon Sep 17 00:00:00 2001 From: Luke Mino-Altherr Date: Mon, 15 Dec 2025 22:13:44 -0500 Subject: [PATCH 1/8] feat: add HuggingFace model import support with UX improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add HuggingFace as a model import source alongside CivitAI - Support URL-encoded filenames (UTF-8 characters like Chinese) - Sort model types alphabetically for easier selection - Add feature flag for HuggingFace import enablement - Implement import source handler pattern for extensibility - Use proper i18n template parameters for error messages 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- public/assets/images/hf-logo.svg | 8 ++ src/components/graph/GraphCanvas.vue | 5 +- src/composables/useFeatureFlags.ts | 11 +++ src/locales/en/main.json | 9 ++ .../assets/components/UploadModelDialog.vue | 14 ++- .../components/UploadModelDialogHeader.vue | 22 ++++- .../assets/components/UploadModelFooter.vue | 4 +- .../assets/components/UploadModelUrlInput.vue | 90 ++++++++++++++----- .../components/UploadModelUrlInputCivitai.vue | 47 ++++++++++ .../assets/composables/useModelTypes.ts | 10 ++- .../composables/useUploadModelWizard.ts | 62 +++++++++---- .../importSources/civitaiImportSource.ts | 35 ++++++++ .../importSources/huggingfaceImportSource.ts | 37 ++++++++ src/platform/assets/types/importSource.ts | 41 +++++++++ src/platform/remoteConfig/types.ts | 1 + 15 files changed, 348 insertions(+), 48 deletions(-) create mode 100644 public/assets/images/hf-logo.svg create mode 100644 src/platform/assets/components/UploadModelUrlInputCivitai.vue create mode 100644 src/platform/assets/importSources/civitaiImportSource.ts create mode 100644 src/platform/assets/importSources/huggingfaceImportSource.ts create mode 100644 src/platform/assets/types/importSource.ts diff --git a/public/assets/images/hf-logo.svg b/public/assets/images/hf-logo.svg new file mode 100644 index 0000000000..ab959d165f --- /dev/null +++ b/public/assets/images/hf-logo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/components/graph/GraphCanvas.vue b/src/components/graph/GraphCanvas.vue index 48d82e44b4..860e2d9323 100644 --- a/src/components/graph/GraphCanvas.vue +++ b/src/components/graph/GraphCanvas.vue @@ -460,8 +460,9 @@ onMounted(async () => { await workflowPersistence.loadTemplateFromUrlIfPresent() // Initialize release store to fetch releases from comfy-api (fire-and-forget) - const { useReleaseStore } = - await import('@/platform/updates/common/releaseStore') + const { useReleaseStore } = await import( + '@/platform/updates/common/releaseStore' + ) const releaseStore = useReleaseStore() void releaseStore.initialize() diff --git a/src/composables/useFeatureFlags.ts b/src/composables/useFeatureFlags.ts index 07b82ff40c..54399dff4f 100644 --- a/src/composables/useFeatureFlags.ts +++ b/src/composables/useFeatureFlags.ts @@ -15,6 +15,7 @@ export enum ServerFeatureFlag { PRIVATE_MODELS_ENABLED = 'private_models_enabled', SUBSCRIPTION_TIERS_ENABLED = 'subscription_tiers_enabled', ONBOARDING_SURVEY_ENABLED = 'onboarding_survey_enabled' + HUGGINGFACE_MODEL_IMPORT_ENABLED = 'huggingface_model_import_enabled' } /** @@ -73,6 +74,16 @@ export function useFeatureFlags() { remoteConfig.value.onboarding_survey_enabled ?? api.getServerFeature(ServerFeatureFlag.ONBOARDING_SURVEY_ENABLED, true) ) + }, + get huggingfaceModelImportEnabled() { + // Check remote config first (from /api/features), fall back to websocket feature flags + return ( + remoteConfig.value.huggingface_model_import_enabled ?? + api.getServerFeature( + ServerFeatureFlag.HUGGINGFACE_MODEL_IMPORT_ENABLED, + false + ) + ) } }) diff --git a/src/locales/en/main.json b/src/locales/en/main.json index f6d66f3c23..5165ade3b2 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -2230,6 +2230,9 @@ "civitaiLinkExample": "Example: https://civitai.com/models/10706/luisap-z-image-and-qwen-pixel-art-refiner?modelVersionId=2225295", "civitaiLinkLabel": "Civitai model download link", "civitaiLinkPlaceholder": "Paste link here", + "genericLinkExample": "Example: https://civitai.com/models/10706/example or https://huggingface.co/example", + "genericLinkLabel": "Model download link", + "genericLinkPlaceholder": "Paste link here", "confirmModelDetails": "Confirm Model Details", "connectionError": "Please check your connection and try again", "errorFileTooLarge": "File exceeds the maximum allowed size limit", @@ -2248,6 +2251,7 @@ "finish": "Finish", "jobId": "Job ID", "loadingModels": "Loading {type}...", + "maxFileSize": "Max file size: 1 GB", "modelAssociatedWithLink": "The model associated with the link you provided:", "modelName": "Model Name", "modelNamePlaceholder": "Enter a name for this model", @@ -2258,6 +2262,7 @@ "noModelsInFolder": "No {type} available in this folder", "notSureLeaveAsIs": "Not sure? Just leave this as is", "onlyCivitaiUrlsSupported": "Only Civitai URLs are supported", + "unsupportedUrlSource": "Only URLs from {sources} are supported", "ownership": "Ownership", "ownershipAll": "All", "ownershipMyModels": "My models", @@ -2285,9 +2290,13 @@ "uploadModelDescription1": "Paste a Civitai model download link to add it to your library.", "uploadModelDescription2": "Only links from https://civitai.com/models are supported at the moment", "uploadModelDescription3": "Max file size: 1 GB", + "uploadModelDescription1Generic": "Paste a model download link to add it to your library.", + "uploadModelDescription2Generic": "Only URLs from the following providers are supported:", "uploadModelFailedToRetrieveMetadata": "Failed to retrieve metadata. Please check the link and try again.", "uploadModelFromCivitai": "Import a model from Civitai", + "uploadModelGeneric": "Import a model", "uploadModelHelpVideo": "Upload Model Help Video", + "uploadModelHelpFooterText": "Need help finding the URLs? Click on a provider below to see a how-to video.", "uploadModelHowDoIFindThis": "How do I find this?", "uploadSuccess": "Model imported successfully!", "ariaLabel": { diff --git a/src/platform/assets/components/UploadModelDialog.vue b/src/platform/assets/components/UploadModelDialog.vue index 5d1e6cdde6..3301c68224 100644 --- a/src/platform/assets/components/UploadModelDialog.vue +++ b/src/platform/assets/components/UploadModelDialog.vue @@ -4,7 +4,13 @@ > + @@ -46,14 +52,17 @@ diff --git a/src/platform/assets/components/UploadModelFooter.vue b/src/platform/assets/components/UploadModelFooter.vue index 68c9bcdff0..672446a319 100644 --- a/src/platform/assets/components/UploadModelFooter.vue +++ b/src/platform/assets/components/UploadModelFooter.vue @@ -42,7 +42,7 @@ size="md" data-attr="upload-model-step1-continue-button" :disabled="!canFetchMetadata || isFetchingMetadata" - @click="emit('fetchMetadata')" + :on-click="() => emit('fetchMetadata')" >