feat(embedding): send embedding to workflow + fix copy button format

- Fix copy button on embedding cards to copy 'embedding:folder/name' format
- Add send-embedding-to-workflow for Prompt (LoraManager), Text (LoraManager),
  and CLIPTextEncode nodes, appending embedding code to text content
- Extend workflow registry to register text-capable nodes by comfyClass
  (not generic widget name 'text') to avoid false matches
- Add mode parameter to update_node_widget API/event for append support
- Fix single/bulk context menus: single shows plain 'Send to Workflow',
  bulk collapses submenu into direct action for embeddings (append-only)
This commit is contained in:
Will Miao
2026-06-11 22:41:42 +08:00
parent 84e9fe2dfb
commit d87863b423
9 changed files with 201 additions and 20 deletions

View File

@@ -1,4 +1,4 @@
import { showToast, openCivitai, copyToClipboard, copyLoraSyntax, sendLoraToWorkflow, openExampleImagesFolder, buildLoraSyntax, sendModelPathToWorkflow } from '../../utils/uiHelpers.js';
import { showToast, openCivitai, copyToClipboard, copyLoraSyntax, sendLoraToWorkflow, sendEmbeddingToWorkflow, openExampleImagesFolder, buildLoraSyntax, sendModelPathToWorkflow } from '../../utils/uiHelpers.js';
import { state, getCurrentPageState } from '../../state/index.js';
import { showModelModal } from './ModelModal.js';
import { toggleShowcase } from './showcase/ShowcaseView.js';
@@ -216,6 +216,11 @@ function handleSendToWorkflow(card, replaceMode, modelType) {
missingNodesMessage,
missingTargetMessage,
});
} else if (modelType === MODEL_TYPES.EMBEDDING) {
const folder = card.dataset.folder || '';
const name = card.dataset.file_name || '';
const embeddingCode = folder ? `embedding:${folder}/${name}` : `embedding:${name}`;
sendEmbeddingToWorkflow(embeddingCode, false);
} else {
showToast('modelCard.sendToWorkflow.checkpointNotImplemented', {}, 'info');
}
@@ -230,8 +235,11 @@ function handleCopyAction(card, modelType) {
const message = translate('modelCard.actions.checkpointNameCopied', {}, 'Checkpoint name copied');
copyToClipboard(checkpointName, message);
} else if (modelType === MODEL_TYPES.EMBEDDING) {
const embeddingName = card.dataset.file_name;
copyToClipboard(embeddingName, 'Embedding name copied');
const folder = card.dataset.folder || '';
const name = card.dataset.file_name || '';
const embeddingCode = folder ? `embedding:${folder}/${name}` : `embedding:${name}`;
const message = translate('modelCard.actions.embeddingNameCopied', {}, 'Embedding syntax copied');
copyToClipboard(embeddingCode, message);
}
}

View File

@@ -1,4 +1,4 @@
import { showToast, openCivitai, sendLoraToWorkflow, sendModelPathToWorkflow, buildLoraSyntax } from '../../utils/uiHelpers.js';
import { showToast, openCivitai, sendLoraToWorkflow, sendEmbeddingToWorkflow, sendModelPathToWorkflow, buildLoraSyntax } from '../../utils/uiHelpers.js';
import { modalManager } from '../../managers/ModalManager.js';
import { MODEL_TYPES } from '../../api/apiConfig.js';
import {
@@ -648,6 +648,10 @@ export async function showModelModal(model, modelType) {
if (modelType === 'checkpoints' && modelWithFullData.sub_type) {
activeModalElement.dataset.subType = modelWithFullData.sub_type;
}
// Store folder for embedding models
if (modelType === 'embeddings' && modelWithFullData.folder) {
activeModalElement.dataset.folder = modelWithFullData.folder;
}
}
updateVersionsTabBadge(updateAvailabilityState.hasUpdateAvailable);
const versionsTabController = initVersionsTab({
@@ -1188,9 +1192,10 @@ async function handleSendToWorkflow(target, modelType) {
missingTargetMessage,
});
} else if (modelType === 'embeddings') {
// For Embedding: Send as LoRA syntax (embedding name only)
const embeddingSyntax = `<embed:${currentFileName}:1>`;
await sendLoraToWorkflow(embeddingSyntax, false, 'embedding');
const folder = modalElement?.dataset?.folder || '';
const name = currentFileName.replace(/\.[^.]+$/, '');
const embeddingCode = folder ? `embedding:${folder}/${name}` : `embedding:${name}`;
await sendEmbeddingToWorkflow(embeddingCode, false);
}
}