Show node by frequency on empty query (#878)

This commit is contained in:
Chenlei Hu
2024-09-19 09:35:22 +09:00
committed by GitHub
parent efa2fa269d
commit 6c4143ca94
8 changed files with 2711 additions and 8 deletions

1
public/assets/CREDIT.txt Normal file
View File

@@ -0,0 +1 @@
Thanks to OpenArt (https://openart.ai) for providing the sorted-custom-node-map data, captured in September 2024.

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,11 @@ import { ref, computed, onUnmounted, onMounted, watchEffect } from 'vue'
import { app as comfyApp } from '@/scripts/app'
import { useSettingStore } from '@/stores/settingStore'
import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'
import { ComfyNodeDefImpl, useNodeDefStore } from '@/stores/nodeDefStore'
import {
ComfyNodeDefImpl,
useNodeDefStore,
useNodeFrequencyStore
} from '@/stores/nodeDefStore'
import { useWorkspaceStore } from '@/stores/workspaceStateStore'
import {
LiteGraph,
@@ -140,6 +144,8 @@ onMounted(async () => {
// node search is triggered
useNodeDefStore().nodeSearchService.endsWithFilterStartSequence('')
// Non-blocking load of node frequencies
useNodeFrequencyStore().loadNodeFrequencies()
emit('ready')
})

View File

@@ -33,6 +33,7 @@
:suggestions="suggestions"
:min-length="0"
:delay="100"
:loading="!nodeFrequencyStore.isLoaded"
@complete="search($event.query)"
@option-select="emit('addNode', $event.value)"
@focused-option-changed="setHoverSuggestion($event)"
@@ -67,7 +68,11 @@ import NodeSearchFilter from '@/components/searchbox/NodeSearchFilter.vue'
import NodeSearchItem from '@/components/searchbox/NodeSearchItem.vue'
import { type FilterAndValue } from '@/services/nodeSearchService'
import NodePreview from '@/components/node/NodePreview.vue'
import { ComfyNodeDefImpl, useNodeDefStore } from '@/stores/nodeDefStore'
import {
ComfyNodeDefImpl,
useNodeDefStore,
useNodeFrequencyStore
} from '@/stores/nodeDefStore'
import { useSettingStore } from '@/stores/settingStore'
import { useI18n } from 'vue-i18n'
import SearchFilterChip from '../common/SearchFilterChip.vue'
@@ -98,13 +103,18 @@ const placeholder = computed(() => {
return props.filters.length === 0 ? t('searchNodes') + '...' : ''
})
const nodeDefStore = useNodeDefStore()
const nodeFrequencyStore = useNodeFrequencyStore()
const search = (query: string) => {
currentQuery.value = query
suggestions.value = [
...useNodeDefStore().nodeSearchService.searchNode(query, props.filters, {
limit: props.searchLimit
})
]
suggestions.value =
query === ''
? nodeFrequencyStore.topNodeDefs
: [
...nodeDefStore.nodeSearchService.searchNode(query, props.filters, {
limit: props.searchLimit
})
]
}
const emit = defineEmits(['addFilter', 'removeFilter', 'addNode'])

View File

@@ -33,6 +33,11 @@
:value="$t('deprecated')"
severity="danger"
/>
<Tag
v-if="showNodeFrequency && nodeFrequency > 0"
:value="formatNumberWithSuffix(nodeFrequency, { roundToInt: true })"
severity="secondary"
/>
<NodeSourceChip
v-if="nodeDef.python_module !== undefined"
:python_module="nodeDef.python_module"
@@ -44,11 +49,12 @@
<script setup lang="ts">
import Tag from 'primevue/tag'
import NodeSourceChip from '@/components/node/NodeSourceChip.vue'
import { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
import { ComfyNodeDefImpl, useNodeFrequencyStore } from '@/stores/nodeDefStore'
import { highlightQuery } from '@/utils/formatUtil'
import { computed } from 'vue'
import { useSettingStore } from '@/stores/settingStore'
import { useNodeBookmarkStore } from '@/stores/nodeBookmarkStore'
import { formatNumberWithSuffix } from '@/utils/formatUtil'
const settingStore = useSettingStore()
const showCategory = computed(() =>
@@ -57,6 +63,13 @@ const showCategory = computed(() =>
const showIdName = computed(() =>
settingStore.get('Comfy.NodeSearchBoxImpl.ShowIdName')
)
const showNodeFrequency = computed(() =>
settingStore.get('Comfy.NodeSearchBoxImpl.ShowNodeFrequency')
)
const nodeFrequencyStore = useNodeFrequencyStore()
const nodeFrequency = computed(() =>
nodeFrequencyStore.getNodeFrequency(props.nodeDef)
)
const nodeBookmarkStore = useNodeBookmarkStore()
const isBookmarked = computed(() =>

View File

@@ -69,6 +69,14 @@ export const CORE_SETTINGS: SettingParams[] = [
type: 'boolean',
defaultValue: false
},
{
id: 'Comfy.NodeSearchBoxImpl.ShowNodeFrequency',
category: ['Comfy', 'Node Search Box', 'ShowNodeFrequency'],
name: 'Show node frequency in search results',
tooltip: 'Only applies to the default implementation',
type: 'boolean',
defaultValue: false
},
{
id: 'Comfy.Sidebar.Location',
category: ['Comfy', 'Sidebar', 'Location'],

View File

@@ -5,6 +5,8 @@ import { Type, Transform, plainToClass, Expose } from 'class-transformer'
import { ComfyWidgetConstructor } from '@/scripts/widgets'
import { TreeNode } from 'primevue/treenode'
import { buildTree } from '@/utils/treeUtil'
import { computed, ref } from 'vue'
import axios from 'axios'
export class BaseInputSpec<T = any> {
name: string
@@ -338,3 +340,44 @@ export const useNodeDefStore = defineStore('nodeDef', {
}
}
})
export const useNodeFrequencyStore = defineStore('nodeFrequency', () => {
const topNodeDefLimit = ref(64)
const nodeFrequencyLookup = ref<Record<string, number>>({})
const nodeNamesByFrequency = computed(() =>
Object.keys(nodeFrequencyLookup.value)
)
const isLoaded = ref(false)
const loadNodeFrequencies = async () => {
if (!isLoaded.value) {
try {
const response = await axios.get('/assets/sorted-custom-node-map.json')
nodeFrequencyLookup.value = response.data
isLoaded.value = true
} catch (error) {
console.error('Error loading node frequencies:', error)
}
}
}
const getNodeFrequency = (nodeDef: ComfyNodeDefImpl) => {
return nodeFrequencyLookup.value[nodeDef.name] ?? 0
}
const nodeDefStore = useNodeDefStore()
const topNodeDefs = computed<ComfyNodeDefImpl[]>(() => {
return nodeNamesByFrequency.value
.map((nodeName: string) => nodeDefStore.nodeDefsByName[nodeName])
.filter((nodeDef: ComfyNodeDefImpl) => nodeDef !== undefined)
.slice(0, topNodeDefLimit.value)
})
return {
nodeNamesByFrequency,
topNodeDefs,
isLoaded,
loadNodeFrequencies,
getNodeFrequency
}
})

View File

@@ -39,3 +39,23 @@ export function highlightQuery(text: string, query: string) {
const regex = new RegExp(`(${query})`, 'gi')
return text.replace(regex, '<span class="highlight">$1</span>')
}
export function formatNumberWithSuffix(
num: number,
{
precision = 1,
roundToInt = false
}: { precision?: number; roundToInt?: boolean } = {}
): string {
const suffixes = ['', 'k', 'm', 'b', 't']
const absNum = Math.abs(num)
if (absNum < 1000) {
return roundToInt ? Math.round(num).toString() : num.toFixed(precision)
}
const exp = Math.min(Math.floor(Math.log10(absNum) / 3), suffixes.length - 1)
const formattedNum = (num / Math.pow(1000, exp)).toFixed(precision)
return `${formattedNum}${suffixes[exp]}`
}