mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-02 22:37:32 +00:00
WIP
This commit is contained in:
@@ -1984,6 +1984,13 @@
|
||||
"noModelsInFolder": "No {type} available in this folder",
|
||||
"searchAssetsPlaceholder": "Type to search...",
|
||||
"uploadModel": "Upload model",
|
||||
"uploadModelFromCivitai": "Upload a model from Civitai",
|
||||
"uploadModelDescription1": "Paste a Civitai model download link to add it to your library.",
|
||||
"uploadModelDescription2": "Only links from https://civitai.com are supported at the moment",
|
||||
"uploadModelDescription3": "Max file size: 1 GB",
|
||||
"civitaiLinkLabel": "Civitai model download link",
|
||||
"civitaiLinkPlaceholder": "Paste link here",
|
||||
"civitaiLinkExample": "Example: https://civitai.com/api/download/models/833921?type=Model&format=SafeTensor",
|
||||
"allModels": "All Models",
|
||||
"allCategory": "All {category}",
|
||||
"unknown": "Unknown",
|
||||
|
||||
@@ -73,11 +73,14 @@ import LeftSidePanel from '@/components/widget/panel/LeftSidePanel.vue'
|
||||
import { useFeatureFlags } from '@/composables/useFeatureFlags'
|
||||
import AssetFilterBar from '@/platform/assets/components/AssetFilterBar.vue'
|
||||
import AssetGrid from '@/platform/assets/components/AssetGrid.vue'
|
||||
import UploadModelDialog from '@/platform/assets/components/UploadModelDialog.vue'
|
||||
import UploadModelDialogHeader from '@/platform/assets/components/UploadModelDialogHeader.vue'
|
||||
import type { AssetDisplayItem } from '@/platform/assets/composables/useAssetBrowser'
|
||||
import { useAssetBrowser } from '@/platform/assets/composables/useAssetBrowser'
|
||||
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
|
||||
import { assetService } from '@/platform/assets/services/assetService'
|
||||
import { formatCategoryLabel } from '@/platform/assets/utils/categoryLabel'
|
||||
import { useDialogStore } from '@/stores/dialogStore'
|
||||
import { useModelToNodeStore } from '@/stores/modelToNodeStore'
|
||||
import { OnCloseKey } from '@/types/widgetTypes'
|
||||
|
||||
@@ -92,6 +95,7 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const dialogStore = useDialogStore()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'asset-select': [asset: AssetDisplayItem]
|
||||
@@ -189,6 +193,10 @@ const { flags } = useFeatureFlags()
|
||||
const isUploadButtonEnabled = computed(() => flags.modelUploadButtonEnabled)
|
||||
|
||||
function handleUploadClick() {
|
||||
// Will be implemented in the future commit
|
||||
dialogStore.showDialog({
|
||||
key: 'upload-model',
|
||||
headerComponent: UploadModelDialogHeader,
|
||||
component: UploadModelDialog
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
74
src/platform/assets/components/UploadModelDialog.vue
Normal file
74
src/platform/assets/components/UploadModelDialog.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<div class="upload-model-dialog flex flex-col gap-6 p-8">
|
||||
<div class="flex flex-col gap-2">
|
||||
<p class="text-base">
|
||||
{{ $t('assetBrowser.uploadModelDescription1') }}
|
||||
</p>
|
||||
<ul class="list-disc space-y-1 pl-5 text-sm text-muted">
|
||||
<li>{{ $t('assetBrowser.uploadModelDescription2') }}</li>
|
||||
<li>{{ $t('assetBrowser.uploadModelDescription3') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<form class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="civitai-link" class="font-medium">
|
||||
{{ $t('assetBrowser.civitaiLinkLabel') }}
|
||||
</label>
|
||||
<InputText
|
||||
id="civitai-link"
|
||||
v-model="modelLink"
|
||||
:placeholder="$t('assetBrowser.civitaiLinkPlaceholder')"
|
||||
class="w-full"
|
||||
/>
|
||||
<small class="text-muted">
|
||||
{{ $t('assetBrowser.civitaiLinkExample') }}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<Button
|
||||
severity="primary"
|
||||
:label="$t('g.continue')"
|
||||
:disabled="!modelLink || isLoading"
|
||||
:loading="isLoading"
|
||||
@click="handleContinue"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Button from 'primevue/button'
|
||||
import InputText from 'primevue/inputtext'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { assetService } from '@/platform/assets/services/assetService'
|
||||
|
||||
const modelLink = ref('')
|
||||
const isLoading = ref(false)
|
||||
|
||||
async function handleContinue() {
|
||||
if (!modelLink.value) return
|
||||
|
||||
isLoading.value = true
|
||||
try {
|
||||
const metadata = await assetService.getAssetMetadata(modelLink.value)
|
||||
console.log('Metadata retrieved:', metadata)
|
||||
// TODO: Show metadata confirmation and proceed with upload
|
||||
} catch (error) {
|
||||
console.error('Failed to retrieve metadata:', error)
|
||||
// TODO: Show error message to user
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.upload-model-dialog {
|
||||
min-width: 600px;
|
||||
min-height: 400px;
|
||||
}
|
||||
</style>
|
||||
10
src/platform/assets/components/UploadModelDialogHeader.vue
Normal file
10
src/platform/assets/components/UploadModelDialogHeader.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<div class="flex items-center gap-2">
|
||||
<span>{{ $t('assetBrowser.uploadModelFromCivitai') }}</span>
|
||||
<Badge :value="$t('g.beta')" class="bg-white text-black" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Badge from 'primevue/badge'
|
||||
</script>
|
||||
@@ -249,6 +249,73 @@ function createAssetService() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves metadata from a download URL without downloading the file
|
||||
*
|
||||
* @param url - Download URL to retrieve metadata from (will be URL-encoded)
|
||||
* @returns Promise with metadata including content_length, final_url, filename, etc.
|
||||
* @throws Error if metadata retrieval fails
|
||||
*/
|
||||
async function getAssetMetadata(url: string): Promise<{
|
||||
content_length: number
|
||||
final_url: string
|
||||
content_type?: string
|
||||
filename?: string
|
||||
name?: string
|
||||
tags?: string[]
|
||||
}> {
|
||||
const encodedUrl = encodeURIComponent(url)
|
||||
const res = await api.fetchApi(
|
||||
`${ASSETS_ENDPOINT}/metadata?url=${encodedUrl}`
|
||||
)
|
||||
|
||||
if (!res.ok) {
|
||||
const errorText = await res.text().catch(() => 'Unknown error')
|
||||
throw new Error(
|
||||
`Failed to retrieve metadata: Server returned ${res.status}. ${errorText}`
|
||||
)
|
||||
}
|
||||
|
||||
return await res.json()
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads an asset by providing a URL to download from
|
||||
*
|
||||
* @param params - Upload parameters
|
||||
* @param params.url - HTTP/HTTPS URL to download from
|
||||
* @param params.name - Display name (determines extension)
|
||||
* @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<AssetItem & { created_new: boolean }> - Asset object with created_new flag
|
||||
* @throws Error if upload fails
|
||||
*/
|
||||
async function uploadAssetFromUrl(params: {
|
||||
url: string
|
||||
name: string
|
||||
tags?: string[]
|
||||
user_metadata?: Record<string, any>
|
||||
preview_id?: string
|
||||
}): Promise<AssetItem & { created_new: boolean }> {
|
||||
const res = await api.fetchApi(ASSETS_ENDPOINT, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(params)
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
const errorText = await res.text().catch(() => 'Unknown error')
|
||||
throw new Error(
|
||||
`Failed to upload asset: Server returned ${res.status}. ${errorText}`
|
||||
)
|
||||
}
|
||||
|
||||
return await res.json()
|
||||
}
|
||||
|
||||
return {
|
||||
getAssetModelFolders,
|
||||
getAssetModels,
|
||||
@@ -256,7 +323,9 @@ function createAssetService() {
|
||||
getAssetsForNodeType,
|
||||
getAssetDetails,
|
||||
getAssetsByTag,
|
||||
deleteAsset
|
||||
deleteAsset,
|
||||
getAssetMetadata,
|
||||
uploadAssetFromUrl
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user