Merge pull request #29 from nathannlu/vindennt/chatbot

Vindennt/chatbot
This commit is contained in:
Nathan
2024-07-19 23:25:25 -07:00
committed by GitHub
5 changed files with 859 additions and 27 deletions
+31
View File
@@ -0,0 +1,31 @@
import { nimbus } from "../resource/index.js";
export async function getBotResponse(message) {
try {
const data = await nimbus.chatbot.sendMessage({
message: message,
origin: "ComfyUI Cloud Chat",
});
return data;
} catch (e) {
throw new Error(e.message);
}
}
export function isValidWorkflow(workflow) {
return workflow && workflow.nodes && workflow.edges;
}
export function parseWorkflowFromBot(response) {
const cleanedResponse = response.responses.bot
.replace(/^\s*```json\s*/, "")
.replace(/\s*```\s*$/, "");
try {
return JSON.parse(cleanedResponse);
} catch (error) {
console.error("Failed to parse JSON:", error);
return cleanedResponse;
}
}
+406
View File
@@ -0,0 +1,406 @@
/* eslint-disable no-unused-vars */
export function getInputType(name) {
const nameTypeMap = {
LATENT: "LATENT",
MODEL: "MODEL",
CLIP: "CLIP",
VAE: "VAE",
CONDITIONING: "CONDITIONING",
IMAGE: "IMAGE",
MASK: "MASK",
CLIP_VISION_OUTPUT: "CLIP_VISION_OUTPUT",
positive: "CONDITIONING",
negative: "CONDITIONING",
CONTROL_NET: "CONTROL_NET",
STYLE_MODEL: "STYLE_MODEL",
CLIP_VISION: "CLIP_VISION",
GLIGEN: "GLIGEN",
latent: "LATENT",
UPSCALE_MODEL: "UPSCALE_MODEL",
output: "LATENT",
denoised_output: "LATENT",
SIGMAS: "SIGMAS",
SAMPLER: "SAMPLER",
high_sigmas: "SIGMAS",
low_sigmas: "SIGMAS",
GUIDER: "GUIDER",
NOISE: "NOISE",
PHOTOMAKER: "PHOTOMAKER",
stage_c: "LATENT",
stage_b: "LATENT",
controlnet_input: "IMAGE",
STRING: "STRING",
"*": "*",
INT: "INT",
FLOAT: "FLOAT",
BLIP_MODEL: "BLIP_MODEL",
bus: "BUS",
model: "MODEL",
clip: "CLIP",
vae: "VAE",
latent_filename: "STRING",
latent_image: "LATENT",
image_filename: "STRING",
conditioning_filename: "STRING",
NAME_STRING: "STRING",
conditioning: "CONDITIONING",
parsed_text: "STRING",
raw_text: "STRING",
NUMBER: "NUMBER",
image_a_pass: "IMAGE",
image_b_pass: "IMAGE",
filepath_text: "STRING",
filename_text: "STRING",
MASK_IMAGE: "IMAGE",
clipseg_model: "CLIPSEG_MODEL",
IMAGES_BATCH: "IMAGE",
MASKS_BATCH: "MASK",
MASK_IMAGES_BATCH: "IMAGE",
IMAGES: "IMAGE",
DICT: "DICT",
BOOLEAN: "BOOLEAN",
composited_images: "IMAGE",
ssao_images: "IMAGE",
specular_mask_images: "IMAGE",
ssdo_images: "IMAGE",
ssdo_image_masks: "IMAGE",
light_source_image_masks: "IMAGE",
aspect_number: "NUMBER",
aspect_float: "FLOAT",
is_landscape_bool: "NUMBER",
aspect_ratio_common: "STRING",
aspect_type: "STRING",
image: "IMAGE",
images: "IMAGE",
color_palettes: "LIST",
CROP_DATA: "CROP_DATA",
mask: "MASK",
shadow_map: "IMAGE",
highlight_map: "IMAGE",
width_num: "NUMBER",
height_num: "NUMBER",
width_float: "FLOAT",
height_float: "FLOAT",
width_int: "INT",
height_int: "INT",
MASKS: "MASK",
INT_PLACES: "INT",
"latent(s)": "LATENT",
tensor_w_num: "NUMBER",
tensor_h_num: "NUMBER",
masks: "MASK",
cropped_mask: "MASK",
crop_data: "CROP_DATA",
top_int: "INT",
left_int: "INT",
right_int: "INT",
bottom_int: "INT",
midas_model: "MIDAS_MODEL",
number: "NUMBER",
float: "FLOAT",
int: "INT",
SEED: "SEED",
positive_string: "STRING",
negative_string: "STRING",
seed: "SEED",
SAM_MODEL: "SAM_MODEL",
SAM_PARAMETERS: "SAM_PARAMETERS",
samples: "LATENT",
IMAGE_BOUNDS: "IMAGE_BOUNDS",
LIST: "LIST",
TEXT_A_PASS: "STRING",
TEXT_B_PASS: "STRING",
SCORE_NUMBER: "NUMBER",
COMPARISON_TEXT: "STRING",
result_text: "STRING",
replacement_count_number: "NUMBER",
replacement_count_float: "FLOAT",
replacement_count_int: "INT",
f: "B",
o: "O",
u: "O",
n: "L",
d: "E",
line_text: "STRING",
dictionary: "DICT",
MODEL_NAME_TEXT: "STRING",
image_pass: "IMAGE",
IMAGE_PASS: "IMAGE",
output_path: "STRING",
processed_count: "NUMBER",
BBOX_DETECTOR: "BBOX_DETECTOR",
SEGS: "SEGS",
cropped: "IMAGE",
cropped_refined: "IMAGE",
cropped_refined_alpha: "IMAGE",
cnet_images: "IMAGE",
segs: "SEGS",
basic_pipe: "BASIC_PIPE",
combined_mask: "MASK",
batch_masks: "MASK",
cropped_enhanced_alpha: "IMAGE",
detailer_pipe: "DETAILER_PIPE",
refiner_basic_pipe_opt: "BASIC_PIPE",
bbox_detector: "BBOX_DETECTOR",
sam_model_opt: "SAM_MODEL",
segm_detector_opt: "SEGM_DETECTOR",
detailer_hook: "DETAILER_HOOK",
refiner_model: "MODEL",
refiner_clip: "CLIP",
refiner_positive: "CONDITIONING",
refiner_negative: "CONDITIONING",
base_basic_pipe: "BASIC_PIPE",
refiner_basic_pipe: "BASIC_PIPE",
UPSCALER: "UPSCALER",
PK_HOOK: "PK_HOOK",
DETAILER_HOOK: "DETAILER_HOOK",
UPSCALER_HOOK: "UPSCALER_HOOK",
SEGS_HEADER: "SEGS_HEADER",
SEG_ELT: "SEG_ELT",
seg_elt: "SEG_ELT",
cropped_image: "IMAGE",
crop_region: "SEG_ELT_crop_region",
bbox: "SEG_ELT_bbox",
control_net_wrapper: "SEG_ELT_control_net_wrapper",
confidence: "FLOAT",
label: "STRING",
left: "INT",
top: "INT",
right: "INT",
bottom: "INT",
KSAMPLER: "KSAMPLER",
KSAMPLER_ADVANCED: "KSAMPLER_ADVANCED",
selected_value: "*",
selected_label: "STRING",
selected_index: "INT",
output1: "*",
populated_text: "STRING",
BASIC_PIPE: "BASIC_PIPE",
REGIONAL_PROMPTS: "REGIONAL_PROMPTS",
filtered_SEGS: "SEGS",
remained_SEGS: "SEGS",
signal_opt: "*",
bool: "BOOLEAN",
signal: "*",
batch: "INT",
height: "INT",
width: "INT",
channel: "INT",
wildcard: "STRING",
segs_labels: "STRING",
count: "INT",
total: "INT",
value: "*",
TRANSFORMERS_CLASSIFIER: "TRANSFORMERS_CLASSIFIER",
scheduler: [
"normal",
"karras",
"exponential",
"sgm_uniform",
"simple",
"ddim_uniform",
],
SEGM_DETECTOR: "SEGM_DETECTOR",
TIMESTEP_KF: "TIMESTEP_KEYFRAME",
LATENT_KF: "LATENT_KEYFRAME",
model_opt: "MODEL",
CN_WEIGHTS: "CONTROL_NET_WEIGHTS",
TK_SHORTCUT: "TIMESTEP_KEYFRAME",
proc_IMAGE: "IMAGE",
SPARSE_METHOD: "SPARSE_METHOD",
cn_extras: "CN_WEIGHTS_EXTRAS",
"ABG_CHARACTER_MASK (MASK)": "MASK",
POSE_KEYPOINT: "POSE_KEYPOINT",
tracking: "TRACKING",
prompt: "STRING",
OPTICAL_FLOW: "OPTICAL_FLOW",
PREVIEW_IMAGE: "IMAGE",
INPAINTING_MASK: "MASK",
preprocessor: [
"none",
"TilePreprocessor",
"TTPlanet_TileGF_Preprocessor",
"TTPlanet_TileSimple_Preprocessor",
"AnimeFace_SemSegPreprocessor",
"BinaryPreprocessor",
"Zoe-DepthMapPreprocessor",
"ColorPreprocessor",
"DepthAnythingPreprocessor",
"Zoe_DepthAnythingPreprocessor",
"DensePosePreprocessor",
"OneFormer-COCO-SemSegPreprocessor",
"OneFormer-ADE20K-SemSegPreprocessor",
"M-LSDPreprocessor",
"AnyLineArtPreprocessor_aux",
"DWPreprocessor",
"AnimalPosePreprocessor",
"DSINE-NormalMapPreprocessor",
"MediaPipe-FaceMeshPreprocessor",
"LineArtPreprocessor",
"MiDaS-NormalMapPreprocessor",
"MiDaS-DepthMapPreprocessor",
"CannyEdgePreprocessor",
"ShufflePreprocessor",
"Metric3D-DepthMapPreprocessor",
"Metric3D-NormalMapPreprocessor",
"AnimeLineArtPreprocessor",
"SAMPreprocessor",
"HEDPreprocessor",
"FakeScribblePreprocessor",
"ScribblePreprocessor",
"Scribble_XDoG_Preprocessor",
"Scribble_PiDiNet_Preprocessor",
"DiffusionEdge_Preprocessor",
"SavePoseKpsAsJsonFile",
"FacialPartColoringFromPoseKps",
"UpperBodyTrackingFromPoseKps",
"PiDiNetPreprocessor",
"OpenposePreprocessor",
"LeReS-DepthMapPreprocessor",
"Unimatch_OptFlowPreprocessor",
"MaskOptFlow",
"ImageLuminanceDetector",
"ImageIntensityDetector",
"UniFormer-SemSegPreprocessor",
"SemSegPreprocessor",
"MeshGraphormer-DepthMapPreprocessor",
"MeshGraphormer+ImpactDetector-DepthMapPreprocessor",
"Manga2Anime_LineArt_Preprocessor",
"BAE-NormalMapPreprocessor",
"TEEDPreprocessor",
"LineartStandardPreprocessor",
],
"RESOLUTION (INT)": "INT",
"IMAGE_GEN_WIDTH (INT)": "INT",
"IMAGE_GEN_HEIGHT (INT)": "INT",
"Full prompt": "STRING",
"Short prompt": "STRING",
"Compiled prompt": "CONDITIONING",
Value: "STRING",
Value2: "STRING",
mix: "INT",
Filenames: "VHS_FILENAMES",
frame_count: "INT",
audio: "VHS_AUDIO",
video_info: "VHS_VIDEOINFO",
meta_batch: "VHS_BatchManager",
"source_fps🟨": "FLOAT",
"source_frame_count🟨": "INT",
"source_duration🟨": "FLOAT",
"source_width🟨": "INT",
"source_height🟨": "INT",
"loaded_fps🟦": "FLOAT",
"loaded_frame_count🟦": "INT",
"loaded_duration🟦": "FLOAT",
"loaded_width🟦": "INT",
"loaded_height🟦": "INT",
"fps🟨": "FLOAT",
"frame_count🟨": "INT",
"duration🟨": "FLOAT",
"width🟨": "INT",
"height🟨": "INT",
"fps🟦": "FLOAT",
"frame_count🟦": "INT",
"duration🟦": "FLOAT",
"width🟦": "INT",
"height🟦": "INT",
LATENT_A: "LATENT",
A_count: "INT",
LATENT_B: "LATENT",
B_count: "INT",
IMAGE_A: "IMAGE",
IMAGE_B: "IMAGE",
MASK_A: "MASK",
MASK_B: "MASK",
modelname: "STRING",
sampler_name: [
"euler",
"euler_ancestral",
"heun",
"heunpp2",
"dpm_2",
"dpm_2_ancestral",
"lms",
"dpm_fast",
"dpm_adaptive",
"dpmpp_2s_ancestral",
"dpmpp_sde",
"dpmpp_sde_gpu",
"dpmpp_2m",
"dpmpp_2m_sde",
"dpmpp_2m_sde_gpu",
"dpmpp_3m_sde",
"dpmpp_3m_sde_gpu",
"ddpm",
"lcm",
"ddim",
"uni_pc",
"uni_pc_bh2",
],
scheduler_name: "STRING",
s: "STRING",
x: "INT",
y: "INT",
REMBG_SESSION: "REMBG_SESSION",
red: "MASK",
green: "MASK",
blue: "MASK",
cyan: "MASK",
magenta: "MASK",
yellow: "MASK",
black: "MASK",
white: "MASK",
CLIP_SEG: "CLIP_SEG",
description: "STRING",
response: "STRING",
context: "STRING",
};
const matchName = nameTypeMap[name];
if (matchName) {
return matchName;
} else {
console.log("not matching name, will return unknown: ", name);
return "XXX UNKNOWN INPUT TYPE XXX";
}
}
// originally was in in file that imported app
function scanNodeInputOutput() {
const nameTypeMap = new Map();
function updateNameTypeMap(input, output) {
const maxLength = Math.min(input.length, output.length);
for (let i = 0; i < maxLength; i++) {
const inputName = input[i];
const outputName = output[i];
// Add to nameTypeMap if inputName is not already present
if (!nameTypeMap.has(inputName)) {
nameTypeMap[inputName] = outputName;
}
}
}
console.log(LiteGraph.registered_node_types);
if (LiteGraph.registered_node_types) {
// Get the first node in the list
for (const [key, nodeType] of Object.entries(
LiteGraph.registered_node_types
)) {
console.log(key);
if (nodeType.nodeData?.output !== undefined) {
updateNameTypeMap(
nodeType.nodeData.output_name,
nodeType.nodeData.output
);
}
}
console.log(JSON.stringify(nameTypeMap));
} else {
console.log("No registered nodes found.");
}
return nameTypeMap;
}
+275
View File
@@ -0,0 +1,275 @@
// import { api, app } from './comfy/comfy.js'
import { app } from "../comfy/comfy.js";
import {
getBotResponse,
isValidWorkflow,
parseWorkflowFromBot,
} from "./chatbot.js";
import { loadGraphFromPrompt } from "./workflow.js";
import { setButtonDefault } from "../button/ui.js";
import { authDialog } from "../auth/index.js";
import { getApiToken } from "../utils.js";
const CHAT_BUTTON_ID = "chat-button";
const CHAT_BOX_ID = "chat-box";
const CHAT_INPUT_ID = "chat-input";
const CHAT_MESSAGES_ID = "chat-messages";
const CHAT_SEND_BUTTON_ID = "chat-send-button";
const apiToken = getApiToken();
const doesApiTokenExist = !!apiToken;
let canSendMessage = true;
const toggleChatBox = async () => {
const chatBox = document.getElementById(CHAT_BOX_ID);
if (chatBox.style.display === "none") {
chatBox.style.display = "block";
} else {
chatBox.style.display = "none";
}
};
const createChatButton = () => {
const chatButton = document.createElement("div");
chatButton.id = CHAT_BUTTON_ID;
// Set up the button styles and gradient background
chatButton.style.position = "fixed";
chatButton.style.bottom = "0";
chatButton.style.right = "0";
chatButton.style.margin = "20px";
chatButton.style.background = "linear-gradient(160deg, #8A2BE2, #1E90FF)"; // Gradient background
chatButton.style.color = "white";
chatButton.style.borderRadius = "50%";
chatButton.style.width = "60px";
chatButton.style.height = "60px";
chatButton.style.zIndex = 9999;
chatButton.style.display = "flex";
chatButton.style.alignItems = "center";
chatButton.style.justifyContent = "center";
chatButton.style.cursor = "pointer";
// Create and append SVG chat bubble icon
const chatIcon = document.createElementNS(
"http://www.w3.org/2000/svg",
"svg"
);
chatIcon.setAttribute("viewBox", "0 0 512 512");
chatIcon.setAttribute("width", "20"); // Adjust size as needed
chatIcon.setAttribute("height", "20"); // Adjust size as needed
chatIcon.setAttribute("fill", "currentColor"); // Use current text color
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute(
"d",
"M416,0H96C43.072,0,0,43.072,0,96v405.333c0,4.48,2.816,8.491,7.04,10.027c1.195,0.427,2.411,0.64,3.627,0.64c3.115,0,6.123-1.344,8.192-3.84L122.325,384H416c52.928,0,96-43.072,96-96V96C512,43.072,468.928,0,416,0z"
);
chatIcon.appendChild(path);
chatButton.appendChild(chatIcon);
return chatButton;
};
const createChatBox = () => {
const chatBox = document.createElement("div");
chatBox.id = CHAT_BOX_ID;
chatBox.style.position = "fixed";
chatBox.style.bottom = "100px";
chatBox.style.right = "0";
chatBox.style.backgroundColor = "white";
chatBox.style.width = "300px";
chatBox.style.height = "500px";
chatBox.style.zIndex = 9999;
chatBox.style.borderRadius = "10px";
chatBox.style.display = "none"; // Initially hidden
// Messages section
const chatMessages = document.createElement("div");
chatMessages.id = CHAT_MESSAGES_ID;
chatMessages.style.height = "80%";
chatMessages.style.overflowY = "auto";
chatMessages.style.padding = "10px";
chatMessages.style.color = "black";
chatBox.appendChild(chatMessages);
// Input section
const chatInputContainer = document.createElement("div");
chatInputContainer.style.position = "absolute";
chatInputContainer.style.bottom = "0";
chatInputContainer.style.width = "100%";
chatInputContainer.style.padding = "10px";
chatInputContainer.style.boxSizing = "border-box";
chatInputContainer.style.backgroundColor = "#f1f1f1";
chatInputContainer.style.borderBottomLeftRadius = "10px";
chatInputContainer.style.borderBottomRightRadius = "10px";
// Flexbox layout for horizontal alignment
chatInputContainer.style.display = "flex";
chatInputContainer.style.alignItems = "center";
// Input field
const chatInput = document.createElement("input");
chatInput.id = CHAT_INPUT_ID;
chatInput.type = "text";
chatInput.style.flex = "1"; // Allow the input to grow and take up available space
chatInput.style.padding = "10px";
chatInput.style.boxSizing = "border-box";
chatInput.style.border = "1px solid #ccc";
chatInput.style.borderRadius = "4px";
chatInput.placeholder = "Describe your desired workflow...";
// Send button
const chatSendButton = document.createElement("button");
chatSendButton.id = CHAT_SEND_BUTTON_ID;
chatSendButton.style.width = "40px";
chatSendButton.style.height = "40px";
chatSendButton.style.marginLeft = "10px";
chatSendButton.style.padding = "0"; // Remove default padding
chatSendButton.style.border = "none";
chatSendButton.style.backgroundColor = "#007acc";
chatSendButton.style.color = "white";
chatSendButton.style.cursor = "pointer";
chatSendButton.style.borderRadius = "50%";
chatSendButton.style.display = "flex";
chatSendButton.style.alignItems = "center";
chatSendButton.style.justifyContent = "center";
// Create and style the SVG icon
const sendIcon = document.createElementNS(
"http://www.w3.org/2000/svg",
"svg"
);
sendIcon.setAttribute("fill", "#ffffff"); // Use white color for the icon
sendIcon.setAttribute("viewBox", "0 0 52 52");
sendIcon.setAttribute("enable-background", "new 0 0 52 52");
sendIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
sendIcon.setAttribute("class", "send-icon");
sendIcon.setAttribute("xml:space", "preserve");
sendIcon.setAttribute("width", "18px"); // Adjust size as needed
sendIcon.setAttribute("height", "18px"); // Adjust size as needed
// Create the path element for the SVG
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute(
"d",
"M2.1,44.5l4.4-16.3h18.6c0.5,0,1-0.5,1-1v-2c0-0.5-0.5-1-1-1H6.5l-4.3-16l0,0C2.1,8,2,7.7,2,7.4C2,6.7,2.7,6,3.5,6.1c0.2,0,0.3,0.1,0.5,0.1l0,0l0,0l0,0l0,0l45,18.5c0.6,0.2,1,0.8,1,1.4s-0.4,1.1-0.9,1.3l0,0L4,46.4l0,0c-0.2,0.1-0.4,0.1-0.6,0.1C2.6,46.4,2,45.8,2,45C2,44.8,2,44.7,2.1,44.5L2.1,44.5z"
);
sendIcon.appendChild(path);
// Append SVG to button
chatSendButton.appendChild(sendIcon);
// Add event listener
chatSendButton.addEventListener("click", sendMessage);
// Append input and button to container
chatInputContainer.appendChild(chatInput);
chatInputContainer.appendChild(chatSendButton);
chatBox.appendChild(chatInputContainer);
return chatBox;
};
const updateMessageBoxStatus = (canSendMessage) => {
const button = document.getElementById(CHAT_SEND_BUTTON_ID);
if (button) {
button.style.backgroundColor = canSendMessage ? "#007acc" : "#cccccc"; // Change color based on `isActive`
}
const input = document.getElementById(CHAT_INPUT_ID);
if (input) {
input.placeholder = canSendMessage ? "Describe your desired workflow..." : "Generating workflow...";
input.disabled = !canSendMessage;
}
};
const sendMessage = async () => {
if (!doesApiTokenExist) {
toggleChatBox();
setButtonDefault();
return authDialog.show();
}
const chatInput = document.getElementById(CHAT_INPUT_ID);
const chatMessages = document.getElementById(CHAT_MESSAGES_ID);
const message = chatInput.value.trim();
if (message) {
if (!canSendMessage) {
return;
} else {
canSendMessage = false;
updateMessageBoxStatus(canSendMessage);
}
const messageElement = document.createElement("div");
messageElement.innerText = message;
messageElement.style.marginBottom = "10px";
messageElement.style.padding = "10px";
messageElement.style.backgroundColor = "#A7DBFD";
messageElement.style.borderRadius = "4px";
chatMessages.appendChild(messageElement);
chatMessages.scrollTop = chatMessages.scrollHeight; // Scroll to the bottom
chatInput.value = "";
try {
const response = await getBotResponse(message);
let botMessage = "";
const parsedBotResponse = parseWorkflowFromBot(response);
if (isValidWorkflow(parsedBotResponse)) {
botMessage = JSON.stringify(parsedBotResponse);
} else {
botMessage = response.responses.bot;
}
const botMessageElement = document.createElement("div");
botMessageElement.innerText = botMessage;
botMessageElement.style.marginBottom = "10px";
botMessageElement.style.padding = "10px";
botMessageElement.style.backgroundColor = "#DFE8EE";
botMessageElement.style.borderRadius = "4px";
botMessageElement.style.wordWrap = "break-word"; // Wrap long words
botMessageElement.style.overflow = "hidden"; // Hide overflow text
botMessageElement.style.textOverflow = "ellipsis"; // Show ellipsis if text overflows
// Optionally, set a max-width if you want to control the width of the message box
botMessageElement.style.maxWidth = "calc(100% - 20px)"; // Adjust max-width based on container width and padding
chatMessages.appendChild(botMessageElement);
chatMessages.scrollTop = chatMessages.scrollHeight; // Scroll to the bottom
loadGraphFromPrompt(parsedBotResponse);
} catch (error) {
console.error(error);
} finally {
canSendMessage = true;
updateMessageBoxStatus(canSendMessage);
}
}
};
const registerChat = () => {
// With js, append an bottom that opens up a chatbox in the bottom right hand corner
const chatButton = createChatButton();
const chatBox = createChatBox();
document.body.appendChild(chatBox);
document.body.appendChild(chatButton);
chatButton.addEventListener("click", toggleChatBox);
};
/** @typedef {import('../../../web/types/comfy.js').ComfyExtension} ComfyExtension*/
/** @type {ComfyExtension} */
const ext = {
name: "nathannlu.ComfyUI-Chat",
// ComfyUI extension init
init() {
registerChat();
},
};
app.registerExtension(ext);
+116
View File
@@ -0,0 +1,116 @@
import { app } from "../comfy/comfy.js";
import { getInputType } from "./edgeTypes.js";
function getInputIndex(node, inputName) {
return node.inputs.findIndex(
(input) => input.name === getInputType(inputName)
);
}
// translates chatgpt input to immediately loadable graph format
function transformInputToGraph(input) {
const baseGraph = {
last_node_id: input.nodes.length,
last_link_id: input.edges.length,
nodes: [],
links: [],
groups: [],
config: {},
extra: {},
version: 0.4,
};
const xStep = 300; // step for node positions
const yStep = 300; // step for node positions
const yBase = 100; // base y position
const nodesById = {}; // pointer of nodes by id for easier/faster search
let x = 100; // starting x post
let y = yBase; // starting y post
let columnCounter = 0; // counter for columns
// Create nodes with positions in order
input.nodes.forEach((node, index) => {
const newNode = {
id: node.id,
type: node.class_type,
pos: [x, y],
size: [200, 50], // TODO: write a function to get the node's actual height for better placement
flags: {},
order: index,
mode: 0,
inputs: [],
outputs: [],
properties: {},
widgets_values: node.widget_values ? Object.values(node.widget_values) : []
};
baseGraph.nodes.push(newNode);
nodesById[node.id] = newNode;
if (columnCounter % 3 === 0) {
x += xStep;
y = yBase;
} else {
// y += newNode.size[1] + yStep;
y += yStep;
}
columnCounter++;
});
// Insert edges
input.edges.forEach((edgeData, index) => {
const fromNode = nodesById[edgeData.from];
const toNode = nodesById[edgeData.to];
// Adding output to fromNode
let outputIndex = edgeData.from_output;
// add inputs
let inputIndex = getInputIndex(toNode, edgeData.to_input);
// if input doesnt already exist
if (inputIndex < 0) {
toNode.inputs.push({
name: edgeData.to_input,
type: getInputType(edgeData.to_input),
link: index + 1,
});
}
// add outputs
fromNode.outputs.push({
name: getInputType(edgeData.to_input),
// name: edgeData.input,
type: getInputType(edgeData.to_input),
links: [],
slot_index: fromNode.outputs.length,
});
outputIndex = fromNode.outputs.length - 1;
inputIndex = fromNode.inputs.length - 1;
// add links
const link = [
index + 1, // Link id
fromNode.id, // Origin node id
edgeData.from_output,
// getOutputIndex(fromNode, edgeData.to_input), // origin index
toNode.id, // Destination node id
getInputIndex(toNode, edgeData.to_input), // destination index
getInputType(edgeData.to_input),
];
fromNode.outputs[outputIndex].links.push(link[0]);
baseGraph.links.push(link);
});
return baseGraph;
}
export function loadGraphFromPrompt(generatedWorkflow) {
const translatedData = transformInputToGraph(generatedWorkflow);
app.loadGraphData(translatedData, true);
app.graph.change();
}
+31 -27
View File
@@ -17,14 +17,14 @@ const workflowRun = {
retrieveOutput: {
method: "GET",
path: "/workflow/{workflow_id}/runs/{run_id}/outputs",
}
}
},
};
const workflow = {
// upload local
init: {
method: "POST",
path: "/workflow/init"
path: "/workflow/init",
},
create: {
method: "POST",
@@ -40,71 +40,75 @@ const workflow = {
},
error: {
method: "POST",
path: "/workflow/error"
}
}
path: "/workflow/error",
},
};
const billing = {
retrieveCustomerSession: {
method: "GET",
path: "/stripe/get-customer-session"
path: "/stripe/get-customer-session",
},
retrieveUsage: {
method: "GET",
path: "/stripe/usage"
path: "/stripe/usage",
},
retrieveCredits: {
method: "GET",
path: "/stripe/credits"
path: "/stripe/credits",
},
}
};
const auth = {
register: {
method: "POST",
path: "/auth/register"
path: "/auth/register",
},
login: {
method: "POST",
path: "/auth/login"
}
}
path: "/auth/login",
},
};
const support = {
feedback: {
method: "POST",
path: "/support/feedback"
path: "/support/feedback",
},
support: {
method: "POST",
path: "/support/support"
path: "/support/support",
},
docs: {
method: "POST",
path: "/support/docs"
path: "/support/docs",
},
tooltipHover: {
method: "POST",
path: "/support/tooltipHover"
path: "/support/tooltipHover",
},
tooltipDocs: {
method: "POST",
path: "/support/tooltipDocs"
path: "/support/tooltipDocs",
},
assistant: {
method: "POST",
path: "/support/assistant"
}
}
path: "/support/assistant",
},
};
const chatbot = {
sendMessage: {
method: "POST",
path: "/chat/send-message",
},
};
export const apiEndpoints = {
workflowRun,
workflow,
billing,
auth,
support
}
support,
chatbot
};