Files
nathannlu-ComfyUI-Cloud/js/chatbot/ext.js
T

276 lines
9.6 KiB
JavaScript

// 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);