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.
278 lines
8.8 KiB
278 lines
8.8 KiB
document.addEventListener("DOMContentLoaded", async function () { |
|
const patternSelector = document.getElementById("patternSelector"); |
|
const modelSelector = document.getElementById("modelSelector"); |
|
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 openaiApiKeyInput = document.getElementById("apiKeyInput"); |
|
const claudeApiKeyInput = document.getElementById("claudeApiKeyInput"); |
|
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", () => { |
|
configSection.classList.remove("hidden"); |
|
}); |
|
copyButton.textContent = "Copy"; |
|
copyButton.id = "copyButton"; |
|
document.addEventListener("click", function (e) { |
|
if (e.target && e.target.id === "copyButton") { |
|
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) { |
|
var tempDiv = document.createElement("div"); |
|
tempDiv.innerHTML = html; |
|
|
|
tempDiv.querySelectorAll("br").forEach((br) => br.replaceWith("\n")); |
|
|
|
tempDiv.querySelectorAll("p, div").forEach((block) => { |
|
block.prepend("\n"); |
|
block.replaceWith(...block.childNodes); |
|
}); |
|
|
|
return tempDiv.textContent.trim(); |
|
} |
|
|
|
async function submitQuery(userInputValue) { |
|
userInput.value = ""; // Clear the input after submitting |
|
const systemCommand = await window.electronAPI.invoke( |
|
"get-pattern-content", |
|
patternSelector.value |
|
); |
|
const selectedModel = modelSelector.value; |
|
responseContainer.innerHTML = ""; // Clear previous responses |
|
if (responseContainer.classList.contains("hidden")) { |
|
responseContainer.classList.remove("hidden"); |
|
responseContainer.appendChild(copyButton); |
|
} |
|
window.electronAPI.send( |
|
"start-query", |
|
systemCommand, |
|
userInputValue, |
|
selectedModel |
|
); |
|
} |
|
|
|
function copyToClipboard() { |
|
const containerClone = responseContainer.cloneNode(true); |
|
const copyButtonClone = containerClone.querySelector("#copyButton"); |
|
if (copyButtonClone) { |
|
copyButtonClone.parentNode.removeChild(copyButtonClone); |
|
} |
|
|
|
const plainText = htmlToPlainText(containerClone.innerHTML); |
|
|
|
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); |
|
} |
|
} |
|
|
|
async function loadModels() { |
|
try { |
|
const models = await window.electronAPI.invoke("get-models"); |
|
modelSelector.innerHTML = ""; // Clear existing options first |
|
models.gptModels.forEach((model) => { |
|
const option = document.createElement("option"); |
|
option.value = model.id; |
|
option.textContent = model.id; |
|
modelSelector.appendChild(option); |
|
}); |
|
models.claudeModels.forEach((model) => { |
|
const option = document.createElement("option"); |
|
option.value = model; |
|
option.textContent = model; |
|
modelSelector.appendChild(option); |
|
}); |
|
models.ollamaModels.forEach((model) => { |
|
const option = document.createElement("option"); |
|
option.value = model; |
|
option.textContent = model; |
|
modelSelector.appendChild(option); |
|
}); |
|
} catch (error) { |
|
console.error("Failed to load models:", error); |
|
} |
|
} |
|
|
|
updatePatternsButton.addEventListener("click", () => { |
|
window.electronAPI.send("update-patterns"); |
|
}); |
|
|
|
// Load patterns and models on startup |
|
loadPatterns(); |
|
loadModels(); |
|
|
|
// Listen for model responses |
|
window.electronAPI.on("model-response", (message) => { |
|
const formattedMessage = message.replace(/\n/g, "<br>"); |
|
responseContainer.innerHTML += formattedMessage; // Append new data as it arrives |
|
}); |
|
|
|
window.electronAPI.on("model-response-end", (message) => { |
|
// Handle the end of the model response if needed |
|
}); |
|
|
|
window.electronAPI.on("model-response-error", (message) => { |
|
alert(message); |
|
}); |
|
|
|
window.electronAPI.on("file-response", (message) => { |
|
if (message.startsWith("Error")) { |
|
alert(message); |
|
return; |
|
} |
|
submitQuery(message); |
|
}); |
|
|
|
window.electronAPI.on; |
|
"reload-app", |
|
() => { |
|
// Reload the app |
|
loadModels(); |
|
location.reload(); |
|
}; |
|
|
|
// 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 openAIKey = openaiApiKeyInput.value; |
|
const claudeKey = claudeApiKeyInput.value; |
|
window.electronAPI |
|
.invoke("save-api-keys", { openAIKey, claudeKey }) |
|
.then(() => { |
|
alert("API Keys saved successfully."); |
|
configSection.classList.add("hidden"); |
|
openaiApiKeyInput.value = ""; |
|
claudeApiKeyInput.value = ""; |
|
// Reload the models |
|
loadModels(); |
|
}) |
|
.catch((err) => { |
|
console.error("Error saving API keys:", err); |
|
alert("Failed to save API Keys."); |
|
}); |
|
}); |
|
|
|
// 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 the model |
|
}); |
|
|
|
// 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"); |
|
} |
|
} |
|
});
|
|
|