Files
Azornes-Comfyui-Model-Resolver/web/resolver/views/missing_model_state_methods.js
T

170 lines
6.3 KiB
JavaScript

import { normalizeSourceKey } from '../utils/source_labels.js';
export const missingModelStateMethods = {
getBestLocalMatch(missing = {}, minConfidence = 0) {
const matches = Array.isArray(missing.matches) ? missing.matches : [];
return matches
.filter(match => Number(match.confidence) >= minConfidence)
.sort((a, b) => Number(b.confidence || 0) - Number(a.confidence || 0))[0] || null;
},
getMissingModelSummaryStats(missingModels = []) {
return missingModels.reduce((stats, missing) => {
const best = this.getBestLocalMatch(missing, 70);
if (best?.confidence === 100) {
stats.exact += 1;
} else if (best) {
stats.partial += 1;
} else {
stats.none += 1;
}
return stats;
}, { exact: 0, partial: 0, none: 0 });
},
getMissingSourceStatus(missing = {}, source = '') {
const state = this.searchResultCache.get(this.getMissingSearchKey(missing));
const progress = state?.sourceProgress?.[source];
const resultStatus = this.getMissingSourceResultStatus(missing, source, state);
if (progress?.status === 'found') return resultStatus || 'found';
if (progress?.status === 'error' && progress.providerState) {
return progress.providerState;
}
if (progress?.status) return progress.status;
if (resultStatus) return resultStatus;
return 'idle';
},
hasMissingSourceSearchAttempt(missing = {}, source = '', state = null) {
const searchState = state || this.searchResultCache?.get(this.getMissingSearchKey(missing));
const explicitSources = new Set(
Array.isArray(searchState?.explicitSearchSources) ? searchState.explicitSearchSources : []
);
return explicitSources.has(source) || explicitSources.has('all');
},
isLocalDatabaseDownloadSource(downloadSource = {}) {
const source = normalizeSourceKey(downloadSource?.source || '');
return source === 'local' || source === 'model_list' || source === 'popular';
},
shouldDisplayKnownDownloadSource(missing = {}, downloadSource = {}, state = null) {
if (!downloadSource?.url) return false;
if (!this.isLocalDatabaseDownloadSource(downloadSource)) return true;
return this.hasMissingSourceSearchAttempt(missing, 'local', state);
},
getMissingSourceResultStatus(missing = {}, source = '', state = null) {
const results = state?.results || {};
const candidates = [];
if (source === 'local') {
if (!this.hasMissingSourceSearchAttempt(missing, source, state)) return '';
candidates.push(results.model_list, results.popular);
} else if (source === 'huggingface') {
candidates.push(results.huggingface);
} else if (source === 'civitai') {
candidates.push(results.civitai);
} else if (source === 'civarchive') {
candidates.push(results.civarchive);
} else if (source === 'lora_manager_archive') {
candidates.push(results.lora_manager_archive);
}
if (['huggingface', 'civitai', 'civarchive'].includes(source)) {
const customResults = Array.isArray(results.custom) ? results.custom : [];
customResults
.filter(result => normalizeSourceKey(result?.source || '', { trim: false }) === source)
.forEach(result => candidates.push(result));
}
const downloadSource = missing.download_source || {};
const mappedDownloadSource = {
model_list: 'local',
popular: 'local',
workflow: 'civitai'
}[downloadSource.source] || downloadSource.source;
if (mappedDownloadSource === source && downloadSource.url) {
candidates.push(downloadSource);
}
return this.getSearchResultStatusLevel(candidates);
},
getSearchResultStatusLevel(resultOrResults) {
const results = Array.isArray(resultOrResults)
? resultOrResults.flatMap(result => Array.isArray(result) ? result : [result])
: [resultOrResults];
let hasPartial = false;
let hasUnknownFound = false;
for (const result of results) {
if (!result) continue;
const confidence = Number(result.confidence);
const hasConfidence = Number.isFinite(confidence);
const matchType = String(result.match_type || '').toLowerCase();
if (hasConfidence) {
if (confidence >= 100) return 'exact';
if (confidence > 0) {
hasPartial = true;
continue;
}
}
if (matchType === 'exact' || result.source === 'popular') {
return 'exact';
}
if (matchType === 'partial' || matchType === 'fuzzy' || matchType === 'similar') {
hasPartial = true;
continue;
}
if (result.url || result.download_url) {
hasUnknownFound = true;
}
}
if (hasPartial) return 'partial';
if (hasUnknownFound) return 'found';
return '';
},
hasRenderableSearchState(state = {}) {
return Boolean(
(state.lastAttemptSources || []).length
|| Object.keys(state.sourceProgress || {}).length
|| this.hasSearchResults(state.results || {})
|| state.lastAttemptError
);
},
isMissingModelResolved(missing = {}) {
if (!missing) return false;
return Boolean(missing.__isExistingResolved);
},
isMissingModelInactive(missing = {}) {
if (!missing) return false;
const references = Array.isArray(missing.all_node_refs) && missing.all_node_refs.length
? missing.all_node_refs
: [missing];
return references.every(reference => (
reference?.active === false || reference?.connected === false
));
},
isAutoDownloadModel(missing = {}) {
return Boolean(missing?.auto_download_capable || missing?.auto_download_candidate);
},
getResolvedMissingCount(missingModels = []) {
return missingModels.reduce((count, missing) => (
count + (this.isMissingModelResolved(missing) ? 1 : 0)
), 0);
},
};