fabric is an open-source framework for augmenting humans using AI. It provides a modular framework for solving specific problems using a crowdsourced set of AI prompts that can be used anywhere.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
8.8 KiB

9 months ago
document.addEventListener("DOMContentLoaded", async function () {
const patternSelector = document.getElementById("patternSelector");
const userInput = document.getElementById("userInput");
const submitButton = document.getElementById("submit");
const responseContainer = document.getElementById("responseContainer");
const themeChanger = document.getElementById("themeChanger");
const configButton = document.getElementById("configButton");
const configSection = document.getElementById("configSection");
const saveApiKeyButton = document.getElementById("saveApiKey");
const apiKeyInput = document.getElementById("apiKeyInput");
const originalPlaceholder = userInput.placeholder;
const updatePatternsButton = document.getElementById("updatePatternsButton");
const copyButton = document.createElement("button");
window.electronAPI.on("patterns-ready", () => {
console.log("Patterns are ready. Refreshing the pattern list.");
loadPatterns();
});
window.electronAPI.on("request-api-key", () => {
// Show the API key input section or modal to the user
configSection.classList.remove("hidden"); // Assuming 'configSection' is your API key input area
});
copyButton.textContent = "Copy";
copyButton.id = "copyButton";
document.addEventListener("click", function (e) {
if (e.target && e.target.id === "copyButton") {
// Your copy to clipboard function
copyToClipboard();
}
});
window.electronAPI.on("no-api-key", () => {
alert("API key is missing. Please enter your OpenAI API key.");
});
window.electronAPI.on("patterns-updated", () => {
alert("Patterns updated. Refreshing the pattern list.");
loadPatterns();
});
function htmlToPlainText(html) {
// Create a temporary div element to hold the HTML
var tempDiv = document.createElement("div");
tempDiv.innerHTML = html;
// Replace <br> tags with newline characters
tempDiv.querySelectorAll("br").forEach((br) => br.replaceWith("\n"));
// Replace block elements like <p> and <div> with newline characters
tempDiv.querySelectorAll("p, div").forEach((block) => {
block.prepend("\n"); // Add a newline before the block element's content
block.replaceWith(...block.childNodes); // Replace the block element with its own contents
});
// Return the text content, trimming leading and trailing newlines
return tempDiv.textContent.trim();
}
async function submitQuery(userInputValue) {
userInput.value = ""; // Clear the input after submitting
systemCommand = await window.electronAPI.invoke(
"get-pattern-content",
patternSelector.value
);
responseContainer.innerHTML = ""; // Clear previous responses
if (responseContainer.classList.contains("hidden")) {
console.log("contains hidden");
responseContainer.classList.remove("hidden");
responseContainer.appendChild(copyButton);
}
window.electronAPI.send(
"start-query-openai",
systemCommand,
userInputValue
);
}
function copyToClipboard() {
const containerClone = responseContainer.cloneNode(true);
// Remove the copy button from the clone
const copyButtonClone = containerClone.querySelector("#copyButton");
if (copyButtonClone) {
copyButtonClone.parentNode.removeChild(copyButtonClone);
}
// Convert HTML to plain text, preserving newlines
const plainText = htmlToPlainText(containerClone.innerHTML);
// Use a temporary textarea for copying
const textArea = document.createElement("textarea");
textArea.style.position = "absolute";
textArea.style.left = "-9999px";
textArea.setAttribute("aria-hidden", "true");
textArea.value = plainText;
document.body.appendChild(textArea);
textArea.select();
try {
document.execCommand("copy");
console.log("Text successfully copied to clipboard");
} catch (err) {
console.error("Failed to copy text: ", err);
}
document.body.removeChild(textArea);
}
async function loadPatterns() {
try {
const patterns = await window.electronAPI.invoke("get-patterns");
patternSelector.innerHTML = ""; // Clear existing options first
patterns.forEach((pattern) => {
const option = document.createElement("option");
option.value = pattern;
option.textContent = pattern;
patternSelector.appendChild(option);
});
} catch (error) {
console.error("Failed to load patterns:", error);
}
}
function fallbackCopyTextToClipboard(text) {
const textArea = document.createElement("textarea");
textArea.value = text;
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
const successful = document.execCommand("copy");
const msg = successful ? "successful" : "unsuccessful";
console.log("Fallback: Copying text command was " + msg);
} catch (err) {
console.error("Fallback: Oops, unable to copy", err);
}
document.body.removeChild(textArea);
}
updatePatternsButton.addEventListener("click", () => {
window.electronAPI.send("update-patterns");
});
// Load patterns on startup
try {
const patterns = await window.electronAPI.invoke("get-patterns");
patterns.forEach((pattern) => {
const option = document.createElement("option");
option.value = pattern;
option.textContent = pattern;
patternSelector.appendChild(option);
});
} catch (error) {
console.error("Failed to load patterns:", error);
}
// Listen for OpenAI responses
window.electronAPI.on("openai-response", (message) => {
const formattedMessage = message.replace(/\n/g, "<br>");
responseContainer.innerHTML += formattedMessage; // Append new data as it arrives
});
window.electronAPI.on("file-response", (message) => {
if (message.startsWith("Error")) {
alert(message);
return;
}
submitQuery(message);
});
// Submit button click handler
submitButton.addEventListener("click", async () => {
const userInputValue = userInput.value;
submitQuery(userInputValue);
});
// Theme changer click handler
themeChanger.addEventListener("click", function (e) {
e.preventDefault();
document.body.classList.toggle("light-theme");
themeChanger.innerText =
themeChanger.innerText === "Dark" ? "Light" : "Dark";
});
// Config button click handler - toggles the config section visibility
configButton.addEventListener("click", function (e) {
e.preventDefault();
configSection.classList.toggle("hidden");
});
// Save API Key button click handler
saveApiKeyButton.addEventListener("click", () => {
const apiKey = apiKeyInput.value;
window.electronAPI
.invoke("save-api-key", apiKey)
.then(() => {
alert("API Key saved successfully.");
// Optionally hide the config section and clear the input after saving
configSection.classList.add("hidden");
apiKeyInput.value = "";
})
.catch((err) => {
console.error("Error saving API key:", err);
alert("Failed to save API Key.");
});
});
// Handler for pattern selection change
patternSelector.addEventListener("change", async () => {
const selectedPattern = patternSelector.value;
const systemCommand = await window.electronAPI.invoke(
"get-pattern-content",
selectedPattern
);
// Use systemCommand as part of the input for querying OpenAI
});
// drag and drop
userInput.addEventListener("dragover", (event) => {
event.stopPropagation();
event.preventDefault();
// Add some visual feedback
userInput.classList.add("drag-over");
userInput.placeholder = "Drop file here";
});
userInput.addEventListener("dragleave", (event) => {
event.stopPropagation();
event.preventDefault();
// Remove visual feedback
userInput.classList.remove("drag-over");
userInput.placeholder = originalPlaceholder;
});
userInput.addEventListener("drop", (event) => {
event.stopPropagation();
event.preventDefault();
const file = event.dataTransfer.files[0];
userInput.classList.remove("drag-over");
userInput.placeholder = originalPlaceholder;
processFile(file);
});
function processFile(file) {
const fileType = file.type;
const reader = new FileReader();
let content = "";
reader.onload = (event) => {
content = event.target.result;
userInput.value = content;
submitQuery(content);
};
if (fileType === "text/plain" || fileType === "image/svg+xml") {
reader.readAsText(file);
} else if (
fileType === "application/pdf" ||
fileType.match(/wordprocessingml/)
) {
// For PDF and DOCX, we need to handle them in the main process due to complexity
window.electronAPI.send("process-complex-file", file.path);
} else {
console.error("Unsupported file type");
}
}
});