Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e58d0a82d | ||
|
|
55a4eff01b | ||
|
|
45cf18299f | ||
|
|
c7898c47f1 | ||
|
|
17ab373b9c | ||
|
|
f6368fe20b |
@@ -61,7 +61,7 @@ class TaskContent:
|
||||
description: str
|
||||
downloadPlatform: str
|
||||
downloadUrl: str
|
||||
sizeBytes: int
|
||||
sizeBytes: float
|
||||
hashes: Optional[dict[str, str]] = None
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
@@ -71,7 +71,7 @@ class TaskContent:
|
||||
self.description = kwargs.get("description", None)
|
||||
self.downloadPlatform = kwargs.get("downloadPlatform", None)
|
||||
self.downloadUrl = kwargs.get("downloadUrl", None)
|
||||
self.sizeBytes = int(kwargs.get("sizeBytes", 0))
|
||||
self.sizeBytes = float(kwargs.get("sizeBytes", 0))
|
||||
self.hashes = kwargs.get("hashes", None)
|
||||
|
||||
def to_dict(self):
|
||||
@@ -382,7 +382,7 @@ async def download_model_file(
|
||||
# When parsing model information from HuggingFace API,
|
||||
# the file size was not found and needs to be obtained from the response header.
|
||||
if total_size == 0:
|
||||
total_size = int(response.headers.get("content-length", 0))
|
||||
total_size = float(response.headers.get("content-length", 0))
|
||||
task_content.sizeBytes = total_size
|
||||
task_status.totalSize = total_size
|
||||
set_task_content(task_id, task_content)
|
||||
|
||||
@@ -386,7 +386,7 @@ class Information:
|
||||
model_base_paths = utils.resolve_model_base_paths()
|
||||
for model_type in model_base_paths:
|
||||
|
||||
folders, extensions = folder_paths.folder_names_and_paths[model_type]
|
||||
folders, *others = folder_paths.folder_names_and_paths[model_type]
|
||||
for path_index, base_path in enumerate(folders):
|
||||
files = utils.recursive_search_files(base_path, request)
|
||||
|
||||
|
||||
@@ -117,10 +117,10 @@ class ModelManager:
|
||||
result = []
|
||||
|
||||
include_hidden_files = utils.get_setting_value(request, "scan.include_hidden_files", False)
|
||||
folders, extensions = folder_paths.folder_names_and_paths[folder]
|
||||
folders, *others = folder_paths.folder_names_and_paths[folder]
|
||||
|
||||
def get_file_info(entry: os.DirEntry[str], base_path: str, path_index: int):
|
||||
fullname = entry.path.replace(base_path, "")
|
||||
fullname = utils.normalize_path(entry.path).replace(f"{base_path}/", "")
|
||||
basename = os.path.splitext(fullname)[0]
|
||||
extension = os.path.splitext(fullname)[1]
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "comfyui-model-manager"
|
||||
description = "Manage models: browsing, download and delete."
|
||||
version = "2.3.1"
|
||||
version = "2.3.3"
|
||||
license = { file = "LICENSE" }
|
||||
dependencies = ["markdownify"]
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
:items="sortOrderOptions"
|
||||
></ResponseSelect>
|
||||
<ResponseSelect
|
||||
v-model="currentCardSize"
|
||||
v-model="cardSizeFlag"
|
||||
:items="cardSizeOptions"
|
||||
></ResponseSelect>
|
||||
</div>
|
||||
@@ -77,7 +77,14 @@ import { genModelKey } from 'utils/model'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { isMobile, gutter, cardSize } = useConfig()
|
||||
const {
|
||||
isMobile,
|
||||
gutter,
|
||||
cardSize,
|
||||
cardSizeMap,
|
||||
cardSizeFlag,
|
||||
dialog: settings,
|
||||
} = useConfig()
|
||||
|
||||
const { data, folders } = useModels()
|
||||
const { t } = useI18n()
|
||||
@@ -198,48 +205,24 @@ const contentStyle = computed(() => ({
|
||||
paddingRight: `1rem`,
|
||||
}))
|
||||
|
||||
const currentCardSize = computed({
|
||||
get: () => {
|
||||
const options = cardSizeOptions.value.map((item) => item.value)
|
||||
const current = [cardSize.value.width, cardSize.value.height].join('x')
|
||||
if (options.includes(current)) {
|
||||
return current
|
||||
}
|
||||
return 'custom'
|
||||
},
|
||||
set: (val) => {
|
||||
if (val === 'custom') {
|
||||
app.ui?.settings.show(t('size.customTip'))
|
||||
return
|
||||
}
|
||||
|
||||
const [width, height] = val.split('x')
|
||||
app.ui?.settings.setSettingValue(
|
||||
'ModelManager.UI.CardWidth',
|
||||
parseInt(width),
|
||||
)
|
||||
app.ui?.settings.setSettingValue(
|
||||
'ModelManager.UI.CardHeight',
|
||||
parseInt(height),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
const cardSizeOptions = computed(() => {
|
||||
const defineOptions = {
|
||||
extraLarge: '240x320',
|
||||
large: '180x240',
|
||||
medium: '120x160',
|
||||
small: '80x120',
|
||||
custom: 'custom',
|
||||
const customSize = 'size.custom'
|
||||
|
||||
const customOptionMap = {
|
||||
...cardSizeMap.value,
|
||||
[customSize]: 'custom',
|
||||
}
|
||||
|
||||
return Object.entries(defineOptions).map(([key, value]) => {
|
||||
return Object.keys(customOptionMap).map((key) => {
|
||||
return {
|
||||
label: t(`size.${key}`),
|
||||
value,
|
||||
command() {
|
||||
currentCardSize.value = value
|
||||
label: t(key),
|
||||
value: key,
|
||||
command: () => {
|
||||
if (key === customSize) {
|
||||
settings.showCardSizeSetting()
|
||||
} else {
|
||||
cardSizeFlag.value = key
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
110
src/components/SettingCardSize.vue
Normal file
110
src/components/SettingCardSize.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div class="flex h-full flex-col">
|
||||
<div class="flex-1 px-4">
|
||||
<DataTable :value="sizeList">
|
||||
<Column field="name" :header="$t('name')">
|
||||
<template #body="{ data, field }">
|
||||
{{ $t(data[field]) }}
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="width" :header="$t('width')" class="min-w-36">
|
||||
<template #body="{ data, field }">
|
||||
<span class="flex items-center gap-4">
|
||||
<Slider
|
||||
v-model="data[field]"
|
||||
class="flex-1"
|
||||
v-bind="sizeStint"
|
||||
></Slider>
|
||||
<span>{{ data[field] }}</span>
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="height" :header="$t('height')" class="min-w-36">
|
||||
<template #body="{ data, field }">
|
||||
<span class="flex items-center gap-4">
|
||||
<Slider
|
||||
v-model="data[field]"
|
||||
class="flex-1"
|
||||
v-bind="sizeStint"
|
||||
></Slider>
|
||||
<span>{{ data[field] }}</span>
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
</div>
|
||||
<div class="flex justify-between px-4">
|
||||
<div></div>
|
||||
<div class="flex gap-2">
|
||||
<Button
|
||||
icon="pi pi-refresh"
|
||||
:label="$t('reset')"
|
||||
@click="handleReset"
|
||||
></Button>
|
||||
<Button :label="$t('cancel')" @click="handleCancelEditor"></Button>
|
||||
<Button :label="$t('save')" @click="handleSaveSizeMap"></Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useConfig } from 'hooks/config'
|
||||
import { useDialog } from 'hooks/dialog'
|
||||
import Button from 'primevue/button'
|
||||
import Column from 'primevue/column'
|
||||
import DataTable from 'primevue/datatable'
|
||||
import Slider from 'primevue/slider'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const { cardSizeMap, defaultCardSizeMap } = useConfig()
|
||||
const dialog = useDialog()
|
||||
|
||||
const sizeList = ref()
|
||||
|
||||
const sizeStint = {
|
||||
step: 10,
|
||||
min: 80,
|
||||
max: 320,
|
||||
}
|
||||
|
||||
const resolveSizeMap = (sizeMap: Record<string, string>) => {
|
||||
return Object.entries(sizeMap).map(([key, value]) => {
|
||||
const [width, height] = value.split('x')
|
||||
return {
|
||||
id: key,
|
||||
name: key,
|
||||
width: parseInt(width),
|
||||
height: parseInt(height),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const resolveSizeList = (
|
||||
sizeList: { name: string; width: number; height: number }[],
|
||||
) => {
|
||||
return Object.fromEntries(
|
||||
sizeList.map(({ name, width, height }) => {
|
||||
return [name, [width, height].join('x')]
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
sizeList.value = resolveSizeMap(cardSizeMap.value)
|
||||
})
|
||||
|
||||
const handleReset = () => {
|
||||
sizeList.value = resolveSizeMap(defaultCardSizeMap)
|
||||
}
|
||||
|
||||
const handleCancelEditor = () => {
|
||||
sizeList.value = resolveSizeMap(cardSizeMap.value)
|
||||
dialog.close()
|
||||
}
|
||||
|
||||
const handleSaveSizeMap = () => {
|
||||
cardSizeMap.value = resolveSizeList(sizeList.value)
|
||||
dialog.close()
|
||||
}
|
||||
</script>
|
||||
@@ -1,11 +1,14 @@
|
||||
import SettingCardSize from 'components/SettingCardSize.vue'
|
||||
import { request } from 'hooks/request'
|
||||
import { defineStore } from 'hooks/store'
|
||||
import { $el, app, ComfyDialog } from 'scripts/comfyAPI'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
import { computed, onMounted, onUnmounted, readonly, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useToast } from './toast'
|
||||
|
||||
export const useConfig = defineStore('config', (store) => {
|
||||
const { t } = useI18n()
|
||||
|
||||
const mobileDeviceBreakPoint = 759
|
||||
const isMobile = ref(window.innerWidth < mobileDeviceBreakPoint)
|
||||
|
||||
@@ -21,23 +24,59 @@ export const useConfig = defineStore('config', (store) => {
|
||||
window.removeEventListener('resize', checkDeviceType)
|
||||
})
|
||||
|
||||
const cardSize = ref({
|
||||
width:
|
||||
app.ui?.settings.getSettingValue<number>('ModelManager.UI.CardWidth') ??
|
||||
240,
|
||||
height:
|
||||
app.ui?.settings.getSettingValue<number>('ModelManager.UI.CardHeight') ??
|
||||
310,
|
||||
const defaultCardSizeMap = readonly({
|
||||
'size.extraLarge': '240x320',
|
||||
'size.large': '180x240',
|
||||
'size.medium': '120x160',
|
||||
'size.small': '80x120',
|
||||
})
|
||||
|
||||
const cardSizeMap = ref<Record<string, string>>({ ...defaultCardSizeMap })
|
||||
const cardSizeFlag = ref('size.extraLarge')
|
||||
const cardSize = computed(() => {
|
||||
const size = cardSizeMap.value[cardSizeFlag.value]
|
||||
const [width = '120', height = '240'] = size.split('x')
|
||||
return {
|
||||
width: parseInt(width),
|
||||
height: parseInt(height),
|
||||
}
|
||||
})
|
||||
|
||||
const config = {
|
||||
isMobile,
|
||||
gutter: 16,
|
||||
cardSize,
|
||||
defaultCardSizeMap: defaultCardSizeMap,
|
||||
cardSizeMap: cardSizeMap,
|
||||
cardSizeFlag: cardSizeFlag,
|
||||
cardSize: cardSize,
|
||||
cardWidth: 240,
|
||||
aspect: 7 / 9,
|
||||
dialog: {
|
||||
showCardSizeSetting: () => {
|
||||
store.dialog.open({
|
||||
key: 'setting.cardSize',
|
||||
title: t('setting.cardSize'),
|
||||
content: SettingCardSize,
|
||||
defaultSize: {
|
||||
width: 500,
|
||||
height: 390,
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
watch(cardSizeFlag, (val) => {
|
||||
app.ui?.settings.setSettingValue('ModelManager.UI.CardSize', val)
|
||||
})
|
||||
|
||||
watch(cardSizeMap, (val) => {
|
||||
app.ui?.settings.setSettingValue(
|
||||
'ModelManager.UI.CardSizeMap',
|
||||
JSON.stringify(val),
|
||||
)
|
||||
})
|
||||
|
||||
useAddConfigSettings(store)
|
||||
|
||||
return config
|
||||
@@ -109,36 +148,27 @@ function useAddConfigSettings(store: import('hooks/store').StoreProvider) {
|
||||
defaultValue: undefined,
|
||||
})
|
||||
|
||||
// UI settings
|
||||
const defaultCardSize = store.config.defaultCardSizeMap
|
||||
|
||||
app.ui?.settings.addSetting({
|
||||
id: 'ModelManager.UI.CardWidth',
|
||||
category: [t('modelManager'), t('setting.ui'), 'CardWidth'],
|
||||
name: t('setting.cardWidth'),
|
||||
type: 'slider',
|
||||
defaultValue: 240,
|
||||
attrs: {
|
||||
min: 80,
|
||||
max: 320,
|
||||
step: 10,
|
||||
},
|
||||
onChange(value) {
|
||||
store.config.cardSize.value.width = value
|
||||
id: 'ModelManager.UI.CardSize',
|
||||
category: [t('modelManager'), t('setting.ui'), 'CardSize'],
|
||||
name: t('setting.cardSize'),
|
||||
defaultValue: 'size.extraLarge',
|
||||
type: 'hidden',
|
||||
onChange: (val) => {
|
||||
store.config.cardSizeFlag.value = val
|
||||
},
|
||||
})
|
||||
|
||||
app.ui?.settings.addSetting({
|
||||
id: 'ModelManager.UI.CardHeight',
|
||||
category: [t('modelManager'), t('setting.ui'), 'CardHeight'],
|
||||
name: t('setting.cardHeight'),
|
||||
type: 'slider',
|
||||
defaultValue: 320,
|
||||
attrs: {
|
||||
min: 80,
|
||||
max: 320,
|
||||
step: 10,
|
||||
},
|
||||
id: 'ModelManager.UI.CardSizeMap',
|
||||
category: [t('modelManager'), t('setting.ui'), 'CardSizeMap'],
|
||||
name: t('setting.cardSize'),
|
||||
defaultValue: JSON.stringify(defaultCardSize),
|
||||
type: 'hidden',
|
||||
onChange(value) {
|
||||
store.config.cardSize.value.height = value
|
||||
store.config.cardSizeMap.value = JSON.parse(value)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
10
src/i18n.ts
10
src/i18n.ts
@@ -25,6 +25,10 @@ const messages = {
|
||||
none: 'None',
|
||||
uploadFile: 'Upload File',
|
||||
tapToChange: 'Tap description to change content',
|
||||
name: 'Name',
|
||||
width: 'Width',
|
||||
height: 'Height',
|
||||
reset: 'Reset',
|
||||
sort: {
|
||||
name: 'Name',
|
||||
size: 'Largest',
|
||||
@@ -57,6 +61,7 @@ const messages = {
|
||||
includeHiddenFiles: 'Include hidden files(start with .)',
|
||||
excludeScanTypes: 'Exclude scan types (separate with commas)',
|
||||
ui: 'UI',
|
||||
cardSize: 'Card Size',
|
||||
},
|
||||
},
|
||||
zh: {
|
||||
@@ -82,6 +87,10 @@ const messages = {
|
||||
none: '无',
|
||||
uploadFile: '上传文件',
|
||||
tapToChange: '点击描述可更改内容',
|
||||
name: '名称',
|
||||
width: '宽度',
|
||||
height: '高度',
|
||||
reset: '重置',
|
||||
sort: {
|
||||
name: '名称',
|
||||
size: '最大',
|
||||
@@ -114,6 +123,7 @@ const messages = {
|
||||
includeHiddenFiles: '包含隐藏文件(以 . 开头的文件或文件夹)',
|
||||
excludeScanTypes: '排除扫描类型(使用英文逗号隔开)',
|
||||
ui: '外观',
|
||||
cardSize: '卡片尺寸',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user