mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-20 18:51:26 -03:00
feat(checkpoints): add Enrich HF Metadata (AI) to card context menu
The option only existed in the LoRA page menu. Move updateEnrichMenuItem and enrichWithAgent into ModelContextMenuMixin so both pages share the implementation, and add the menu item to the checkpoints template.
This commit is contained in:
@@ -25,6 +25,7 @@ export class CheckpointContextMenu extends BaseContextMenu {
|
|||||||
showMenu(x, y, card) {
|
showMenu(x, y, card) {
|
||||||
super.showMenu(x, y, card);
|
super.showMenu(x, y, card);
|
||||||
this.updateExcludeMenuItem();
|
this.updateExcludeMenuItem();
|
||||||
|
this.updateEnrichMenuItem(card);
|
||||||
|
|
||||||
// Update the "Move to other root" label based on current model type
|
// Update the "Move to other root" label based on current model type
|
||||||
const moveOtherItem = this.menu.querySelector('[data-action="move-other"]');
|
const moveOtherItem = this.menu.querySelector('[data-action="move-other"]');
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { BaseContextMenu } from './BaseContextMenu.js';
|
import { BaseContextMenu } from './BaseContextMenu.js';
|
||||||
import { ModelContextMenuMixin } from './ModelContextMenuMixin.js';
|
import { ModelContextMenuMixin } from './ModelContextMenuMixin.js';
|
||||||
import { state } from '../../state/index.js';
|
|
||||||
import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js';
|
import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js';
|
||||||
import { copyLoraSyntax, sendLoraToWorkflow, buildLoraSyntax, showToast } from '../../utils/uiHelpers.js';
|
import { copyLoraSyntax, sendLoraToWorkflow, buildLoraSyntax } from '../../utils/uiHelpers.js';
|
||||||
import { showExcludeModal, showDeleteModal } from '../../utils/modalUtils.js';
|
import { showExcludeModal, showDeleteModal } from '../../utils/modalUtils.js';
|
||||||
import { moveManager } from '../../managers/MoveManager.js';
|
import { moveManager } from '../../managers/MoveManager.js';
|
||||||
|
|
||||||
@@ -27,16 +26,6 @@ export class LoraContextMenu extends BaseContextMenu {
|
|||||||
this.updateEnrichMenuItem(card);
|
this.updateEnrichMenuItem(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEnrichMenuItem(card) {
|
|
||||||
const enrichItem = this.menu?.querySelector('[data-action="enrich-hf-llm"]');
|
|
||||||
if (!enrichItem) return;
|
|
||||||
const hasHfUrl = !!card.dataset.hf_url;
|
|
||||||
enrichItem.classList.toggle('disabled', !hasHfUrl);
|
|
||||||
enrichItem.title = hasHfUrl
|
|
||||||
? ''
|
|
||||||
: 'Link this model to a HuggingFace repo first (Link Model \u2192 Link to HuggingFace)';
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMenuAction(action, menuItem) {
|
handleMenuAction(action, menuItem) {
|
||||||
// First try to handle with common actions
|
// First try to handle with common actions
|
||||||
if (ModelContextMenuMixin.handleCommonMenuActions.call(this, action)) {
|
if (ModelContextMenuMixin.handleCommonMenuActions.call(this, action)) {
|
||||||
@@ -75,9 +64,6 @@ export class LoraContextMenu extends BaseContextMenu {
|
|||||||
case 'refresh-metadata':
|
case 'refresh-metadata':
|
||||||
getModelApiClient().refreshSingleModelMetadata(this.currentCard.dataset.filepath);
|
getModelApiClient().refreshSingleModelMetadata(this.currentCard.dataset.filepath);
|
||||||
break;
|
break;
|
||||||
case 'enrich-hf-llm':
|
|
||||||
this.enrichWithAgent(this.currentCard.dataset.filepath);
|
|
||||||
break;
|
|
||||||
case 'exclude':
|
case 'exclude':
|
||||||
showExcludeModal(this.currentCard.dataset.filepath);
|
showExcludeModal(this.currentCard.dataset.filepath);
|
||||||
break;
|
break;
|
||||||
@@ -87,68 +73,6 @@ export class LoraContextMenu extends BaseContextMenu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async enrichWithAgent(filePath) {
|
|
||||||
const { agentManager } = await import('../../managers/AgentManager.js');
|
|
||||||
|
|
||||||
const configured = await agentManager.isLlmConfigured();
|
|
||||||
if (!configured) {
|
|
||||||
showToast('toast.agent.llmNotConfigured', {}, 'warning');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
agentManager.connect();
|
|
||||||
|
|
||||||
const progressUI = state.loadingManager.showEnhancedProgress(
|
|
||||||
'Enriching metadata with AI...'
|
|
||||||
);
|
|
||||||
|
|
||||||
function cleanupCallbacks() {
|
|
||||||
const pIdx = agentManager.progressCallbacks.indexOf(onProgress);
|
|
||||||
if (pIdx >= 0) agentManager.progressCallbacks.splice(pIdx, 1);
|
|
||||||
const cIdx = agentManager.completeCallbacks.indexOf(onComplete);
|
|
||||||
if (cIdx >= 0) agentManager.completeCallbacks.splice(cIdx, 1);
|
|
||||||
const eIdx = agentManager.errorCallbacks.indexOf(onError);
|
|
||||||
if (eIdx >= 0) agentManager.errorCallbacks.splice(eIdx, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const onProgress = (data) => {
|
|
||||||
if (data.status === 'processing' && data.current_path && data.updated_data && Object.keys(data.updated_data).length > 0) {
|
|
||||||
if (state.virtualScroller?.updateSingleItem) {
|
|
||||||
state.virtualScroller.updateSingleItem(data.current_path, data.updated_data);
|
|
||||||
}
|
|
||||||
const pct = data.total > 0 ? Math.floor((data.processed / data.total) * 100) : 0;
|
|
||||||
const name = data.current_path.split('/').pop();
|
|
||||||
progressUI.updateProgress(pct, name, `Processing ${name}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
agentManager.onProgress(onProgress);
|
|
||||||
|
|
||||||
const onComplete = (data) => {
|
|
||||||
cleanupCallbacks();
|
|
||||||
|
|
||||||
if (data.status === 'completed') {
|
|
||||||
progressUI.complete(data.summary || 'Enrich complete');
|
|
||||||
showToast('toast.agent.enrichComplete', { summary: data.summary || 'Done' }, 'success');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
agentManager.onComplete(onComplete);
|
|
||||||
|
|
||||||
const onError = (data) => {
|
|
||||||
cleanupCallbacks();
|
|
||||||
state.loadingManager.hide();
|
|
||||||
showToast('toast.agent.enrichFailed', { error: data.error || 'Unknown error' }, 'error');
|
|
||||||
};
|
|
||||||
agentManager.onError(onError);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await agentManager.executeSkill('enrich_hf_metadata', [filePath]);
|
|
||||||
} catch (error) {
|
|
||||||
cleanupCallbacks();
|
|
||||||
state.loadingManager.hide();
|
|
||||||
showToast('toast.agent.enrichFailed', { error: error.message }, 'error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sendLoraToWorkflow(replaceMode) {
|
sendLoraToWorkflow(replaceMode) {
|
||||||
const card = this.currentCard;
|
const card = this.currentCard;
|
||||||
const usageTips = JSON.parse(card.dataset.usage_tips || '{}');
|
const usageTips = JSON.parse(card.dataset.usage_tips || '{}');
|
||||||
|
|||||||
@@ -278,6 +278,79 @@ export const ModelContextMenuMixin = {
|
|||||||
setTimeout(() => urlInput.focus(), 50);
|
setTimeout(() => urlInput.focus(), 50);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// HF metadata enrichment (AI agent) methods
|
||||||
|
updateEnrichMenuItem(card) {
|
||||||
|
const enrichItem = this.menu?.querySelector('[data-action="enrich-hf-llm"]');
|
||||||
|
if (!enrichItem) return;
|
||||||
|
const hasHfUrl = !!card.dataset.hf_url;
|
||||||
|
enrichItem.classList.toggle('disabled', !hasHfUrl);
|
||||||
|
enrichItem.title = hasHfUrl
|
||||||
|
? ''
|
||||||
|
: 'Link this model to a HuggingFace repo first (Link Model → Link to HuggingFace)';
|
||||||
|
},
|
||||||
|
|
||||||
|
async enrichWithAgent(filePath) {
|
||||||
|
const { agentManager } = await import('../../managers/AgentManager.js');
|
||||||
|
|
||||||
|
const configured = await agentManager.isLlmConfigured();
|
||||||
|
if (!configured) {
|
||||||
|
showToast('toast.agent.llmNotConfigured', {}, 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
agentManager.connect();
|
||||||
|
|
||||||
|
const progressUI = state.loadingManager.showEnhancedProgress(
|
||||||
|
'Enriching metadata with AI...'
|
||||||
|
);
|
||||||
|
|
||||||
|
function cleanupCallbacks() {
|
||||||
|
const pIdx = agentManager.progressCallbacks.indexOf(onProgress);
|
||||||
|
if (pIdx >= 0) agentManager.progressCallbacks.splice(pIdx, 1);
|
||||||
|
const cIdx = agentManager.completeCallbacks.indexOf(onComplete);
|
||||||
|
if (cIdx >= 0) agentManager.completeCallbacks.splice(cIdx, 1);
|
||||||
|
const eIdx = agentManager.errorCallbacks.indexOf(onError);
|
||||||
|
if (eIdx >= 0) agentManager.errorCallbacks.splice(eIdx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onProgress = (data) => {
|
||||||
|
if (data.status === 'processing' && data.current_path && data.updated_data && Object.keys(data.updated_data).length > 0) {
|
||||||
|
if (state.virtualScroller?.updateSingleItem) {
|
||||||
|
state.virtualScroller.updateSingleItem(data.current_path, data.updated_data);
|
||||||
|
}
|
||||||
|
const pct = data.total > 0 ? Math.floor((data.processed / data.total) * 100) : 0;
|
||||||
|
const name = data.current_path.split('/').pop();
|
||||||
|
progressUI.updateProgress(pct, name, `Processing ${name}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
agentManager.onProgress(onProgress);
|
||||||
|
|
||||||
|
const onComplete = (data) => {
|
||||||
|
cleanupCallbacks();
|
||||||
|
|
||||||
|
if (data.status === 'completed') {
|
||||||
|
progressUI.complete(data.summary || 'Enrich complete');
|
||||||
|
showToast('toast.agent.enrichComplete', { summary: data.summary || 'Done' }, 'success');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
agentManager.onComplete(onComplete);
|
||||||
|
|
||||||
|
const onError = (data) => {
|
||||||
|
cleanupCallbacks();
|
||||||
|
state.loadingManager.hide();
|
||||||
|
showToast('toast.agent.enrichFailed', { error: data.error || 'Unknown error' }, 'error');
|
||||||
|
};
|
||||||
|
agentManager.onError(onError);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await agentManager.executeSkill('enrich_hf_metadata', [filePath]);
|
||||||
|
} catch (error) {
|
||||||
|
cleanupCallbacks();
|
||||||
|
state.loadingManager.hide();
|
||||||
|
showToast('toast.agent.enrichFailed', { error: error.message }, 'error');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
parseModelId(value) {
|
parseModelId(value) {
|
||||||
if (value === undefined || value === null || value === '') {
|
if (value === undefined || value === null || value === '') {
|
||||||
return null;
|
return null;
|
||||||
@@ -388,6 +461,9 @@ export const ModelContextMenuMixin = {
|
|||||||
case 'link-hf':
|
case 'link-hf':
|
||||||
this.showLinkHfModal();
|
this.showLinkHfModal();
|
||||||
return true;
|
return true;
|
||||||
|
case 'enrich-hf-llm':
|
||||||
|
this.enrichWithAgent(this.currentCard.dataset.filepath);
|
||||||
|
return true;
|
||||||
case 'set-nsfw':
|
case 'set-nsfw':
|
||||||
this.showNSFWLevelSelector(null, null, this.currentCard);
|
this.showNSFWLevelSelector(null, null, this.currentCard);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -25,6 +25,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="context-menu-item" data-action="enrich-hf-llm">
|
||||||
|
<i class="fas fa-wand-magic-sparkles"></i> <span>{{ t('loras.contextMenu.enrichHfAgent') }}</span>
|
||||||
|
</div>
|
||||||
<div class="context-menu-separator menu-section-break"></div>
|
<div class="context-menu-separator menu-section-break"></div>
|
||||||
<!-- Workflow -->
|
<!-- Workflow -->
|
||||||
<div class="context-menu-item" data-action="copyname"><i class="fas fa-copy"></i> {{ t('loras.contextMenu.copyFilename') }}</div>
|
<div class="context-menu-item" data-action="copyname"><i class="fas fa-copy"></i> {{ t('loras.contextMenu.copyFilename') }}</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user