598 lines
20 KiB
JavaScript
598 lines
20 KiB
JavaScript
const PROMPT_WIDGET_NAMES = new Set([
|
|
'text',
|
|
'prompt',
|
|
'positive',
|
|
'negative',
|
|
'positive_prompt',
|
|
'negative_prompt',
|
|
'prompt_positive',
|
|
'prompt_negative',
|
|
'text_positive',
|
|
'text_negative',
|
|
'text_a',
|
|
'text_b',
|
|
'text_g',
|
|
'text_l',
|
|
'text_1',
|
|
'text_2',
|
|
]);
|
|
|
|
const PROMPT_NODE_TYPE_PATTERN = /(?:clip.*text|text.*encode|primitive.*string|string.*multiline|text.*multiline|multiline.*text|conditioning.*text|textinput)/i;
|
|
const PROMPT_NODE_TYPE_SCORE_RULES = [
|
|
{ pattern: /(?:clip.*text|text.*encode)/i, score: 500 },
|
|
{ pattern: /conditioning.*text/i, score: 420 },
|
|
{ pattern: /(?:primitive.*string|string.*multiline|text.*multiline|multiline.*text|textinput)/i, score: 320 },
|
|
];
|
|
const SCALAR_WIDGET_TYPES = new Set(['STRING', 'INT', 'FLOAT', 'BOOLEAN']);
|
|
const PROMPT_INPUT_NAMES = new Set(['text', 'prompt', 'text_input', 'string']);
|
|
const TEXT_WIDGET_TYPES = new Set(['STRING', 'TEXT']);
|
|
const NON_TEXT_WIDGET_TYPES = new Set([
|
|
'BOOLEAN',
|
|
'COMBO',
|
|
'DROPDOWN',
|
|
'ENUM',
|
|
'FLOAT',
|
|
'INT',
|
|
'LIST',
|
|
'NUMBER',
|
|
'SELECT',
|
|
'SLIDER',
|
|
]);
|
|
const NON_PROMPT_WIDGET_NAME_PATTERN = /^(?:after_generate|batch(?:_size)?|cfg|control_after_generate|counter|denoise|extension|filename(?:_prefix)?|folder|format|height|list|mode|output(?:_name|_path)?|path|prefix|sampler|scheduler|seed|steps|suffix|width)$/i;
|
|
|
|
function normalizePromptName(value) {
|
|
return String(value ?? '')
|
|
.trim()
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, '_')
|
|
.replace(/^_+|_+$/g, '');
|
|
}
|
|
|
|
function getInputName(input = {}) {
|
|
return String(
|
|
input?.name
|
|
|| input?.widget_name
|
|
|| input?.widgetName
|
|
|| input?.widget?.name
|
|
|| input?.widget?.widget
|
|
|| ''
|
|
).trim();
|
|
}
|
|
|
|
function getRoleFromLabel(value) {
|
|
const token = normalizePromptName(value);
|
|
if (!token) return '';
|
|
|
|
const parts = new Set(token.split('_').filter(Boolean));
|
|
if (parts.has('negative') || parts.has('neg') || parts.has('uncond') || parts.has('unconditional')) {
|
|
return 'negative';
|
|
}
|
|
if (parts.has('positive') || parts.has('pos') || parts.has('cond') || parts.has('conditional')) {
|
|
return 'positive';
|
|
}
|
|
return '';
|
|
}
|
|
|
|
function isPromptInputName(value) {
|
|
const token = normalizePromptName(value);
|
|
return PROMPT_WIDGET_NAMES.has(token)
|
|
|| PROMPT_INPUT_NAMES.has(token)
|
|
|| token.includes('prompt')
|
|
|| token.startsWith('text_')
|
|
|| token.endsWith('_text');
|
|
}
|
|
|
|
function isWidgetInput(input = {}) {
|
|
if (!input || typeof input !== 'object') return false;
|
|
if (
|
|
input.widget !== undefined
|
|
|| input.widget_name !== undefined
|
|
|| input.widgetName !== undefined
|
|
|| input.isWidget === true
|
|
) return true;
|
|
|
|
const type = String(input.type || '').trim().toUpperCase();
|
|
return input.link == null && SCALAR_WIDGET_TYPES.has(type);
|
|
}
|
|
|
|
function getWidgetInputs(node = {}) {
|
|
const inputs = Array.isArray(node.inputs) ? node.inputs : [];
|
|
return inputs.filter(isWidgetInput);
|
|
}
|
|
|
|
function getWidgetNames(node = {}, valueCount = 0) {
|
|
const names = Array.from({ length: valueCount }, () => '');
|
|
const setName = (index, value) => {
|
|
if (index < 0 || index >= names.length || names[index]) return;
|
|
const name = getInputName(value);
|
|
if (name) names[index] = name;
|
|
};
|
|
|
|
const widgets = Array.isArray(node.widgets) ? node.widgets : [];
|
|
widgets.forEach((widget, index) => setName(index, widget));
|
|
|
|
const widgetInputs = getWidgetInputs(node);
|
|
widgetInputs.forEach((input, index) => setName(index, input));
|
|
|
|
const scalarInputs = (Array.isArray(node.inputs) ? node.inputs : [])
|
|
.filter(input => input && input.link == null && (
|
|
isWidgetInput(input)
|
|
|| SCALAR_WIDGET_TYPES.has(String(input.type || '').trim().toUpperCase())
|
|
));
|
|
scalarInputs.forEach((input, index) => setName(index, input));
|
|
|
|
return names;
|
|
}
|
|
|
|
function getWidgetInput(node = {}, widgetIndex = -1, widgetName = '') {
|
|
const inputs = Array.isArray(node.inputs) ? node.inputs : [];
|
|
const normalizedName = normalizePromptName(widgetName);
|
|
if (normalizedName) {
|
|
const named = inputs.find(input => normalizePromptName(getInputName(input)) === normalizedName);
|
|
if (named) return named;
|
|
}
|
|
|
|
const widgetInputs = getWidgetInputs(node);
|
|
return widgetInputs[widgetIndex]
|
|
|| inputs.filter(input => input && input.link == null)[widgetIndex]
|
|
|| null;
|
|
}
|
|
|
|
function getWidgetDescriptors(node = {}) {
|
|
const values = Array.isArray(node.widgets_values) ? node.widgets_values : [];
|
|
const names = getWidgetNames(node, values.length);
|
|
const widgets = Array.isArray(node.widgets) ? node.widgets : [];
|
|
const namedValues = node.widgets_values_named && typeof node.widgets_values_named === 'object'
|
|
? node.widgets_values_named
|
|
: {};
|
|
|
|
return Array.from({ length: values.length }, (_, index) => {
|
|
const value = values[index];
|
|
const name = names[index] || '';
|
|
const namedValue = name && Object.prototype.hasOwnProperty.call(namedValues, name)
|
|
? namedValues[name]
|
|
: value;
|
|
return {
|
|
index,
|
|
name,
|
|
value: namedValue,
|
|
input: getWidgetInput(node, index, name),
|
|
widget: widgets[index] || null,
|
|
};
|
|
});
|
|
}
|
|
|
|
function collectWorkflowNodeEntries(workflow = {}) {
|
|
const entries = [];
|
|
if (!workflow || typeof workflow !== 'object') return entries;
|
|
|
|
const appendNodes = (nodes, {
|
|
graphKey,
|
|
isTopLevel,
|
|
subgraphId = '',
|
|
subgraphName = '',
|
|
}) => {
|
|
if (!Array.isArray(nodes)) return;
|
|
for (const node of nodes) {
|
|
if (!node || typeof node !== 'object' || node.id == null) continue;
|
|
entries.push({
|
|
node,
|
|
graphKey,
|
|
isTopLevel,
|
|
subgraphId,
|
|
subgraphName,
|
|
nodeKey: `${graphKey}:${String(node.id)}`,
|
|
});
|
|
}
|
|
};
|
|
|
|
appendNodes(workflow.nodes, { graphKey: 'top', isTopLevel: true });
|
|
const subgraphs = workflow.definitions?.subgraphs;
|
|
if (Array.isArray(subgraphs)) {
|
|
subgraphs.forEach((subgraph, index) => {
|
|
if (!subgraph || typeof subgraph !== 'object') return;
|
|
const subgraphId = String(subgraph.id ?? `index-${index}`);
|
|
appendNodes(subgraph.nodes, {
|
|
graphKey: `sub:${subgraphId}`,
|
|
isTopLevel: false,
|
|
subgraphId,
|
|
subgraphName: String(subgraph.name || subgraph.title || '').trim(),
|
|
});
|
|
});
|
|
}
|
|
|
|
return entries;
|
|
}
|
|
|
|
function getOutputLinks(node = {}) {
|
|
const links = [];
|
|
for (const output of Array.isArray(node.outputs) ? node.outputs : []) {
|
|
const values = Array.isArray(output?.links)
|
|
? output.links
|
|
: output?.link != null
|
|
? [output.link]
|
|
: [];
|
|
for (const link of values) {
|
|
if (link != null && link !== '') links.push(String(link));
|
|
}
|
|
}
|
|
return links;
|
|
}
|
|
|
|
function getSerializedLinkSource(link) {
|
|
const values = Array.isArray(link)
|
|
? link
|
|
: [
|
|
link?.id ?? link?.link_id,
|
|
link?.origin_id ?? link?.originId ?? link?.source_id ?? link?.sourceId,
|
|
];
|
|
const linkId = values[0];
|
|
const originNodeId = values[1];
|
|
if (linkId == null || linkId === '' || originNodeId == null || originNodeId === '') return null;
|
|
return { linkId: String(linkId), originNodeId: String(originNodeId) };
|
|
}
|
|
|
|
function buildGraphConnections(entries, workflow = {}) {
|
|
const sourcesByLink = new Map();
|
|
for (const entry of entries) {
|
|
for (const link of getOutputLinks(entry.node)) {
|
|
sourcesByLink.set(`${entry.graphKey}:${link}`, entry.nodeKey);
|
|
}
|
|
}
|
|
|
|
const entriesByNodeKey = new Map(entries.map(entry => [entry.nodeKey, entry]));
|
|
const addSerializedLinks = (links, graphKey) => {
|
|
for (const link of Array.isArray(links) ? links : []) {
|
|
const serialized = getSerializedLinkSource(link);
|
|
if (!serialized) continue;
|
|
const sourceNodeKey = `${graphKey}:${serialized.originNodeId}`;
|
|
if (!entriesByNodeKey.has(sourceNodeKey)) continue;
|
|
const linkKey = `${graphKey}:${serialized.linkId}`;
|
|
if (!sourcesByLink.has(linkKey)) sourcesByLink.set(linkKey, sourceNodeKey);
|
|
}
|
|
};
|
|
|
|
addSerializedLinks(workflow.links, 'top');
|
|
const subgraphs = Array.isArray(workflow.definitions?.subgraphs)
|
|
? workflow.definitions.subgraphs
|
|
: [];
|
|
for (const [index, subgraph] of subgraphs.entries()) {
|
|
if (!subgraph || typeof subgraph !== 'object') continue;
|
|
const subgraphId = String(subgraph.id ?? `index-${index}`);
|
|
addSerializedLinks(subgraph.links, `sub:${subgraphId}`);
|
|
}
|
|
|
|
return { sourcesByLink };
|
|
}
|
|
|
|
function resolveRole(roleCandidates) {
|
|
const candidates = Array.from(new Set(roleCandidates)).filter(Boolean);
|
|
return {
|
|
role: candidates.length === 1 ? candidates[0] : 'unknown',
|
|
roleCandidates: candidates,
|
|
};
|
|
}
|
|
|
|
function getNodeRoleCandidates(entry) {
|
|
const node = entry.node;
|
|
const candidates = [];
|
|
for (const label of [
|
|
node.title,
|
|
node.name,
|
|
node.properties?.['Node name for S&R'],
|
|
node.properties?.node_name,
|
|
node.properties?.nodeName,
|
|
node.type,
|
|
]) {
|
|
const role = getRoleFromLabel(label);
|
|
if (role) candidates.push(role);
|
|
}
|
|
|
|
return candidates;
|
|
}
|
|
|
|
function isDedicatedTextNode(node = {}) {
|
|
const nodeType = String(node.type || node.comfyClass || '').trim();
|
|
return PROMPT_NODE_TYPE_PATTERN.test(nodeType);
|
|
}
|
|
|
|
function isPromptPathInput(entry, input = {}) {
|
|
const name = normalizePromptName(getInputName(input));
|
|
const type = normalizeWidgetType(input.type);
|
|
if (!name && !type) return false;
|
|
if (NON_PROMPT_WIDGET_NAME_PATTERN.test(name)) return false;
|
|
if (
|
|
type === 'INT'
|
|
|| type === 'FLOAT'
|
|
|| type === 'BOOLEAN'
|
|
|| type === 'COMBO'
|
|
|| type === 'DROPDOWN'
|
|
|| type === 'ENUM'
|
|
|| type === 'LIST'
|
|
|| type === 'NUMBER'
|
|
|| type === 'SELECT'
|
|
|| type === 'SLIDER'
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
return Boolean(
|
|
getRoleFromLabel(name)
|
|
|| isPromptInputName(name)
|
|
|| name.includes('conditioning')
|
|
|| type === 'STRING'
|
|
|| type === 'TEXT'
|
|
|| type.includes('STRING')
|
|
|| type.includes('TEXT')
|
|
|| type.includes('CONDITIONING')
|
|
|| (isDedicatedTextNode(entry.node) && Boolean(name))
|
|
);
|
|
}
|
|
|
|
function addRoleCandidate(roleCandidatesByNodeKey, nodeKey, role) {
|
|
if (!role) return;
|
|
const candidates = roleCandidatesByNodeKey.get(nodeKey) || [];
|
|
if (!candidates.includes(role)) candidates.push(role);
|
|
roleCandidatesByNodeKey.set(nodeKey, candidates);
|
|
}
|
|
|
|
function buildRoleCandidatesFromGraph(entries, sourcesByLink) {
|
|
const roleCandidatesByNodeKey = new Map();
|
|
for (const entry of entries) {
|
|
roleCandidatesByNodeKey.set(entry.nodeKey, getNodeRoleCandidates(entry));
|
|
}
|
|
|
|
const entriesByNodeKey = new Map(entries.map(entry => [entry.nodeKey, entry]));
|
|
const visitUpstream = (startEntry, role) => {
|
|
const queue = [startEntry];
|
|
const visited = new Set();
|
|
while (queue.length) {
|
|
const entry = queue.shift();
|
|
if (!entry || visited.has(entry.nodeKey)) continue;
|
|
visited.add(entry.nodeKey);
|
|
addRoleCandidate(roleCandidatesByNodeKey, entry.nodeKey, role);
|
|
|
|
for (const input of Array.isArray(entry.node.inputs) ? entry.node.inputs : []) {
|
|
if (input?.link == null || input.link === '' || !isPromptPathInput(entry, input)) continue;
|
|
const sourceNodeKey = sourcesByLink.get(`${entry.graphKey}:${String(input.link)}`);
|
|
const sourceEntry = entriesByNodeKey.get(sourceNodeKey);
|
|
if (sourceEntry && !visited.has(sourceEntry.nodeKey)) queue.push(sourceEntry);
|
|
}
|
|
}
|
|
};
|
|
|
|
for (const entry of entries) {
|
|
for (const input of Array.isArray(entry.node.inputs) ? entry.node.inputs : []) {
|
|
const role = getRoleFromLabel(getInputName(input));
|
|
if (!role || input?.link == null || input.link === '') continue;
|
|
const sourceNodeKey = sourcesByLink.get(`${entry.graphKey}:${String(input.link)}`);
|
|
const sourceEntry = entriesByNodeKey.get(sourceNodeKey);
|
|
if (sourceEntry) visitUpstream(sourceEntry, role);
|
|
}
|
|
}
|
|
|
|
return roleCandidatesByNodeKey;
|
|
}
|
|
|
|
function normalizeWidgetType(value) {
|
|
const rawValue = Array.isArray(value) ? value[0] : value;
|
|
return String(rawValue ?? '')
|
|
.trim()
|
|
.toUpperCase()
|
|
.replace(/[^A-Z0-9]+/g, '_');
|
|
}
|
|
|
|
function getDescriptorWidgetType(descriptor = {}) {
|
|
return normalizeWidgetType(
|
|
descriptor.input?.type
|
|
|| descriptor.widget?.type
|
|
|| descriptor.input?.widget?.type
|
|
|| descriptor.input?.widget?.widget_type
|
|
|| descriptor.input?.widget?.widgetType
|
|
);
|
|
}
|
|
|
|
function hasWidgetChoices(descriptor = {}) {
|
|
return [descriptor.input, descriptor.widget, descriptor.input?.widget]
|
|
.some(source => Array.isArray(source?.options) && source.options.length > 0);
|
|
}
|
|
|
|
function isNonTextWidgetType(type) {
|
|
return NON_TEXT_WIDGET_TYPES.has(type)
|
|
|| type.includes('COMBO')
|
|
|| type.includes('DROPDOWN')
|
|
|| type.includes('ENUM')
|
|
|| type.includes('LIST')
|
|
|| type.includes('SELECT')
|
|
|| type.includes('SLIDER');
|
|
}
|
|
|
|
function isTextLikeDescriptor(descriptor = {}) {
|
|
const type = getDescriptorWidgetType(descriptor);
|
|
return TEXT_WIDGET_TYPES.has(type)
|
|
|| type.includes('STRING')
|
|
|| type.includes('TEXT');
|
|
}
|
|
|
|
function isPromptTextDescriptor(descriptor = {}, { node = {}, hasGraphPromptRole = false } = {}) {
|
|
const name = normalizePromptName(descriptor.name);
|
|
const type = getDescriptorWidgetType(descriptor);
|
|
const hasExplicitPromptName = Boolean(
|
|
getRoleFromLabel(descriptor.name)
|
|
|| PROMPT_WIDGET_NAMES.has(name)
|
|
|| PROMPT_INPUT_NAMES.has(name)
|
|
|| name.includes('prompt')
|
|
|| name.startsWith('text_')
|
|
|| name.endsWith('_text')
|
|
);
|
|
if (isNonTextWidgetType(type) || hasWidgetChoices(descriptor)) return false;
|
|
if (NON_PROMPT_WIDGET_NAME_PATTERN.test(name)) return false;
|
|
|
|
return hasExplicitPromptName
|
|
|| (isTextLikeDescriptor(descriptor) && (
|
|
isDedicatedTextNode(node)
|
|
|| hasGraphPromptRole
|
|
));
|
|
}
|
|
|
|
function getPromptLabelScore(value, role = '') {
|
|
const label = String(value ?? '').trim();
|
|
const token = normalizePromptName(label);
|
|
if (!token) return 0;
|
|
|
|
let score = 0;
|
|
if (role && getRoleFromLabel(label) === role) score += 180;
|
|
if (token.includes('prompt')) score += 110;
|
|
if (token === 'text' || token.includes('text')) score += 35;
|
|
return score;
|
|
}
|
|
|
|
function getPromptNodeTypeScore(value) {
|
|
const nodeType = String(value ?? '').trim();
|
|
return PROMPT_NODE_TYPE_SCORE_RULES.find(rule => rule.pattern.test(nodeType))?.score || 0;
|
|
}
|
|
|
|
export function getPromptCandidateScore(prompt = {}, role = '') {
|
|
const requestedRole = String(role || '').trim();
|
|
const roleCandidates = Array.isArray(prompt.role_candidates)
|
|
? prompt.role_candidates
|
|
: [];
|
|
let score = 0;
|
|
|
|
if (requestedRole && prompt.role === requestedRole) score += 1000;
|
|
else if (requestedRole && roleCandidates.includes(requestedRole)) score += 650;
|
|
|
|
score += getPromptNodeTypeScore(prompt.node_type);
|
|
score += getPromptLabelScore(prompt.node_title, requestedRole);
|
|
score += getPromptLabelScore(prompt.widget_name, requestedRole);
|
|
return score;
|
|
}
|
|
|
|
export function sortPromptCandidates(prompts = [], role = '') {
|
|
if (!Array.isArray(prompts)) return [];
|
|
|
|
return prompts
|
|
.map((prompt, index) => ({
|
|
prompt,
|
|
index,
|
|
score: getPromptCandidateScore(prompt, role),
|
|
}))
|
|
.sort((left, right) => right.score - left.score || left.index - right.index)
|
|
.map(({ prompt }) => prompt);
|
|
}
|
|
|
|
function promptIdentity(entry, descriptor) {
|
|
return `${entry.graphKey}:${String(entry.node.id)}:${descriptor.index}:${normalizePromptName(descriptor.name)}`;
|
|
}
|
|
|
|
function findWorkflowNodeForPrompt(workflow = {}, prompt = {}) {
|
|
const nodeId = String(prompt.node_id ?? '');
|
|
if (!nodeId) return null;
|
|
|
|
if (prompt.is_top_level !== false) {
|
|
return (workflow.nodes || []).find(node => String(node?.id) === nodeId) || null;
|
|
}
|
|
|
|
const subgraphId = String(prompt.subgraph_id || '');
|
|
const subgraphs = Array.isArray(workflow.definitions?.subgraphs)
|
|
? workflow.definitions.subgraphs
|
|
: [];
|
|
return subgraphs
|
|
.find(subgraph => String(subgraph?.id ?? '') === subgraphId)
|
|
?.nodes?.find(node => String(node?.id) === nodeId) || null;
|
|
}
|
|
|
|
export function extractWorkflowPrompts(workflow = {}) {
|
|
const entries = collectWorkflowNodeEntries(workflow);
|
|
if (!entries.length) return [];
|
|
|
|
const { sourcesByLink } = buildGraphConnections(entries, workflow);
|
|
const roleCandidatesByNodeKey = buildRoleCandidatesFromGraph(entries, sourcesByLink);
|
|
|
|
const prompts = [];
|
|
for (const entry of entries) {
|
|
const node = entry.node;
|
|
const descriptors = getWidgetDescriptors(node);
|
|
const nodeRoleCandidates = roleCandidatesByNodeKey.get(entry.nodeKey) || [];
|
|
const stringDescriptorCount = descriptors.filter(descriptor => (
|
|
descriptor && typeof descriptor.value === 'string'
|
|
)).length;
|
|
|
|
for (const descriptor of descriptors) {
|
|
if (!descriptor || typeof descriptor.value !== 'string') continue;
|
|
const text = descriptor.value;
|
|
|
|
const isUnnamedTextFallback = !descriptor.name
|
|
&& !descriptor.input
|
|
&& stringDescriptorCount === 1
|
|
&& (isDedicatedTextNode(node) || nodeRoleCandidates.length === 1);
|
|
const candidate = Boolean(
|
|
isPromptTextDescriptor(descriptor, {
|
|
node,
|
|
hasGraphPromptRole: nodeRoleCandidates.length > 0,
|
|
})
|
|
|| isUnnamedTextFallback
|
|
);
|
|
if (!candidate) continue;
|
|
|
|
const combinedRole = resolveRole([
|
|
...nodeRoleCandidates,
|
|
getRoleFromLabel(descriptor.name),
|
|
]);
|
|
const widgetInput = descriptor.input || getWidgetInput(node, descriptor.index, descriptor.name);
|
|
prompts.push({
|
|
id: promptIdentity(entry, descriptor),
|
|
node_id: node.id,
|
|
node_type: String(node.type || node.comfyClass || '').trim(),
|
|
node_title: String(node.title || '').trim(),
|
|
widget_index: descriptor.index,
|
|
widget_name: descriptor.name,
|
|
text,
|
|
role: combinedRole.role,
|
|
role_candidates: combinedRole.roleCandidates,
|
|
is_top_level: entry.isTopLevel,
|
|
subgraph_id: entry.subgraphId,
|
|
subgraph_name: entry.subgraphName,
|
|
linked: Boolean(
|
|
widgetInput
|
|
&& widgetInput.link != null
|
|
&& widgetInput.link !== ''
|
|
),
|
|
});
|
|
}
|
|
}
|
|
|
|
return prompts;
|
|
}
|
|
|
|
export function updateWorkflowPromptValue(workflow, prompt = {}, value = '') {
|
|
if (!workflow || !prompt || prompt.linked) return false;
|
|
|
|
const node = findWorkflowNodeForPrompt(workflow, prompt);
|
|
const widgetIndex = Number(prompt.widget_index);
|
|
if (!node || !Array.isArray(node.widgets_values) || !Number.isInteger(widgetIndex) || widgetIndex < 0) {
|
|
return false;
|
|
}
|
|
|
|
const widgetInput = getWidgetInput(node, widgetIndex, prompt.widget_name);
|
|
if (widgetInput && widgetInput.link != null && widgetInput.link !== '') return false;
|
|
|
|
const nextValue = String(value ?? '');
|
|
node.widgets_values[widgetIndex] = nextValue;
|
|
if (
|
|
prompt.widget_name
|
|
&& node.widgets_values_named
|
|
&& typeof node.widgets_values_named === 'object'
|
|
&& Object.prototype.hasOwnProperty.call(node.widgets_values_named, prompt.widget_name)
|
|
) {
|
|
node.widgets_values_named[prompt.widget_name] = nextValue;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
export function getPromptRoleLabel(role) {
|
|
if (role === 'positive') return 'Positive prompt';
|
|
if (role === 'negative') return 'Negative prompt';
|
|
return 'Unclassified prompt';
|
|
}
|