mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-09 07:00:06 +00:00
Missing model download dialog test (#656)
* Test prep * Add missing model dialog test * Basic test of download model * Add comment * Adjust setting in test * Change download dir to not interfere with other tests
This commit is contained in:
@@ -14,28 +14,42 @@
|
||||
}"
|
||||
>
|
||||
<template #option="slotProps">
|
||||
<div class="missing-model-item" :style="{ '--progress': `${slotProps.option.progress}%` }">
|
||||
<div
|
||||
class="missing-model-item"
|
||||
:style="{ '--progress': `${slotProps.option.progress}%` }"
|
||||
>
|
||||
<div class="model-info">
|
||||
<div class="model-details">
|
||||
<span class="model-type" :title=slotProps.option.hint>{{ slotProps.option.label }}</span>
|
||||
<span class="model-type" :title="slotProps.option.hint">{{
|
||||
slotProps.option.label
|
||||
}}</span>
|
||||
</div>
|
||||
<div v-if="slotProps.option.error" class="model-error">
|
||||
{{ slotProps.option.error }}
|
||||
</div>
|
||||
<div v-if="slotProps.option.error" class="model-error">{{ slotProps.option.error }}</div>
|
||||
</div>
|
||||
<div class="model-action">
|
||||
<Button
|
||||
v-if="slotProps.option.action && !slotProps.option.downloading && !slotProps.option.completed && !slotProps.option.error"
|
||||
v-if="
|
||||
slotProps.option.action &&
|
||||
!slotProps.option.downloading &&
|
||||
!slotProps.option.completed &&
|
||||
!slotProps.option.error
|
||||
"
|
||||
@click="slotProps.option.action.callback"
|
||||
:label="slotProps.option.action.text"
|
||||
class="p-button-sm p-button-outlined model-action-button"
|
||||
/>
|
||||
<div v-if="slotProps.option.downloading" class="download-progress">
|
||||
<span class="progress-text">{{ slotProps.option.progress.toFixed(2) }}%</span>
|
||||
<span class="progress-text"
|
||||
>{{ slotProps.option.progress.toFixed(2) }}%</span
|
||||
>
|
||||
</div>
|
||||
<div v-if="slotProps.option.completed" class="download-complete">
|
||||
<i class="pi pi-check" style="color: var(--green-500);"></i>
|
||||
<i class="pi pi-check" style="color: var(--green-500)"></i>
|
||||
</div>
|
||||
<div v-if="slotProps.option.error" class="download-error">
|
||||
<i class="pi pi-times" style="color: var(--red-600);"></i>
|
||||
<i class="pi pi-times" style="color: var(--red-600)"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -50,8 +64,15 @@ import ListBox from 'primevue/listbox'
|
||||
import Button from 'primevue/button'
|
||||
import { api } from '@/scripts/api'
|
||||
import { DownloadModelStatus } from '@/types/apiTypes'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
|
||||
const allowedSources = ['https://civitai.com/', 'https://huggingface.co/']
|
||||
const settingStore = useSettingStore()
|
||||
const allowedSources = settingStore.get(
|
||||
'Comfy.Workflow.ModelDownload.AllowedSources'
|
||||
)
|
||||
const allowedSuffixes = settingStore.get(
|
||||
'Comfy.Workflow.ModelDownload.AllowedSuffixes'
|
||||
)
|
||||
|
||||
interface ModelInfo {
|
||||
name: string
|
||||
@@ -78,19 +99,50 @@ const handleDownloadProgress = (detail: DownloadModelStatus) => {
|
||||
}
|
||||
if (!lastModel) return
|
||||
if (detail.status === 'in_progress') {
|
||||
modelDownloads.value[lastModel] = { ...modelDownloads.value[lastModel], downloading: true, progress: detail.progress_percentage, completed: false }
|
||||
modelDownloads.value[lastModel] = {
|
||||
...modelDownloads.value[lastModel],
|
||||
downloading: true,
|
||||
progress: detail.progress_percentage,
|
||||
completed: false
|
||||
}
|
||||
} else if (detail.status === 'pending') {
|
||||
modelDownloads.value[lastModel] = { ...modelDownloads.value[lastModel], downloading: true, progress: 0, completed: false }
|
||||
modelDownloads.value[lastModel] = {
|
||||
...modelDownloads.value[lastModel],
|
||||
downloading: true,
|
||||
progress: 0,
|
||||
completed: false
|
||||
}
|
||||
} else if (detail.status === 'completed') {
|
||||
modelDownloads.value[lastModel] = { ...modelDownloads.value[lastModel], downloading: false, progress: 100, completed: true }
|
||||
modelDownloads.value[lastModel] = {
|
||||
...modelDownloads.value[lastModel],
|
||||
downloading: false,
|
||||
progress: 100,
|
||||
completed: true
|
||||
}
|
||||
} else if (detail.status === 'error') {
|
||||
modelDownloads.value[lastModel] = { ...modelDownloads.value[lastModel], downloading: false, progress: 0, error: detail.message, completed: false }
|
||||
modelDownloads.value[lastModel] = {
|
||||
...modelDownloads.value[lastModel],
|
||||
downloading: false,
|
||||
progress: 0,
|
||||
error: detail.message,
|
||||
completed: false
|
||||
}
|
||||
}
|
||||
// TODO: other statuses?
|
||||
}
|
||||
|
||||
const triggerDownload = async (url: string, directory: string, filename: string) => {
|
||||
modelDownloads.value[filename] = { name: filename, directory, url, downloading: true, progress: 0 }
|
||||
const triggerDownload = async (
|
||||
url: string,
|
||||
directory: string,
|
||||
filename: string
|
||||
) => {
|
||||
modelDownloads.value[filename] = {
|
||||
name: filename,
|
||||
directory,
|
||||
url,
|
||||
downloading: true,
|
||||
progress: 0
|
||||
}
|
||||
const download = await api.internalDownloadModel(url, directory, filename, 1)
|
||||
handleDownloadProgress(download)
|
||||
}
|
||||
@@ -100,43 +152,43 @@ api.addEventListener('download_progress', (event) => {
|
||||
})
|
||||
|
||||
const missingModels = computed(() => {
|
||||
return props.missingModels
|
||||
.map((model) => {
|
||||
const downloadInfo = modelDownloads.value[model.name]
|
||||
if (!allowedSources.some((source) => model.url.startsWith(source))) {
|
||||
return {
|
||||
label: `${model.directory} / ${model.name}`,
|
||||
hint: model.url,
|
||||
error: 'Download not allowed from this source'
|
||||
}
|
||||
}
|
||||
if (!model.name.endsWith('.safetensors') && !model.name.endsWith('.sft')) {
|
||||
return {
|
||||
label: `${model.directory} / ${model.name}`,
|
||||
hint: model.url,
|
||||
error: 'Only .safetensors models are allowed'
|
||||
}
|
||||
}
|
||||
if (model.directory_invalid) {
|
||||
return {
|
||||
label: `${model.directory} / ${model.name}`,
|
||||
hint: model.url,
|
||||
error: 'Invalid directory specified (does this require custom nodes?)'
|
||||
}
|
||||
}
|
||||
return props.missingModels.map((model) => {
|
||||
const downloadInfo = modelDownloads.value[model.name]
|
||||
if (!allowedSources.some((source) => model.url.startsWith(source))) {
|
||||
return {
|
||||
label: `${model.directory} / ${model.name}`,
|
||||
hint: model.url,
|
||||
downloading: downloadInfo?.downloading ?? false,
|
||||
completed: downloadInfo?.completed ?? false,
|
||||
progress: downloadInfo?.progress ?? 0,
|
||||
error: downloadInfo?.error,
|
||||
action: {
|
||||
text: 'Download',
|
||||
callback: () => triggerDownload(model.url, model.directory, model.name)
|
||||
}
|
||||
error:
|
||||
'Download not allowed from this source: ' + allowedSources.join(', ')
|
||||
}
|
||||
})
|
||||
}
|
||||
if (!allowedSuffixes.some((suffix) => model.name.endsWith(suffix))) {
|
||||
return {
|
||||
label: `${model.directory} / ${model.name}`,
|
||||
hint: model.url,
|
||||
error: 'Only allowed suffixes are ' + allowedSuffixes.join(', ')
|
||||
}
|
||||
}
|
||||
if (model.directory_invalid) {
|
||||
return {
|
||||
label: `${model.directory} / ${model.name}`,
|
||||
hint: model.url,
|
||||
error: 'Invalid directory specified (does this require custom nodes?)'
|
||||
}
|
||||
}
|
||||
return {
|
||||
label: `${model.directory} / ${model.name}`,
|
||||
hint: model.url,
|
||||
downloading: downloadInfo?.downloading ?? false,
|
||||
completed: downloadInfo?.completed ?? false,
|
||||
progress: downloadInfo?.progress ?? 0,
|
||||
error: downloadInfo?.error,
|
||||
action: {
|
||||
text: 'Download',
|
||||
callback: () => triggerDownload(model.url, model.directory, model.name)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -246,7 +298,9 @@ const missingModels = computed(() => {
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.download-progress, .download-complete, .download-error {
|
||||
.download-progress,
|
||||
.download-complete,
|
||||
.download-error {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -258,7 +312,8 @@ const missingModels = computed(() => {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.download-complete i, .download-error i {
|
||||
.download-complete i,
|
||||
.download-error i {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user